Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081// Screenshot tour of the editor-libraries slice:// boot → open main.cjs (microlighter highlight mirror active, textarea text// transparent) → open notes.md (micro-composer replaces the textarea stack).// Start the dev server first (node scripts/serve.mjs on :8931), then run:// node scripts/screenshot-editor.mjs// Shots land in /tmp/nib-shots-editor/*.png.import { chromium } from 'playwright';import { mkdirSync } from 'node:fs';
const DIR = '/tmp/nib-shots-editor';mkdirSync(DIR, { recursive: true });
const browser = await chromium.launch();const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });page.on('pageerror', (e) => console.log('[pageerror]', e.message));page.on('console', (m) => { if (m.type() === 'error') console.log('[console.error]', m.text()); });
// 1. Boot: calm default — node_modules collapsed, editor empty.await page.goto('http://localhost:8931/demo/harness.html');await page.waitForSelector('#tree [data-path="/app"]', { timeout: 10000 });await page.waitForSelector('#sb-boot:has-text("VFS ready")', { timeout: 10000 });await page.waitForTimeout(500);await page.screenshot({ path: `${DIR}/1-boot.png` });console.log('1-boot.png — booted: explorer tree, empty editor, OUTPUT panel ready');
// 2. Open main.cjs — the microlighter mirror paints behind the transparent// textarea and registers CSS Custom Highlights. Waits + assertions are the// proof (the PNG cannot be inspected here).await page.click('#tree [data-path="/app/main.cjs"]');await page.waitForSelector('#tabs .tab[data-path="/app/main.cjs"]');await page.waitForFunction(() => document.getElementById('content')?.value.includes('node:fs'), null, { timeout: 10000 });// The mirror must be visible, the textarea text transparent, and highlights// registered after a rAF.await page.waitForFunction(() => { const wrap = document.getElementById('hl-wrap'); const body = document.getElementById('editor-body'); return !wrap.hidden && body.classList.contains('hl-on');}, null, { timeout: 10000 });await page.waitForFunction(() => CSS.highlights.size > 0, null, { timeout: 10000 });const hlStats = await page.evaluate(() => ({ highlights: CSS.highlights.size, mirrorChars: document.getElementById('hl-mirror')?.textContent.length ?? 0, contentChars: document.getElementById('content')?.value.length ?? 0, mirrorLang: document.getElementById('hl-mirror')?.dataset.language ?? null,}));console.log('2-code-highlight.png — main.cjs open:', JSON.stringify(hlStats));if (hlStats.highlights <= 0) throw new Error('no CSS Custom Highlights registered');if (hlStats.mirrorChars !== hlStats.contentChars) throw new Error('mirror out of sync with textarea');await page.waitForTimeout(300);await page.screenshot({ path: `${DIR}/2-code-highlight.png` });console.log('2-code-highlight.png — main.cjs with microlighter mirror (neon tokens behind transparent text)');
// 3. Open notes.md — the composer replaces the textarea stack entirely.await page.click('#tree [data-path="/app/notes.md"]');await page.waitForSelector('#tabs .tab[data-path="/app/notes.md"]');await page.waitForFunction(() => { const md = document.getElementById('md-editor'); const content = document.getElementById('content'); const gutter = document.getElementById('gutter'); return md && !md.hidden && content.hidden && gutter.hidden;}, null, { timeout: 10000 });await page.waitForSelector('#md-editor [contenteditable]', { state: 'visible', timeout: 10000 });const mdStats = await page.evaluate(() => { const input = document.querySelector('#md-editor [contenteditable]'); return { composerVisible: !document.getElementById('md-editor').hidden, textareaHidden: document.getElementById('content').hidden, gutterHidden: document.getElementById('gutter').hidden, text: input?.textContent ?? '', dirty: document.querySelector('#tabs .tab[data-path="/app/notes.md"]')?.dataset.dirty ?? null, };});console.log('3-md-composer.png — notes.md open:', JSON.stringify(mdStats));if (!mdStats.text.includes('# scratch')) throw new Error('composer did not load the seeded markdown');await page.waitForTimeout(300);await page.screenshot({ path: `${DIR}/3-md-composer.png` });console.log('3-md-composer.png — notes.md in the micro-composer (textarea stack hidden, composer active)');
await browser.close();console.log(`done — 3 shots in ${DIR}`);