igneum/tools/ui-mock/site-shots.cjs
igneum-labs f499c2919b Site, 7 October 2026 evening (the project lead's four asks through main, one landing): (1) the bar's nav to the right: the mark and the devnet pill on the left, Mine, Network, Learn and the controls right-aligned with the same gaps and sizes, each open panel anchored under its button (the script sets --panel-left) and a panel that would run past the container aligned to its button's right edge, the phone sheet unchanged; (2) no lateral scroll: tools/ci/scroll-width-check.mjs on the gate (scrollWidth equals clientWidth on every route at 390, 768, 1024, 1280 and 1440 in both themes; only a table, code or diagram scrolls inside its own overflow-x box; self-test with a 100vw plus 20 px fixture known-failed first); (3) LG-5, the launch text: the front page leads with the three wants (hardware that stays useful, income without a cliff, a fair supply) and the live network with finality is the second screen; the litepaper's regulatory note reads "Not legal advice." alone over its eight sentences from future.md 8.3 (the project lead: counsel not yet; the string "counsel is engaged" is in both forbidden-strings lists and gone from the research heading), the pay sentence stays; the journey's phase line reads Devnet 3 live, testnet next; (4) LG-1, /income: docs/analysis/income-tiers.md published as a page by tools/launch/income-page.mjs (checked on the gate against the document), listed under Learn, labels on every number, no price of IGN anywhere
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 19:12:04 +00:00

15 lines
3.1 KiB
JavaScript

// Site captures off the recorded feed (7 October 2026): the bar at 1440 and 390 dark, the leaderboard at 1440 dark, the /live
// inspector on a block whose shard awaits a prover (opened by its row in the block table), /income at 1440 dark.
// node tools/ui-mock/site-shots.cjs <base url> <out dir> (tools/site-serve.mjs with IGNEUM_LIVE_FIXTURE behind <base url>)
const base = process.argv[2], out = process.argv[3];
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const shot = async (w, h, route, sel, file, before) => { const p = await browser.newPage({ viewport: { width: w, height: h }, colorScheme: 'dark', reducedMotion: 'reduce' }); await p.goto(base + route + '?theme=dark', { waitUntil: 'load' }); await p.waitForTimeout(2500); let note = ''; if (before) note = await before(p); const el = sel ? await p.$(sel) : null; if (el) await el.screenshot({ path: out + '/' + file }); else await p.screenshot({ path: out + '/' + file }); console.log(file, note); await p.close(); };
await shot(1440, 900, '/', 'nav.nav', '01-bar-1440-dark.png', async (p) => { await p.evaluate(() => document.getElementById('nav-btn-learn').click()); await p.waitForTimeout(300); const r = await p.evaluate(() => { const pl = document.querySelector('#nav-panel-learn').getBoundingClientRect(), b = document.getElementById('nav-btn-learn').getBoundingClientRect(); return 'learn panel right ' + Math.round(pl.right) + ' button right ' + Math.round(b.right) + ' viewport ' + window.innerWidth; }); return r; });
await shot(390, 844, '/', 'nav.nav', '02-bar-390-dark.png');
await shot(1440, 1000, '/live', '#weights', '03-leaderboard-1440-dark.png', async (p) => p.evaluate(() => { document.getElementById('weights').scrollIntoView(); const tg = document.getElementById('w-toggle'); return 'rows ' + document.querySelectorAll('#w-body tr').length + ', toggle ' + (tg && !tg.hidden ? tg.textContent : 'hidden') + ', tag ' + document.getElementById('w-tag').textContent; }));
await shot(1280, 900, '/live', 'aside', '04-inspector-awaiting-1280-dark.png', async (p) => { const hash = await p.evaluate(async () => { const d = await (await fetch('/api/live?window=300')).json(); const rows = new Set([...document.querySelectorAll('#tbody tr[data-hash]')].map((t) => t.getAttribute('data-hash'))); const b = (d.blocks || []).filter((x) => rows.has(x.hash)).sort((a, b) => b.ts - a.ts).find((x) => (x.shards || []).some((s) => s.state === 'planned' && !s.prover)) || (d.blocks || []).filter((x) => rows.has(x.hash)).find((x) => (x.shards || []).some((s) => s.state === 'planned')); return b ? b.hash : ''; }); if (!hash) return 'no planned block among the table rows'; await p.evaluate((h) => { const tr = document.querySelector('#tbody tr[data-hash="' + h + '"]'); tr.scrollIntoView(); tr.click(); }, hash); await p.waitForTimeout(500); return await p.evaluate(() => 'count: ' + document.getElementById('i-shard-count').textContent + ' | first: ' + (document.querySelector('#i-shards li') || {}).textContent); });
await shot(1440, 1100, '/income', null, '05-income-1440-dark.png');
await browser.close();
})().catch((e) => { console.error(e); process.exit(1); });