Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/dev/probe_typstink.mjs

4.6 KiB, 1 run

created by r2519314175:97, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1// probe_typstink.mjs — photograph what the live view really draws.
2//
3// Three faults were reported together: ghosted/double-struck glyphs on all body
4// text, solid black bars where the contents entries belong, and filled black boxes
5// over inline `#link` spans. This drives the shipped path — the Doc panel's Compile
6// button, which is what arms the live view — and photographs the pages, then counts
7// what is in the shadow root and what colour the browser has resolved for it.
8//
9// It asserts nothing and is not a verifier.
10//
11// eval "$(bash dev/world.sh 5 --env)"
12// node dev/probe_typstink.mjs
13import fs from 'node:fs';
14import { open, scratch } from './harness.mjs';
15
16const WORK = scratch('typstink');
17fs.mkdirSync(WORK, { recursive: true });
18
19const DOC = `#set page(width: 400pt, height: 300pt, margin: 24pt)
20#set text(size: 11pt)
21= A heading
22#outline()
23Some ordinary body text, long enough to wrap onto a second line so that a
24double-struck run would be obvious to anybody looking at it.
25
26Created using #link("https://typst.app")[Typst] and #link("https://rust-lang.org")[Rust].
27== Another heading
28More text under it.
29`;
30
31const s = await open({ name: 'typstink' });
32const p = s.page;
33await p.setViewportSize({ width: 1600, height: 1000 });
34await p.waitForTimeout(1200);
35await p.evaluate(async (src) => {
36 const m = await import('/pkg/oxedyne_daimond.js');
37 m.set_locked_packs('');
38 await m.write_file('inkprobe/main.typ', src);
39}, DOC);
40await p.evaluate(() => window.DaimondDoc.show('inkprobe/main.typ'));
41await p.waitForTimeout(1200);
42await p.click('[data-act="compile"]', { force: true });
43for (let i = 0; i < 120; i++) {
44 const st = await p.evaluate(() => window.DaimondTypstWatch.state());
45 if (st.drawn) break;
46 await new Promise(r => setTimeout(r, 500));
47}
48await p.waitForTimeout(1200);
49
50const seen = await p.evaluate(() => {
51 const h = document.getElementById('typst-live');
52 const sr = h.querySelector('.tl-pages').shadowRoot;
53 const tsel = sr.querySelectorAll('.tsel');
54 const link = sr.querySelectorAll('.pseudo-link');
55 const glyph = sr.querySelectorAll('.outline_glyph');
56 const cs = (el) => el ? getComputedStyle(el) : null;
57 const a = cs(tsel[0]), b = cs(link[0]);
58 return {
59 state: window.DaimondTypstWatch.state(),
60 styles: sr.querySelectorAll('style').length,
61 styleText: Array.from(sr.querySelectorAll('style')).map(s => s.textContent.length),
62 tsel: tsel.length, link: link.length, glyph: glyph.length,
63 tselColour: a ? a.color : null,
64 tselSize: a ? a.fontSize : null,
65 tselBox: tsel[0] ? JSON.stringify(tsel[0].getBoundingClientRect()) : null,
66 linkFill: b ? b.getAttribute ? getComputedStyle(link[0]).fill : null : null,
67 linkBox: link[0] ? JSON.stringify(link[0].getBoundingClientRect()) : null,
68 onclicks: sr.querySelectorAll('[onclick]').length,
69 };
70});
71console.log(JSON.stringify(seen, null, 1));
72
73// ── And the settings the view now offers ───────────────────────
74const set = await p.evaluate(() => {
75 const w = window.DaimondTypstWatch;
76 const bar = document.querySelector('#typst-live .tl-bar');
77 return { bar: bar ? bar.textContent.replace(/\s+/g, ' ').trim() : null,
78 buttons: Array.from(bar.querySelectorAll('button')).map(b => b.textContent + '|' + b.title),
79 state: (({ zoom, dark, pages }) => ({ zoom, dark, pages }))(w.state()) };
80});
81console.log('bar: ' + JSON.stringify(set, null, 1));
82await p.evaluate(() => { window.DaimondTypstWatch.dark(true); window.DaimondTypstWatch.zoom(1.5); });
83await p.waitForTimeout(600);
84const nightBox = await p.evaluate(() => {
85 const r = document.querySelector('#typst-live .tl-scroll').getBoundingClientRect();
86 return { x: r.x, y: r.y, width: r.width, height: r.height,
87 state: window.DaimondTypstWatch.state() };
88});
89await p.screenshot({ path: `${WORK}/night.png`, clip: {
90 x: Math.floor(nightBox.x), y: Math.floor(nightBox.y),
91 width: Math.floor(nightBox.width), height: Math.floor(Math.min(nightBox.height, 500)) } });
92console.log(`night+zoom: zoom ${nightBox.state.zoom}, dark ${nightBox.state.dark}, `
93 + `at page ${nightBox.state.at ? nightBox.state.at.page + 1 : '?'}`);
94await p.evaluate(() => { window.DaimondTypstWatch.dark(false); window.DaimondTypstWatch.zoom(1); });
95await p.waitForTimeout(400);
96
97const box = await p.evaluate(() => {
98 const r = document.querySelector('#typst-live .tl-scroll').getBoundingClientRect();
99 return { x: r.x, y: r.y, width: r.width, height: r.height };
100});
101await p.screenshot({ path: `${WORK}/live.png`, clip: {
102 x: Math.floor(box.x), y: Math.floor(box.y),
103 width: Math.floor(box.width), height: Math.floor(Math.min(box.height, 700)) } });
104console.log('wrote ' + WORK + '/live.png');
105await s.close();