Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/dev/shot_triage_panel.mjs

4.8 KiB, 1 run

created by r2519314175:201, 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// dev/shot_triage_panel.mjs — the Notes view with a real plan on it, photographed
2// at a desktop dock width and at an iPhone width.
3//
4// The plan is put up through `DaimondTriage.hold`, so this pays for no turn and
5// draws exactly what a run would have drawn. The notes are the owner's own
6// eighteen and the plan is the one a real model wrote from them.
7//
8// eval "$(bash dev/world.sh N --env)"
9// node dev/shot_triage_panel.mjs
10
11import fs from 'node:fs';
12import path from 'node:path';
13import { fileURLToPath } from 'node:url';
14import { open, scratch } from './harness.mjs';
15
16const HERE = path.dirname(fileURLToPath(import.meta.url));
17const NOTES = JSON.parse(fs.readFileSync(path.join(HERE, 'fixtures', 'triage_notes_18.json'), 'utf8')).notes;
18const PLAN = fs.readFileSync(path.join(HERE, 'fixtures', 'triage_plan_18.json'), 'utf8');
19const OUT = process.env.TRG_SHOT_DIR || path.join(HERE, 'shots');
20const TAG = process.argv[2] || 'now';
21
22const profile = scratch('pw', 'trgshot-' + process.pid);
23const s = await open({ name: 'trgshot' + process.pid, profile });
24const p = s.page;
25
26await p.evaluate((notes) => {
27 const key = Object.keys(localStorage).find((k) => k.indexOf('daimond-improve') !== -1)
28 || 'daimond-improve';
29 localStorage.setItem(key, JSON.stringify({ v: 3, notes }));
30 if (window.DaimondImprove) window.DaimondImprove.reset();
31}, NOTES);
32await p.evaluate(() => { window.DaimondPanels.show('social'); });
33await p.waitForTimeout(400);
34await p.evaluate(() => { if (window.DaimondImprove) window.DaimondImprove.onOpen(); });
35await p.waitForTimeout(800);
36const held = await p.evaluate((t) => !!window.DaimondTriage.hold(t), PLAN);
37console.log('plan held:', held, '· notes:', await p.evaluate(() => window.DaimondImprove.notes().length));
38
39fs.mkdirSync(OUT, { recursive: true });
40
41/// Photograph the panel, not the window: the evidence is the ink.
42///
43/// In two crops, because the whole panel is five thousand pixels tall and a
44/// picture scaled to fit one screen shows nothing about a border. The head crop
45/// is the control row and the first drafts -- `trg-row`, `trg-plan`, `trg-head`,
46/// `trg-kind`, `trg-draft` -- and the tail crop is the notes in no draft,
47/// `trg-left`.
48async function ink(label) {
49 const el = await p.$('#improve-triage');
50 if (!el) { console.log('no #improve-triage'); return; }
51 const box = await el.boundingBox();
52 if (!box) { console.log('no box'); return; }
53 const crop = async (name, y, h) => {
54 const f = path.join(OUT, `triage-${label}-${name}-${TAG}.png`);
55 await p.screenshot({ path: f, timeout: 8000,
56 clip: { x: box.x, y: Math.max(0, y), width: box.width, height: h } })
57 .catch((e) => console.log('shot failed', e.message));
58 console.log(' ', name, '→', f);
59 };
60 // The panel scrolls inside the dock, so the crops are taken by scrolling the
61 // wanted part into view rather than by asking for a y far below the fold.
62 await el.evaluate((e) => e.scrollIntoView({ block: 'start' }));
63 await p.waitForTimeout(300);
64 const top = await el.boundingBox();
65 await crop('head', top.y, Math.min(760, p.viewportSize().height - Math.max(0, top.y)));
66 // THE JOIN between two drafts, which is the whole question: where does one
67 // end and the next begin.
68 const second = (await p.$$('#improve-triage .trg-draft'))[1];
69 if (second) {
70 await second.evaluate((e) => e.scrollIntoView({ block: 'center' }));
71 await p.waitForTimeout(300);
72 const sb = await second.boundingBox();
73 if (sb) await crop('join', Math.max(0, sb.y - 150), 320);
74 }
75 const left = await p.$('#improve-triage .trg-left');
76 if (left) {
77 await left.evaluate((e) => e.scrollIntoView({ block: 'center' }));
78 await p.waitForTimeout(300);
79 const lb = await left.boundingBox();
80 if (lb) await crop('left', Math.max(0, lb.y - 40), Math.min(500, p.viewportSize().height - Math.max(0, lb.y - 40)));
81 }
82 console.log(label, 'panel box', JSON.stringify(box));
83}
84
85await p.setViewportSize({ width: 1854, height: 961 });
86await p.waitForTimeout(500);
87await ink('desktop');
88
89// Below the breakpoint the panels are sheets, and whatever was last on top is
90// on top -- a settings sheet was, the first time this ran, and the picture was
91// of that. Anything over the panel is dismissed before the panel is asked for.
92await p.setViewportSize({ width: 390, height: 844 });
93await p.waitForTimeout(700);
94for (let i = 0; i < 4; i++) { await p.keyboard.press('Escape'); await p.waitForTimeout(150); }
95await p.evaluate(() => { window.DaimondPanels.show('social'); });
96await p.waitForTimeout(700);
97console.log('on top at 390:', await p.evaluate(() => {
98 const vis = [...document.querySelectorAll('.sheet, .modal, .panel')]
99 .filter((e) => e.getClientRects().length)
100 .map((e) => e.id || e.className.split(' ')[0]);
101 return vis.slice(-6).join(' | ');
102}));
103await ink('iphone');
104
105await s.close();
106try { fs.rmSync(profile, { recursive: true, force: true }); } catch (e) { /* gone */ }