clickshot — screenshots you can click
clickshot captures discrete screens of a running web app and stitches them into a single
offline .html. The output has two views:
- Board — every captured screen as a thumbnail, laid out by the real navigation graph, with arrows for each click-transition and a "▶ start" badge on each entry point. Grasp the whole product at a glance; click any frame to open it.
- Screen — the chosen screen rendered live in a near-fullscreen modal (the board stays dimmed behind, so it reads as one screen among many). Spots that lead to another captured screen are marked with a pulsing blue box; click one to move there.
It is not a live clone (the captured app's JavaScript is dead) and not a source exporter. It freezes rendered states plus the clicks between them.
When to use
- Archive or share a UI as one file — send it, commit it, open it years later, no server needed.
- Turn a walkthrough / user flow into a clickable artifact for a demo or a bug report.
- Study or document a product's UX offline.
Pipeline: capture → build → open
1. Capture → a capture dir (state-*.json, state-*.png, resources.json, manifest.json)
Two modes, identical output format:
-
Human / logged-in (BYO login): you drive a real browser, log in yourself, browse normally. Screens auto-capture on route change; a floating button captures URL-unchanged states (modals, expanded panels).
node capture-live.mjs <startUrl> <outDir>Credentials are never stored — only the browser session persists locally in
pw-profile/(gitignored), so you log in once. -
Scripted / agent-driven (no login): give a flow of selectors to click. Headless, reproducible.
node capture.mjs <startUrl|localFile> <flow.json> <outDir> # flow.json = [{ "click": "<css selector>", "label": "…", "wait": 500 }, …]
2. Build → one offline .html
node build.mjs <captureDir> <out.html>
Fonts / images / CSS are inlined and de-duplicated across screens; a metadata stamp (source URL + capture date) is added automatically.
3. Open
Just open the .html. Start on the board, click a frame to explore, follow the blue markers to
move between screens. Esc / the backdrop / ✕ returns to the board; ◀ ▶ (or arrow keys) step
through screens.
Guardrails (important)
- Never store or ask for credentials. Human capture means the person logs in on their own browser. clickshot only keeps a local browser session, never a password.
- A capture contains whatever was on screen — possibly real data. Keep capture dirs and built
files out of version control unless you know the data is safe (the shipped
.gitignorealready excludes them). For anything you plan to share publicly, capture with dummy accounts / test data. - Every output is stamped with source URL + capture date so a viewer can't mistake it for the live site. Don't remove the stamp.
- Only capture apps you are authorized to use.
How it works (for maintainers)
- Capture primitive is
rrweb-snapshot(notouterHTML) so shadow DOM,adoptedStyleSheets, canvas, and inline images survive. The clicked element per transition is recorded by rrweb node id. build.mjsrebuilds each snapshot into an iframe document, tags hotspots (data-cs-goto), injects a tiny navigation shim (the captured JS is dead), serializes with declarative shadow DOM, inlines and de-duplicates assets, then emits the board + modal shell.- Verify offline: open the file in an offline browser context and confirm 0 console and network errors — that proves it is truly self-contained.