A Pluto notebook becomes a Therapy component
Snapshot takes a Pluto.jl notebook and emits a lean Therapy component — supported interactive sliders and plots run in the browser as WebAssembly, with no Julia server, no Pluto frontend, and no multi-megabyte statefile. It drops into any static host as a standalone page, or into a Therapy app as native DOM — themeable, with or without reactivity.
The problem it solves
Pluto's classic static export is faithful but heavy: it bakes the entire session state (~2.6 MB) into the HTML and ships the full Pluto frontend to re-hydrate it. For a page of sliders and a plot, that's a lot of bytes — and it locks the look to Pluto's chrome.
The lean export keeps rendered notebook content and verified interactions, while omitting Pluto's editor and session machinery. For notebooks whose interactions compile, this can substantially reduce frontend and session-state overhead.
The pipeline
At export time the notebook runs once in Pluto. Then, per notebook:
Extract the reactive graph
Pluto already knows the dependency graph + which cells depend on a @bind widget. Snapshot groups co-dependent bond cells and lifts each dependent cell into a pure function.
Compile to WebAssembly islands
Each bond group compiles to a small WasmGC module via WasmTarget.jl — verified at export time against real notebook re-runs before it ships.
Server-render every cell
Each cell's output is written straight into the page as HTML, following Pluto's own decisions about ordering, output, and visibility. Nothing structural is invented.
Hydrate with signals + islands
A tiny runtime wires each <bond> input to the wasm island that owns it. Move a slider and only the dependent cells recompute — figures redraw on a live <canvas>, numbers update in place.
Why it maps cleanly
Pluto's reactive model and Therapy's signals model are the same idea, so the translation is direct:
Theming: copy Pluto, swap the variables
The export ports Pluto's own output CSS almost verbatim — markdown, admonitions, tables, code, the tree viewer, the table of contents — and re-points every Pluto color variable at a DaisyUI token.
So the notebook renders exactly as Pluto does, but one attribute — data-theme="…" on <html> — restyles the whole site at once. The 🎨 picker in the nav sets it: because each notebook is native DOM (no iframe), the chrome and every notebook reskin together, seamlessly, with one click.
Plain native controls with no authored class or inline style inherit those theme tokens too. A class, inline style, or data-snapshot-unstyled leaves the control's appearance with the notebook author.
Two ways to use it
Standalone page
Export a notebook and serve the HTML anywhere — GitHub Pages, S3, a CDN. No server.
export_notebook("notebook.jl")
# → notebook.html + .islands/Component in a Therapy app
Embed the notebook inside a larger Therapy site and let the host's theme drive it. This gallery does exactly that.
export_notebook("notebook.jl";
therapy=true,
theme_picker=false)Trust boundary
Exporting executes the notebook and its package environment with the permissions of the Julia process. Snapshot is an exporter, not a sandbox. Build only trusted notebooks locally; use a disposable, network-restricted runner without credentials for community-supplied code. Generated HTML is author-controlled content and should be served from an origin isolated from authenticated applications.
The package works on any static host. snapshot.show is a separate hosted service, not a runtime dependency of Snapshot.jl.
The classic export (not recommended)
Passing therapy=false explicitly selects the original full-Pluto export — Pluto's standard static HTML plus a JavaScript bundle that hydrates the @bind cells in Pluto's static export, alongside Snapshot's island assets. It still works:
export_notebook("notebook.jl"; therapy=false)See it in action
Every notebook in the gallery is a live Therapy component. Try the theme picker.