storebound/media/teaser/README.md
CRT f07f3acbd8 teaser v4: calm 60 s 16:9 cut, from an empty folder to ready on both stores
Nine scenes of 6-7 s, one slow camera move each, soft dissolves, one plain-English caption per scene at the top
(on screen at least 4 s): the stores' to-do list and one rejection mail, `init` in an empty folder, the agent prompt
and `release plan` (25 steps), store text and renders in 7 sizes x 4 languages, `play products --dry` and
`catalog diff`, the scan's declarations proposal with the ask-owner line, three findings with plain reasons turning
green, the desktop release timeline and Store readiness "No blockers", Submit and the end card.

Every CLI line is real output: tests/teaser.test.ts runs each command (store answers from
tests/helpers/teaser-store-mock.ts, preloaded through bunfig.toml, never the network) and checks scene lengths,
caption holds, the 55-65 s total and 16:9 only. The vertical output is gone; the web version targets 4.5 MB.
Calmer music (D major pads, soft pluck, bells on scene changes). desktop.ts adds the Store readiness frame.
2026-10-12 01:48:03 +08:00

64 lines
5.4 KiB
Markdown

# storebound teaser (60 s, 16:9)
A calm, scripted motion piece: from an empty folder to everything ready on both stores. Every frame is a pure function
of time, rendered from an HTML/CSS/JS timeline in headless Chrome and encoded with ffmpeg. The music and the sound
design are original and synthesized from scratch in the same browser (Web Audio `OfflineAudioContext`): no samples,
no downloaded audio, nothing to license.
One idea per scene, 6-7 s each, one slow camera move per scene, soft dissolves between scenes. Each scene has one
plain-English caption at the top, fully on screen for at least 4 s; below it, the real product.
| s | shows | caption |
|---|---|---|
| 0-6 | the demo game's icon, "Done"; the stores' to-do list line by line; one rejection mail (Guideline 2.1) | Your app is done. The stores are not. |
| 6-12 | an empty folder; `bunx storebound init` is typed; the files it creates list in | storebound takes it from an empty folder. |
| 12-19 | the prompt "Get my app ready for both stores."; `storebound release plan 1.0.0`: 25 steps in fix order | You ask once. It plans every step. |
| 19-26 | the demo game's store text in 4 languages; its renders in 7 store sizes x 4 languages | Store text and screenshots. Every language, every size. |
| 26-33 | `play products --dry` (174 regions), then `catalog diff` (175 / 174 region prices, 0 mismatches) | In-app products on both stores, priced in 175 countries. |
| 33-40 | the scan's declarations proposal: detected answers with file:line, one "ask owner" line highlighted; 764 Data safety answers | The forms, answered from your code. It asks what it can't know. |
| 40-47 | `storebound scan`: three findings, each with a plain reason; fixed, the re-scan is clean | It catches rejections before Apple does. |
| 47-54 | the desktop app: the release timeline with both stores on one track, then Store readiness: "No blockers" | Both stores, one view. Ready for review. |
| 54-60 | "Submit for Review" with the cursor resting on it (it never clicks), then the end card: storebound.dev, Open source · CLI · Desktop app | You press Submit. That's it. |
| file | what |
|---|---|
| `script.js` | the timeline: scenes in seconds, camera moves, captions, every line shown, the sound cues |
| `desktop.ts` | the desktop frames: apps/desktop's Vite dev server in fixture mode (`VITE_FIXTURES=1`, example.com-style data), captured headlessly in dark at 1280x800 @2x with the dev markers hidden, plus `boxes.json` (callout targets) -> `out/desktop/` |
| `index.html` + `teaser.js` | the picture; `window.teaser.seek(t)` sets every element for time `t` |
| `music.js` | calm music (D major, one chord per scene: pads, a slow soft pluck, a quiet sub) and soft sound design: a bell and an airy swell on each scene change, key clicks, quiet ticks, chimes for the fixes |
| `render.ts` | frames at 60 fps blended to 30 fps -> ffmpeg (H.264 high, yuv420p), sound -> loudnorm (-16 LUFS, -1.5 dBTP), mux, poster, the 1280x720 web version |
| `icons/` | the mouse cursor and the UI icons: Phosphor files copied unchanged by `bun tools/site-icons.ts` (no hand-written SVG; CI checks it) |
Every CLI line in the video is real output, and `tests/teaser.test.ts` runs each command and checks every line (the
clock prefix and the "(0s)" timer left out):
- `storebound init` in an empty temp folder.
- `storebound release plan 1.0.0`, `play products --dry` and `catalog diff` in that folder, with the stores answered by
`tests/helpers/teaser-store-mock.ts` (preloaded through a `bunfig.toml` in the folder, so the children `release plan`
starts use it too; nothing reaches the network): a brand-new app record with nothing on it for the plan and the dry
run, then the two products on both stores for the diff. Regions: the App Store's 175 storefronts, Google Play 174
(the count Play answered in a recorded read-only run).
- `storebound scan` of `tests/fixtures/scan/teaser` (findings, declarations proposal) and of `teaser-fixed` after the
fixes, and the Data safety answer count of `storebound check`.
The plain reasons under the findings and the callouts on the desktop frames are annotations, set apart from the CLI
text. The store text is `examples/demo-game/store/shots/copy.json`, the screenshots its real renders, the app icon its
`store/icon/icon.png`. The mail row is fictional: no real names or addresses, no mail-app branding. The test also checks
the timing: scenes 6-7 s, captions on screen at least 4 s, 55-65 s in total, 16:9 only.
## Render
Needs Bun, ffmpeg, Playwright (repo devDependency; Playwright's Chromium or an installed Google Chrome) and the demo
game's store renders:
```sh
cd examples/demo-game && bun serve.ts & bun ../../cli/index.ts shots capture && bun ../../cli/index.ts shots fonts && bun ../../cli/index.ts shots render
# from the repo root
bun media/teaser/render.ts > media/teaser/out/render.log 2>&1 & # master, sound, poster, web version: about 15 min
bun media/teaser/render.ts --desktop # capture the desktop app frames again (after a UI change)
bun media/teaser/render.ts --stills 2,12.5,30 # PNG stills in out/stills for a quick layout check
bun media/teaser/render.ts --serve --port 8750 # live preview: /index.html?play=1 (or ?t=12.5)
```
Outputs (gitignored) in `media/teaser/out/`: `teaser-1920x1080.mp4` (master), `teaser-web.mp4` (1280x720, about
4.5 MB) with `poster-web.jpg`, `teaser-1920x1080-silent.mp4`, `poster-1920x1080.jpg`, `music.wav`.