Runnable, self-contained example apps built on gptdiff-js: generate a unified diff and smartapply it, entirely in the browser, powered by NanoGPT. No server, no build, no install.
Live demos · diff → smartapply · realtime video overlay · 3d object studio · AI-liftoff comic · MARVIS · count to 100
The gptdiff family — gptdiff (CLI + Python API) · gptdiff-js (browser port) · gptdiff-js-examples (you are here)
The original demo: one self-contained file that uses gptdiff-js (loaded from esm.sh) with
NanoGPT's xiaomi/mimo-v2.5-pro-ultraspeed, streaming progress (live tokens + USD cost) as it works.
index.html ──▶ NanoGPT (auth, diff, apply — all from the browser)
Open the page, authenticate one of two ways, then edit the file + goal and hit Diff & apply:
- Sign in with NanoGPT — browser OAuth (PKCE). Requires the page be served over http
(loopback) or https, since OAuth redirects there. The key is stored in
localStorage. - paste key — paste a key from nano-gpt.com → Settings → API. Works even when
the file is opened directly (
file://).
npx serve . # then open the printed http://localhost:3000Use the localhost URL (the page auto-switches 127.0.0.1 → localhost to match NanoGPT's
loopback handling). Opening via file:// works too, but only with the paste key option.
It's a static file — drop it on any HTTPS host and OAuth works cleanly (no loopback quirks):
npx netlify deploy --prod --dir . # or Cloudflare Pages / Vercel / GitHub Pages / Surge- Auth — browser PKCE: registers a client, redirects to NanoGPT consent, exchanges the
code for a key (all NanoGPT auth endpoints are CORS-open). Key cached in
localStorage. - Diff → apply —
generateDiff(buildEnvironment(files), goal)thensmartapply(diff, files), with a streamingcallLlminjected so the diff/file build up live and exact token/cost figures come from NanoGPT'sx_nanogpt_pricing. - A no-op (empty/unparseable diff, or unchanged result) is shown explicitly, not silently.
A second demo that shows gptdiff editing a multi-file project: a broadcast/stream overlay built from SVG layers + a GSAP timeline + a JSON config + the preview that stitches them together. Describe a change in the Goal box and gptdiff rewrites all of them — adding or removing files as needed — and the looping preview re-renders live (opening → middle hold → closing, on repeat).
There is no real filesystem. The "project" is an in-memory { path: content } map (a
virtual FS) held in the page. smartapply returns a fresh map; the harness diffs it against
the current one (added / removed / changed) and swaps the result into the DOM by rebuilding a
single sandboxed <iframe srcdoc>. A tiny mini-bundler inlines every file into that one
document:
<!-- include-config: config.json -->→<script>window.OVERLAY_CONFIG = {…}</script><!-- include: layers/foo.svg -->→ the raw SVG markup (so GSAP can animate its shapes)- local
<script src="overlay.js">→ inlined; the GSAP CDN<script>is left untouched
So it stays a plain static HTML file — open it directly (file://) or serve it; nothing is
ever written to disk.
Export bundle runs the same bundler and downloads overlay-bundle.html: one self-contained,
transparent 1920×1080 file you can drop into an OBS Browser Source, screen-record, or hand to
a video editor.
The seed project lives in overlay/ (preview.html, overlay.js, config.json,
layers/*.svg). When served, overlay.html fetches those files; opened via file:// it falls
back to an identical copy embedded in the page.
npx serve . # then open http://localhost:3000/overlay.htmlA multi-file project that renders in 3D: gptdiff edits the geometry (object.js), the
material (material.js), an SVG texture.svg, the lighting/animation (effects.js) and a
scene.json config; the preview on the right rebuilds the object live with Three.js
and OrbitControls (drag to orbit, scroll to zoom). Describe a change in the Goal box
("turn it into a glowing crystal") and all the files are rewritten at once.
Same virtual-FS + sandboxed <iframe srcdoc> + mini-bundler pattern as the overlay:
<!-- include-config: scene.json -->→<script>window.SCENE_CONFIG = {…}</script><!-- include-texture: texture.svg -->→window.SCENE_TEXTURE_SVG(the SVG as a data URL)- local
<script src="object.js">(andmaterial.js,effects.js) → inlined; the Three.js importmap / CDN<script>is left untouched
Download exports a real 3D-modelling file — .glb (binary glTF, embeds the material + the
SVG texture) or .obj (geometry-only, universal) — that imports straight into Blender, Maya,
Unity, or Three.js. The exporter runs inside the sandboxed preview and hands the bytes to the
page via postMessage, which triggers the download.
The seed project lives in object3d/ (preview.html, scene.json, object.js, material.js,
texture.svg, effects.js); served, object3d.html fetches it, and via file:// it falls
back to an embedded copy.
npx serve . # then open http://localhost:3000/object3d.htmlA demo where the re-render actually generates an image. It's a comic page —
LIFTOFF, a cyborg (NOVA) and an emergent AI (HELIX) living through the moment of AI
liftoff — built from a multi-file project: a JSON art-direction config.json (shared style
- palette + a character bible) and one JSON file per panel under
panels/(span,shot,cast,scene,caption,dialogue,fx).
Describe a change in the Goal box ("make it more action packed") and gptdiff rewrites the
config + panels — adding or removing panels as it sees fit. The harness then organizes
every panel into one prompt (style + character bible + each panel's scene/caption/dialogue/FX,
in reading order) and draws the whole portrait page in a single gpt-image-2 render via
NanoGPT's OpenAI-compatible image endpoint — the model lays out the panels, gutters and
lettering itself:
POST https://nano-gpt.com/v1/images/generations
{ "model": "gpt-image-2", "prompt": <one prompt for the entire page>, "n": 1,
"size": "1024x1536", "response_format": "b64_json" } ──▶ { data: [{ b64_json }], cost }
Because the character bible is pinned into the one prompt ("keep these characters consistent in every panel"), NOVA and HELIX stay recognizable across the page. The result is cached per prompt hash, so re-running an unchanged page is free; 🎲 new take forces a fresh sample, and the composed prompt is shown under the page so you can see exactly what was sent.
The seed project lives in comic/ (config.json + panels/*.json); served, comic.html
fetches it, and via file:// it falls back to an embedded copy. Export PNG downloads the
rendered page.
Image generation is not free — nothing is drawn until you click 🎨 render page (or run a goal with auto-render on). Each render is one
gpt-image-2call (a 1024×1536 page; NanoGPT returns the exactcost).
npx serve . # then open http://localhost:3000/comic.htmlA demo where the multi-file project is a character you talk to — and a single gptdiff
action updates all of it at once. MARVIS (Mostly Autonomous, Rather Volatile Intelligence
System) is a sardonic, faintly unhinged open-weights lab assistant in the spirit of GLaDOS or
JARVIS — an it, not a he or a she. The "project" is MARVIS: soul.md (who it is), mood.md
(how it feels now), memory.md (what it keeps), portrait.md (how it looks), talkingto.md
(who you are — the boss), and chat.md (the visible script).
The pitch, aimed squarely at the #keep4o crowd — the people for whom a retired model meant a companion just disappeared: MARVIS can't disappear. It has a soul, a mood and a memory, and each one is a plain file you own, running on open-weight models you pick, routed through NanoGPT (an OpenRouter-style aggregator — one key, inference across every provider).
You don't type replies — you direct. One box drives the scene: type something to say or a
note for what happens next ("the lab loses power"), or leave it blank to just let it continue.
Hit ▶ continue and gptdiff advances the scene by exactly one beat across every file — it
answers in chat.md, mood.md is rewritten (a live mood badge reflects it), a line may
stick in memory.md, and portrait.md only moves when its appearance changes.
chat.md renders RPG-style on a dark, cinematic HUD stage: MARVIS's lines sit on the
left with its face as the avatar, yours on the right with none, and stage directions
drift between them as prose — a different colour and weight, no left/right alignment — so it reads
like a scene you're steering. The gptdiff machinery (model picker, its editable files, the live
diff) is tucked behind an under-the-hood reveal so the stage stays clean for presenting.
Nothing about MARVIS is hardcoded — the whole character is config files that hot-reload as you type and travel in save/share. Alongside the six story files there are three config files (shown gold):
config.json— name, the page copy (title, tagline, role), the image model/size, and the default direction sent when you leave the box blank.brief.md— the director's brief: the full prompt prepended to every beat. Edit it and the next ▶ continue obeys the new rules instantly.style.css— this page's entire theme. Edit it and the page re-skins live.
And gptdiff sees all of them — so MARVIS can change everything: rename itself in config.json,
re-skin the lab in style.css (an alarm turns the page red), even evolve its own brief.md. After
every beat the config and theme are re-applied, so a self-edit takes effect immediately. The brief
asks it to treat those meta-files as rare, deliberate moves rather than every-beat edits. You can do
the same by hand, and either way it all saves and shares like the rest.
When portrait.md changes (or you press 🎨 render face), its face is drawn from that file
with seedream-v5.0-lite via NanoGPT's image endpoint, and flows straight into its chat
avatar:
POST https://nano-gpt.com/v1/images/generations
{ "model": "seedream-v5.0-lite", "prompt": <portrait.md>, "n": 1,
"size": "832x1216", "response_format": "b64_json" } ──▶ { data: [{ b64_json }], cost }
Save / load / share — all client-side, no server:
- 💾 save downloads
marvis.json(its files, its director's brief and its current face) — drop it back via 📂 load to restore it exactly. - 🔗 share link folds the whole being — soul, mood, memory, portrait, the entire
conversation, the director's brief, the config and the theme — into the URL hash itself,
gzip-compressed with the browser's native
CompressionStream(no library, no upload, no account, no server). Open the link and you get that exact MARVIS, yours to keep. The face is left out of the link to keep it short; it re-renders fromportrait.md. - It also auto-persists to
localStorage, so a refresh keeps it; 🧹 clear conversation resets the chat/mood/memory to the opening while keeping the soul, look and brief.
Renders are cached per portrait hash; 🎲 new look forces a fresh sample. The seed lives in
marvis/ (six story *.md files + config.json / brief.md / style.css); served, marvis.html fetches them, and via file:// it falls
back to an embedded copy.
npx serve . # then open http://localhost:3000/marvis.htmlA third demo that turns gptdiff into a reliability loop. There's one uneditable file —
count — holding a single integer. Each step the harness asks gptdiff to add 1, applies the
diff, and verifies the result is exactly the previous number plus one:
for (i = 0; count < 100; i++):
diff = generateDiff({ count }, "increment by exactly 1")
count = Number(smartapply(diff).count)
if count !== prev + 1: FAIL and stop
PASS when count reaches 100
The loop ends three ways, each spelled out: it passes when it reaches 100 (every step verified), fails the instant a step doesn't land on n+1 (showing what the model wrote vs. what was expected), or stops when you press Stop — which aborts the in-flight call and makes clear it was a user interruption, not a pass or fail. Cumulative tokens/cost and a per-step log show what counting to 100 actually costs on the selected model.
npx serve . # then open http://localhost:3000/count.htmlindex.html— the single-file diff → smartapply demo (builds a playable game).overlay.html— the multi-file realtime video-overlay demo (virtual FS + live preview + export).overlay/— the seed overlay project (SVG layers, GSAP timeline, JSON config, preview).object3d.html— the multi-file 3D object studio (Three.js preview + drag-to-orbit +.glb/.objexport).object3d/— the seed 3D project (object.jsgeometry,material.js,texture.svg,effects.js,scene.json, preview).comic.html— the AI-liftoff comic; the whole page is drawn in onegpt-image-2render via NanoGPT.comic/— the seed comic project (config.jsonart direction +panels/*.json).marvis.html— MARVIS, a Portal/JARVIS-style assistant you direct; one*continue conversation*beat movessoul/mood/memory/portrait/chat, face drawn withseedream-v5.0-lite, plus client-side save / load / share-by-URL (no server).marvis/— the seed MARVIS project: story files (soul.md,mood.md,memory.md,portrait.md,talkingto.md,chat.md) + config files (config.json,brief.md,style.css) that drive name/copy, the prompt, and the page theme.count.html— the count-to-100 reliability loop (diff → apply → verify n+1, pass / fail / stop).