Problem
#121 / #122 added a cross-platform `chromium` binary to the dev shell. The binary itself works:
```
$ nix develop -c chromium --version
Google Chrome 147.0.7727.138
```
But the typical headless invocations don't reliably capture rendered SPA content. Against a SvelteKit Vercel preview:
```
chromium --headless=new --disable-gpu --virtual-time-budget=20000 --dump-dom https://example.vercel.app/deploy
```
returns the bare HTML shell — `` contains only the SvelteKit module-preload `<script>` block. `--screenshot` produces a blank PNG, `--print-to-pdf` produces a blank PDF. Manually opening the same URL in a real browser renders the page within ~1s.
`--virtual-time-budget` advances clock time only while JS is actively running — once the app awaits a fetch (e.g. registry load) virtual time pauses, so increasing the budget doesn't help. `--run-all-compositor-stages-before-draw` doesn't help either.
What we want
A `nix develop -c` invocation that renders an arbitrary URL, waits until the page settles (network idle or a configurable selector visible), and emits the post-hydration DOM / a screenshot / a PDF. Use cases: debugging SPA preview deploys, capturing rendering errors that only surface after JS load, comparing rendered output across PRs.
Options
- CDP via small Node script: drive Chrome through DevTools Protocol, await `Page.loadEventFired` plus a network-idle window, then `Runtime.evaluate('document.documentElement.outerHTML')`. Most flexible, no extra package required if we shell out the Chrome binary the dev shell already has.
- `pkgs.playwright`: cross-platform, has a CLI (`playwright codegen`/`playwright cli`) but most use cases want the Node API. Adds a Node/dep surface.
- `pkgs.puppeteer`: similar to playwright but smaller scope.
- `pkgs.chromium` + `--virtual-time-budget` + waiting on a specific event: experimentally fragile for SPAs.
Concrete proposal: add a small `render` mkTask script (CDP-driven) that takes a URL and emits DOM + screenshot + console errors, layered on the existing `chromium` binary. Keeps the cross-platform story working and avoids pulling in a second browser-bundle dependency.
Acceptance
Problem
#121 / #122 added a cross-platform `chromium` binary to the dev shell. The binary itself works:
```
$ nix develop -c chromium --version
Google Chrome 147.0.7727.138
```
But the typical headless invocations don't reliably capture rendered SPA content. Against a SvelteKit Vercel preview:
```
chromium --headless=new --disable-gpu --virtual-time-budget=20000 --dump-dom https://example.vercel.app/deploy
```
returns the bare HTML shell — `` contains only the SvelteKit module-preload `<script>` block. `--screenshot` produces a blank PNG, `--print-to-pdf` produces a blank PDF. Manually opening the same URL in a real browser renders the page within ~1s.
`--virtual-time-budget` advances clock time only while JS is actively running — once the app awaits a fetch (e.g. registry load) virtual time pauses, so increasing the budget doesn't help. `--run-all-compositor-stages-before-draw` doesn't help either.
What we want
A `nix develop -c` invocation that renders an arbitrary URL, waits until the page settles (network idle or a configurable selector visible), and emits the post-hydration DOM / a screenshot / a PDF. Use cases: debugging SPA preview deploys, capturing rendering errors that only surface after JS load, comparing rendered output across PRs.
Options
Concrete proposal: add a small `render` mkTask script (CDP-driven) that takes a URL and emits DOM + screenshot + console errors, layered on the existing `chromium` binary. Keeps the cross-platform story working and avoids pulling in a second browser-bundle dependency.
Acceptance