videowright 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/README.md +91 -0
  2. package/dist/cli/argv.d.ts +28 -0
  3. package/dist/cli/argv.d.ts.map +1 -0
  4. package/dist/cli/argv.js +115 -0
  5. package/dist/cli/argv.js.map +1 -0
  6. package/dist/cli/bin.d.ts +7 -0
  7. package/dist/cli/bin.d.ts.map +1 -0
  8. package/dist/cli/bin.js +10 -0
  9. package/dist/cli/bin.js.map +1 -0
  10. package/dist/cli/dev.d.ts +19 -0
  11. package/dist/cli/dev.d.ts.map +1 -0
  12. package/dist/cli/dev.js +104 -0
  13. package/dist/cli/dev.js.map +1 -0
  14. package/dist/cli/discover.d.ts +29 -0
  15. package/dist/cli/discover.d.ts.map +1 -0
  16. package/dist/cli/discover.js +104 -0
  17. package/dist/cli/discover.js.map +1 -0
  18. package/dist/cli/discover_project.d.ts +29 -0
  19. package/dist/cli/discover_project.d.ts.map +1 -0
  20. package/dist/cli/discover_project.js +108 -0
  21. package/dist/cli/discover_project.js.map +1 -0
  22. package/dist/cli/errors.d.ts +10 -0
  23. package/dist/cli/errors.d.ts.map +1 -0
  24. package/dist/cli/errors.js +13 -0
  25. package/dist/cli/errors.js.map +1 -0
  26. package/dist/cli/ffmpeg.d.ts +57 -0
  27. package/dist/cli/ffmpeg.d.ts.map +1 -0
  28. package/dist/cli/ffmpeg.js +122 -0
  29. package/dist/cli/ffmpeg.js.map +1 -0
  30. package/dist/cli/index.d.ts +7 -0
  31. package/dist/cli/index.d.ts.map +1 -0
  32. package/dist/cli/index.js +152 -0
  33. package/dist/cli/index.js.map +1 -0
  34. package/dist/cli/playwright_check.d.ts +44 -0
  35. package/dist/cli/playwright_check.d.ts.map +1 -0
  36. package/dist/cli/playwright_check.js +20 -0
  37. package/dist/cli/playwright_check.js.map +1 -0
  38. package/dist/cli/prompt.d.ts +13 -0
  39. package/dist/cli/prompt.d.ts.map +1 -0
  40. package/dist/cli/prompt.js +47 -0
  41. package/dist/cli/prompt.js.map +1 -0
  42. package/dist/cli/render.d.ts +60 -0
  43. package/dist/cli/render.d.ts.map +1 -0
  44. package/dist/cli/render.js +471 -0
  45. package/dist/cli/render.js.map +1 -0
  46. package/dist/cli/script_cmd.d.ts +26 -0
  47. package/dist/cli/script_cmd.d.ts.map +1 -0
  48. package/dist/cli/script_cmd.js +88 -0
  49. package/dist/cli/script_cmd.js.map +1 -0
  50. package/dist/cli/time_shim.d.ts +44 -0
  51. package/dist/cli/time_shim.d.ts.map +1 -0
  52. package/dist/cli/time_shim.js +390 -0
  53. package/dist/cli/time_shim.js.map +1 -0
  54. package/dist/cli/ts_loader.d.ts +28 -0
  55. package/dist/cli/ts_loader.d.ts.map +1 -0
  56. package/dist/cli/ts_loader.js +95 -0
  57. package/dist/cli/ts_loader.js.map +1 -0
  58. package/dist/cli/vite_helpers.d.ts +62 -0
  59. package/dist/cli/vite_helpers.d.ts.map +1 -0
  60. package/dist/cli/vite_helpers.js +273 -0
  61. package/dist/cli/vite_helpers.js.map +1 -0
  62. package/dist/index.d.ts +11 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +14 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/player/hash_router.d.ts +23 -0
  67. package/dist/player/hash_router.d.ts.map +1 -0
  68. package/dist/player/hash_router.js +49 -0
  69. package/dist/player/hash_router.js.map +1 -0
  70. package/dist/player/hud.d.ts +33 -0
  71. package/dist/player/hud.d.ts.map +1 -0
  72. package/dist/player/hud.js +357 -0
  73. package/dist/player/hud.js.map +1 -0
  74. package/dist/player/index.d.ts +123 -0
  75. package/dist/player/index.d.ts.map +1 -0
  76. package/dist/player/index.js +848 -0
  77. package/dist/player/index.js.map +1 -0
  78. package/dist/player/input.d.ts +14 -0
  79. package/dist/player/input.d.ts.map +1 -0
  80. package/dist/player/input.js +90 -0
  81. package/dist/player/input.js.map +1 -0
  82. package/dist/player/slot.d.ts +22 -0
  83. package/dist/player/slot.d.ts.map +1 -0
  84. package/dist/player/slot.js +43 -0
  85. package/dist/player/slot.js.map +1 -0
  86. package/dist/player/transitions/cut.d.ts +7 -0
  87. package/dist/player/transitions/cut.d.ts.map +1 -0
  88. package/dist/player/transitions/cut.js +9 -0
  89. package/dist/player/transitions/cut.js.map +1 -0
  90. package/dist/player/transitions/fade.d.ts +7 -0
  91. package/dist/player/transitions/fade.d.ts.map +1 -0
  92. package/dist/player/transitions/fade.js +18 -0
  93. package/dist/player/transitions/fade.js.map +1 -0
  94. package/dist/player/transitions/index.d.ts +4 -0
  95. package/dist/player/transitions/index.d.ts.map +1 -0
  96. package/dist/player/transitions/index.js +4 -0
  97. package/dist/player/transitions/index.js.map +1 -0
  98. package/dist/player/transitions/slide.d.ts +6 -0
  99. package/dist/player/transitions/slide.d.ts.map +1 -0
  100. package/dist/player/transitions/slide.js +35 -0
  101. package/dist/player/transitions/slide.js.map +1 -0
  102. package/dist/script/index.d.ts +2 -0
  103. package/dist/script/index.d.ts.map +1 -0
  104. package/dist/script/index.js +2 -0
  105. package/dist/script/index.js.map +1 -0
  106. package/dist/script/script.d.ts +10 -0
  107. package/dist/script/script.d.ts.map +1 -0
  108. package/dist/script/script.js +41 -0
  109. package/dist/script/script.js.map +1 -0
  110. package/dist/segment/SegmentRunner.d.ts +52 -0
  111. package/dist/segment/SegmentRunner.d.ts.map +1 -0
  112. package/dist/segment/SegmentRunner.js +187 -0
  113. package/dist/segment/SegmentRunner.js.map +1 -0
  114. package/dist/segment/defineConfig.d.ts +6 -0
  115. package/dist/segment/defineConfig.d.ts.map +1 -0
  116. package/dist/segment/defineConfig.js +7 -0
  117. package/dist/segment/defineConfig.js.map +1 -0
  118. package/dist/segment/defineSegment.d.ts +7 -0
  119. package/dist/segment/defineSegment.d.ts.map +1 -0
  120. package/dist/segment/defineSegment.js +25 -0
  121. package/dist/segment/defineSegment.js.map +1 -0
  122. package/dist/segment/index.d.ts +5 -0
  123. package/dist/segment/index.d.ts.map +1 -0
  124. package/dist/segment/index.js +4 -0
  125. package/dist/segment/index.js.map +1 -0
  126. package/dist/timeline/index.d.ts +73 -0
  127. package/dist/timeline/index.d.ts.map +1 -0
  128. package/dist/timeline/index.js +142 -0
  129. package/dist/timeline/index.js.map +1 -0
  130. package/dist/timeline/loadAudioTrack.d.ts +18 -0
  131. package/dist/timeline/loadAudioTrack.d.ts.map +1 -0
  132. package/dist/timeline/loadAudioTrack.js +44 -0
  133. package/dist/timeline/loadAudioTrack.js.map +1 -0
  134. package/dist/timeline/loadVoiceover.d.ts +18 -0
  135. package/dist/timeline/loadVoiceover.d.ts.map +1 -0
  136. package/dist/timeline/loadVoiceover.js +38 -0
  137. package/dist/timeline/loadVoiceover.js.map +1 -0
  138. package/dist/timeline/resolveTiming.d.ts +28 -0
  139. package/dist/timeline/resolveTiming.d.ts.map +1 -0
  140. package/dist/timeline/resolveTiming.js +63 -0
  141. package/dist/timeline/resolveTiming.js.map +1 -0
  142. package/dist/timeline/validateTiming.d.ts +29 -0
  143. package/dist/timeline/validateTiming.d.ts.map +1 -0
  144. package/dist/timeline/validateTiming.js +62 -0
  145. package/dist/timeline/validateTiming.js.map +1 -0
  146. package/dist/types.d.ts +216 -0
  147. package/dist/types.d.ts.map +1 -0
  148. package/dist/types.js +6 -0
  149. package/dist/types.js.map +1 -0
  150. package/package.json +47 -0
  151. package/skill/SKILL.md +64 -0
  152. package/skill/assets/hello_world/PLAN.md +31 -0
  153. package/skill/assets/hello_world/README.md +27 -0
  154. package/skill/assets/hello_world/audio/audio_plan.md +14 -0
  155. package/skill/assets/hello_world/segments/hello_intro.ts +69 -0
  156. package/skill/assets/hello_world/segments/hello_outro.ts +71 -0
  157. package/skill/assets/hello_world/timeline.ts +15 -0
  158. package/skill/assets/hello_world/voiceover_script/script.md +10 -0
  159. package/skill/assets/install/package.json +10 -0
  160. package/skill/assets/install/tsconfig.json +23 -0
  161. package/skill/assets/styles/editorial-mono/STYLE.md +124 -0
  162. package/skill/assets/styles/editorial-mono/brand.md +85 -0
  163. package/skill/assets/styles/editorial-mono/reference/animations.jsx +752 -0
  164. package/skill/assets/styles/editorial-mono/reference/scenes.html +563 -0
  165. package/skill/assets/styles/editorial-mono/sample/bullet.ts +101 -0
  166. package/skill/assets/styles/editorial-mono/sample/content.ts +104 -0
  167. package/skill/assets/styles/editorial-mono/sample/cta.ts +113 -0
  168. package/skill/assets/styles/editorial-mono/sample/feature.ts +111 -0
  169. package/skill/assets/styles/editorial-mono/sample/grid.ts +97 -0
  170. package/skill/assets/styles/editorial-mono/sample/kinetic.ts +96 -0
  171. package/skill/assets/styles/editorial-mono/sample/section.ts +101 -0
  172. package/skill/assets/styles/editorial-mono/sample/stat.ts +128 -0
  173. package/skill/assets/styles/editorial-mono/sample/title.ts +97 -0
  174. package/skill/assets/styles/editorial-mono/sample/ui-showcase.ts +159 -0
  175. package/skill/assets/styles/editorial-mono/tokens.css +44 -0
  176. package/skill/assets/styles/iso-diagram/STYLE.md +109 -0
  177. package/skill/assets/styles/iso-diagram/brand.md +32 -0
  178. package/skill/assets/styles/iso-diagram/reference/animations.jsx +673 -0
  179. package/skill/assets/styles/iso-diagram/reference/scenes.html +427 -0
  180. package/skill/assets/styles/iso-diagram/sample/bullet.ts +144 -0
  181. package/skill/assets/styles/iso-diagram/sample/content.ts +192 -0
  182. package/skill/assets/styles/iso-diagram/sample/cta.ts +162 -0
  183. package/skill/assets/styles/iso-diagram/sample/feature.ts +205 -0
  184. package/skill/assets/styles/iso-diagram/sample/grid.ts +181 -0
  185. package/skill/assets/styles/iso-diagram/sample/kinetic.ts +102 -0
  186. package/skill/assets/styles/iso-diagram/sample/section.ts +149 -0
  187. package/skill/assets/styles/iso-diagram/sample/stat.ts +164 -0
  188. package/skill/assets/styles/iso-diagram/sample/title.ts +173 -0
  189. package/skill/assets/styles/iso-diagram/sample/ui-showcase.ts +162 -0
  190. package/skill/assets/styles/iso-diagram/tokens.css +40 -0
  191. package/skill/assets/styles/motion-engineering/STYLE.md +106 -0
  192. package/skill/assets/styles/motion-engineering/brand.md +29 -0
  193. package/skill/assets/styles/motion-engineering/reference/animations.jsx +673 -0
  194. package/skill/assets/styles/motion-engineering/reference/scenes.html +513 -0
  195. package/skill/assets/styles/motion-engineering/sample/bullet.ts +176 -0
  196. package/skill/assets/styles/motion-engineering/sample/content.ts +228 -0
  197. package/skill/assets/styles/motion-engineering/sample/cta.ts +209 -0
  198. package/skill/assets/styles/motion-engineering/sample/feature.ts +299 -0
  199. package/skill/assets/styles/motion-engineering/sample/grid.ts +190 -0
  200. package/skill/assets/styles/motion-engineering/sample/kinetic.ts +159 -0
  201. package/skill/assets/styles/motion-engineering/sample/section.ts +196 -0
  202. package/skill/assets/styles/motion-engineering/sample/stat.ts +230 -0
  203. package/skill/assets/styles/motion-engineering/sample/title.ts +219 -0
  204. package/skill/assets/styles/motion-engineering/sample/ui-showcase.ts +267 -0
  205. package/skill/assets/styles/motion-engineering/tokens.css +40 -0
  206. package/skill/assets/styles/neon-terminal/STYLE.md +105 -0
  207. package/skill/assets/styles/neon-terminal/brand.md +27 -0
  208. package/skill/assets/styles/neon-terminal/reference/animations.jsx +673 -0
  209. package/skill/assets/styles/neon-terminal/reference/scenes.html +387 -0
  210. package/skill/assets/styles/neon-terminal/sample/bullet.ts +113 -0
  211. package/skill/assets/styles/neon-terminal/sample/content.ts +117 -0
  212. package/skill/assets/styles/neon-terminal/sample/cta.ts +131 -0
  213. package/skill/assets/styles/neon-terminal/sample/feature.ts +112 -0
  214. package/skill/assets/styles/neon-terminal/sample/grid.ts +128 -0
  215. package/skill/assets/styles/neon-terminal/sample/kinetic.ts +105 -0
  216. package/skill/assets/styles/neon-terminal/sample/section.ts +96 -0
  217. package/skill/assets/styles/neon-terminal/sample/stat.ts +123 -0
  218. package/skill/assets/styles/neon-terminal/sample/title.ts +122 -0
  219. package/skill/assets/styles/neon-terminal/sample/ui-showcase.ts +127 -0
  220. package/skill/assets/styles/neon-terminal/tokens.css +39 -0
  221. package/skill/assets/styles/risograph/STYLE.md +110 -0
  222. package/skill/assets/styles/risograph/brand.md +26 -0
  223. package/skill/assets/styles/risograph/reference/animations.jsx +673 -0
  224. package/skill/assets/styles/risograph/reference/scenes.html +403 -0
  225. package/skill/assets/styles/risograph/sample/bullet.ts +124 -0
  226. package/skill/assets/styles/risograph/sample/content.ts +135 -0
  227. package/skill/assets/styles/risograph/sample/cta.ts +149 -0
  228. package/skill/assets/styles/risograph/sample/feature.ts +152 -0
  229. package/skill/assets/styles/risograph/sample/grid.ts +123 -0
  230. package/skill/assets/styles/risograph/sample/kinetic.ts +125 -0
  231. package/skill/assets/styles/risograph/sample/section.ts +130 -0
  232. package/skill/assets/styles/risograph/sample/stat.ts +145 -0
  233. package/skill/assets/styles/risograph/sample/title.ts +132 -0
  234. package/skill/assets/styles/risograph/sample/ui-showcase.ts +147 -0
  235. package/skill/assets/styles/risograph/tokens.css +39 -0
  236. package/skill/assets/styles/swiss-console/STYLE.md +107 -0
  237. package/skill/assets/styles/swiss-console/brand.md +37 -0
  238. package/skill/assets/styles/swiss-console/reference/animations.jsx +673 -0
  239. package/skill/assets/styles/swiss-console/reference/scenes.html +420 -0
  240. package/skill/assets/styles/swiss-console/sample/bullet.ts +122 -0
  241. package/skill/assets/styles/swiss-console/sample/content.ts +137 -0
  242. package/skill/assets/styles/swiss-console/sample/cta.ts +109 -0
  243. package/skill/assets/styles/swiss-console/sample/feature.ts +163 -0
  244. package/skill/assets/styles/swiss-console/sample/grid.ts +145 -0
  245. package/skill/assets/styles/swiss-console/sample/kinetic.ts +117 -0
  246. package/skill/assets/styles/swiss-console/sample/section.ts +127 -0
  247. package/skill/assets/styles/swiss-console/sample/stat.ts +148 -0
  248. package/skill/assets/styles/swiss-console/sample/title.ts +148 -0
  249. package/skill/assets/styles/swiss-console/sample/ui-showcase.ts +198 -0
  250. package/skill/assets/styles/swiss-console/tokens.css +39 -0
  251. package/skill/install/INSTALL.md +400 -0
  252. package/skill/references/audio/audio_plan.md +199 -0
  253. package/skill/references/audio/build.md +208 -0
  254. package/skill/references/audio/cue_template.md +219 -0
  255. package/skill/references/audio/ffmpeg_cookbook.md +267 -0
  256. package/skill/references/audio/music/music.md +171 -0
  257. package/skill/references/audio/music/providers/elevenlabs.md +170 -0
  258. package/skill/references/audio/music/providers/manual.md +140 -0
  259. package/skill/references/audio/music/providers/openverse.md +265 -0
  260. package/skill/references/audio/sfx/providers/elevenlabs.md +152 -0
  261. package/skill/references/audio/sfx/providers/manual.md +117 -0
  262. package/skill/references/audio/sfx/providers/openverse.md +243 -0
  263. package/skill/references/audio/sfx/sfx.md +149 -0
  264. package/skill/references/audio/styles.md +102 -0
  265. package/skill/references/audio/sync.md +237 -0
  266. package/skill/references/audio/voiceover/animation_sync.md +142 -0
  267. package/skill/references/audio/voiceover/provider_script.md +153 -0
  268. package/skill/references/audio/voiceover/providers/elevenlabs.md +288 -0
  269. package/skill/references/audio/voiceover/providers/manual.md +100 -0
  270. package/skill/references/audio/voiceover/script_writing.md +100 -0
  271. package/skill/references/audio/voiceover/style_intake.md +56 -0
  272. package/skill/references/audio/voiceover/sync_algorithm.md +167 -0
  273. package/skill/references/audio/voiceover.md +296 -0
  274. package/skill/references/audio.md +135 -0
  275. package/skill/references/authoring_segment.md +446 -0
  276. package/skill/references/create_or_edit_video.md +232 -0
  277. package/skill/references/dev_server.md +157 -0
  278. package/skill/references/export.md +145 -0
  279. package/skill/references/new_video.md +117 -0
  280. package/skill/references/project_structure.md +144 -0
  281. package/skill/references/setup.md +109 -0
  282. package/skill/references/setup_new_style.md +158 -0
  283. package/skill/references/styles.md +154 -0
  284. package/skill/references/testing.md +115 -0
  285. package/skill/references/types.md +240 -0
  286. package/src/cli/entry/components/copy_button.ts +42 -0
  287. package/src/cli/entry/components/download_modal.ts +204 -0
  288. package/src/cli/entry/components/empty_state.ts +55 -0
  289. package/src/cli/entry/components/hide_hud_tab.ts +37 -0
  290. package/src/cli/entry/components/icons.ts +31 -0
  291. package/src/cli/entry/components/top_bar.ts +69 -0
  292. package/src/cli/entry/components/video_card.ts +57 -0
  293. package/src/cli/entry/dev_frame.ts +189 -0
  294. package/src/cli/entry/entry_index.ts +16 -0
  295. package/src/cli/entry/entry_video.ts +24 -0
  296. package/src/cli/entry/index.html +12 -0
  297. package/src/cli/entry/parse_slug.ts +14 -0
  298. package/src/cli/entry/render.html +17 -0
  299. package/src/cli/entry/render_entry.ts +121 -0
  300. package/src/cli/entry/styles/base.css +45 -0
  301. package/src/cli/entry/styles/components.css +605 -0
  302. package/src/cli/entry/styles/tokens.css +44 -0
  303. package/src/cli/entry/video.html +22 -0
  304. package/src/cli/entry/views/homepage.ts +66 -0
  305. package/src/cli/entry/views/video_view.ts +286 -0
  306. package/src/cli/entry/virtual.d.ts +8 -0
@@ -0,0 +1,563 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Editorial Mono — Reference Scenes</title>
6
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
7
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
8
+ <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
9
+ <link rel="stylesheet" href="../tokens.css" />
10
+ <style>
11
+ html, body { margin: 0; padding: 0; height: 100%; background: #0a0a0a; }
12
+ body { font-family: var(--font-body); }
13
+ /* Editorial Mono scene primitives */
14
+ .em-canvas { position: absolute; inset: 0; background: var(--color-bg); color: var(--color-fg); overflow: hidden; }
15
+ .em-label { font-family: var(--font-mono); font-size: 18px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--color-muted); font-weight: 500; }
16
+ .em-rule { background: var(--color-border); height: 1px; width: 100%; }
17
+ .em-rule-v { background: var(--color-border); width: 1px; height: 100%; }
18
+ .em-display { font-family: var(--font-display); font-weight: 400; line-height: 0.98; letter-spacing: -0.01em; color: var(--color-fg); }
19
+ .em-display.italic { font-style: italic; }
20
+ .em-body { font-family: var(--font-body); font-weight: 400; color: var(--color-fg); line-height: 1.4; }
21
+ .em-muted { color: var(--color-muted); }
22
+ .em-accent { color: var(--color-accent); }
23
+ .em-page-frame {
24
+ position: absolute;
25
+ left: var(--safe-x); right: var(--safe-x);
26
+ top: 56px; height: 1px;
27
+ background: var(--color-border);
28
+ }
29
+ .em-page-frame.bottom { top: auto; bottom: 56px; }
30
+ .em-folio {
31
+ position: absolute;
32
+ left: var(--safe-x);
33
+ top: 30px;
34
+ font-family: var(--font-mono); font-size: 14px; letter-spacing: 0.16em;
35
+ text-transform: uppercase; color: var(--color-muted);
36
+ }
37
+ .em-folio.right { left: auto; right: var(--safe-x); }
38
+ </style>
39
+ </head>
40
+ <body>
41
+
42
+ <script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
43
+ <script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
44
+ <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
45
+
46
+ <div id="root"></div>
47
+
48
+ <script type="text/babel" src="animations.jsx"></script>
49
+ <script type="text/babel">
50
+
51
+ /* ──────────────────────────────────────────────────────────────────────
52
+ * Editorial Mono — Reference Scenes
53
+ * Each scene is a Sprite with a 4-second window. Demo product: "Beacon".
54
+ * ────────────────────────────────────────────────────────────────────── */
55
+
56
+ const SCENE = 4; // seconds per scene
57
+ const FADE = 0.25;
58
+
59
+ // ── Easing alias used inside scenes ──────────────────────────────────
60
+ const EOUT = Easing.easeOutQuart;
61
+ const EIN = Easing.easeInCubic;
62
+
63
+ // ── Reusable: fade-up text that uses local sprite time but parameterised
64
+ // by an `at` offset so we can stagger multiple lines within one scene.
65
+ function FadeUp({
66
+ children,
67
+ at = 0, // seconds into the scene to start entering
68
+ hold = SCENE, // seconds visible
69
+ rise = 24, // px to drift up
70
+ className = '',
71
+ style = {},
72
+ }) {
73
+ const { localTime } = useSprite();
74
+ const t = localTime - at;
75
+ let opacity = 0, ty = rise;
76
+ if (t < 0) { opacity = 0; ty = rise; }
77
+ else if (t < 0.6) {
78
+ const k = EOUT(clamp(t / 0.6, 0, 1));
79
+ opacity = k;
80
+ ty = rise * (1 - k);
81
+ } else {
82
+ opacity = 1; ty = 0;
83
+ }
84
+ // exit fade in last FADE seconds of scene
85
+ const exitStart = SCENE - FADE;
86
+ if (localTime > exitStart) {
87
+ const k = EIN(clamp((localTime - exitStart) / FADE, 0, 1));
88
+ opacity *= (1 - k);
89
+ }
90
+ return (
91
+ <div className={className} style={{ ...style, opacity, transform: `translateY(${ty}px)` }}>
92
+ {children}
93
+ </div>
94
+ );
95
+ }
96
+
97
+ // ── Page frame chrome (folios + rules) shared across all scenes
98
+ function PageChrome({ folio, right }) {
99
+ return (
100
+ <Sprite start={0} end={SCENE * 10} keepMounted>
101
+ <div className="em-folio">{folio}</div>
102
+ <div className="em-folio right">{right}</div>
103
+ <div className="em-page-frame" />
104
+ <div className="em-page-frame bottom" />
105
+ </Sprite>
106
+ );
107
+ }
108
+
109
+ // ── Scene 1: Title card ──────────────────────────────────────────────
110
+ function TitleScene() {
111
+ return (
112
+ <Sprite start={0} end={SCENE}>
113
+ <div style={{ position: 'absolute', left: 'var(--safe-x)', top: 240 }}>
114
+ <FadeUp at={0} className="em-label" style={{ marginBottom: 48 }}>
115
+ Vol. 01 / 2026 / Issue One
116
+ </FadeUp>
117
+ <FadeUp at={0.2}>
118
+ <div className="em-display" style={{ fontSize: 320 }}>
119
+ Beacon<span className="em-accent" style={{ fontStyle: 'italic' }}>.</span>
120
+ </div>
121
+ </FadeUp>
122
+ <FadeUp at={0.6} className="em-body em-muted" style={{ fontSize: 40, marginTop: 56, maxWidth: 1100, fontFamily: 'var(--font-display)', fontStyle: 'italic', color: 'var(--color-fg)' }}>
123
+ Long-running agents for research labs.
124
+ </FadeUp>
125
+ </div>
126
+ </Sprite>
127
+ );
128
+ }
129
+
130
+ // ── Scene 2: Section header ──────────────────────────────────────────
131
+ function SectionScene() {
132
+ return (
133
+ <Sprite start={SCENE} end={SCENE * 2}>
134
+ <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
135
+ alignItems: 'center', justifyContent: 'center', gap: 56 }}>
136
+ <FadeUp at={0} className="em-label">Chapter One</FadeUp>
137
+ <FadeUp at={0.15} style={{ width: 240, height: 1, background: 'var(--color-border)' }} rise={8} />
138
+ <FadeUp at={0.3}>
139
+ <div className="em-display italic" style={{ fontSize: 220, textAlign: 'center' }}>
140
+ The Problem
141
+ </div>
142
+ </FadeUp>
143
+ <FadeUp at={0.55} style={{ width: 240, height: 1, background: 'var(--color-border)' }} rise={8} />
144
+ </div>
145
+ </Sprite>
146
+ );
147
+ }
148
+
149
+ // ── Scene 3: Kinetic statement ───────────────────────────────────────
150
+ function KineticScene() {
151
+ // word-by-word fade-up; last word gets a red underline draw
152
+ const words = [
153
+ { t: 'Most', at: 0.00 },
154
+ { t: 'agents', at: 0.15 },
155
+ { t: 'fail', at: 0.30 },
156
+ { t: 'because', at: 0.45 },
157
+ { t: 'they', at: 0.60 },
158
+ { t: 'forget', at: 0.75, accent: true },
159
+ ];
160
+ return (
161
+ <Sprite start={SCENE * 2} end={SCENE * 3}>
162
+ {({ localTime }) => {
163
+ const underlineP = clamp((localTime - 1.7) / 0.6, 0, 1);
164
+ return (
165
+ <div style={{ position: 'absolute', left: 'var(--safe-x)', top: 260, maxWidth: 1500 }}>
166
+ <FadeUp at={0} className="em-label" style={{ marginBottom: 48 }}>
167
+ Statement
168
+ </FadeUp>
169
+ <div className="em-display italic" style={{ fontSize: 180, lineHeight: 1.0, display: 'flex', flexWrap: 'wrap', columnGap: 38, rowGap: 12 }}>
170
+ {words.map((w, i) => (
171
+ <FadeUp key={i} at={w.at} rise={28} style={{ position: 'relative' }}>
172
+ <span>{w.t}{i === words.length - 1 ? '.' : ''}</span>
173
+ {w.accent && (
174
+ <div style={{
175
+ position: 'absolute',
176
+ left: 0, right: 'auto', bottom: 18,
177
+ height: 8,
178
+ width: `calc(${underlineP * 100}% - ${underlineP > 0 ? '14px' : '0px'})`,
179
+ background: 'var(--color-accent)',
180
+ }} />
181
+ )}
182
+ </FadeUp>
183
+ ))}
184
+ </div>
185
+ </div>
186
+ );
187
+ }}
188
+ </Sprite>
189
+ );
190
+ }
191
+
192
+ // ── Scene 4: Bullet reveal ───────────────────────────────────────────
193
+ function BulletScene() {
194
+ const items = [
195
+ { n: '01', t: 'Context windows decay.' },
196
+ { n: '02', t: 'Tool selection drifts.' },
197
+ { n: '03', t: 'Plans go stale.' },
198
+ { n: '04', t: 'Errors compound.' },
199
+ ];
200
+ return (
201
+ <Sprite start={SCENE * 3} end={SCENE * 4}>
202
+ <div style={{ position: 'absolute', left: 'var(--safe-x)', top: 200, right: 'var(--safe-x)' }}>
203
+ <FadeUp at={0} className="em-label" style={{ marginBottom: 64 }}>
204
+ Failure Modes
205
+ </FadeUp>
206
+ <FadeUp at={0.15}>
207
+ <div className="em-display italic" style={{ fontSize: 80, marginBottom: 80 }}>
208
+ Where agents break.
209
+ </div>
210
+ </FadeUp>
211
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 32 }}>
212
+ {items.map((it, i) => (
213
+ <FadeUp key={it.n} at={0.5 + i * 0.18} rise={18}>
214
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 48 }}>
215
+ <span className="em-label" style={{ fontSize: 22, color: 'var(--color-accent)', minWidth: 64 }}>{it.n}</span>
216
+ <span style={{ width: 32, height: 1, background: 'var(--color-fg)', alignSelf: 'center' }} />
217
+ <span className="em-body" style={{ fontSize: 48, fontWeight: 500 }}>{it.t}</span>
218
+ </div>
219
+ </FadeUp>
220
+ ))}
221
+ </div>
222
+ </div>
223
+ </Sprite>
224
+ );
225
+ }
226
+
227
+ // ── Scene 5: Stat card ───────────────────────────────────────────────
228
+ function StatScene() {
229
+ return (
230
+ <Sprite start={SCENE * 4} end={SCENE * 5}>
231
+ {({ localTime }) => {
232
+ // Count-up over 900ms after a 200ms delay
233
+ const cP = clamp((localTime - 0.2) / 0.9, 0, 1);
234
+ const value = Math.round(EOUT(cP) * 84);
235
+ const underlineP = clamp((localTime - 1.4) / 0.7, 0, 1);
236
+ return (
237
+ <div style={{ position: 'absolute', inset: 0,
238
+ display: 'grid', gridTemplateColumns: '1fr 1fr',
239
+ alignItems: 'center',
240
+ padding: '0 var(--safe-x)', gap: 80 }}>
241
+ <div>
242
+ <FadeUp at={0} className="em-label" style={{ marginBottom: 48 }}>
243
+ Finding · 03
244
+ </FadeUp>
245
+ <div style={{ position: 'relative', display: 'inline-block' }}>
246
+ <div className="em-display" style={{ fontSize: 380, lineHeight: 0.9 }}>
247
+ {value}<span className="em-accent">%</span>
248
+ </div>
249
+ <div style={{
250
+ position: 'absolute', left: 0, bottom: -16,
251
+ height: 6, width: `${underlineP * 80}%`,
252
+ background: 'var(--color-accent)',
253
+ }} />
254
+ </div>
255
+ </div>
256
+ <FadeUp at={0.4} rise={20}>
257
+ <div className="em-body" style={{ fontSize: 44, lineHeight: 1.3, maxWidth: 640, fontWeight: 400 }}>
258
+ of agent failures occur <em style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic' }}>after</em> the fourth tool call.
259
+ </div>
260
+ <div className="em-label" style={{ marginTop: 32 }}>
261
+ Source · Beacon Logs, Q1 2026
262
+ </div>
263
+ </FadeUp>
264
+ </div>
265
+ );
266
+ }}
267
+ </Sprite>
268
+ );
269
+ }
270
+
271
+ // ── Scene 6: Feature card ────────────────────────────────────────────
272
+ function FeatureScene() {
273
+ return (
274
+ <Sprite start={SCENE * 5} end={SCENE * 6}>
275
+ <div style={{ position: 'absolute', left: 'var(--safe-x)', top: 220, right: 'var(--safe-x)' }}>
276
+ <FadeUp at={0} className="em-label" style={{ marginBottom: 64 }}>
277
+ Feature · 01 of 03
278
+ </FadeUp>
279
+ <div style={{ display: 'grid', gridTemplateColumns: '180px 1fr', gap: 64, alignItems: 'start' }}>
280
+ <FadeUp at={0.15}>
281
+ {/* Editorial 'dropcap' style mark */}
282
+ <div style={{
283
+ width: 140, height: 140,
284
+ border: '1px solid var(--color-fg)',
285
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
286
+ fontFamily: 'var(--font-display)', fontSize: 100, fontStyle: 'italic',
287
+ }}>C</div>
288
+ </FadeUp>
289
+ <div>
290
+ <FadeUp at={0.25}>
291
+ <div className="em-display italic" style={{ fontSize: 140 }}>
292
+ Checkpoint memory.
293
+ </div>
294
+ </FadeUp>
295
+ <FadeUp at={0.5} rise={16}>
296
+ <div className="em-body" style={{ fontSize: 32, lineHeight: 1.4, maxWidth: 1100, marginTop: 48, fontWeight: 400 }}>
297
+ Beacon snapshots an agent's reasoning state at each tool boundary.
298
+ When a plan goes stale, the agent rewinds — not to the start, but
299
+ to the last point its model of the world was correct.
300
+ </div>
301
+ </FadeUp>
302
+ </div>
303
+ </div>
304
+ </div>
305
+ </Sprite>
306
+ );
307
+ }
308
+
309
+ // ── Scene 7: Card grid ───────────────────────────────────────────────
310
+ function CardGridScene() {
311
+ const cards = [
312
+ { n: '01', name: 'Memory', d: 'Persistent state across long sessions.' },
313
+ { n: '02', name: 'Reasoning', d: 'Plans that adapt to fresh evidence.' },
314
+ { n: '03', name: 'Recovery', d: 'Rewind to a last-known-good moment.' },
315
+ ];
316
+ return (
317
+ <Sprite start={SCENE * 6} end={SCENE * 7}>
318
+ <div style={{ position: 'absolute', left: 'var(--safe-x)', top: 220, right: 'var(--safe-x)' }}>
319
+ <FadeUp at={0} className="em-label" style={{ marginBottom: 64 }}>
320
+ The Architecture
321
+ </FadeUp>
322
+ <FadeUp at={0.15}>
323
+ <div className="em-display italic" style={{ fontSize: 100, marginBottom: 96 }}>
324
+ Three primitives.
325
+ </div>
326
+ </FadeUp>
327
+ <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 1, background: 'var(--color-border)' }}>
328
+ {cards.map((c, i) => (
329
+ <FadeUp key={c.n} at={0.45 + i * 0.18} rise={20}>
330
+ <div style={{ background: 'var(--color-bg)', padding: '48px 56px 56px', minHeight: 360 }}>
331
+ <div className="em-label em-accent" style={{ marginBottom: 32, color: 'var(--color-accent)' }}>{c.n}</div>
332
+ <div className="em-display" style={{ fontSize: 64, marginBottom: 32 }}>{c.name}</div>
333
+ <div className="em-body em-muted" style={{ fontSize: 24, lineHeight: 1.4, maxWidth: 320 }}>{c.d}</div>
334
+ </div>
335
+ </FadeUp>
336
+ ))}
337
+ </div>
338
+ </div>
339
+ </Sprite>
340
+ );
341
+ }
342
+
343
+ // ── Scene 8: UI showcase ─────────────────────────────────────────────
344
+ function UIShowcaseScene() {
345
+ return (
346
+ <Sprite start={SCENE * 7} end={SCENE * 8}>
347
+ {({ localTime }) => {
348
+ const arrow1 = clamp((localTime - 1.0) / 0.5, 0, 1);
349
+ const arrow2 = clamp((localTime - 1.4) / 0.5, 0, 1);
350
+ return (
351
+ <>
352
+ <FadeUp at={0} className="em-label" style={{ position: 'absolute', left: 'var(--safe-x)', top: 110 }}>
353
+ Plate II · The Console
354
+ </FadeUp>
355
+
356
+ {/* product mock */}
357
+ <FadeUp at={0.2}>
358
+ <div style={{
359
+ position: 'absolute', left: 360, top: 200, width: 1200, height: 680,
360
+ background: 'var(--color-surface)',
361
+ border: '1px solid var(--color-fg)',
362
+ }}>
363
+ {/* window header */}
364
+ <div style={{ height: 48, borderBottom: '1px solid var(--color-fg)',
365
+ display: 'flex', alignItems: 'center', padding: '0 20px', gap: 10 }}>
366
+ <span style={{ width: 10, height: 10, borderRadius: 5, border: '1px solid var(--color-fg)' }} />
367
+ <span style={{ width: 10, height: 10, borderRadius: 5, border: '1px solid var(--color-fg)' }} />
368
+ <span style={{ width: 10, height: 10, borderRadius: 5, border: '1px solid var(--color-fg)' }} />
369
+ <span className="em-label" style={{ marginLeft: 16, fontSize: 13 }}>BEACON · session 41ac</span>
370
+ </div>
371
+ {/* fake content */}
372
+ <div style={{ padding: 32, display: 'grid', gridTemplateColumns: '240px 1fr', gap: 32, height: 'calc(100% - 48px)' }}>
373
+ <div style={{ borderRight: '1px solid var(--color-border)', paddingRight: 24, display: 'flex', flexDirection: 'column', gap: 14 }}>
374
+ {['Run', 'Memory', 'Plan', 'Tools', 'Trace'].map((x, i) => (
375
+ <div key={x} className="em-body" style={{ fontSize: 18, color: i === 2 ? 'var(--color-fg)' : 'var(--color-muted)', fontWeight: i === 2 ? 500 : 400 }}>{x}</div>
376
+ ))}
377
+ </div>
378
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
379
+ <div className="em-display" style={{ fontSize: 36 }}>Plan · v3</div>
380
+ {['Read the eval spec', 'Generate 12 candidate prompts', 'Score each against the rubric', 'Select top-3 by F1', 'Iterate the top-3 with reasoning trace'].map((s, i) => (
381
+ <div key={i} style={{ display: 'flex', gap: 16, alignItems: 'baseline' }}>
382
+ <span className="em-label" style={{ fontSize: 13, color: 'var(--color-muted)', minWidth: 32 }}>{String(i+1).padStart(2,'0')}</span>
383
+ <span className="em-body" style={{ fontSize: 20 }}>{s}</span>
384
+ </div>
385
+ ))}
386
+ </div>
387
+ </div>
388
+ </div>
389
+ </FadeUp>
390
+
391
+ {/* callouts */}
392
+ <div style={{ position: 'absolute', left: 80, top: 360, width: 280, opacity: arrow1 }}>
393
+ <div className="em-label em-accent">A · Sidebar</div>
394
+ <div className="em-body" style={{ fontSize: 20, marginTop: 8, lineHeight: 1.35 }}>
395
+ Five views of the same run.
396
+ </div>
397
+ <div style={{ height: 1, width: `${arrow1 * 200}px`, background: 'var(--color-accent)', marginTop: 14 }} />
398
+ </div>
399
+ <div style={{ position: 'absolute', left: 1580, top: 540, width: 260, opacity: arrow2, textAlign: 'right' }}>
400
+ <div className="em-label em-accent" style={{ color: 'var(--color-accent)' }}>B · Plan</div>
401
+ <div className="em-body" style={{ fontSize: 20, marginTop: 8, lineHeight: 1.35 }}>
402
+ Versioned, diff-able, replayable.
403
+ </div>
404
+ <div style={{ height: 1, width: `${arrow2 * 200}px`, background: 'var(--color-accent)', marginTop: 14, marginLeft: 'auto' }} />
405
+ </div>
406
+ </>
407
+ );
408
+ }}
409
+ </Sprite>
410
+ );
411
+ }
412
+
413
+ // ── Scene 9: Content card ────────────────────────────────────────────
414
+ function ContentScene() {
415
+ return (
416
+ <Sprite start={SCENE * 8} end={SCENE * 9}>
417
+ <div style={{ position: 'absolute', left: 'var(--safe-x)', right: 'var(--safe-x)', top: 200 }}>
418
+ <FadeUp at={0} className="em-label" style={{ marginBottom: 48 }}>
419
+ On the Record
420
+ </FadeUp>
421
+ <FadeUp at={0.2}>
422
+ <div className="em-display italic" style={{ fontSize: 120, marginBottom: 64 }}>
423
+ What we believe.
424
+ </div>
425
+ </FadeUp>
426
+ <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 96 }}>
427
+ <FadeUp at={0.45} rise={16}>
428
+ <div className="em-body" style={{ fontSize: 28, lineHeight: 1.5, fontWeight: 400 }}>
429
+ The next decade of AI infrastructure will be built around <em style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic' }}>long</em> runs — agents that work for hours, not seconds. The bottleneck won't be the model. It will be everything around the model.
430
+ </div>
431
+ </FadeUp>
432
+ <FadeUp at={0.65} rise={16}>
433
+ <div className="em-body em-muted" style={{ fontSize: 22, lineHeight: 1.55 }}>
434
+ We're building Beacon for that world. A workbench for long-running agents: memory, recovery, observability. Designed for the people doing the actual work — research engineers at labs, founders shipping product, evaluators who need to know what their model just did and why.
435
+ </div>
436
+ </FadeUp>
437
+ </div>
438
+ </div>
439
+ </Sprite>
440
+ );
441
+ }
442
+
443
+ // ── Scene 10: CTA / outro ────────────────────────────────────────────
444
+ function CTAScene() {
445
+ return (
446
+ <Sprite start={SCENE * 9} end={SCENE * 10}>
447
+ <div style={{ position: 'absolute', inset: 0,
448
+ display: 'flex', flexDirection: 'column',
449
+ alignItems: 'center', justifyContent: 'center', gap: 56 }}>
450
+ <FadeUp at={0} className="em-label">Continued in Vol. 02</FadeUp>
451
+ <FadeUp at={0.15}>
452
+ <div className="em-display italic" style={{ fontSize: 180, textAlign: 'center' }}>
453
+ Read the brief.
454
+ </div>
455
+ </FadeUp>
456
+ <FadeUp at={0.4}>
457
+ <div style={{ display: 'flex', alignItems: 'center', gap: 24 }}>
458
+ <span className="em-body" style={{ fontSize: 36, fontWeight: 500 }}>beacon.run</span>
459
+ <span className="em-accent" style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic', fontSize: 60, lineHeight: 1 }}>→</span>
460
+ </div>
461
+ </FadeUp>
462
+ <FadeUp at={0.65} style={{ position: 'absolute', bottom: 96 }}>
463
+ {/* placeholder logo lockup */}
464
+ <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
465
+ <div style={{ width: 24, height: 24, border: '1.5px solid var(--color-fg)', position: 'relative' }}>
466
+ <div style={{ position: 'absolute', inset: 6, background: 'var(--color-accent)' }} />
467
+ </div>
468
+ <span className="em-label" style={{ fontSize: 14, letterSpacing: '0.2em' }}>Beacon · 2026</span>
469
+ </div>
470
+ </FadeUp>
471
+ </div>
472
+ </Sprite>
473
+ );
474
+ }
475
+
476
+ // ── Lower-third overlay (connective element demo) ────────────────────
477
+ // Shown briefly during the content scene to demonstrate the lower-third pattern.
478
+ function LowerThirdDemo() {
479
+ // appears at SCENE*8 + 1.2s, hides at SCENE*8 + 3.5s
480
+ const start = SCENE * 8 + 1.2;
481
+ const end = SCENE * 8 + 3.5;
482
+ return (
483
+ <Sprite start={start} end={end}>
484
+ {({ localTime, duration }) => {
485
+ const inP = clamp(localTime / 0.4, 0, 1);
486
+ const outP = clamp((duration - localTime) / 0.4, 0, 1);
487
+ const op = EOUT(inP) * EOUT(outP);
488
+ return (
489
+ <div style={{
490
+ position: 'absolute',
491
+ left: 'var(--safe-x)', right: 'var(--safe-x)',
492
+ bottom: 140,
493
+ opacity: op, transform: `translateY(${(1 - inP) * 8}px)`,
494
+ }}>
495
+ <div style={{ height: 1, background: 'var(--color-border)', marginBottom: 16 }} />
496
+ <div className="em-label" style={{ fontSize: 16 }}>
497
+ Lower Third · Connective Element
498
+ </div>
499
+ </div>
500
+ );
501
+ }}
502
+ </Sprite>
503
+ );
504
+ }
505
+
506
+ // ── Scene labels for designer reference (small, top right) ───────────
507
+ function SceneCounter() {
508
+ const labels = [
509
+ '01 · Title', '02 · Section header', '03 · Kinetic statement',
510
+ '04 · Bullet reveal', '05 · Stat card', '06 · Feature card',
511
+ '07 · Card grid', '08 · UI showcase', '09 · Content card', '10 · CTA / outro'
512
+ ];
513
+ const time = useTime();
514
+ const idx = Math.min(9, Math.floor(time / SCENE));
515
+ return (
516
+ <div style={{
517
+ position: 'absolute', top: 30, right: 'var(--safe-x)',
518
+ fontFamily: 'var(--font-mono)', fontSize: 14, letterSpacing: '0.16em',
519
+ textTransform: 'uppercase', color: 'var(--color-muted)',
520
+ }}>
521
+ {labels[idx]}
522
+ </div>
523
+ );
524
+ }
525
+
526
+ // ── Root ─────────────────────────────────────────────────────────────
527
+ function App() {
528
+ const total = SCENE * 10;
529
+ return (
530
+ <Stage
531
+ width={1920}
532
+ height={1080}
533
+ duration={total}
534
+ background="var(--color-bg)"
535
+ persistKey="editorial-mono-ref"
536
+ >
537
+ <div className="em-canvas">
538
+ {/* persistent chrome */}
539
+ <PageChrome folio="Beacon · Vol. 01" right="" />
540
+ <SceneCounter />
541
+
542
+ <TitleScene />
543
+ <SectionScene />
544
+ <KineticScene />
545
+ <BulletScene />
546
+ <StatScene />
547
+ <FeatureScene />
548
+ <CardGridScene />
549
+ <UIShowcaseScene />
550
+ <ContentScene />
551
+ <LowerThirdDemo />
552
+ <CTAScene />
553
+ </div>
554
+ </Stage>
555
+ );
556
+ }
557
+
558
+ ReactDOM.createRoot(document.getElementById('root')).render(<App />);
559
+
560
+ </script>
561
+
562
+ </body>
563
+ </html>
@@ -0,0 +1,101 @@
1
+ import { defineSegment } from "videowright";
2
+
3
+ let host: HTMLElement | null = null;
4
+
5
+ export default defineSegment({
6
+ id: "editorial-mono-sample-bullet",
7
+ advances: [2.5, 5.0],
8
+ voiceover: "Bullet reveals in Editorial Mono. Numbered items stagger in along the left rail.",
9
+
10
+ mount(el) {
11
+ host = el;
12
+ el.innerHTML = `
13
+ <div style="
14
+ position: relative;
15
+ height: 100%;
16
+ background: var(--color-bg);
17
+ color: var(--color-fg);
18
+ overflow: hidden;
19
+ ">
20
+ <div style="position: absolute; left: var(--safe-x); top: 200px; right: var(--safe-x);">
21
+ <div data-ref="label" style="
22
+ font-family: var(--font-mono);
23
+ font-size: 14px;
24
+ letter-spacing: 0.16em;
25
+ text-transform: uppercase;
26
+ color: var(--color-muted);
27
+ margin-bottom: 64px;
28
+ opacity: 0;
29
+ ">Failure Modes</div>
30
+
31
+ <div data-ref="headline" style="
32
+ font-family: var(--font-display);
33
+ font-style: italic;
34
+ font-size: 80px;
35
+ line-height: 0.98;
36
+ margin-bottom: 80px;
37
+ opacity: 0;
38
+ ">Where agents break.</div>
39
+
40
+ <div style="display: flex; flex-direction: column; gap: 32px;">
41
+ <div data-ref="item0" style="display: flex; align-items: baseline; gap: 48px; opacity: 0;">
42
+ <span style="font-family: var(--font-mono); font-size: 22px; letter-spacing: 0.16em; color: var(--color-accent); min-width: 64px;">01</span>
43
+ <span style="width: 32px; height: 1px; background: var(--color-fg); align-self: center; flex-shrink: 0;"></span>
44
+ <span style="font-family: var(--font-body); font-size: 48px; font-weight: 500;">Context windows decay.</span>
45
+ </div>
46
+ <div data-ref="item1" style="display: flex; align-items: baseline; gap: 48px; opacity: 0;">
47
+ <span style="font-family: var(--font-mono); font-size: 22px; letter-spacing: 0.16em; color: var(--color-accent); min-width: 64px;">02</span>
48
+ <span style="width: 32px; height: 1px; background: var(--color-fg); align-self: center; flex-shrink: 0;"></span>
49
+ <span style="font-family: var(--font-body); font-size: 48px; font-weight: 500;">Tool selection drifts.</span>
50
+ </div>
51
+ <div data-ref="item2" style="display: flex; align-items: baseline; gap: 48px; opacity: 0;">
52
+ <span style="font-family: var(--font-mono); font-size: 22px; letter-spacing: 0.16em; color: var(--color-accent); min-width: 64px;">03</span>
53
+ <span style="width: 32px; height: 1px; background: var(--color-fg); align-self: center; flex-shrink: 0;"></span>
54
+ <span style="font-family: var(--font-body); font-size: 48px; font-weight: 500;">Plans go stale.</span>
55
+ </div>
56
+ <div data-ref="item3" style="display: flex; align-items: baseline; gap: 48px; opacity: 0;">
57
+ <span style="font-family: var(--font-mono); font-size: 22px; letter-spacing: 0.16em; color: var(--color-accent); min-width: 64px;">04</span>
58
+ <span style="width: 32px; height: 1px; background: var(--color-fg); align-self: center; flex-shrink: 0;"></span>
59
+ <span style="font-family: var(--font-body); font-size: 48px; font-weight: 500;">Errors compound.</span>
60
+ </div>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ `;
65
+ },
66
+
67
+ async play(ctx) {
68
+ const label = host?.querySelector('[data-ref="label"]') as HTMLElement;
69
+ const headline = host?.querySelector('[data-ref="headline"]') as HTMLElement;
70
+
71
+ const ease = "cubic-bezier(0.16, 1, 0.3, 1)";
72
+ const opts = { fill: "forwards" as const, easing: ease };
73
+
74
+ label.animate([{ opacity: 0 }, { opacity: 1 }], { ...opts, duration: 480 });
75
+
76
+ headline.animate(
77
+ [
78
+ { opacity: 0, transform: "translateY(16px)" },
79
+ { opacity: 1, transform: "translateY(0)" },
80
+ ],
81
+ { ...opts, duration: 480, delay: 150 },
82
+ );
83
+
84
+ for (let i = 0; i < 4; i++) {
85
+ const item = host?.querySelector(`[data-ref="item${i}"]`) as HTMLElement;
86
+ item.animate(
87
+ [
88
+ { opacity: 0, transform: "translateY(18px)" },
89
+ { opacity: 1, transform: "translateY(0)" },
90
+ ],
91
+ { ...opts, duration: 480, delay: 500 + i * 120 },
92
+ );
93
+ }
94
+
95
+ await ctx.waitForNext();
96
+ },
97
+
98
+ unmount() {
99
+ host = null;
100
+ },
101
+ });