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,403 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Risograph — Reference Scenes</title>
6
+ <link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Archivo:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
7
+ <link rel="stylesheet" href="../tokens.css" />
8
+ <style>
9
+ html, body { margin: 0; padding: 0; height: 100%; background: #2a2620; font-family: var(--font-body); }
10
+ .ri-canvas { position: absolute; inset: 0; background: var(--color-bg); color: var(--color-fg); overflow: hidden; }
11
+ /* Grain layer */
12
+ .ri-canvas::after {
13
+ content: ''; position: absolute; inset: 0; pointer-events: none;
14
+ background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.6 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
15
+ opacity: 0.18; mix-blend-mode: multiply;
16
+ }
17
+ .ri-display { font-family: var(--font-display); font-weight: 900; line-height: 0.9; letter-spacing: -0.025em; text-transform: none; }
18
+ .ri-body { font-family: var(--font-body); }
19
+ .ri-mono { font-family: var(--font-mono); }
20
+ .ri-pink { color: var(--color-accent); }
21
+ .ri-blue { color: var(--color-fg); }
22
+ .ri-yellow { color: var(--color-second); }
23
+ /* Misregistered text — wrap the text in a misreg span and we render twice */
24
+ .misreg { position: relative; display: inline-block; }
25
+ .misreg .ghost {
26
+ position: absolute; left: 3px; top: 3px; color: var(--color-accent);
27
+ z-index: 0; pointer-events: none;
28
+ }
29
+ .misreg .top { position: relative; z-index: 1; color: var(--color-fg); }
30
+ .misreg.pink .ghost { color: var(--color-fg); }
31
+ .misreg.pink .top { color: var(--color-accent); }
32
+ .ri-tag { display: inline-block; padding: 6px 12px; background: var(--color-second); color: var(--color-fg); font-family: var(--font-body); font-weight: 700; font-size: 14px; letter-spacing: 0.1em; text-transform: uppercase; }
33
+ </style>
34
+ </head>
35
+ <body>
36
+ <script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
37
+ <script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
38
+ <script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
39
+ <div id="root"></div>
40
+ <script type="text/babel" src="animations.jsx"></script>
41
+ <script type="text/babel">
42
+ const SCENE = 4;
43
+
44
+ // Misregistered text (display only)
45
+ function Misreg({ children, pink = false, style = {} }) {
46
+ return <span className={`misreg ${pink ? 'pink' : ''}`} style={style}>
47
+ <span className="ghost" aria-hidden="true">{children}</span>
48
+ <span className="top">{children}</span>
49
+ </span>;
50
+ }
51
+
52
+ // Stop-motion stamp-in: jumps from 0 → 1 in 4 frames over `dur`, with slight rotation jitter
53
+ function Stamp({ at = 0, dur = 0.35, rot = 0, jitter = 2, children, style = {} }) {
54
+ const { localTime } = useSprite();
55
+ const p = clamp((localTime - at) / dur, 0, 1);
56
+ const step = Math.floor(p * 5) / 5; // 5 frames
57
+ // Jitter while stamping in, then settle
58
+ const jit = step < 1 ? (Math.sin(step * 23) * jitter) : 0;
59
+ const op = step === 0 ? 0 : 1;
60
+ const sc = 0.85 + step * 0.15;
61
+ return <div style={{ ...style, opacity: op, transform: `rotate(${rot + jit}deg) scale(${sc})`, transformOrigin: 'center' }}>{children}</div>;
62
+ }
63
+
64
+ // Counter that ticks
65
+ function Ticker({ to, at = 0, dur = 1.0, suffix = '' }) {
66
+ const { localTime } = useSprite();
67
+ const p = clamp((localTime - at) / dur, 0, 1);
68
+ const step = Math.floor(p * 12) / 12;
69
+ return <span>{Math.round(to * step)}{suffix}</span>;
70
+ }
71
+
72
+ // Pink flash transition — last 200ms of each scene flashes pink
73
+ function FlashOut() {
74
+ const { localTime, duration } = useSprite();
75
+ const remain = duration - localTime;
76
+ const op = remain < 0.15 ? clamp((0.15 - remain) / 0.05, 0, 1) : 0;
77
+ return <div style={{ position: 'absolute', inset: 0, background: 'var(--color-accent)', opacity: op, mixBlendMode: 'multiply', pointerEvents: 'none', zIndex: 10 }} />;
78
+ }
79
+
80
+ function Counter() {
81
+ const t = useTime();
82
+ const i = Math.min(9, Math.floor(t / SCENE));
83
+ return <div className="ri-display ri-pink" style={{ position: 'absolute', right: 80, top: 60, fontSize: 36, transform: 'rotate(-3deg)' }}>
84
+ ★ {String(i+1).padStart(2,'0')}/10 ★
85
+ </div>;
86
+ }
87
+
88
+ // ─── Scene 1 — Title ─────────────────────────────────────────────
89
+ function S1() {
90
+ return <Sprite start={0} end={SCENE}>
91
+ {/* Pink star top-left */}
92
+ <Stamp at={0.2} rot={-15} style={{ position: 'absolute', left: 140, top: 140 }}>
93
+ <svg width="160" height="160"><polygon points="80,0 100,60 160,60 110,100 130,160 80,124 30,160 50,100 0,60 60,60" fill="var(--color-accent)" /></svg>
94
+ </Stamp>
95
+ <Stamp at={0.5} rot={-2} style={{ position: 'absolute', left: 120, top: 320 }}>
96
+ <div className="ri-mono" style={{ fontSize: 22, letterSpacing: '0.1em', fontWeight: 600 }}>BEACON · LONG-RUNNING AGENTS</div>
97
+ </Stamp>
98
+ <Stamp at={0.9} rot={-2} style={{ position: 'absolute', left: 120, top: 380 }}>
99
+ <div className="ri-display" style={{ fontSize: 380 }}>
100
+ <Misreg>BEACON.</Misreg>
101
+ </div>
102
+ </Stamp>
103
+ <Stamp at={1.5} rot={2} style={{ position: 'absolute', left: 280, top: 780 }}>
104
+ <div className="ri-display ri-pink" style={{ fontSize: 92 }}>agents that don't forget.</div>
105
+ </Stamp>
106
+ <Stamp at={2.0} rot={-4} style={{ position: 'absolute', right: 200, top: 700 }}>
107
+ <svg width="120" height="120"><polygon points="60,0 70,50 120,60 70,70 60,120 50,70 0,60 50,50" fill="var(--color-second)" /></svg>
108
+ </Stamp>
109
+ <Counter />
110
+ <FlashOut />
111
+ </Sprite>;
112
+ }
113
+
114
+ // ─── Scene 2 — Section ───────────────────────────────────────────
115
+ function S2() {
116
+ return <Sprite start={SCENE} end={SCENE*2}>
117
+ <Stamp at={0.3} rot={-4} style={{ position: 'absolute', left: 80, top: 100 }}>
118
+ <div className="ri-display ri-pink" style={{ fontSize: 760, lineHeight: 0.85 }}>
119
+ <Misreg pink>02</Misreg>
120
+ </div>
121
+ </Stamp>
122
+ <Stamp at={1.0} rot={-2} style={{ position: 'absolute', left: 700, top: 560 }}>
123
+ <div className="ri-display" style={{ fontSize: 200 }}>
124
+ <Misreg>the architecture</Misreg>
125
+ </div>
126
+ </Stamp>
127
+ <Stamp at={1.6} rot={1} style={{ position: 'absolute', left: 720, top: 820 }}>
128
+ <div className="ri-body" style={{ fontSize: 30, fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.1em' }}>memory · reasoning · recovery</div>
129
+ </Stamp>
130
+ <Counter />
131
+ <FlashOut />
132
+ </Sprite>;
133
+ }
134
+
135
+ // ─── Scene 3 — Kinetic ───────────────────────────────────────────
136
+ function S3() {
137
+ const words = [
138
+ { t: 'most', rot: -2, pink: false, size: 200 },
139
+ { t: 'agents', rot: 1, pink: false, size: 220 },
140
+ { t: 'fail', rot: -3, pink: false, size: 240 },
141
+ { t: 'because', rot: 1, pink: false, size: 180 },
142
+ { t: 'they', rot: -1, pink: false, size: 200 },
143
+ { t: 'forget.', rot: 2, pink: true, size: 360 },
144
+ ];
145
+ return <Sprite start={SCENE*2} end={SCENE*3}>
146
+ <div style={{ position: 'absolute', left: 120, top: 220, right: 120 }}>
147
+ {words.map((w, i) => (
148
+ <Stamp key={i} at={0.3 + i*0.22} rot={w.rot} style={{ display: 'inline-block', marginRight: 30, verticalAlign: 'baseline' }}>
149
+ <div className="ri-display" style={{ fontSize: w.size, color: w.pink ? 'var(--color-accent)' : 'var(--color-fg)' }}>
150
+ <Misreg pink={w.pink}>{w.t}</Misreg>
151
+ </div>
152
+ </Stamp>
153
+ ))}
154
+ </div>
155
+ <Counter />
156
+ <FlashOut />
157
+ </Sprite>;
158
+ }
159
+
160
+ // ─── Scene 4 — Bullet ────────────────────────────────────────────
161
+ function S4() {
162
+ const items = [
163
+ { n: '01', t: 'context decays.', tag: null },
164
+ { n: '02', t: 'tools drift.', tag: null },
165
+ { n: '03', t: 'plans go stale.', tag: 'main fail' },
166
+ { n: '04', t: 'errors compound.', tag: null },
167
+ { n: '05', t: 'recovery means restart.', tag: null },
168
+ ];
169
+ return <Sprite start={SCENE*3} end={SCENE*4}>
170
+ <Stamp at={0.2} rot={-2} style={{ position: 'absolute', left: 120, top: 120 }}>
171
+ <div className="ri-display" style={{ fontSize: 140 }}><Misreg>where agents break:</Misreg></div>
172
+ </Stamp>
173
+ <div style={{ position: 'absolute', left: 140, right: 140, top: 380 }}>
174
+ {items.map((it, i) => (
175
+ <Stamp key={it.n} at={0.7 + i*0.18} rot={(i%2===0?-0.5:0.5)} style={{ display: 'flex', alignItems: 'baseline', gap: 32, padding: '14px 0' }}>
176
+ <span className="ri-display ri-pink" style={{ fontSize: 96, minWidth: 130 }}>{it.n}</span>
177
+ <span className="ri-display ri-blue" style={{ fontSize: 76 }}>{it.t}</span>
178
+ {it.tag && <span className="ri-tag" style={{ marginLeft: 'auto', transform: 'rotate(-2deg)' }}>{it.tag}</span>}
179
+ </Stamp>
180
+ ))}
181
+ </div>
182
+ <Counter />
183
+ <FlashOut />
184
+ </Sprite>;
185
+ }
186
+
187
+ // ─── Scene 5 — Stat ──────────────────────────────────────────────
188
+ function S5() {
189
+ return <Sprite start={SCENE*4} end={SCENE*5}>
190
+ <Stamp at={0.2} rot={-1} style={{ position: 'absolute', left: 120, top: 120 }}>
191
+ <div className="ri-mono" style={{ fontSize: 22, letterSpacing: '0.1em', fontWeight: 700, textTransform: 'uppercase' }}>★ failure data · Q1 2026</div>
192
+ </Stamp>
193
+ {/* Big riso pink blob */}
194
+ <Stamp at={0.4} rot={4} style={{ position: 'absolute', left: 140, top: 240 }}>
195
+ <svg width="1300" height="700" style={{ overflow: 'visible' }}>
196
+ <ellipse cx="650" cy="350" rx="640" ry="310" fill="var(--color-accent)" />
197
+ </svg>
198
+ </Stamp>
199
+ <Stamp at={0.8} rot={-3} style={{ position: 'absolute', left: 280, top: 360 }}>
200
+ <div className="ri-display" style={{ fontSize: 560, color: 'var(--color-bg)', lineHeight: 0.85 }}>
201
+ <Misreg><Ticker to={84} at={0.9} dur={1.0} />%</Misreg>
202
+ </div>
203
+ </Stamp>
204
+ <Stamp at={2.0} rot={-1} style={{ position: 'absolute', left: 140, bottom: 140, width: 1300 }}>
205
+ <div className="ri-body" style={{ fontSize: 40, fontWeight: 600, lineHeight: 1.3 }}>
206
+ of agent failures happen <span className="ri-pink">after</span> the 4th tool call. one bad memory step and the rest is rebuild.
207
+ </div>
208
+ <div className="ri-mono" style={{ fontSize: 16, marginTop: 14, letterSpacing: '0.1em' }}>BEACON.LOGS · N=12,840</div>
209
+ </Stamp>
210
+ <Counter />
211
+ <FlashOut />
212
+ </Sprite>;
213
+ }
214
+
215
+ // ─── Scene 6 — Feature ───────────────────────────────────────────
216
+ function S6() {
217
+ return <Sprite start={SCENE*5} end={SCENE*6}>
218
+ {/* Left: riso cut-paper shape */}
219
+ <Stamp at={0.3} rot={-3} style={{ position: 'absolute', left: 100, top: 200 }}>
220
+ <svg width="720" height="720" style={{ overflow: 'visible' }}>
221
+ {/* Pink shape behind */}
222
+ <path d="M 80 100 Q 360 -20 640 120 Q 720 380 580 600 Q 280 720 100 540 Q 20 320 80 100 Z" fill="var(--color-accent)" />
223
+ </svg>
224
+ </Stamp>
225
+ <Stamp at={0.5} rot={2} style={{ position: 'absolute', left: 160, top: 260 }}>
226
+ <svg width="700" height="700" style={{ overflow: 'visible' }}>
227
+ {/* Stacked memory rectangles */}
228
+ {[0,1,2,3].map(i => (
229
+ <g key={i}>
230
+ <rect x={60} y={80 + i*120} width={520} height={92} fill="var(--color-fg)" />
231
+ <text x={90} y={140 + i*120} fontFamily="var(--font-mono)" fontWeight="700" fontSize="32" fill="var(--color-bg)">snap_{String(i).padStart(3,'0')}</text>
232
+ <text x={520} y={140 + i*120} fontFamily="var(--font-mono)" fontWeight="700" fontSize="32" fill={i===2 ? 'var(--color-second)' : 'var(--color-bg)'}>{i===2 ? '↶' : '✓'}</text>
233
+ </g>
234
+ ))}
235
+ </svg>
236
+ </Stamp>
237
+ {/* Right copy */}
238
+ <Stamp at={0.4} rot={-1} style={{ position: 'absolute', right: 120, top: 180 }}>
239
+ <div className="ri-mono ri-pink" style={{ fontSize: 22, letterSpacing: '0.15em', fontWeight: 700 }}>★ FEATURE 01 / 03</div>
240
+ </Stamp>
241
+ <Stamp at={0.7} rot={-2} style={{ position: 'absolute', right: 120, top: 240, width: 720 }}>
242
+ <div className="ri-display" style={{ fontSize: 130 }}><Misreg>checkpoint memory.</Misreg></div>
243
+ </Stamp>
244
+ <Stamp at={1.3} rot={0} style={{ position: 'absolute', right: 120, top: 560, width: 720 }}>
245
+ <div className="ri-body" style={{ fontSize: 30, lineHeight: 1.45, fontWeight: 500 }}>
246
+ we snapshot the agent's reasoning at every tool boundary. when a plan goes stale, the agent <span className="ri-pink" style={{ fontWeight: 700 }}>rewinds</span> to the last point its world model was correct.
247
+ </div>
248
+ </Stamp>
249
+ <Stamp at={1.8} rot={-1} style={{ position: 'absolute', right: 120, bottom: 160, width: 720, display: 'flex', gap: 36, paddingTop: 24, borderTop: '4px solid var(--color-fg)' }}>
250
+ <div><div className="ri-mono" style={{ fontSize: 13, letterSpacing: '0.15em', fontWeight: 700 }}>SNAP/MIN</div><div className="ri-display ri-pink" style={{ fontSize: 110 }}><Ticker to={120} at={1.9} /></div></div>
251
+ <div><div className="ri-mono" style={{ fontSize: 13, letterSpacing: '0.15em', fontWeight: 700 }}>RESTORE</div><div className="ri-display ri-pink" style={{ fontSize: 110 }}><Ticker to={9} at={1.9} suffix="ms" /></div></div>
252
+ </Stamp>
253
+ <Counter />
254
+ <FlashOut />
255
+ </Sprite>;
256
+ }
257
+
258
+ // ─── Scene 7 — 3 cards ───────────────────────────────────────────
259
+ function S7() {
260
+ const cards = [
261
+ { name: 'memory', sub: 'remembers', shape: 'circ', col: 'pink' },
262
+ { name: 'reasoning', sub: 'revises', shape: 'tri', col: 'blue' },
263
+ { name: 'recovery', sub: 'rewinds', shape: 'sq', col: 'pink' },
264
+ ];
265
+ return <Sprite start={SCENE*6} end={SCENE*7}>
266
+ <Stamp at={0.2} rot={-2} style={{ position: 'absolute', left: 120, top: 120 }}>
267
+ <div className="ri-display" style={{ fontSize: 140 }}><Misreg>three primitives.</Misreg></div>
268
+ </Stamp>
269
+ <div style={{ position: 'absolute', left: 140, right: 140, top: 400, display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 48 }}>
270
+ {cards.map((c, i) => (
271
+ <Stamp key={c.name} at={0.7 + i*0.2} rot={(i%2===0?-2:2)}>
272
+ <div style={{ background: c.col === 'pink' ? 'var(--color-accent)' : 'var(--color-fg)', padding: 36, minHeight: 560, color: c.col === 'pink' ? 'var(--color-fg)' : 'var(--color-bg)' }}>
273
+ <div className="ri-mono" style={{ fontSize: 16, letterSpacing: '0.2em', fontWeight: 700 }}>0{i+1} / 03</div>
274
+ <svg width="100%" height="260" style={{ marginTop: 32 }}>
275
+ {c.shape === 'circ' && <circle cx="50%" cy="130" r="100" fill="var(--color-bg)" />}
276
+ {c.shape === 'tri' && <polygon points="200,30 380,230 20,230" fill="var(--color-accent)" />}
277
+ {c.shape === 'sq' && <rect x="80" y="30" width="240" height="200" fill="var(--color-bg)" transform="rotate(-4 200 130)" />}
278
+ </svg>
279
+ <div className="ri-display" style={{ fontSize: 90, marginTop: 32 }}>{c.name}</div>
280
+ <div className="ri-body" style={{ fontSize: 26, fontWeight: 600, marginTop: 4, opacity: 0.85 }}>~ {c.sub} ~</div>
281
+ </div>
282
+ </Stamp>
283
+ ))}
284
+ </div>
285
+ <Counter />
286
+ <FlashOut />
287
+ </Sprite>;
288
+ }
289
+
290
+ // ─── Scene 8 — UI showcase (flat 2-color UI) ─────────────────────
291
+ function S8() {
292
+ return <Sprite start={SCENE*7} end={SCENE*8}>
293
+ <Stamp at={0.2} rot={-2} style={{ position: 'absolute', left: 120, top: 100 }}>
294
+ <div className="ri-display" style={{ fontSize: 110 }}><Misreg>the console.</Misreg></div>
295
+ </Stamp>
296
+ <Stamp at={0.6} rot={-0.5} style={{ position: 'absolute', left: 120, top: 320, right: 120 }}>
297
+ <div style={{ position: 'relative', height: 700, background: 'var(--color-fg)', color: 'var(--color-bg)' }}>
298
+ {/* Pink misregistration ghost layer */}
299
+ <div style={{ position: 'absolute', inset: 0, left: 4, top: 4, background: 'var(--color-accent)', mixBlendMode: 'multiply', opacity: 0.6 }} />
300
+ <div style={{ position: 'relative', display: 'grid', gridTemplateColumns: '220px 1fr 260px', height: '100%' }}>
301
+ <div style={{ padding: 24, borderRight: '3px solid var(--color-bg)' }}>
302
+ <div className="ri-display ri-pink" style={{ fontSize: 28, marginBottom: 24 }}>BEACON</div>
303
+ {['runs','memory','plans','tools','traces','evals'].map((x, i) => (
304
+ <div key={x} className="ri-body" style={{ padding: '10px 12px', fontSize: 18, fontWeight: 700, background: i===1 ? 'var(--color-accent)' : 'transparent', color: i===1 ? 'var(--color-fg)' : 'var(--color-bg)' }}>★ {x}</div>
305
+ ))}
306
+ </div>
307
+ <div style={{ padding: 28 }}>
308
+ <div className="ri-mono" style={{ fontSize: 14, letterSpacing: '0.2em', fontWeight: 700, marginBottom: 22 }}>TIMELINE · 41AC</div>
309
+ <svg width="100%" height="200">
310
+ <line x1="20" y1="100" x2="98%" y2="100" stroke="var(--color-bg)" strokeWidth="3" />
311
+ {[0.05,0.18,0.31,0.44,0.57,0.70,0.83,0.95].map((p, i) => (
312
+ <g key={i}>
313
+ <circle cx={`${p*100}%`} cy="100" r={i===5 ? 16 : 10} fill={i===5 ? 'var(--color-accent)' : 'var(--color-bg)'} stroke="var(--color-bg)" strokeWidth="3" />
314
+ </g>
315
+ ))}
316
+ </svg>
317
+ <div className="ri-display ri-pink" style={{ fontSize: 40, marginTop: 28 }}>★ active: snap_006</div>
318
+ <div className="ri-mono" style={{ fontSize: 16, marginTop: 16, lineHeight: 1.7, fontWeight: 600 }}>
319
+ <div>[t05] tool.search → 12 results</div>
320
+ <div style={{ color: 'var(--color-accent)' }}>[t06] plan.revise → step 4 dropped</div>
321
+ <div>[t07] memory.snap → ok</div>
322
+ </div>
323
+ </div>
324
+ <div style={{ padding: 24, borderLeft: '3px solid var(--color-bg)' }}>
325
+ <div className="ri-mono" style={{ fontSize: 14, letterSpacing: '0.2em', fontWeight: 700, marginBottom: 16 }}>MEMORY</div>
326
+ {[0,1,2,3,4,5,6,7].map(i => (
327
+ <div key={i} className="ri-mono" style={{ fontSize: 13, padding: '6px 0', display: 'flex', justifyContent: 'space-between', color: i === 5 ? 'var(--color-accent)' : 'var(--color-bg)', fontWeight: 700 }}>
328
+ <span>snap_{String(i).padStart(3,'0')}</span><span>{i === 5 ? '● now' : (i*0.4).toFixed(1)+'s'}</span>
329
+ </div>
330
+ ))}
331
+ </div>
332
+ </div>
333
+ </div>
334
+ </Stamp>
335
+ <Counter />
336
+ <FlashOut />
337
+ </Sprite>;
338
+ }
339
+
340
+ // ─── Scene 9 — Content ───────────────────────────────────────────
341
+ function S9() {
342
+ return <Sprite start={SCENE*8} end={SCENE*9}>
343
+ <Stamp at={0.2} rot={-3} style={{ position: 'absolute', left: 120, top: 140 }}>
344
+ <div className="ri-display" style={{ fontSize: 160 }}><Misreg>what we believe.</Misreg></div>
345
+ </Stamp>
346
+ <div style={{ position: 'absolute', left: 140, right: 140, top: 460 }}>
347
+ <Stamp at={0.7} rot={-1}>
348
+ <div className="ri-body" style={{ fontSize: 44, lineHeight: 1.4, fontWeight: 600, maxWidth: 1500 }}>
349
+ the next decade of AI is not about <span style={{ background: 'var(--color-accent)', padding: '0 8px', boxDecorationBreak: 'clone' }}>bigger models</span>.
350
+ </div>
351
+ </Stamp>
352
+ <Stamp at={1.4} rot={1} style={{ marginTop: 36 }}>
353
+ <div className="ri-body" style={{ fontSize: 36, lineHeight: 1.4, maxWidth: 1500, fontWeight: 500 }}>
354
+ it's about agents that can <span className="ri-pink" style={{ fontWeight: 700 }}>run long enough to matter</span> — and the unglamorous infrastructure that lets them.
355
+ </div>
356
+ </Stamp>
357
+ <Stamp at={2.0} rot={-2} style={{ marginTop: 60 }}>
358
+ <div className="ri-display ri-pink" style={{ fontSize: 40 }}>★ ★ ★</div>
359
+ <div className="ri-mono" style={{ fontSize: 18, fontWeight: 700, letterSpacing: '0.15em', marginTop: 10 }}>BEACON TEAM · 2026.05</div>
360
+ </Stamp>
361
+ </div>
362
+ <Counter />
363
+ <FlashOut />
364
+ </Sprite>;
365
+ }
366
+
367
+ // ─── Scene 10 — CTA ──────────────────────────────────────────────
368
+ function S10() {
369
+ return <Sprite start={SCENE*9} end={SCENE*10}>
370
+ <Stamp at={0.2} rot={-15} style={{ position: 'absolute', left: 120, top: 140 }}>
371
+ <svg width="180" height="180"><polygon points="90,0 110,70 180,70 122,112 145,180 90,140 35,180 58,112 0,70 70,70" fill="var(--color-second)" /></svg>
372
+ </Stamp>
373
+ <Stamp at={0.5} rot={-2} style={{ position: 'absolute', left: 0, right: 0, top: 320, textAlign: 'center' }}>
374
+ <div className="ri-display" style={{ fontSize: 320 }}>
375
+ <Misreg pink>start it.</Misreg>
376
+ </div>
377
+ </Stamp>
378
+ <Stamp at={1.4} rot={2} style={{ position: 'absolute', left: 0, right: 0, top: 680, textAlign: 'center' }}>
379
+ <div className="ri-display ri-blue" style={{ fontSize: 120, display: 'inline-block', background: 'var(--color-accent)', padding: '12px 36px' }}>beacon.run</div>
380
+ </Stamp>
381
+ <Stamp at={1.9} rot={12} style={{ position: 'absolute', right: 200, bottom: 200 }}>
382
+ <svg width="140" height="140"><polygon points="70,0 86,54 140,54 96,86 112,140 70,108 28,140 44,86 0,54 54,54" fill="var(--color-accent)" /></svg>
383
+ </Stamp>
384
+ <Stamp at={2.4} rot={0} style={{ position: 'absolute', left: 0, right: 0, bottom: 80, textAlign: 'center' }}>
385
+ <div className="ri-mono" style={{ fontSize: 18, fontWeight: 700, letterSpacing: '0.25em' }}>★ BEACON · MAY 2026 ★</div>
386
+ </Stamp>
387
+ <Counter />
388
+ </Sprite>;
389
+ }
390
+
391
+ function App() {
392
+ return (
393
+ <Stage width={1920} height={1080} duration={SCENE*10} background="var(--color-bg)" persistKey="risograph-ref">
394
+ <div className="ri-canvas">
395
+ <S1 /><S2 /><S3 /><S4 /><S5 /><S6 /><S7 /><S8 /><S9 /><S10 />
396
+ </div>
397
+ </Stage>
398
+ );
399
+ }
400
+ ReactDOM.createRoot(document.getElementById('root')).render(<App />);
401
+ </script>
402
+ </body>
403
+ </html>
@@ -0,0 +1,124 @@
1
+ import { defineSegment } from "videowright";
2
+
3
+ let host: HTMLElement | null = null;
4
+
5
+ export default defineSegment({
6
+ id: "risograph-sample-bullet",
7
+ advances: [2.0, 4.0],
8
+ voiceover:
9
+ "Bullet reveals in Risograph. Each row stamps in with a pink number, blue text, and an optional yellow tag chip.",
10
+
11
+ mount(el) {
12
+ host = el;
13
+ el.innerHTML = `
14
+ <div style="
15
+ position: relative;
16
+ height: 100%;
17
+ background: var(--color-bg);
18
+ color: var(--color-fg);
19
+ font-family: var(--font-body);
20
+ overflow: hidden;
21
+ ">
22
+ <div style="
23
+ position: absolute; inset: 0; pointer-events: none;
24
+ background-image: url(&quot;data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.6 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>&quot;);
25
+ opacity: var(--grain-opacity); mix-blend-mode: multiply;
26
+ "></div>
27
+
28
+ <div data-ref="headline" style="
29
+ position: absolute;
30
+ left: var(--safe-x);
31
+ top: 120px;
32
+ font-family: var(--font-display);
33
+ font-size: 140px;
34
+ line-height: 0.9;
35
+ letter-spacing: -0.025em;
36
+ transform: rotate(-2deg);
37
+ opacity: 0;
38
+ ">
39
+ <span style="position: relative; display: inline-block;">
40
+ <span style="position: absolute; left: var(--misreg); top: var(--misreg); color: var(--color-accent); pointer-events: none;" aria-hidden="true">where agents break:</span>
41
+ <span style="position: relative;">where agents break:</span>
42
+ </span>
43
+ </div>
44
+
45
+ <div style="position: absolute; left: 140px; right: 140px; top: 380px; display: flex; flex-direction: column; gap: 0;">
46
+ <div data-ref="row0" style="display: flex; align-items: baseline; gap: 32px; padding: 14px 0; opacity: 0; transform: rotate(-0.5deg);">
47
+ <span style="font-family: var(--font-display); font-size: 96px; color: var(--color-accent); min-width: 130px;">01</span>
48
+ <span style="font-family: var(--font-display); font-size: 76px;">context decays.</span>
49
+ </div>
50
+ <div data-ref="row1" style="display: flex; align-items: baseline; gap: 32px; padding: 14px 0; opacity: 0; transform: rotate(0.5deg);">
51
+ <span style="font-family: var(--font-display); font-size: 96px; color: var(--color-accent); min-width: 130px;">02</span>
52
+ <span style="font-family: var(--font-display); font-size: 76px;">tools drift.</span>
53
+ </div>
54
+ <div data-ref="row2" style="display: flex; align-items: baseline; gap: 32px; padding: 14px 0; opacity: 0; transform: rotate(-0.5deg);">
55
+ <span style="font-family: var(--font-display); font-size: 96px; color: var(--color-accent); min-width: 130px;">03</span>
56
+ <span style="font-family: var(--font-display); font-size: 76px;">plans go stale.</span>
57
+ <span style="
58
+ display: inline-block; padding: 6px 12px; margin-left: auto;
59
+ background: var(--color-second); color: var(--color-fg);
60
+ font-family: var(--font-body); font-weight: 700; font-size: 14px;
61
+ letter-spacing: 0.1em; text-transform: uppercase;
62
+ transform: rotate(-2deg);
63
+ ">main fail</span>
64
+ </div>
65
+ <div data-ref="row3" style="display: flex; align-items: baseline; gap: 32px; padding: 14px 0; opacity: 0; transform: rotate(0.5deg);">
66
+ <span style="font-family: var(--font-display); font-size: 96px; color: var(--color-accent); min-width: 130px;">04</span>
67
+ <span style="font-family: var(--font-display); font-size: 76px;">errors compound.</span>
68
+ </div>
69
+ <div data-ref="row4" style="display: flex; align-items: baseline; gap: 32px; padding: 14px 0; opacity: 0; transform: rotate(-0.5deg);">
70
+ <span style="font-family: var(--font-display); font-size: 96px; color: var(--color-accent); min-width: 130px;">05</span>
71
+ <span style="font-family: var(--font-display); font-size: 76px;">recovery means restart.</span>
72
+ </div>
73
+ </div>
74
+
75
+ <div data-ref="counter" style="
76
+ position: absolute;
77
+ right: var(--safe-x);
78
+ top: 60px;
79
+ font-family: var(--font-display);
80
+ font-size: 36px;
81
+ color: var(--color-accent);
82
+ transform: rotate(-3deg);
83
+ opacity: 0;
84
+ ">&#9733; 04/10 &#9733;</div>
85
+ </div>
86
+ `;
87
+ },
88
+
89
+ async play(ctx) {
90
+ const headline = host?.querySelector('[data-ref="headline"]') as HTMLElement;
91
+ const counter = host?.querySelector('[data-ref="counter"]') as HTMLElement;
92
+
93
+ const ease = "steps(6, end)";
94
+ const opts = { fill: "forwards" as const, easing: ease };
95
+
96
+ counter.animate([{ opacity: 0 }, { opacity: 1 }], { ...opts, duration: 200 });
97
+
98
+ headline.animate(
99
+ [
100
+ { opacity: 0, transform: "rotate(-2deg) scale(0.9)" },
101
+ { opacity: 1, transform: "rotate(-2deg) scale(1)" },
102
+ ],
103
+ { ...opts, duration: 300, delay: 200 },
104
+ );
105
+
106
+ for (let i = 0; i < 5; i++) {
107
+ const row = host?.querySelector(`[data-ref="row${i}"]`) as HTMLElement;
108
+ const rot = i % 2 === 0 ? -0.5 : 0.5;
109
+ row.animate(
110
+ [
111
+ { opacity: 0, transform: `rotate(${rot}deg) scale(0.9)` },
112
+ { opacity: 1, transform: `rotate(${rot}deg) scale(1)` },
113
+ ],
114
+ { ...opts, duration: 280, delay: 700 + i * 160 },
115
+ );
116
+ }
117
+
118
+ await ctx.waitForNext();
119
+ },
120
+
121
+ unmount() {
122
+ host = null;
123
+ },
124
+ });