From d0f4016319b61ccf6a331f02a78707ef2b731616 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Wed, 4 Nov 2026 13:11:19 -0800 Subject: [PATCH 1/6] Add the demo video script Co-Authored-By: Claude Opus 5.5 --- demo-video/SCRIPT.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 demo-video/SCRIPT.md diff --git a/demo-video/SCRIPT.md b/demo-video/SCRIPT.md new file mode 100644 index 0000000..12a5d72 --- /dev/null +++ b/demo-video/SCRIPT.md @@ -0,0 +1,37 @@ +INTRO STORYBOOK + +What if you took every page and component of your UI, and laid it out next to each other. +**[Application splits horizontally into pieces]** + +Now, let’s copy those components, and put them into every state the user will see - error states, empty states, easy ones, hard ones. +**\[Zoom in on one, split it down the column into error state, empty state, etc]** + +StorybookJS has made it easy for users to do exactly that for the past 10 years. With the advent of coding agents, it’s more useful than ever - you can use the Storybook as a control surface by pointing to the specific page you want changed +**\[Human hand points to a spot, Robot comes and hammers on it]** + +INTRO SNAPSHOT + +But most changes have unforseseen consequences. +**\[Pieces of the robot’s contstruction bang down and damge the components below it]** + +How can you understand the full ripples of a code change? +**\[Zoom out for a radial “bump” of the entire compoent grid]** + +Enter Chromatic. This is a cloud service which renders every component of a Storybook to an image. Change the code, render every component to another image, and compare. +**\[Photo Booth, put the component in front of camera take picture, change component, take another picture, line up the pictures to highlight the difference]** + +This works great, but it requires waiting on a cloud service. At 0.8 cents per image, this was a reasonable expense at the speed of human code. But for a modest library of 1,000 stories, that’s 8 bucks for each time you even look at a code change! + +ENTER SELFIE + +Introducing Selfie.dev - a snapshot testing tool which runs locally and in the cloud. Now your coding agent can take the snapshots itself, without waiting (or paying) for a cloud rendering service. +**[Robot taking lots of goofy selfies with the components]** + +It works just like git. Screenshots are stored locally wherever the agent is running, and also in the cloud so that every commit in GitHub shows the complete visual consequences of the code change. +**\[Several robots on the ground, each with their own suitcase of photos, waving up to an agent in a cloud with its own suitcase]** + +Screenshots are generated inside a reproducible container, so that you get the exact same pixels wherever the test is run. Screenshots are hashed on their content, and most runs change very few snapshots. The client and server show each other the set of hashes for all of the images. They only need to send the full image if a hash has changed. +**\[Robot takes a single photo out of the suitecase, folds it into a paper airplane, and throws it up to the cloud]** + +If you’re using StorybookJS, you can start using the Selfie locally to review your changes right now, at selfie.dev. If you want to use it in the cloud on your GitHub repositories, you can add yourself to our waitlist and get a launch discount when we launch in mid-November. +**\[Robots signing up outside of a space pad, then launching into space as they take selfies out the window]** From d24404844a235b1cccadaae0e531ae69b69f2464 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Wed, 4 Nov 2026 13:53:40 -0800 Subject: [PATCH 2/6] Add the demo video as a HyperFrames film, with subtitles Co-Authored-By: Claude Opus 5.5 --- demo-video/.gitignore | 4 + demo-video/README.md | 25 + demo-video/REVIEW.md | 9 + demo-video/SCRIPT.md | 69 +- demo-video/assets/fonts/BagelFatOne.woff2 | Bin 0 -> 24376 bytes demo-video/assets/fonts/Jost.woff2 | Bin 0 -> 26576 bytes demo-video/assets/lib.js | 302 +++ demo-video/assets/mascot-cutout.png | Bin 0 -> 630216 bytes demo-video/assets/style.css | 44 + demo-video/build.mjs | 141 ++ demo-video/compositions/approvals.html | 54 + demo-video/compositions/bucks.html | 54 + demo-video/compositions/captions.html | 65 + demo-video/compositions/chromatic.html | 45 + demo-video/compositions/cold.html | 55 + demo-video/compositions/compare.html | 39 + demo-video/compositions/cost.html | 42 + demo-video/compositions/git.html | 70 + demo-video/compositions/goofy.html | 59 + demo-video/compositions/hash.html | 66 + demo-video/compositions/launch.html | 79 + demo-video/compositions/pinned.html | 36 + demo-video/compositions/reveal.html | 54 + demo-video/compositions/ripple.html | 54 + demo-video/compositions/split.html | 44 + demo-video/compositions/start.html | 51 + demo-video/compositions/states.html | 59 + demo-video/compositions/storybook.html | 55 + demo-video/hyperframes.json | 12 + demo-video/index.html | 37 + demo-video/meta.json | 5 + demo-video/package-lock.json | 2049 +++++++++++++++++++++ demo-video/package.json | 8 + demo-video/scenes.json | 22 + demo-video/subtitles.srt | 191 ++ 35 files changed, 3875 insertions(+), 24 deletions(-) create mode 100644 demo-video/.gitignore create mode 100644 demo-video/README.md create mode 100644 demo-video/REVIEW.md create mode 100644 demo-video/assets/fonts/BagelFatOne.woff2 create mode 100644 demo-video/assets/fonts/Jost.woff2 create mode 100644 demo-video/assets/lib.js create mode 100644 demo-video/assets/mascot-cutout.png create mode 100644 demo-video/assets/style.css create mode 100644 demo-video/build.mjs create mode 100644 demo-video/compositions/approvals.html create mode 100644 demo-video/compositions/bucks.html create mode 100644 demo-video/compositions/captions.html create mode 100644 demo-video/compositions/chromatic.html create mode 100644 demo-video/compositions/cold.html create mode 100644 demo-video/compositions/compare.html create mode 100644 demo-video/compositions/cost.html create mode 100644 demo-video/compositions/git.html create mode 100644 demo-video/compositions/goofy.html create mode 100644 demo-video/compositions/hash.html create mode 100644 demo-video/compositions/launch.html create mode 100644 demo-video/compositions/pinned.html create mode 100644 demo-video/compositions/reveal.html create mode 100644 demo-video/compositions/ripple.html create mode 100644 demo-video/compositions/split.html create mode 100644 demo-video/compositions/start.html create mode 100644 demo-video/compositions/states.html create mode 100644 demo-video/compositions/storybook.html create mode 100644 demo-video/hyperframes.json create mode 100644 demo-video/index.html create mode 100644 demo-video/meta.json create mode 100644 demo-video/package-lock.json create mode 100644 demo-video/package.json create mode 100644 demo-video/scenes.json create mode 100644 demo-video/subtitles.srt diff --git a/demo-video/.gitignore b/demo-video/.gitignore new file mode 100644 index 0000000..09890b2 --- /dev/null +++ b/demo-video/.gitignore @@ -0,0 +1,4 @@ +renders/ +snapshots/ +.hyperframes/ +.thumbnails/ diff --git a/demo-video/README.md b/demo-video/README.md new file mode 100644 index 0000000..46f7d0a --- /dev/null +++ b/demo-video/README.md @@ -0,0 +1,25 @@ +# Demo video + +A [HyperFrames](https://hyperframes.heygen.com) film: HTML and GSAP, rendered to MP4. + +| File | Owns | +|---|---| +| `SCRIPT.md` | The words. One paragraph is one scene, and the bold line under it is the visual hint. | +| `scenes.json` | Each scene's slot in seconds, in the same order. A scene's beats stretch to fit its slot. | +| `compositions/.html` | Each scene's pictures. | +| `assets/lib.js`, `assets/style.css` | The shared art: robot, cards, grid, booth, rocket. | +| `index.html`, `compositions/captions.html`, `subtitles.srt` | Generated. Don't edit them. | + +```sh +npm install +node build.mjs # after changing SCRIPT.md or scenes.json +npx hyperframes preview # edit and scrub in the browser +npx hyperframes check # lint, layout, and motion +npx hyperframes render -o renders/selfie-demo.mp4 +``` + +## Adding the voiceover + +Generate one audio file per paragraph of `SCRIPT.md`. Set each scene's `dur` in `scenes.json` to its file's length plus a small pause, and add each file as an `