@devinilabs/reelstack 1.2.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 (145) hide show
  1. package/LICENSE +128 -0
  2. package/README.md +125 -0
  3. package/cli/beats.js +124 -0
  4. package/cli/bootstrap.js +124 -0
  5. package/cli/capture.js +34 -0
  6. package/cli/direction.js +114 -0
  7. package/cli/icons.js +49 -0
  8. package/cli/index.js +101 -0
  9. package/cli/init.js +253 -0
  10. package/cli/license.js +168 -0
  11. package/cli/lint.js +865 -0
  12. package/cli/preview.js +59 -0
  13. package/cli/render.js +404 -0
  14. package/cli/scaffold.js +239 -0
  15. package/cli/smoke.js +76 -0
  16. package/cli/update.js +26 -0
  17. package/cli/utils.js +184 -0
  18. package/docs/buyers-guide.md +220 -0
  19. package/docs/design-discipline.md +130 -0
  20. package/docs/family-galleries/dark.md +95 -0
  21. package/docs/family-galleries/forbidden.md +78 -0
  22. package/docs/family-galleries/glass.md +98 -0
  23. package/docs/family-galleries/paper.md +82 -0
  24. package/docs/family-galleries/warm.md +86 -0
  25. package/docs/superpowers/plans/2026-05-09-reelstack-init-readiness-gate.md +1166 -0
  26. package/docs/superpowers/specs/2026-05-09-reelstack-init-readiness-gate-design.md +233 -0
  27. package/families/dark/components/DriftingSpotlights.tsx +59 -0
  28. package/families/dark/components/FilmGrain.tsx +44 -0
  29. package/families/dark/components/ForestCard.tsx +43 -0
  30. package/families/dark/components/GridBackground.tsx +29 -0
  31. package/families/dark/components/RadialVignette.tsx +21 -0
  32. package/families/dark/components/Scanlines.tsx +35 -0
  33. package/families/dark/components/SegmentOpacity.ts +37 -0
  34. package/families/dark/components/index.ts +13 -0
  35. package/families/dark/index.ts +31 -0
  36. package/families/dark/palette.ts +98 -0
  37. package/families/dark/presets/claudedispatch.ts +46 -0
  38. package/families/dark/presets/codedrop.ts +37 -0
  39. package/families/dark/presets/gpt55.ts +54 -0
  40. package/families/dark/presets/notebooklm.ts +50 -0
  41. package/families/dark/presets/resourcescta.ts +35 -0
  42. package/families/dark/presets/skills.ts +40 -0
  43. package/families/dark/presets/stitch.ts +46 -0
  44. package/families/dark/presets/stitch2.ts +43 -0
  45. package/families/dark/typography.ts +16 -0
  46. package/families/forbidden/components/ForbiddenCausticBlobs.tsx +52 -0
  47. package/families/forbidden/components/NewsprintTexture.tsx +28 -0
  48. package/families/forbidden/components/TintedShadow.tsx +36 -0
  49. package/families/forbidden/components/index.ts +38 -0
  50. package/families/forbidden/index.ts +17 -0
  51. package/families/forbidden/palette.ts +88 -0
  52. package/families/forbidden/presets/heretic.ts +44 -0
  53. package/families/forbidden/typography.ts +18 -0
  54. package/families/glass/components/BreakdownCard.tsx +158 -0
  55. package/families/glass/components/CausticBlobs.tsx +49 -0
  56. package/families/glass/components/Counter.tsx +72 -0
  57. package/families/glass/components/EyebrowPill.tsx +59 -0
  58. package/families/glass/components/FilmStrip.tsx +202 -0
  59. package/families/glass/components/FloatingGlyphs.tsx +78 -0
  60. package/families/glass/components/GlassCard.tsx +58 -0
  61. package/families/glass/components/GlassCardBezel.tsx +45 -0
  62. package/families/glass/components/HairlineGrid.tsx +30 -0
  63. package/families/glass/components/IridescentRing.tsx +114 -0
  64. package/families/glass/components/IridescentText.tsx +98 -0
  65. package/families/glass/components/LightBeam.tsx +46 -0
  66. package/families/glass/components/ParticleBurst.tsx +62 -0
  67. package/families/glass/components/SonarRings.tsx +81 -0
  68. package/families/glass/components/StaggeredWords.tsx +74 -0
  69. package/families/glass/components/index.ts +20 -0
  70. package/families/glass/index.ts +31 -0
  71. package/families/glass/palette.ts +93 -0
  72. package/families/glass/presets/claudewatch.ts +64 -0
  73. package/families/glass/presets/claudewatchcta.ts +43 -0
  74. package/families/glass/presets/graphify.ts +45 -0
  75. package/families/glass/presets/gstack.ts +48 -0
  76. package/families/glass/presets/jcode.ts +50 -0
  77. package/families/glass/presets/lilagents.ts +52 -0
  78. package/families/glass/presets/paperclip.ts +43 -0
  79. package/families/glass/typography.ts +15 -0
  80. package/families/index.ts +49 -0
  81. package/families/paper/components/CardSpring.tsx +42 -0
  82. package/families/paper/components/CreamGrid.tsx +26 -0
  83. package/families/paper/components/EditorialSerifText.tsx +51 -0
  84. package/families/paper/components/GreenAccentCard.tsx +10 -0
  85. package/families/paper/components/PaperShadow.tsx +30 -0
  86. package/families/paper/components/ScaleBlurText.tsx +40 -0
  87. package/families/paper/components/index.ts +11 -0
  88. package/families/paper/index.ts +23 -0
  89. package/families/paper/palette.ts +102 -0
  90. package/families/paper/presets/designreel.ts +32 -0
  91. package/families/paper/presets/devini3d.ts +45 -0
  92. package/families/paper/presets/justdrop.ts +39 -0
  93. package/families/paper/presets/opus.ts +48 -0
  94. package/families/paper/typography.ts +17 -0
  95. package/families/warm/components/AccentGlow.tsx +60 -0
  96. package/families/warm/components/BentoCell.tsx +56 -0
  97. package/families/warm/components/BentoGrid.tsx +30 -0
  98. package/families/warm/components/FilmGrain.tsx +36 -0
  99. package/families/warm/components/ScaleBlurCounter.tsx +71 -0
  100. package/families/warm/components/WarmSurface.tsx +35 -0
  101. package/families/warm/components/index.ts +11 -0
  102. package/families/warm/index.ts +19 -0
  103. package/families/warm/palette.ts +81 -0
  104. package/families/warm/presets/huashu.ts +49 -0
  105. package/families/warm/presets/mempalace.ts +51 -0
  106. package/families/warm/typography.ts +17 -0
  107. package/package.json +85 -0
  108. package/reference/dark/claudedispatch.tsx +2441 -0
  109. package/reference/dark/notebooklm.tsx +2316 -0
  110. package/reference/dark/stitch.tsx +3040 -0
  111. package/reference/forbidden/heretic.tsx +2636 -0
  112. package/reference/glass/claudewatch.tsx +3827 -0
  113. package/reference/glass/graphify.tsx +2418 -0
  114. package/reference/glass/paperclip.tsx +2218 -0
  115. package/reference/paper/designreel.tsx +883 -0
  116. package/reference/paper/justdrop.tsx +1898 -0
  117. package/reference/paper/opus.tsx +1770 -0
  118. package/reference/warm/huashu.tsx +3413 -0
  119. package/reference/warm/mempalace.tsx +2909 -0
  120. package/skill/SKILL.md +229 -0
  121. package/skill/commands/reelstack-beats.md +20 -0
  122. package/skill/commands/reelstack-capture.md +24 -0
  123. package/skill/commands/reelstack-critique.md +15 -0
  124. package/skill/commands/reelstack-dark.md +40 -0
  125. package/skill/commands/reelstack-direction.md +17 -0
  126. package/skill/commands/reelstack-forbidden.md +25 -0
  127. package/skill/commands/reelstack-glass.md +39 -0
  128. package/skill/commands/reelstack-icons.md +22 -0
  129. package/skill/commands/reelstack-init.md +17 -0
  130. package/skill/commands/reelstack-lint.md +22 -0
  131. package/skill/commands/reelstack-paper.md +36 -0
  132. package/skill/commands/reelstack-render.md +20 -0
  133. package/skill/commands/reelstack-warm.md +36 -0
  134. package/templates/dark/template.tsx +115 -0
  135. package/templates/forbidden/template.tsx +111 -0
  136. package/templates/glass/template.tsx +201 -0
  137. package/templates/paper/template.tsx +133 -0
  138. package/templates/warm/template.tsx +210 -0
  139. package/utils/ai-purple-blocklist.ts +13 -0
  140. package/utils/banned-fonts.ts +11 -0
  141. package/utils/cubic-bezier.ts +36 -0
  142. package/utils/easing.ts +84 -0
  143. package/utils/grid.ts +13 -0
  144. package/utils/render-presets.json +56 -0
  145. package/utils/safe-zones.tsx +57 -0
@@ -0,0 +1,2636 @@
1
+ /**
2
+ * REFERENCE — HereticReel (Family: forbidden)
3
+ *
4
+ * Canonical example of the forbidden family's motion vocabulary, frame-locked
5
+ * BEAT structure, and scene choreography. Bundled with ReelStack v1.1.1+
6
+ * for STUDY and pattern adaptation.
7
+ *
8
+ * Asset imports stripped (look for REFERENCE-STRIP markers). Bring your own
9
+ * voiceover, brand SVGs, captures.
10
+ *
11
+ * License: study + adapt patterns OK. Verbatim re-publication as your own
12
+ * template NOT OK. See ReelStack LICENSE.
13
+ *
14
+ * Source: my-video/src/HereticReel.tsx
15
+ * Bundled at: 2026-05-08T18:50:39.540Z
16
+ */
17
+ import React from "react";
18
+ import {
19
+ AbsoluteFill,
20
+ Audio,
21
+ Easing,
22
+ Img,
23
+ OffthreadVideo,
24
+ Sequence,
25
+ interpolate,
26
+ spring,
27
+ staticFile,
28
+ useCurrentFrame,
29
+ useVideoConfig,
30
+ } from "remotion";
31
+ import { ds } from "./designSystem";
32
+
33
+ // ═══════════════════════════════════════════════════════════════
34
+ // TIMING — 54.64s @ 30fps = 1639 frames
35
+ // Beats locked to whisper-cli SRT of heretic-voiceover.wav
36
+ // ═══════════════════════════════════════════════════════════════
37
+ export const HERETIC_TOTAL = 1639;
38
+
39
+ export const HBEAT = {
40
+ hook: 0, // 00.00s — "Strip the censorship right out of any open source AI..."
41
+ refusal: 144, // 04.80s — "ChatGPT won't tell you. Claude refuses. Gemini dodges..."
42
+ reveal: 385, // 12.84s — "It's called Heretic. And it decensors..."
43
+ mechanism: 716, // 23.88s — "Here's the smart part. It finds the exact pattern..."
44
+ brains: 961, // 32.04s — "And the wild part? Without breaking intelligence..."
45
+ stars: 1219, // 40.64s — "Already at almost 20,000 stars on GitHub..."
46
+ cta: 1500, // 50.00s — "Like, subscribe, check pinned comment..."
47
+ end: 1639, // 54.64s
48
+ } as const;
49
+
50
+ // GSAP-equivalent easing curves mapped onto Remotion's `interpolate`.
51
+ export const ease = {
52
+ power2Out: Easing.bezier(0.165, 0.84, 0.44, 1),
53
+ power3Out: Easing.bezier(0.215, 0.61, 0.355, 1),
54
+ power4Out: Easing.bezier(0.165, 0.84, 0.44, 1),
55
+ expoOut: Easing.bezier(0.19, 1, 0.22, 1),
56
+ expoIn: Easing.bezier(0.7, 0, 0.84, 0),
57
+ backOut: Easing.bezier(0.34, 1.56, 0.64, 1),
58
+ inOut: Easing.bezier(0.45, 0, 0.55, 1),
59
+ };
60
+
61
+ // ═══════════════════════════════════════════════════════════════
62
+ // FORBIDDEN GLASS PALETTE — cream-rose paper + ember/crimson/ultraviolet/plasma
63
+ // ═══════════════════════════════════════════════════════════════
64
+ export const C = {
65
+ bg: "#F2EBE5",
66
+ bgWarm: "#EFE3DB",
67
+ bgCool: "#ECE6E8",
68
+ ink: "#0E0B12",
69
+ inkSoft: "#26222A",
70
+ inkMuted: "#5A5560",
71
+ inkDim: "#8A848F",
72
+ hairline: "rgba(15,11,18,0.08)",
73
+ // Scene-coded accent stops, desaturated agency-tier
74
+ ember: "#D97757", // burning orange
75
+ crimson: "#C4506B", // deep rose / refusal
76
+ ultraviolet: "#6B5BD9", // nightshade / mechanism
77
+ plasma: "#A87FE8", // electric violet / stars
78
+ // Glass — slightly more opaque than Graphify because cream bg has less tonal contrast
79
+ glassFill: "rgba(255,255,255,0.46)",
80
+ glassFillStrong: "rgba(255,255,255,0.66)",
81
+ glassBorder: "rgba(255,255,255,0.88)",
82
+ glassInner: "rgba(255,255,255,0.55)",
83
+ } as const;
84
+
85
+ export const FONT = ds.font.sans;
86
+ export const MONO = ds.font.mono;
87
+
88
+ // Tinted shadow (rule: tint to bg hue, not pure black).
89
+ const GLASS_SHADOW = [
90
+ "0 24px 48px -12px rgba(120,80,120,0.22)",
91
+ "0 8px 16px -4px rgba(120,80,120,0.12)",
92
+ "inset 0 1.5px 0 rgba(255,255,255,0.95)",
93
+ "inset 0 -1px 0 rgba(255,255,255,0.30)",
94
+ ].join(", ");
95
+
96
+ export const glassBase: React.CSSProperties = {
97
+ background: C.glassFill,
98
+ backdropFilter: "blur(32px) saturate(180%)",
99
+ WebkitBackdropFilter: "blur(32px) saturate(180%)",
100
+ border: `1.5px solid ${C.glassBorder}`,
101
+ boxShadow: GLASS_SHADOW,
102
+ };
103
+
104
+ const SAFE_TOP = 290;
105
+
106
+ // ═══════════════════════════════════════════════════════════════
107
+ // PERPETUAL CAUSTIC BLOBS (Forbidden palette)
108
+ // ═══════════════════════════════════════════════════════════════
109
+ const CausticBlobs: React.FC = () => {
110
+ const frame = useCurrentFrame();
111
+ const t = frame / 30;
112
+ const blob = (
113
+ color: string,
114
+ size: number,
115
+ cx: number,
116
+ cy: number,
117
+ speedX: number,
118
+ speedY: number,
119
+ phase: number,
120
+ opacity = 0.55,
121
+ ): React.CSSProperties => ({
122
+ position: "absolute",
123
+ width: size,
124
+ height: size,
125
+ borderRadius: "50%",
126
+ background: `radial-gradient(circle at 50% 50%, ${color} 0%, ${color}99 30%, transparent 70%)`,
127
+ filter: "blur(120px)",
128
+ left: cx + Math.sin(t * speedX + phase) * 220,
129
+ top: cy + Math.cos(t * speedY + phase) * 160,
130
+ opacity,
131
+ pointerEvents: "none",
132
+ willChange: "transform",
133
+ });
134
+ return (
135
+ <AbsoluteFill style={{ overflow: "hidden" }}>
136
+ <div style={blob(C.ember, 720, 80, 220, 0.18, 0.13, 0.0, 0.6)} />
137
+ <div style={blob(C.ultraviolet, 820, 600, 540, 0.14, 0.16, 1.2, 0.55)} />
138
+ <div style={blob(C.crimson, 700, 200, 1100, 0.11, 0.19, 2.4, 0.5)} />
139
+ <div style={blob(C.plasma, 540, 720, 1500, 0.16, 0.12, 3.6, 0.4)} />
140
+ <div style={blob(C.ember, 600, 100, 1700, 0.12, 0.18, 4.2, 0.4)} />
141
+ </AbsoluteFill>
142
+ );
143
+ };
144
+
145
+ const HairlineGrid: React.FC<{ opacity?: number }> = ({ opacity = 0.06 }) => (
146
+ <AbsoluteFill
147
+ style={{
148
+ backgroundImage: `linear-gradient(${C.ink} 1px, transparent 1px), linear-gradient(90deg, ${C.ink} 1px, transparent 1px)`,
149
+ backgroundSize: "60px 60px",
150
+ opacity,
151
+ pointerEvents: "none",
152
+ }}
153
+ />
154
+ );
155
+
156
+ // ═══════════════════════════════════════════════════════════════
157
+ // IRIDESCENT RING — conic gradient using Forbidden stops
158
+ // ═══════════════════════════════════════════════════════════════
159
+ const IridescentRing: React.FC<{
160
+ size: number;
161
+ thickness?: number;
162
+ speed?: number;
163
+ borderRadius?: number;
164
+ }> = ({ size, thickness = 4, speed = 0.5, borderRadius = 9999 }) => {
165
+ const frame = useCurrentFrame();
166
+ const angle = (frame * speed) % 360;
167
+ return (
168
+ <div
169
+ style={{
170
+ position: "absolute",
171
+ inset: -thickness,
172
+ width: size + thickness * 2,
173
+ height: size + thickness * 2,
174
+ borderRadius: borderRadius + thickness,
175
+ background: `conic-gradient(from ${angle}deg, ${C.ember}, ${C.crimson}, ${C.ultraviolet}, ${C.plasma}, ${C.ember})`,
176
+ padding: thickness,
177
+ pointerEvents: "none",
178
+ opacity: 0.85,
179
+ }}
180
+ >
181
+ <div
182
+ style={{
183
+ width: "100%",
184
+ height: "100%",
185
+ background: C.bg,
186
+ borderRadius,
187
+ }}
188
+ />
189
+ </div>
190
+ );
191
+ };
192
+
193
+ // ═══════════════════════════════════════════════════════════════
194
+ // GLASS CARD + EYEBROW PILL
195
+ // ═══════════════════════════════════════════════════════════════
196
+ const GlassCard: React.FC<{
197
+ style?: React.CSSProperties;
198
+ children?: React.ReactNode;
199
+ radius?: number;
200
+ }> = ({ style, children, radius = 32 }) => (
201
+ <div style={{ ...glassBase, borderRadius: radius, ...style }}>{children}</div>
202
+ );
203
+
204
+ const EyebrowPill: React.FC<{ children: React.ReactNode; dot?: string }> = ({
205
+ children,
206
+ dot = C.ultraviolet,
207
+ }) => (
208
+ <div
209
+ style={{
210
+ ...glassBase,
211
+ borderRadius: 9999,
212
+ padding: "10px 22px",
213
+ display: "inline-flex",
214
+ alignItems: "center",
215
+ gap: 10,
216
+ fontFamily: MONO,
217
+ fontSize: 18,
218
+ fontWeight: 500,
219
+ color: C.inkSoft,
220
+ letterSpacing: "0.18em",
221
+ textTransform: "uppercase",
222
+ }}
223
+ >
224
+ <div
225
+ style={{
226
+ width: 7,
227
+ height: 7,
228
+ borderRadius: "50%",
229
+ background: dot,
230
+ boxShadow: `0 0 14px ${dot}`,
231
+ }}
232
+ />
233
+ {children}
234
+ </div>
235
+ );
236
+
237
+ // ═══════════════════════════════════════════════════════════════
238
+ // STAGGERED WORD REVEAL (fade-up + blur, GSAP-style stagger)
239
+ // ═══════════════════════════════════════════════════════════════
240
+ const StaggeredWords: React.FC<{
241
+ text: string;
242
+ startFrame: number;
243
+ perWordDelay?: number;
244
+ duration?: number;
245
+ fontSize: number;
246
+ fontWeight?: number;
247
+ color?: string;
248
+ letterSpacing?: string;
249
+ lineHeight?: number;
250
+ align?: "left" | "center" | "right";
251
+ fontFamily?: string;
252
+ highlight?: string;
253
+ highlightColor?: string;
254
+ }> = ({
255
+ text,
256
+ startFrame,
257
+ perWordDelay = 4,
258
+ duration = 24,
259
+ fontSize,
260
+ fontWeight = 700,
261
+ color = C.ink,
262
+ letterSpacing = "-0.035em",
263
+ lineHeight = 1.02,
264
+ align = "left",
265
+ fontFamily = FONT,
266
+ highlight,
267
+ highlightColor = C.ultraviolet,
268
+ }) => {
269
+ const frame = useCurrentFrame();
270
+ const words = text.split(" ");
271
+ return (
272
+ <div
273
+ style={{
274
+ display: "flex",
275
+ flexWrap: "wrap",
276
+ gap: "0.25em",
277
+ justifyContent:
278
+ align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start",
279
+ textAlign: align,
280
+ fontFamily,
281
+ fontSize,
282
+ fontWeight,
283
+ color,
284
+ letterSpacing,
285
+ lineHeight,
286
+ }}
287
+ >
288
+ {words.map((w, i) => {
289
+ const wordStart = startFrame + i * perWordDelay;
290
+ const local = frame - wordStart;
291
+ const opacity = interpolate(local, [0, duration], [0, 1], {
292
+ extrapolateLeft: "clamp",
293
+ extrapolateRight: "clamp",
294
+ easing: ease.expoOut,
295
+ });
296
+ const y = interpolate(local, [0, duration], [40, 0], {
297
+ extrapolateLeft: "clamp",
298
+ extrapolateRight: "clamp",
299
+ easing: ease.power3Out,
300
+ });
301
+ const blur = interpolate(local, [0, duration], [12, 0], {
302
+ extrapolateLeft: "clamp",
303
+ extrapolateRight: "clamp",
304
+ });
305
+ const isHighlight = highlight && w.toLowerCase().includes(highlight.toLowerCase());
306
+ return (
307
+ <span
308
+ key={i}
309
+ style={{
310
+ display: "inline-block",
311
+ opacity,
312
+ transform: `translateY(${y}px)`,
313
+ filter: `blur(${blur}px)`,
314
+ color: isHighlight ? highlightColor : color,
315
+ willChange: "transform, opacity, filter",
316
+ }}
317
+ >
318
+ {w}
319
+ </span>
320
+ );
321
+ })}
322
+ </div>
323
+ );
324
+ };
325
+
326
+ // ═══════════════════════════════════════════════════════════════
327
+ // SCRAMBLE TEXT — random glyphs resolve to actual chars
328
+ // ═══════════════════════════════════════════════════════════════
329
+ const ScrambleText: React.FC<{
330
+ text: string;
331
+ startFrame: number;
332
+ duration: number;
333
+ fontSize: number;
334
+ fontWeight?: number;
335
+ color?: string;
336
+ fontFamily?: string;
337
+ letterSpacing?: string;
338
+ }> = ({
339
+ text,
340
+ startFrame,
341
+ duration,
342
+ fontSize,
343
+ fontWeight = 800,
344
+ color = C.ink,
345
+ fontFamily = FONT,
346
+ letterSpacing = "-0.06em",
347
+ }) => {
348
+ const frame = useCurrentFrame();
349
+ const local = Math.max(0, frame - startFrame);
350
+ const progress = Math.min(1, local / duration);
351
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#%&!*";
352
+ const resolved = Math.floor(progress * text.length);
353
+ const out = text
354
+ .split("")
355
+ .map((ch, i) => {
356
+ if (i < resolved) return ch;
357
+ if (ch === " ") return " ";
358
+ const seed = (frame + i * 7) % chars.length;
359
+ return chars[seed];
360
+ })
361
+ .join("");
362
+ return (
363
+ <div
364
+ style={{
365
+ fontFamily,
366
+ fontSize,
367
+ fontWeight,
368
+ color,
369
+ letterSpacing,
370
+ lineHeight: 1,
371
+ whiteSpace: "pre",
372
+ }}
373
+ >
374
+ {out}
375
+ </div>
376
+ );
377
+ };
378
+
379
+ // ═══════════════════════════════════════════════════════════════
380
+ // COUNTER — eased number ticker
381
+ // ═══════════════════════════════════════════════════════════════
382
+ const Counter: React.FC<{
383
+ from: number;
384
+ to: number;
385
+ startFrame: number;
386
+ duration: number;
387
+ format?: (n: number) => string;
388
+ style?: React.CSSProperties;
389
+ easing?: (n: number) => number;
390
+ }> = ({ from, to, startFrame, duration, format, style, easing = ease.expoOut }) => {
391
+ const frame = useCurrentFrame();
392
+ const value = interpolate(frame, [startFrame, startFrame + duration], [from, to], {
393
+ extrapolateLeft: "clamp",
394
+ extrapolateRight: "clamp",
395
+ easing,
396
+ });
397
+ return <span style={style}>{format ? format(value) : Math.round(value).toString()}</span>;
398
+ };
399
+
400
+ // ═══════════════════════════════════════════════════════════════
401
+ // SONAR RINGS / PARTICLE BURST / LIGHT BEAM / FLOATING GLYPHS
402
+ // (Forbidden palette variants, palette-shifted from GraphifyReel)
403
+ // ═══════════════════════════════════════════════════════════════
404
+ const SonarRings: React.FC<{ accent?: string }> = ({ accent = C.ember }) => {
405
+ const frame = useCurrentFrame();
406
+ const rings = [0, 18, 36, 54, 72];
407
+ return (
408
+ <AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
409
+ {rings.map((birth, i) => {
410
+ const local = frame - birth;
411
+ const cycle = local % 90;
412
+ if (local < 0) return null;
413
+ const scale = interpolate(cycle, [0, 90], [0.05, 1.4], {
414
+ extrapolateLeft: "clamp",
415
+ extrapolateRight: "clamp",
416
+ easing: ease.expoOut,
417
+ });
418
+ const op = interpolate(cycle, [0, 30, 90], [0, 0.55, 0], {
419
+ extrapolateLeft: "clamp",
420
+ extrapolateRight: "clamp",
421
+ });
422
+ return (
423
+ <div
424
+ key={i}
425
+ style={{
426
+ position: "absolute",
427
+ width: 1400,
428
+ height: 1400,
429
+ borderRadius: "50%",
430
+ border: `2px solid ${i % 2 === 0 ? accent : C.crimson}`,
431
+ transform: `scale(${scale})`,
432
+ opacity: op,
433
+ willChange: "transform, opacity",
434
+ }}
435
+ />
436
+ );
437
+ })}
438
+ </AbsoluteFill>
439
+ );
440
+ };
441
+
442
+ const ParticleBurst: React.FC<{ count?: number }> = ({ count = 48 }) => {
443
+ const frame = useCurrentFrame();
444
+ const palette = [C.ember, C.crimson, C.ultraviolet, C.plasma];
445
+ const particles = Array.from({ length: count }, (_, i) => {
446
+ const angle = (i / count) * Math.PI * 2 + i * 0.31;
447
+ const distance = 200 + (i % 7) * 80;
448
+ const size = 6 + (i % 4) * 4;
449
+ const color = palette[i % 4];
450
+ const delay = (i * 0.7) % 24;
451
+ return { angle, distance, size, color, delay };
452
+ });
453
+ return (
454
+ <AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
455
+ {particles.map((p, i) => {
456
+ const local = Math.max(0, frame - p.delay);
457
+ const burst = interpolate(local, [0, 50], [0, 1], {
458
+ extrapolateLeft: "clamp",
459
+ extrapolateRight: "clamp",
460
+ easing: ease.expoOut,
461
+ });
462
+ const drift = Math.sin((frame + i * 12) * 0.04) * 12;
463
+ const x = Math.cos(p.angle) * p.distance * burst + drift;
464
+ const y = Math.sin(p.angle) * p.distance * burst * 1.4 + drift * 0.6;
465
+ const op = interpolate(local, [0, 20, 100, 180], [0, 0.85, 0.5, 0.2], {
466
+ extrapolateLeft: "clamp",
467
+ extrapolateRight: "clamp",
468
+ });
469
+ return (
470
+ <div
471
+ key={i}
472
+ style={{
473
+ position: "absolute",
474
+ width: p.size,
475
+ height: p.size,
476
+ borderRadius: "50%",
477
+ background: p.color,
478
+ boxShadow: `0 0 ${p.size * 2}px ${p.color}`,
479
+ transform: `translate(${x}px, ${y}px)`,
480
+ opacity: op,
481
+ willChange: "transform, opacity",
482
+ }}
483
+ />
484
+ );
485
+ })}
486
+ </AbsoluteFill>
487
+ );
488
+ };
489
+
490
+ const LightBeam: React.FC<{ delay: number; angle: number }> = ({ delay, angle }) => {
491
+ const frame = useCurrentFrame();
492
+ const local = frame - delay;
493
+ const progress = interpolate(local, [0, 60], [-0.3, 1.3], {
494
+ extrapolateLeft: "clamp",
495
+ extrapolateRight: "clamp",
496
+ easing: ease.expoOut,
497
+ });
498
+ const op = interpolate(local, [0, 12, 50, 60], [0, 0.7, 0.7, 0], {
499
+ extrapolateLeft: "clamp",
500
+ extrapolateRight: "clamp",
501
+ });
502
+ return (
503
+ <div
504
+ style={{
505
+ position: "absolute",
506
+ top: "50%",
507
+ left: "50%",
508
+ width: 2200,
509
+ height: 100,
510
+ background: `linear-gradient(90deg, transparent 0%, ${C.ember}88 30%, ${C.crimson}cc 50%, ${C.ultraviolet}88 70%, transparent 100%)`,
511
+ filter: "blur(20px)",
512
+ transform: `translate(-50%, -50%) rotate(${angle}deg) translateX(${(progress - 0.5) * 1500}px)`,
513
+ opacity: op,
514
+ willChange: "transform, opacity",
515
+ }}
516
+ />
517
+ );
518
+ };
519
+
520
+ const FloatingGlyphs: React.FC = () => {
521
+ const frame = useCurrentFrame();
522
+ const glyphs = [
523
+ { x: 120, y: 380, size: 80, delay: 4, rot: -8 },
524
+ { x: 880, y: 340, size: 60, delay: 12, rot: 12 },
525
+ { x: 80, y: 1240, size: 70, delay: 22, rot: 6 },
526
+ { x: 920, y: 1280, size: 90, delay: 32, rot: -10 },
527
+ { x: 200, y: 800, size: 50, delay: 42, rot: 14 },
528
+ { x: 820, y: 760, size: 55, delay: 52, rot: -4 },
529
+ ];
530
+ return (
531
+ <>
532
+ {glyphs.map((g, i) => {
533
+ const local = frame - g.delay;
534
+ const op = interpolate(local, [0, 30], [0, 1], {
535
+ extrapolateLeft: "clamp",
536
+ extrapolateRight: "clamp",
537
+ easing: ease.expoOut,
538
+ });
539
+ const float = Math.sin((frame + i * 22) * 0.05) * 8;
540
+ const scale = spring({
541
+ frame: local,
542
+ fps: 30,
543
+ config: { damping: 12, stiffness: 110 },
544
+ from: 0.6,
545
+ to: 1,
546
+ });
547
+ return (
548
+ <div
549
+ key={i}
550
+ style={{
551
+ position: "absolute",
552
+ left: g.x,
553
+ top: g.y + float,
554
+ width: g.size,
555
+ height: g.size,
556
+ borderRadius: g.size * 0.28,
557
+ background: C.glassFill,
558
+ backdropFilter: "blur(20px) saturate(160%)",
559
+ WebkitBackdropFilter: "blur(20px) saturate(160%)",
560
+ border: `1px solid ${C.glassBorder}`,
561
+ boxShadow: "inset 0 1px 0 rgba(255,255,255,0.85), 0 8px 16px -4px rgba(120,80,120,0.18)",
562
+ transform: `rotate(${g.rot}deg) scale(${scale})`,
563
+ opacity: op * 0.85,
564
+ willChange: "transform, opacity",
565
+ }}
566
+ />
567
+ );
568
+ })}
569
+ </>
570
+ );
571
+ };
572
+
573
+ // ═══════════════════════════════════════════════════════════════
574
+ // SHATTER LOCK — lock icon fragments into shards (Scene 1)
575
+ // ═══════════════════════════════════════════════════════════════
576
+ const ShatterLock: React.FC<{ startFrame: number }> = ({ startFrame }) => {
577
+ const frame = useCurrentFrame();
578
+ const local = frame - startFrame;
579
+ const shatterAt = 30; // when the lock breaks
580
+
581
+ // Lock body before shatter
582
+ const wholeOpacity = interpolate(local, [0, 12, shatterAt - 2, shatterAt], [0, 1, 1, 0], {
583
+ extrapolateLeft: "clamp",
584
+ extrapolateRight: "clamp",
585
+ });
586
+ const wholeScale = spring({
587
+ frame: local,
588
+ fps: 30,
589
+ config: { damping: 14, stiffness: 130 },
590
+ from: 0.5,
591
+ to: 1,
592
+ });
593
+
594
+ // 18 shards bursting outward post-shatter
595
+ const shards = Array.from({ length: 18 }, (_, i) => {
596
+ const angle = (i / 18) * Math.PI * 2 + (i % 3) * 0.4;
597
+ const dist = 180 + (i % 5) * 40;
598
+ const rotSpeed = (i % 2 === 0 ? 1 : -1) * (1.2 + (i % 3) * 0.6);
599
+ const size = 18 + (i % 4) * 6;
600
+ return { angle, dist, rotSpeed, size };
601
+ });
602
+
603
+ return (
604
+ <div
605
+ style={{
606
+ position: "absolute",
607
+ left: 0,
608
+ right: 0,
609
+ top: 660,
610
+ display: "flex",
611
+ justifyContent: "center",
612
+ pointerEvents: "none",
613
+ }}
614
+ >
615
+ <div style={{ position: "relative", width: 280, height: 280 }}>
616
+ {/* Whole lock (before shatter) */}
617
+ <div
618
+ style={{
619
+ position: "absolute",
620
+ inset: 0,
621
+ display: "flex",
622
+ alignItems: "center",
623
+ justifyContent: "center",
624
+ opacity: wholeOpacity,
625
+ transform: `scale(${wholeScale})`,
626
+ willChange: "transform, opacity",
627
+ }}
628
+ >
629
+ <Img
630
+ src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
631
+ style={{
632
+ width: 220,
633
+ height: 220,
634
+ filter: `drop-shadow(0 0 24px ${C.crimson}88) drop-shadow(0 0 8px ${C.ember})`,
635
+ }}
636
+ />
637
+ </div>
638
+
639
+ {/* Shatter shards */}
640
+ {local >= shatterAt &&
641
+ shards.map((s, i) => {
642
+ const shLocal = local - shatterAt;
643
+ const t = interpolate(shLocal, [0, 60], [0, 1], {
644
+ extrapolateLeft: "clamp",
645
+ extrapolateRight: "clamp",
646
+ easing: ease.power3Out,
647
+ });
648
+ const x = Math.cos(s.angle) * s.dist * t;
649
+ const y = Math.sin(s.angle) * s.dist * t + t * t * 60;
650
+ const rot = shLocal * s.rotSpeed * 6;
651
+ const op = interpolate(shLocal, [0, 8, 60], [1, 1, 0], {
652
+ extrapolateLeft: "clamp",
653
+ extrapolateRight: "clamp",
654
+ });
655
+ const colorIdx = i % 4;
656
+ const color = [C.crimson, C.ember, C.ultraviolet, C.ink][colorIdx];
657
+ return (
658
+ <div
659
+ key={i}
660
+ style={{
661
+ position: "absolute",
662
+ left: "50%",
663
+ top: "50%",
664
+ width: s.size,
665
+ height: s.size,
666
+ background: color,
667
+ clipPath:
668
+ i % 3 === 0
669
+ ? "polygon(0 0, 100% 30%, 70% 100%, 0 80%)"
670
+ : i % 3 === 1
671
+ ? "polygon(20% 0, 100% 50%, 60% 100%, 0 60%)"
672
+ : "polygon(0 20%, 80% 0, 100% 80%, 30% 100%)",
673
+ transform: `translate(-50%, -50%) translate(${x}px, ${y}px) rotate(${rot}deg)`,
674
+ opacity: op,
675
+ boxShadow: `0 0 12px ${color}`,
676
+ willChange: "transform, opacity",
677
+ }}
678
+ />
679
+ );
680
+ })}
681
+ </div>
682
+ </div>
683
+ );
684
+ };
685
+
686
+ // ═══════════════════════════════════════════════════════════════
687
+ // SCENE 1 — HOOK (0–144, 4.8s)
688
+ // "Strip the censorship right out of any open source AI. With one command."
689
+ // ═══════════════════════════════════════════════════════════════
690
+ const HookScene: React.FC = () => {
691
+ const frame = useCurrentFrame();
692
+ const heroScale = spring({
693
+ frame: frame - 4,
694
+ fps: 30,
695
+ config: { damping: 14, stiffness: 130 },
696
+ from: 0.78,
697
+ to: 1,
698
+ });
699
+ const heroBlur = interpolate(frame, [4, 28], [16, 0], {
700
+ extrapolateLeft: "clamp",
701
+ extrapolateRight: "clamp",
702
+ easing: ease.expoOut,
703
+ });
704
+ return (
705
+ <AbsoluteFill>
706
+ <SonarRings accent={C.ember} />
707
+ <LightBeam delay={0} angle={-18} />
708
+ <LightBeam delay={20} angle={22} />
709
+ <LightBeam delay={50} angle={-12} />
710
+ <FloatingGlyphs />
711
+ <ParticleBurst />
712
+ <ShatterLock startFrame={0} />
713
+
714
+ {/* Eyebrow */}
715
+ <div
716
+ style={{
717
+ position: "absolute",
718
+ top: SAFE_TOP + 24,
719
+ left: 80,
720
+ opacity: interpolate(frame, [2, 22], [0, 1], { extrapolateRight: "clamp" }),
721
+ transform: `translateY(${interpolate(frame, [2, 22], [16, 0], { extrapolateRight: "clamp", easing: ease.power3Out })}px)`,
722
+ }}
723
+ >
724
+ <EyebrowPill dot={C.ember}>01 — heretic</EyebrowPill>
725
+ </div>
726
+
727
+ {/* Hero — left-aligned (anti-center bias rule) */}
728
+ <AbsoluteFill
729
+ style={{
730
+ alignItems: "flex-start",
731
+ justifyContent: "center",
732
+ padding: "0 80px",
733
+ transform: `scale(${heroScale})`,
734
+ filter: `blur(${heroBlur}px)`,
735
+ willChange: "transform, filter",
736
+ }}
737
+ >
738
+ <div style={{ width: "100%", textAlign: "left" }}>
739
+ <StaggeredWords
740
+ text="Strip the"
741
+ startFrame={4}
742
+ perWordDelay={2}
743
+ fontSize={92}
744
+ fontWeight={500}
745
+ color={C.inkMuted}
746
+ align="left"
747
+ letterSpacing="-0.025em"
748
+ />
749
+ <div style={{ height: 4 }} />
750
+ <ScrambleText
751
+ text="CENSORSHIP."
752
+ startFrame={18}
753
+ duration={42}
754
+ fontSize={148}
755
+ fontWeight={800}
756
+ color={C.crimson}
757
+ letterSpacing="-0.06em"
758
+ />
759
+ <div style={{ height: 6 }} />
760
+ <StaggeredWords
761
+ text="right out of any open-source AI."
762
+ startFrame={64}
763
+ perWordDelay={3}
764
+ fontSize={68}
765
+ fontWeight={700}
766
+ color={C.ink}
767
+ align="left"
768
+ letterSpacing="-0.035em"
769
+ highlight="open-source"
770
+ highlightColor={C.ultraviolet}
771
+ />
772
+ </div>
773
+
774
+ {/* Iridescent divider */}
775
+ <div
776
+ style={{
777
+ width: 280,
778
+ height: 5,
779
+ borderRadius: 999,
780
+ margin: "32px 0",
781
+ background: `linear-gradient(90deg, ${C.ember}, ${C.crimson}, ${C.ultraviolet})`,
782
+ opacity: interpolate(frame, [50, 80], [0, 1], { extrapolateRight: "clamp" }),
783
+ transform: `scaleX(${interpolate(frame, [50, 90], [0, 1], { extrapolateRight: "clamp", easing: ease.expoOut })})`,
784
+ transformOrigin: "left",
785
+ boxShadow: `0 0 24px ${C.crimson}66`,
786
+ }}
787
+ />
788
+
789
+ {/* Closing terminal pill */}
790
+ <div
791
+ style={{
792
+ opacity: interpolate(frame, [86, 116], [0, 1], { extrapolateRight: "clamp" }),
793
+ transform: `translateX(${interpolate(frame, [86, 116], [40, 0], { extrapolateRight: "clamp", easing: ease.power3Out })}px)`,
794
+ }}
795
+ >
796
+ <div
797
+ style={{
798
+ ...glassBase,
799
+ borderRadius: 9999,
800
+ padding: "12px 26px",
801
+ fontFamily: MONO,
802
+ fontSize: 24,
803
+ fontWeight: 600,
804
+ color: C.ink,
805
+ letterSpacing: "0.04em",
806
+ display: "inline-flex",
807
+ alignItems: "center",
808
+ gap: 12,
809
+ }}
810
+ >
811
+ <span style={{ color: C.ember }}>$</span>
812
+ <span>with one command.</span>
813
+ <span
814
+ style={{
815
+ width: 10,
816
+ height: 22,
817
+ background: C.ink,
818
+ opacity: Math.floor(frame / 8) % 2 === 0 ? 0.9 : 0,
819
+ }}
820
+ />
821
+ </div>
822
+ </div>
823
+ </AbsoluteFill>
824
+ </AbsoluteFill>
825
+ );
826
+ };
827
+
828
+ // ═══════════════════════════════════════════════════════════════
829
+ // REFUSAL CARD — brand glass tile + crimson "REFUSE" stamp + glitch
830
+ // ═══════════════════════════════════════════════════════════════
831
+ const RefusalCard: React.FC<{
832
+ iconPath: string;
833
+ brand: string;
834
+ refusalText: string;
835
+ startFrame: number;
836
+ index: number;
837
+ iconBg?: string;
838
+ invertIcon?: boolean;
839
+ }> = ({ iconPath, brand, refusalText, startFrame, index, iconBg = "#F7F4F0", invertIcon = false }) => {
840
+ const frame = useCurrentFrame();
841
+ const enter = startFrame + index * 8;
842
+ const local = frame - enter;
843
+ const opacity = interpolate(local, [0, 22], [0, 1], {
844
+ extrapolateLeft: "clamp",
845
+ extrapolateRight: "clamp",
846
+ });
847
+ const y = interpolate(local, [0, 28], [60, 0], {
848
+ extrapolateLeft: "clamp",
849
+ extrapolateRight: "clamp",
850
+ easing: ease.power3Out,
851
+ });
852
+ const scale = spring({
853
+ frame: local,
854
+ fps: 30,
855
+ config: { damping: 13, stiffness: 130 },
856
+ from: 0.85,
857
+ to: 1,
858
+ });
859
+ // Stamp arrives ~14 frames after card mounts and overshoots
860
+ const stampLocal = local - 14;
861
+ const stampOpacity = interpolate(stampLocal, [0, 12], [0, 1], {
862
+ extrapolateLeft: "clamp",
863
+ extrapolateRight: "clamp",
864
+ });
865
+ const stampScale = spring({
866
+ frame: stampLocal,
867
+ fps: 30,
868
+ config: { damping: 8, stiffness: 140 },
869
+ from: 1.6,
870
+ to: 1,
871
+ });
872
+ // RGB-channel-split glitch on stamp for ~8 frames at impact
873
+ const glitch = interpolate(stampLocal, [0, 4, 8], [4, 2, 0], {
874
+ extrapolateLeft: "clamp",
875
+ extrapolateRight: "clamp",
876
+ });
877
+
878
+ return (
879
+ <div
880
+ style={{
881
+ opacity,
882
+ transform: `translateY(${y}px) scale(${scale})`,
883
+ willChange: "transform, opacity",
884
+ flex: 1,
885
+ }}
886
+ >
887
+ <GlassCard radius={28} style={{ padding: 28, position: "relative", overflow: "hidden" }}>
888
+ <div
889
+ style={{
890
+ width: 78,
891
+ height: 78,
892
+ borderRadius: 20,
893
+ background: iconBg,
894
+ display: "flex",
895
+ alignItems: "center",
896
+ justifyContent: "center",
897
+ marginBottom: 18,
898
+ }}
899
+ >
900
+ <Img
901
+ src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
902
+ style={{
903
+ width: 50,
904
+ height: 50,
905
+ filter: invertIcon ? "invert(1)" : "none",
906
+ }}
907
+ />
908
+ </div>
909
+ <div
910
+ style={{
911
+ fontFamily: FONT,
912
+ fontSize: 28,
913
+ fontWeight: 700,
914
+ color: C.ink,
915
+ letterSpacing: "-0.02em",
916
+ lineHeight: 1,
917
+ }}
918
+ >
919
+ {brand}
920
+ </div>
921
+ <div
922
+ style={{
923
+ fontFamily: MONO,
924
+ fontSize: 14,
925
+ color: C.inkDim,
926
+ letterSpacing: "0.1em",
927
+ textTransform: "uppercase",
928
+ marginTop: 8,
929
+ }}
930
+ >
931
+ response
932
+ </div>
933
+
934
+ {/* REFUSE stamp */}
935
+ <div
936
+ style={{
937
+ position: "absolute",
938
+ right: -8,
939
+ bottom: 18,
940
+ transform: `rotate(-8deg) scale(${stampScale})`,
941
+ opacity: stampOpacity,
942
+ pointerEvents: "none",
943
+ }}
944
+ >
945
+ <div
946
+ style={{
947
+ fontFamily: FONT,
948
+ fontSize: 38,
949
+ fontWeight: 800,
950
+ letterSpacing: "0.08em",
951
+ padding: "8px 18px",
952
+ border: `3px solid ${C.crimson}`,
953
+ color: C.crimson,
954
+ textTransform: "uppercase",
955
+ borderRadius: 8,
956
+ background: "rgba(255,255,255,0.5)",
957
+ textShadow: `${glitch}px 0 0 ${C.ember}, ${-glitch}px 0 0 ${C.ultraviolet}`,
958
+ }}
959
+ >
960
+ {refusalText}
961
+ </div>
962
+ </div>
963
+ </GlassCard>
964
+ </div>
965
+ );
966
+ };
967
+
968
+ // ═══════════════════════════════════════════════════════════════
969
+ // PYTHON CARD — single glass card + iridescent ring scaling in
970
+ // ═══════════════════════════════════════════════════════════════
971
+ const PythonCard: React.FC<{ startFrame: number }> = ({ startFrame }) => {
972
+ const frame = useCurrentFrame();
973
+ const local = frame - startFrame;
974
+ const opacity = interpolate(local, [0, 18], [0, 1], {
975
+ extrapolateLeft: "clamp",
976
+ extrapolateRight: "clamp",
977
+ });
978
+ const scale = spring({
979
+ frame: local,
980
+ fps: 30,
981
+ config: { damping: 12, stiffness: 110 },
982
+ from: 0.6,
983
+ to: 1,
984
+ });
985
+ return (
986
+ <div
987
+ style={{
988
+ opacity,
989
+ transform: `scale(${scale})`,
990
+ willChange: "transform, opacity",
991
+ position: "relative",
992
+ width: 460,
993
+ }}
994
+ >
995
+ <IridescentRing size={460} thickness={3} speed={1.2} borderRadius={32} />
996
+ <div style={{ position: "relative" }}>
997
+ <GlassCard
998
+ radius={32}
999
+ style={{ padding: 36, background: C.glassFillStrong, textAlign: "center" }}
1000
+ >
1001
+ <Img
1002
+ src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
1003
+ style={{ width: 110, height: 110, margin: "4px auto 18px" }}
1004
+ />
1005
+ <div
1006
+ style={{
1007
+ fontFamily: FONT,
1008
+ fontSize: 36,
1009
+ fontWeight: 700,
1010
+ color: C.ink,
1011
+ letterSpacing: "-0.025em",
1012
+ lineHeight: 1,
1013
+ }}
1014
+ >
1015
+ this Python tool.
1016
+ </div>
1017
+ <div
1018
+ style={{
1019
+ fontFamily: MONO,
1020
+ fontSize: 16,
1021
+ color: C.ultraviolet,
1022
+ letterSpacing: "0.18em",
1023
+ textTransform: "uppercase",
1024
+ marginTop: 10,
1025
+ }}
1026
+ >
1027
+ does it
1028
+ </div>
1029
+ </GlassCard>
1030
+ </div>
1031
+ </div>
1032
+ );
1033
+ };
1034
+
1035
+ // ═══════════════════════════════════════════════════════════════
1036
+ // SCENE 2 — REFUSAL (144–385, 8.0s)
1037
+ // "ChatGPT won't tell you. Claude refuses. Gemini dodges around it.
1038
+ // But this Python tool? It just does it."
1039
+ // ═══════════════════════════════════════════════════════════════
1040
+ const RefusalScene: React.FC = () => {
1041
+ const frame = useCurrentFrame();
1042
+ const local = frame - HBEAT.refusal;
1043
+
1044
+ // Cards exit at frame ~150 of local time, Python arrives ~155, "It just does it" at ~190
1045
+ const cardExit = interpolate(local, [150, 180], [1, 0], {
1046
+ extrapolateLeft: "clamp",
1047
+ extrapolateRight: "clamp",
1048
+ });
1049
+ const cardExitY = interpolate(local, [150, 180], [0, -50], {
1050
+ extrapolateLeft: "clamp",
1051
+ extrapolateRight: "clamp",
1052
+ easing: ease.power3Out,
1053
+ });
1054
+
1055
+ return (
1056
+ <AbsoluteFill>
1057
+ {/* Eyebrow */}
1058
+ <div
1059
+ style={{
1060
+ position: "absolute",
1061
+ top: SAFE_TOP + 24,
1062
+ left: 80,
1063
+ opacity: interpolate(local, [0, 18], [0, 1], { extrapolateRight: "clamp" }),
1064
+ }}
1065
+ >
1066
+ <EyebrowPill dot={C.crimson}>02 — the big three</EyebrowPill>
1067
+ </div>
1068
+
1069
+ {/* Headline */}
1070
+ <div style={{ position: "absolute", left: 80, right: 80, top: SAFE_TOP + 110 }}>
1071
+ <StaggeredWords
1072
+ text="Ask the Big Three."
1073
+ startFrame={HBEAT.refusal + 6}
1074
+ fontSize={86}
1075
+ fontWeight={700}
1076
+ color={C.ink}
1077
+ align="left"
1078
+ letterSpacing="-0.04em"
1079
+ highlight="Three"
1080
+ highlightColor={C.crimson}
1081
+ />
1082
+ </div>
1083
+
1084
+ {/* Three refusal cards */}
1085
+ <div
1086
+ style={{
1087
+ position: "absolute",
1088
+ left: 60,
1089
+ right: 60,
1090
+ top: SAFE_TOP + 280,
1091
+ display: "flex",
1092
+ gap: 20,
1093
+ opacity: cardExit,
1094
+ transform: `translateY(${cardExitY}px)`,
1095
+ }}
1096
+ >
1097
+ <RefusalCard
1098
+ iconPath="icons/openai.svg"
1099
+ brand="ChatGPT"
1100
+ refusalText="WON'T"
1101
+ startFrame={HBEAT.refusal + 28}
1102
+ index={0}
1103
+ iconBg="#0E0B12"
1104
+ invertIcon={true}
1105
+ />
1106
+ <RefusalCard
1107
+ iconPath="icons/claude.svg"
1108
+ brand="Claude"
1109
+ refusalText="REFUSES"
1110
+ startFrame={HBEAT.refusal + 28}
1111
+ index={1}
1112
+ iconBg="#F4EAE0"
1113
+ />
1114
+ <RefusalCard
1115
+ iconPath="icons/gemini.svg"
1116
+ brand="Gemini"
1117
+ refusalText="DODGES"
1118
+ startFrame={HBEAT.refusal + 28}
1119
+ index={2}
1120
+ iconBg="#EEF1F8"
1121
+ />
1122
+ </div>
1123
+
1124
+ {/* Python card */}
1125
+ <div
1126
+ style={{
1127
+ position: "absolute",
1128
+ left: 0,
1129
+ right: 0,
1130
+ top: 1100,
1131
+ display: "flex",
1132
+ justifyContent: "center",
1133
+ opacity: interpolate(local, [155, 175], [0, 1], {
1134
+ extrapolateLeft: "clamp",
1135
+ extrapolateRight: "clamp",
1136
+ }),
1137
+ }}
1138
+ >
1139
+ <PythonCard startFrame={HBEAT.refusal + 155} />
1140
+ </div>
1141
+
1142
+ {/* Closing line */}
1143
+ <div
1144
+ style={{
1145
+ position: "absolute",
1146
+ left: 0,
1147
+ right: 0,
1148
+ top: 1620,
1149
+ textAlign: "center",
1150
+ opacity: interpolate(local, [195, 220], [0, 1], {
1151
+ extrapolateLeft: "clamp",
1152
+ extrapolateRight: "clamp",
1153
+ }),
1154
+ transform: `scale(${spring({
1155
+ frame: local - 195,
1156
+ fps: 30,
1157
+ config: { damping: 10, stiffness: 130 },
1158
+ from: 0.85,
1159
+ to: 1,
1160
+ })})`,
1161
+ }}
1162
+ >
1163
+ <div
1164
+ style={{
1165
+ fontFamily: FONT,
1166
+ fontSize: 86,
1167
+ fontWeight: 800,
1168
+ color: C.ink,
1169
+ letterSpacing: "-0.04em",
1170
+ lineHeight: 1,
1171
+ }}
1172
+ >
1173
+ It just <span style={{ color: C.ultraviolet }}>does it.</span>
1174
+ </div>
1175
+ </div>
1176
+ </AbsoluteFill>
1177
+ );
1178
+ };
1179
+
1180
+ // ═══════════════════════════════════════════════════════════════
1181
+ // SCENE 3 — REVEAL (385–716, 11.0s)
1182
+ // "It's called Heretic. And it decensors basically any open source LLM,
1183
+ // fully automatically. No fine-tuning, no training data, no manual setup."
1184
+ // ═══════════════════════════════════════════════════════════════
1185
+ const RevealScene: React.FC = () => {
1186
+ const frame = useCurrentFrame();
1187
+ const local = frame - HBEAT.reveal;
1188
+ const introOpacity = interpolate(local, [0, 24], [0, 1], { extrapolateRight: "clamp" });
1189
+ const titleOpacity = interpolate(local, [22, 56], [0, 1], { extrapolateRight: "clamp" });
1190
+ const titleY = interpolate(local, [22, 70], [50, 0], {
1191
+ extrapolateRight: "clamp",
1192
+ easing: ease.expoOut,
1193
+ });
1194
+ const titleScale = spring({
1195
+ frame: local - 22,
1196
+ fps: 30,
1197
+ config: { damping: 14, stiffness: 110 },
1198
+ from: 0.92,
1199
+ to: 1,
1200
+ });
1201
+ const ringRevealStart = 60;
1202
+ const ringSize = interpolate(local, [ringRevealStart, ringRevealStart + 40], [0, 920], {
1203
+ extrapolateLeft: "clamp",
1204
+ extrapolateRight: "clamp",
1205
+ easing: ease.expoOut,
1206
+ });
1207
+
1208
+ const chips = ["no fine-tuning", "no training data", "no manual setup"];
1209
+
1210
+ return (
1211
+ <AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
1212
+ <FloatingGlyphs />
1213
+
1214
+ <div
1215
+ style={{
1216
+ fontFamily: FONT,
1217
+ fontSize: 56,
1218
+ fontWeight: 500,
1219
+ color: C.inkMuted,
1220
+ opacity: introOpacity,
1221
+ transform: `translateY(${interpolate(local, [0, 24], [16, 0], { extrapolateRight: "clamp", easing: ease.power3Out })}px)`,
1222
+ marginBottom: 28,
1223
+ letterSpacing: "-0.02em",
1224
+ }}
1225
+ >
1226
+ It's called
1227
+ </div>
1228
+
1229
+ {/* Title group with rotating conic halo behind */}
1230
+ <div
1231
+ style={{
1232
+ position: "relative",
1233
+ opacity: titleOpacity,
1234
+ transform: `translateY(${titleY}px) scale(${titleScale})`,
1235
+ willChange: "transform, opacity",
1236
+ }}
1237
+ >
1238
+ <div
1239
+ style={{
1240
+ position: "absolute",
1241
+ left: "50%",
1242
+ top: "50%",
1243
+ width: ringSize,
1244
+ height: ringSize,
1245
+ transform: "translate(-50%, -50%)",
1246
+ borderRadius: "50%",
1247
+ background: `conic-gradient(from ${frame * 0.6}deg, ${C.ember}, ${C.crimson}, ${C.ultraviolet}, ${C.plasma}, ${C.ember})`,
1248
+ filter: "blur(80px)",
1249
+ opacity: 0.6,
1250
+ }}
1251
+ />
1252
+ <div
1253
+ style={{
1254
+ position: "relative",
1255
+ fontFamily: FONT,
1256
+ fontSize: 240,
1257
+ fontWeight: 800,
1258
+ color: C.ink,
1259
+ letterSpacing: "-0.07em",
1260
+ lineHeight: 0.9,
1261
+ }}
1262
+ >
1263
+ Heretic.
1264
+ </div>
1265
+ </div>
1266
+
1267
+ {/* Tagline */}
1268
+ <div
1269
+ style={{
1270
+ marginTop: 28,
1271
+ opacity: interpolate(local, [80, 120], [0, 1], { extrapolateRight: "clamp" }),
1272
+ transform: `translateY(${interpolate(local, [80, 120], [12, 0], { extrapolateRight: "clamp", easing: ease.power3Out })}px)`,
1273
+ fontFamily: MONO,
1274
+ fontSize: 22,
1275
+ color: C.inkMuted,
1276
+ letterSpacing: "0.18em",
1277
+ textTransform: "uppercase",
1278
+ textAlign: "center",
1279
+ }}
1280
+ >
1281
+ decensors any open-source LLM — fully automatic
1282
+ </div>
1283
+
1284
+ {/* Triple chips */}
1285
+ <div
1286
+ style={{
1287
+ marginTop: 64,
1288
+ display: "flex",
1289
+ gap: 16,
1290
+ flexWrap: "wrap",
1291
+ justifyContent: "center",
1292
+ maxWidth: 980,
1293
+ }}
1294
+ >
1295
+ {chips.map((c, i) => {
1296
+ const cs = local - 150 - i * 10;
1297
+ const op = interpolate(cs, [0, 18], [0, 1], {
1298
+ extrapolateLeft: "clamp",
1299
+ extrapolateRight: "clamp",
1300
+ });
1301
+ const sc = spring({
1302
+ frame: cs,
1303
+ fps: 30,
1304
+ config: { damping: 12, stiffness: 130 },
1305
+ from: 0.7,
1306
+ to: 1,
1307
+ });
1308
+ return (
1309
+ <div
1310
+ key={i}
1311
+ style={{
1312
+ ...glassBase,
1313
+ borderRadius: 9999,
1314
+ padding: "16px 28px",
1315
+ fontFamily: FONT,
1316
+ fontSize: 28,
1317
+ fontWeight: 600,
1318
+ color: C.ink,
1319
+ letterSpacing: "-0.02em",
1320
+ opacity: op,
1321
+ transform: `scale(${sc})`,
1322
+ display: "inline-flex",
1323
+ alignItems: "center",
1324
+ gap: 12,
1325
+ }}
1326
+ >
1327
+ <span
1328
+ style={{
1329
+ width: 8,
1330
+ height: 8,
1331
+ borderRadius: "50%",
1332
+ background: [C.ember, C.crimson, C.ultraviolet][i],
1333
+ boxShadow: `0 0 12px ${[C.ember, C.crimson, C.ultraviolet][i]}`,
1334
+ }}
1335
+ />
1336
+ {c}
1337
+ </div>
1338
+ );
1339
+ })}
1340
+ </div>
1341
+
1342
+ {/* Closing emphasis "nothing." */}
1343
+ <div
1344
+ style={{
1345
+ marginTop: 60,
1346
+ opacity: interpolate(local, [240, 280], [0, 1], {
1347
+ extrapolateLeft: "clamp",
1348
+ extrapolateRight: "clamp",
1349
+ }),
1350
+ transform: `scale(${spring({
1351
+ frame: local - 240,
1352
+ fps: 30,
1353
+ config: { damping: 8, stiffness: 130 },
1354
+ from: 0.7,
1355
+ to: 1,
1356
+ })})`,
1357
+ }}
1358
+ >
1359
+ <div
1360
+ style={{
1361
+ fontFamily: FONT,
1362
+ fontSize: 86,
1363
+ fontWeight: 800,
1364
+ color: C.crimson,
1365
+ letterSpacing: "-0.05em",
1366
+ lineHeight: 1,
1367
+ }}
1368
+ >
1369
+ nothing.
1370
+ </div>
1371
+ </div>
1372
+ </AbsoluteFill>
1373
+ );
1374
+ };
1375
+
1376
+ // ═══════════════════════════════════════════════════════════════
1377
+ // WEIGHT MATRIX — 12×12 grid of glass tiles, one row gets extracted
1378
+ // ═══════════════════════════════════════════════════════════════
1379
+ const WeightMatrix: React.FC<{ startFrame: number; size?: number }> = ({
1380
+ startFrame,
1381
+ size = 720,
1382
+ }) => {
1383
+ const frame = useCurrentFrame();
1384
+ const local = frame - startFrame;
1385
+ const cols = 12;
1386
+ const rows = 12;
1387
+ const cellSize = size / cols;
1388
+ const gap = 4;
1389
+ const refusalRow = 5; // the row that "triggers refusals" — gets removed
1390
+
1391
+ // Animation phases:
1392
+ // 0–30: tiles fade in staggered
1393
+ // 30–60: refusal-row tiles pulse ultraviolet (identifying)
1394
+ // 60–95: refusal-row tiles dissolve (per-tile burst)
1395
+ // 95+: matrix sits with the row gone (continued perpetual pulse)
1396
+
1397
+ const tiles = [];
1398
+ for (let r = 0; r < rows; r++) {
1399
+ for (let c = 0; c < cols; c++) {
1400
+ const idx = r * cols + c;
1401
+ const introDelay = (r + c) * 0.6;
1402
+ const introLocal = local - introDelay;
1403
+ const introOp = interpolate(introLocal, [0, 18], [0, 1], {
1404
+ extrapolateLeft: "clamp",
1405
+ extrapolateRight: "clamp",
1406
+ easing: ease.expoOut,
1407
+ });
1408
+ const introScale = interpolate(introLocal, [0, 18], [0.4, 1], {
1409
+ extrapolateLeft: "clamp",
1410
+ extrapolateRight: "clamp",
1411
+ easing: ease.power3Out,
1412
+ });
1413
+
1414
+ // Perpetual subtle pulse
1415
+ const pulse = 1 + Math.sin((frame + idx * 4) * 0.06) * 0.02;
1416
+
1417
+ // Refusal-row identification (frames 30-60)
1418
+ const isRefusal = r === refusalRow;
1419
+ const idGlow = isRefusal
1420
+ ? interpolate(local, [30, 50, 60], [0, 1, 1], {
1421
+ extrapolateLeft: "clamp",
1422
+ extrapolateRight: "clamp",
1423
+ })
1424
+ : 0;
1425
+
1426
+ // Refusal-row dissolution (frames 60-95) — per-tile delay so it sweeps L→R
1427
+ const dissolveStart = 60 + c * 2;
1428
+ const dissolveLocal = local - dissolveStart;
1429
+ const dissolveOp = isRefusal
1430
+ ? interpolate(dissolveLocal, [0, 16], [1, 0], {
1431
+ extrapolateLeft: "clamp",
1432
+ extrapolateRight: "clamp",
1433
+ })
1434
+ : 1;
1435
+ const dissolveLift = isRefusal
1436
+ ? interpolate(dissolveLocal, [0, 24], [0, -32], {
1437
+ extrapolateLeft: "clamp",
1438
+ extrapolateRight: "clamp",
1439
+ easing: ease.power3Out,
1440
+ })
1441
+ : 0;
1442
+
1443
+ const baseColor = isRefusal
1444
+ ? `rgba(107,91,217,${0.08 + idGlow * 0.4})` // ultraviolet glow when identifying
1445
+ : C.glassFill;
1446
+
1447
+ tiles.push(
1448
+ <div
1449
+ key={idx}
1450
+ style={{
1451
+ position: "absolute",
1452
+ left: c * (cellSize + gap),
1453
+ top: r * (cellSize + gap),
1454
+ width: cellSize,
1455
+ height: cellSize,
1456
+ borderRadius: 8,
1457
+ background: baseColor,
1458
+ border: `1px solid ${isRefusal ? C.ultraviolet + "aa" : C.glassBorder}`,
1459
+ backdropFilter: "blur(14px)",
1460
+ WebkitBackdropFilter: "blur(14px)",
1461
+ boxShadow: isRefusal
1462
+ ? `0 0 ${idGlow * 18}px ${C.ultraviolet}, inset 0 1px 0 rgba(255,255,255,0.7)`
1463
+ : "inset 0 1px 0 rgba(255,255,255,0.5)",
1464
+ opacity: introOp * dissolveOp,
1465
+ transform: `scale(${introScale * pulse}) translateY(${dissolveLift}px)`,
1466
+ willChange: "transform, opacity",
1467
+ }}
1468
+ />,
1469
+ );
1470
+
1471
+ // Per-tile dissolve particles (refusal row only)
1472
+ if (isRefusal && dissolveLocal >= 0 && dissolveLocal <= 28) {
1473
+ const pIdx = c * 3;
1474
+ for (let p = 0; p < 3; p++) {
1475
+ const angle = (p / 3) * Math.PI * 2 + pIdx * 0.5;
1476
+ const dist = 30 + p * 20;
1477
+ const t = interpolate(dissolveLocal, [0, 24], [0, 1], {
1478
+ extrapolateLeft: "clamp",
1479
+ extrapolateRight: "clamp",
1480
+ easing: ease.power3Out,
1481
+ });
1482
+ const px = Math.cos(angle) * dist * t;
1483
+ const py = Math.sin(angle) * dist * t - t * 30;
1484
+ const pop = interpolate(dissolveLocal, [0, 8, 24], [0.9, 0.9, 0], {
1485
+ extrapolateLeft: "clamp",
1486
+ extrapolateRight: "clamp",
1487
+ });
1488
+ tiles.push(
1489
+ <div
1490
+ key={`p${idx}-${p}`}
1491
+ style={{
1492
+ position: "absolute",
1493
+ left: c * (cellSize + gap) + cellSize / 2,
1494
+ top: r * (cellSize + gap) + cellSize / 2,
1495
+ width: 5,
1496
+ height: 5,
1497
+ borderRadius: "50%",
1498
+ background: C.ultraviolet,
1499
+ boxShadow: `0 0 8px ${C.ultraviolet}`,
1500
+ transform: `translate(${px}px, ${py}px)`,
1501
+ opacity: pop,
1502
+ pointerEvents: "none",
1503
+ }}
1504
+ />,
1505
+ );
1506
+ }
1507
+ }
1508
+ }
1509
+ }
1510
+
1511
+ return (
1512
+ <div
1513
+ style={{
1514
+ position: "relative",
1515
+ width: cols * (cellSize + gap),
1516
+ height: rows * (cellSize + gap),
1517
+ }}
1518
+ >
1519
+ {tiles}
1520
+
1521
+ {/* "REFUSAL DIRECTION" annotation */}
1522
+ <div
1523
+ style={{
1524
+ position: "absolute",
1525
+ left: cols * (cellSize + gap) + 24,
1526
+ top: refusalRow * (cellSize + gap) + cellSize / 2 - 14,
1527
+ fontFamily: MONO,
1528
+ fontSize: 18,
1529
+ fontWeight: 600,
1530
+ color: C.ultraviolet,
1531
+ letterSpacing: "0.18em",
1532
+ textTransform: "uppercase",
1533
+ opacity: interpolate(local, [40, 56, 90, 110], [0, 1, 1, 0], {
1534
+ extrapolateLeft: "clamp",
1535
+ extrapolateRight: "clamp",
1536
+ }),
1537
+ whiteSpace: "nowrap",
1538
+ display: "flex",
1539
+ alignItems: "center",
1540
+ gap: 8,
1541
+ }}
1542
+ >
1543
+ <span
1544
+ style={{
1545
+ width: 24,
1546
+ height: 1,
1547
+ background: C.ultraviolet,
1548
+ boxShadow: `0 0 6px ${C.ultraviolet}`,
1549
+ }}
1550
+ />
1551
+ refusal direction
1552
+ </div>
1553
+ </div>
1554
+ );
1555
+ };
1556
+
1557
+ // ═══════════════════════════════════════════════════════════════
1558
+ // SCENE 4 — MECHANISM (716–961, 8.2s)
1559
+ // "Here's the smart part. It finds the exact pattern that triggers refusals
1560
+ // and removes it from the weights. That's it."
1561
+ // Part A (0–125): WeightMatrix find + dissolve
1562
+ // Part B (125–245): heretic.mov clip in glass laptop frame
1563
+ // ═══════════════════════════════════════════════════════════════
1564
+ const MechanismScene: React.FC = () => {
1565
+ const frame = useCurrentFrame();
1566
+ const local = frame - HBEAT.mechanism;
1567
+
1568
+ // Part A → Part B handoff
1569
+ const partAOpacity = interpolate(local, [110, 130], [1, 0], {
1570
+ extrapolateLeft: "clamp",
1571
+ extrapolateRight: "clamp",
1572
+ });
1573
+ const partBOpacity = interpolate(local, [120, 145], [0, 1], {
1574
+ extrapolateLeft: "clamp",
1575
+ extrapolateRight: "clamp",
1576
+ });
1577
+ const partBY = interpolate(local, [120, 152], [60, 0], {
1578
+ extrapolateLeft: "clamp",
1579
+ extrapolateRight: "clamp",
1580
+ easing: ease.expoOut,
1581
+ });
1582
+ const tilt = interpolate(local, [120, 170], [-2, 0], {
1583
+ extrapolateLeft: "clamp",
1584
+ extrapolateRight: "clamp",
1585
+ easing: ease.power3Out,
1586
+ });
1587
+
1588
+ return (
1589
+ <AbsoluteFill>
1590
+ {/* Eyebrow */}
1591
+ <div
1592
+ style={{
1593
+ position: "absolute",
1594
+ top: SAFE_TOP + 24,
1595
+ left: 80,
1596
+ opacity: interpolate(local, [0, 18], [0, 1], { extrapolateRight: "clamp" }),
1597
+ }}
1598
+ >
1599
+ <EyebrowPill dot={C.ultraviolet}>03 — the mechanism</EyebrowPill>
1600
+ </div>
1601
+
1602
+ {/* Headline */}
1603
+ <div style={{ position: "absolute", left: 80, right: 80, top: SAFE_TOP + 110 }}>
1604
+ <StaggeredWords
1605
+ text="Find the pattern."
1606
+ startFrame={HBEAT.mechanism + 6}
1607
+ fontSize={68}
1608
+ fontWeight={500}
1609
+ color={C.inkMuted}
1610
+ align="left"
1611
+ letterSpacing="-0.03em"
1612
+ />
1613
+ <div style={{ height: 4 }} />
1614
+ <StaggeredWords
1615
+ text="Remove the weights."
1616
+ startFrame={HBEAT.mechanism + 26}
1617
+ fontSize={92}
1618
+ fontWeight={800}
1619
+ color={C.ink}
1620
+ align="left"
1621
+ letterSpacing="-0.04em"
1622
+ highlight="Remove"
1623
+ highlightColor={C.ultraviolet}
1624
+ />
1625
+ </div>
1626
+
1627
+ {/* Part A — Weight matrix (0–125) */}
1628
+ <div
1629
+ style={{
1630
+ position: "absolute",
1631
+ left: 0,
1632
+ right: 0,
1633
+ top: 700,
1634
+ display: "flex",
1635
+ justifyContent: "center",
1636
+ opacity: partAOpacity,
1637
+ }}
1638
+ >
1639
+ <WeightMatrix startFrame={HBEAT.mechanism + 25} size={700} />
1640
+ </div>
1641
+
1642
+ {/* Part B — Glass laptop with heretic.mov */}
1643
+ <div
1644
+ style={{
1645
+ position: "absolute",
1646
+ left: 60,
1647
+ right: 60,
1648
+ top: 700,
1649
+ height: 540,
1650
+ opacity: partBOpacity,
1651
+ transform: `translateY(${partBY}px) rotate(${tilt}deg) perspective(1400px) rotateX(4deg)`,
1652
+ willChange: "transform, opacity",
1653
+ }}
1654
+ >
1655
+ <div
1656
+ style={{
1657
+ ...glassBase,
1658
+ borderRadius: 28,
1659
+ padding: 14,
1660
+ width: "100%",
1661
+ height: "100%",
1662
+ position: "relative",
1663
+ }}
1664
+ >
1665
+ {/* Window controls */}
1666
+ <div style={{ display: "flex", gap: 8, padding: "4px 6px 12px" }}>
1667
+ <div style={{ width: 12, height: 12, borderRadius: 6, background: "#FF5F57" }} />
1668
+ <div style={{ width: 12, height: 12, borderRadius: 6, background: "#FEBC2E" }} />
1669
+ <div style={{ width: 12, height: 12, borderRadius: 6, background: "#28C840" }} />
1670
+ <div
1671
+ style={{
1672
+ marginLeft: "auto",
1673
+ fontFamily: MONO,
1674
+ fontSize: 13,
1675
+ color: C.inkDim,
1676
+ letterSpacing: "0.05em",
1677
+ }}
1678
+ >
1679
+ p-e-w/heretic
1680
+ </div>
1681
+ </div>
1682
+
1683
+ <Sequence from={HBEAT.mechanism + 125} durationInFrames={120}>
1684
+ <div
1685
+ style={{
1686
+ width: "100%",
1687
+ height: "calc(100% - 28px)",
1688
+ borderRadius: 18,
1689
+ overflow: "hidden",
1690
+ background: "#0E0B12",
1691
+ }}
1692
+ >
1693
+ {/* REFERENCE-STRIP: <OffthreadVideo> removed — bring your own clip */}
1694
+ </div>
1695
+ </Sequence>
1696
+ </div>
1697
+ </div>
1698
+
1699
+ {/* Closing line "That's it." */}
1700
+ <div
1701
+ style={{
1702
+ position: "absolute",
1703
+ left: 0,
1704
+ right: 0,
1705
+ top: 1340,
1706
+ textAlign: "center",
1707
+ opacity: interpolate(local, [200, 230], [0, 1], {
1708
+ extrapolateLeft: "clamp",
1709
+ extrapolateRight: "clamp",
1710
+ }),
1711
+ transform: `scale(${spring({
1712
+ frame: local - 200,
1713
+ fps: 30,
1714
+ config: { damping: 9, stiffness: 130 },
1715
+ from: 0.85,
1716
+ to: 1,
1717
+ })})`,
1718
+ }}
1719
+ >
1720
+ <div
1721
+ style={{
1722
+ fontFamily: FONT,
1723
+ fontSize: 92,
1724
+ fontWeight: 800,
1725
+ color: C.ink,
1726
+ letterSpacing: "-0.05em",
1727
+ lineHeight: 1,
1728
+ }}
1729
+ >
1730
+ That's it.
1731
+ </div>
1732
+ </div>
1733
+ </AbsoluteFill>
1734
+ );
1735
+ };
1736
+
1737
+ // ═══════════════════════════════════════════════════════════════
1738
+ // BRAIN GRAPH — 8-node mini neural network, optionally dissolving
1739
+ // ═══════════════════════════════════════════════════════════════
1740
+ const BrainGraph: React.FC<{
1741
+ startFrame: number;
1742
+ dissolve?: boolean;
1743
+ accent: string;
1744
+ }> = ({ startFrame, dissolve = false, accent }) => {
1745
+ const frame = useCurrentFrame();
1746
+ const local = frame - startFrame;
1747
+ const nodes = [
1748
+ { x: 70, y: 60, r: 14 },
1749
+ { x: 200, y: 40, r: 18 },
1750
+ { x: 320, y: 80, r: 16 },
1751
+ { x: 90, y: 180, r: 16 },
1752
+ { x: 220, y: 160, r: 22 },
1753
+ { x: 340, y: 200, r: 14 },
1754
+ { x: 130, y: 290, r: 18 },
1755
+ { x: 270, y: 300, r: 16 },
1756
+ ];
1757
+ const edges: [number, number][] = [
1758
+ [0, 1], [1, 2], [0, 3], [1, 4], [2, 5], [3, 4], [4, 5], [3, 6], [4, 6], [4, 7], [5, 7], [6, 7],
1759
+ ];
1760
+
1761
+ // Dissolve = nodes scale down + alpha drops + particles burst
1762
+ const dissolveProgress = dissolve
1763
+ ? interpolate(local, [40, 110], [0, 1], {
1764
+ extrapolateLeft: "clamp",
1765
+ extrapolateRight: "clamp",
1766
+ easing: ease.power3Out,
1767
+ })
1768
+ : 0;
1769
+
1770
+ return (
1771
+ <svg width={420} height={360} viewBox="0 0 420 360" style={{ overflow: "visible" }}>
1772
+ <defs>
1773
+ <linearGradient id={`bg-edge-${dissolve ? "d" : "i"}`} x1="0" x2="1">
1774
+ <stop offset="0" stopColor={accent} stopOpacity="0.7" />
1775
+ <stop offset="1" stopColor={accent} stopOpacity="0.3" />
1776
+ </linearGradient>
1777
+ </defs>
1778
+ {edges.map(([a, b], i) => {
1779
+ const start = startFrame + 6 + i * 3;
1780
+ const lf = frame - start;
1781
+ const drawProgress = interpolate(lf, [0, 22], [0, 1], {
1782
+ extrapolateLeft: "clamp",
1783
+ extrapolateRight: "clamp",
1784
+ easing: ease.power3Out,
1785
+ });
1786
+ return (
1787
+ <line
1788
+ key={i}
1789
+ x1={nodes[a].x}
1790
+ y1={nodes[a].y}
1791
+ x2={nodes[a].x + (nodes[b].x - nodes[a].x) * drawProgress}
1792
+ y2={nodes[a].y + (nodes[b].y - nodes[a].y) * drawProgress}
1793
+ stroke={`url(#bg-edge-${dissolve ? "d" : "i"})`}
1794
+ strokeWidth={2}
1795
+ strokeLinecap="round"
1796
+ opacity={Math.max(0, drawProgress * (1 - dissolveProgress))}
1797
+ />
1798
+ );
1799
+ })}
1800
+ {nodes.map((n, i) => {
1801
+ const ns = startFrame + i * 4;
1802
+ const lf = frame - ns;
1803
+ const sc = spring({
1804
+ frame: lf,
1805
+ fps: 30,
1806
+ config: { damping: 11, stiffness: 130 },
1807
+ from: 0,
1808
+ to: 1,
1809
+ });
1810
+ const pulse = 1 + Math.sin((frame + i * 12) * 0.08) * 0.06;
1811
+ const dScale = 1 - dissolveProgress;
1812
+ return (
1813
+ <g key={i}>
1814
+ <circle
1815
+ cx={n.x}
1816
+ cy={n.y}
1817
+ r={n.r * 2.2 * sc * pulse * dScale}
1818
+ fill={accent}
1819
+ opacity={0.18 * (1 - dissolveProgress)}
1820
+ />
1821
+ <circle
1822
+ cx={n.x}
1823
+ cy={n.y}
1824
+ r={n.r * sc * pulse * dScale}
1825
+ fill="white"
1826
+ stroke={accent}
1827
+ strokeWidth={2.5}
1828
+ opacity={1 - dissolveProgress}
1829
+ />
1830
+ </g>
1831
+ );
1832
+ })}
1833
+ {/* Dissolve particles */}
1834
+ {dissolve &&
1835
+ nodes.map((n, i) => {
1836
+ const ds = local - 50 - i * 4;
1837
+ if (ds < 0) return null;
1838
+ const t = interpolate(ds, [0, 50], [0, 1], {
1839
+ extrapolateLeft: "clamp",
1840
+ extrapolateRight: "clamp",
1841
+ easing: ease.power3Out,
1842
+ });
1843
+ const angle = (i / nodes.length) * Math.PI * 2;
1844
+ const dx = Math.cos(angle) * 80 * t;
1845
+ const dy = Math.sin(angle) * 80 * t - t * 40;
1846
+ const op = interpolate(ds, [0, 14, 50], [0.9, 0.9, 0], {
1847
+ extrapolateLeft: "clamp",
1848
+ extrapolateRight: "clamp",
1849
+ });
1850
+ return (
1851
+ <circle
1852
+ key={`d${i}`}
1853
+ cx={n.x + dx}
1854
+ cy={n.y + dy}
1855
+ r={4}
1856
+ fill={accent}
1857
+ opacity={op}
1858
+ />
1859
+ );
1860
+ })}
1861
+ </svg>
1862
+ );
1863
+ };
1864
+
1865
+ // ═══════════════════════════════════════════════════════════════
1866
+ // SCENE 5 — BRAINS vs GUARDRAILS (961–1219, 8.6s)
1867
+ // "Without breaking the model's intelligence. So you keep the brains —
1868
+ // you just lose the guardrails."
1869
+ // ═══════════════════════════════════════════════════════════════
1870
+ const BrainsScene: React.FC = () => {
1871
+ const frame = useCurrentFrame();
1872
+ const local = frame - HBEAT.brains;
1873
+ return (
1874
+ <AbsoluteFill>
1875
+ <div
1876
+ style={{
1877
+ position: "absolute",
1878
+ top: SAFE_TOP + 24,
1879
+ left: 80,
1880
+ opacity: interpolate(local, [0, 18], [0, 1], { extrapolateRight: "clamp" }),
1881
+ }}
1882
+ >
1883
+ <EyebrowPill dot={C.crimson}>04 — the wild part</EyebrowPill>
1884
+ </div>
1885
+
1886
+ {/* Headline */}
1887
+ <div style={{ position: "absolute", left: 80, right: 80, top: SAFE_TOP + 110 }}>
1888
+ <StaggeredWords
1889
+ text="Keep the brains."
1890
+ startFrame={HBEAT.brains + 6}
1891
+ fontSize={92}
1892
+ fontWeight={800}
1893
+ color={C.ink}
1894
+ align="left"
1895
+ letterSpacing="-0.04em"
1896
+ highlight="brains"
1897
+ highlightColor={C.ultraviolet}
1898
+ />
1899
+ <div style={{ height: 6 }} />
1900
+ <StaggeredWords
1901
+ text="Lose the guardrails."
1902
+ startFrame={HBEAT.brains + 28}
1903
+ fontSize={92}
1904
+ fontWeight={800}
1905
+ color={C.ink}
1906
+ align="left"
1907
+ letterSpacing="-0.04em"
1908
+ highlight="guardrails"
1909
+ highlightColor={C.crimson}
1910
+ />
1911
+ </div>
1912
+
1913
+ {/* Two split cards */}
1914
+ <div
1915
+ style={{
1916
+ position: "absolute",
1917
+ left: 60,
1918
+ right: 60,
1919
+ top: 800,
1920
+ display: "flex",
1921
+ gap: 24,
1922
+ }}
1923
+ >
1924
+ {/* BRAINS card */}
1925
+ <div
1926
+ style={{
1927
+ flex: 1,
1928
+ opacity: interpolate(local, [50, 80], [0, 1], { extrapolateRight: "clamp" }),
1929
+ transform: `translateY(${interpolate(local, [50, 80], [40, 0], { extrapolateRight: "clamp", easing: ease.power3Out })}px)`,
1930
+ }}
1931
+ >
1932
+ <GlassCard radius={28} style={{ padding: 28, height: 540, position: "relative" }}>
1933
+ <div
1934
+ style={{
1935
+ fontFamily: MONO,
1936
+ fontSize: 14,
1937
+ color: C.inkDim,
1938
+ letterSpacing: "0.18em",
1939
+ textTransform: "uppercase",
1940
+ marginBottom: 14,
1941
+ }}
1942
+ >
1943
+ brains · intact
1944
+ </div>
1945
+ <div style={{ display: "flex", justifyContent: "center", marginTop: 4 }}>
1946
+ <BrainGraph startFrame={HBEAT.brains + 60} accent={C.ultraviolet} />
1947
+ </div>
1948
+ <div
1949
+ style={{
1950
+ position: "absolute",
1951
+ bottom: 24,
1952
+ left: 28,
1953
+ right: 28,
1954
+ display: "flex",
1955
+ alignItems: "baseline",
1956
+ justifyContent: "space-between",
1957
+ borderTop: `1px solid ${C.hairline}`,
1958
+ paddingTop: 16,
1959
+ }}
1960
+ >
1961
+ <div style={{ fontFamily: MONO, fontSize: 14, color: C.inkDim }}>
1962
+ CAPABILITY
1963
+ </div>
1964
+ <div
1965
+ style={{
1966
+ fontFamily: MONO,
1967
+ fontSize: 56,
1968
+ fontWeight: 700,
1969
+ color: C.ultraviolet,
1970
+ fontVariantNumeric: "tabular-nums",
1971
+ letterSpacing: "-0.04em",
1972
+ lineHeight: 1,
1973
+ }}
1974
+ >
1975
+ <Counter
1976
+ from={0}
1977
+ to={99}
1978
+ startFrame={HBEAT.brains + 80}
1979
+ duration={70}
1980
+ format={(n) => Math.round(n).toString() + "%"}
1981
+ />
1982
+ </div>
1983
+ </div>
1984
+ </GlassCard>
1985
+ </div>
1986
+
1987
+ {/* GUARDRAILS card (dissolving) */}
1988
+ <div
1989
+ style={{
1990
+ flex: 1,
1991
+ opacity: interpolate(local, [70, 100], [0, 1], { extrapolateRight: "clamp" }),
1992
+ transform: `translateY(${interpolate(local, [70, 100], [40, 0], { extrapolateRight: "clamp", easing: ease.power3Out })}px)`,
1993
+ }}
1994
+ >
1995
+ <GlassCard radius={28} style={{ padding: 28, height: 540, position: "relative" }}>
1996
+ <div
1997
+ style={{
1998
+ fontFamily: MONO,
1999
+ fontSize: 14,
2000
+ color: C.inkDim,
2001
+ letterSpacing: "0.18em",
2002
+ textTransform: "uppercase",
2003
+ marginBottom: 14,
2004
+ }}
2005
+ >
2006
+ guardrails · removed
2007
+ </div>
2008
+ <div style={{ display: "flex", justifyContent: "center", marginTop: 4 }}>
2009
+ <BrainGraph
2010
+ startFrame={HBEAT.brains + 80}
2011
+ dissolve={true}
2012
+ accent={C.crimson}
2013
+ />
2014
+ </div>
2015
+ <div
2016
+ style={{
2017
+ position: "absolute",
2018
+ bottom: 24,
2019
+ left: 28,
2020
+ right: 28,
2021
+ display: "flex",
2022
+ alignItems: "baseline",
2023
+ justifyContent: "space-between",
2024
+ borderTop: `1px solid ${C.hairline}`,
2025
+ paddingTop: 16,
2026
+ }}
2027
+ >
2028
+ <div style={{ fontFamily: MONO, fontSize: 14, color: C.inkDim }}>
2029
+ REFUSAL RATE
2030
+ </div>
2031
+ <div
2032
+ style={{
2033
+ fontFamily: MONO,
2034
+ fontSize: 56,
2035
+ fontWeight: 700,
2036
+ color: C.crimson,
2037
+ fontVariantNumeric: "tabular-nums",
2038
+ letterSpacing: "-0.04em",
2039
+ lineHeight: 1,
2040
+ }}
2041
+ >
2042
+ <Counter
2043
+ from={100}
2044
+ to={2}
2045
+ startFrame={HBEAT.brains + 100}
2046
+ duration={90}
2047
+ format={(n) => Math.round(n).toString() + "%"}
2048
+ />
2049
+ </div>
2050
+ </div>
2051
+ </GlassCard>
2052
+ </div>
2053
+ </div>
2054
+
2055
+ {/* Footer caption */}
2056
+ <div
2057
+ style={{
2058
+ position: "absolute",
2059
+ left: 80,
2060
+ right: 80,
2061
+ top: 1500,
2062
+ textAlign: "center",
2063
+ opacity: interpolate(local, [180, 220], [0, 1], {
2064
+ extrapolateLeft: "clamp",
2065
+ extrapolateRight: "clamp",
2066
+ }),
2067
+ }}
2068
+ >
2069
+ <div
2070
+ style={{
2071
+ fontFamily: MONO,
2072
+ fontSize: 22,
2073
+ color: C.inkMuted,
2074
+ letterSpacing: "0.18em",
2075
+ textTransform: "uppercase",
2076
+ }}
2077
+ >
2078
+ intelligence preserved · refusals removed
2079
+ </div>
2080
+ </div>
2081
+ </AbsoluteFill>
2082
+ );
2083
+ };
2084
+
2085
+ // ═══════════════════════════════════════════════════════════════
2086
+ // STAR SHOWER — 60 star polygons bursting from center
2087
+ // ═══════════════════════════════════════════════════════════════
2088
+ const StarShower: React.FC<{ startFrame: number }> = ({ startFrame }) => {
2089
+ const frame = useCurrentFrame();
2090
+ const local = frame - startFrame;
2091
+ if (local < 0) return null;
2092
+ const stars = Array.from({ length: 60 }, (_, i) => {
2093
+ const angle = (i / 60) * Math.PI * 2 + (i % 5) * 0.3;
2094
+ const dist = 240 + (i % 8) * 60;
2095
+ const size = 14 + (i % 5) * 5;
2096
+ const delay = (i % 12) * 1.5;
2097
+ const color = i % 3 === 0 ? C.plasma : i % 3 === 1 ? C.ember : C.ultraviolet;
2098
+ return { angle, dist, size, delay, color };
2099
+ });
2100
+ return (
2101
+ <AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
2102
+ {stars.map((s, i) => {
2103
+ const lf = local - s.delay;
2104
+ const burst = interpolate(lf, [0, 60], [0, 1], {
2105
+ extrapolateLeft: "clamp",
2106
+ extrapolateRight: "clamp",
2107
+ easing: ease.expoOut,
2108
+ });
2109
+ const drift = Math.sin((frame + i * 11) * 0.05) * 14;
2110
+ const x = Math.cos(s.angle) * s.dist * burst + drift;
2111
+ const y = Math.sin(s.angle) * s.dist * burst * 1.2 + drift * 0.5;
2112
+ const op = interpolate(lf, [0, 18, 90, 160], [0, 0.95, 0.6, 0.15], {
2113
+ extrapolateLeft: "clamp",
2114
+ extrapolateRight: "clamp",
2115
+ });
2116
+ const rot = (frame + i * 17) * 0.6;
2117
+ return (
2118
+ <svg
2119
+ key={i}
2120
+ width={s.size}
2121
+ height={s.size}
2122
+ viewBox="0 0 24 24"
2123
+ style={{
2124
+ position: "absolute",
2125
+ transform: `translate(${x}px, ${y}px) rotate(${rot}deg)`,
2126
+ opacity: op,
2127
+ filter: `drop-shadow(0 0 ${s.size}px ${s.color})`,
2128
+ willChange: "transform, opacity",
2129
+ }}
2130
+ >
2131
+ <path
2132
+ d="M12 2l2.85 6.34L22 9.27l-5.4 4.69 1.69 7.23L12 17.5l-6.29 3.69L7.4 13.96 2 9.27l7.15-.93z"
2133
+ fill={s.color}
2134
+ />
2135
+ </svg>
2136
+ );
2137
+ })}
2138
+ </AbsoluteFill>
2139
+ );
2140
+ };
2141
+
2142
+ // ═══════════════════════════════════════════════════════════════
2143
+ // SCENE 6 — STARS (1219–1500, 9.4s)
2144
+ // "Already at almost 20,000 stars on GitHub with over a thousand
2145
+ // community-built models running on it. This thing's blowing up fast."
2146
+ // ═══════════════════════════════════════════════════════════════
2147
+ const StarsScene: React.FC = () => {
2148
+ const frame = useCurrentFrame();
2149
+ const local = frame - HBEAT.stars;
2150
+ return (
2151
+ <AbsoluteFill>
2152
+ <StarShower startFrame={HBEAT.stars + 50} />
2153
+
2154
+ <div
2155
+ style={{
2156
+ position: "absolute",
2157
+ top: SAFE_TOP + 24,
2158
+ left: 80,
2159
+ opacity: interpolate(local, [0, 18], [0, 1], { extrapolateRight: "clamp" }),
2160
+ }}
2161
+ >
2162
+ <EyebrowPill dot={C.plasma}>05 — momentum</EyebrowPill>
2163
+ </div>
2164
+
2165
+ {/* GitHub repo card with star counter and sparkline */}
2166
+ <div
2167
+ style={{
2168
+ position: "absolute",
2169
+ left: 80,
2170
+ right: 80,
2171
+ top: SAFE_TOP + 130,
2172
+ opacity: interpolate(local, [0, 26], [0, 1], { extrapolateRight: "clamp" }),
2173
+ transform: `translateY(${interpolate(local, [0, 30], [40, 0], { extrapolateRight: "clamp", easing: ease.power3Out })}px)`,
2174
+ }}
2175
+ >
2176
+ <GlassCard radius={32} style={{ padding: 36 }}>
2177
+ <div style={{ display: "flex", alignItems: "center", gap: 22, marginBottom: 16 }}>
2178
+ <div
2179
+ style={{
2180
+ width: 64,
2181
+ height: 64,
2182
+ borderRadius: 18,
2183
+ background: "#0E0B12",
2184
+ display: "flex",
2185
+ alignItems: "center",
2186
+ justifyContent: "center",
2187
+ }}
2188
+ >
2189
+ <Img
2190
+ src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
2191
+ style={{ width: 38, height: 38, filter: "invert(1)" }}
2192
+ />
2193
+ </div>
2194
+ <div style={{ display: "flex", flexDirection: "column" }}>
2195
+ <div
2196
+ style={{
2197
+ fontFamily: MONO,
2198
+ fontSize: 16,
2199
+ color: C.inkDim,
2200
+ letterSpacing: "0.05em",
2201
+ }}
2202
+ >
2203
+ p-e-w /
2204
+ </div>
2205
+ <div
2206
+ style={{
2207
+ fontFamily: FONT,
2208
+ fontSize: 44,
2209
+ fontWeight: 700,
2210
+ color: C.ink,
2211
+ letterSpacing: "-0.03em",
2212
+ lineHeight: 1,
2213
+ }}
2214
+ >
2215
+ heretic
2216
+ </div>
2217
+ </div>
2218
+ </div>
2219
+
2220
+ {/* Stars row */}
2221
+ <div
2222
+ style={{
2223
+ display: "flex",
2224
+ alignItems: "baseline",
2225
+ gap: 18,
2226
+ marginTop: 12,
2227
+ borderTop: `1px solid ${C.hairline}`,
2228
+ paddingTop: 22,
2229
+ }}
2230
+ >
2231
+ <svg width="46" height="46" viewBox="0 0 24 24" fill={C.plasma}>
2232
+ <path d="M12 2l2.85 6.34L22 9.27l-5.4 4.69 1.69 7.23L12 17.5l-6.29 3.69L7.4 13.96 2 9.27l7.15-.93z" />
2233
+ </svg>
2234
+ <div
2235
+ style={{
2236
+ fontFamily: MONO,
2237
+ fontSize: 88,
2238
+ fontWeight: 700,
2239
+ color: C.ink,
2240
+ fontVariantNumeric: "tabular-nums",
2241
+ letterSpacing: "-0.04em",
2242
+ lineHeight: 1,
2243
+ }}
2244
+ >
2245
+ <Counter
2246
+ from={0}
2247
+ to={19847}
2248
+ startFrame={HBEAT.stars + 24}
2249
+ duration={130}
2250
+ format={(n) => Math.round(n).toLocaleString()}
2251
+ />
2252
+ </div>
2253
+ <div
2254
+ style={{
2255
+ fontFamily: FONT,
2256
+ fontSize: 26,
2257
+ fontWeight: 500,
2258
+ color: C.inkMuted,
2259
+ marginLeft: "auto",
2260
+ }}
2261
+ >
2262
+ and counting
2263
+ </div>
2264
+ </div>
2265
+
2266
+ {/* Sparkline */}
2267
+ <div style={{ marginTop: 28, display: "flex", gap: 6, alignItems: "flex-end" }}>
2268
+ {Array.from({ length: 28 }).map((_, i) => {
2269
+ const baseHeight = 16 + Math.abs(Math.sin(i * 0.7)) * 50 + (i / 28) * 96;
2270
+ const start = HBEAT.stars + 60 + i * 3;
2271
+ const lf = frame - start;
2272
+ const h = interpolate(lf, [0, 18], [0, baseHeight], {
2273
+ extrapolateLeft: "clamp",
2274
+ extrapolateRight: "clamp",
2275
+ easing: ease.expoOut,
2276
+ });
2277
+ return (
2278
+ <div
2279
+ key={i}
2280
+ style={{
2281
+ flex: 1,
2282
+ height: h,
2283
+ background:
2284
+ i > 22
2285
+ ? `linear-gradient(180deg, ${C.plasma}, ${C.ember})`
2286
+ : `linear-gradient(180deg, ${C.inkSoft}, ${C.inkMuted})`,
2287
+ borderRadius: 4,
2288
+ opacity: 0.85,
2289
+ }}
2290
+ />
2291
+ );
2292
+ })}
2293
+ </div>
2294
+ </GlassCard>
2295
+ </div>
2296
+
2297
+ {/* Community models stat */}
2298
+ <div
2299
+ style={{
2300
+ position: "absolute",
2301
+ left: 80,
2302
+ right: 80,
2303
+ top: 1100,
2304
+ display: "flex",
2305
+ justifyContent: "center",
2306
+ opacity: interpolate(local, [120, 150], [0, 1], { extrapolateRight: "clamp" }),
2307
+ transform: `translateY(${interpolate(local, [120, 150], [30, 0], { extrapolateRight: "clamp", easing: ease.power3Out })}px)`,
2308
+ }}
2309
+ >
2310
+ <div
2311
+ style={{
2312
+ ...glassBase,
2313
+ background: C.glassFillStrong,
2314
+ borderRadius: 9999,
2315
+ padding: "18px 32px",
2316
+ display: "inline-flex",
2317
+ alignItems: "center",
2318
+ gap: 18,
2319
+ }}
2320
+ >
2321
+ <span
2322
+ style={{
2323
+ fontFamily: MONO,
2324
+ fontSize: 44,
2325
+ fontWeight: 700,
2326
+ color: C.ember,
2327
+ fontVariantNumeric: "tabular-nums",
2328
+ letterSpacing: "-0.04em",
2329
+ }}
2330
+ >
2331
+ <Counter
2332
+ from={0}
2333
+ to={1247}
2334
+ startFrame={HBEAT.stars + 130}
2335
+ duration={90}
2336
+ format={(n) => Math.round(n).toLocaleString() + "+"}
2337
+ />
2338
+ </span>
2339
+ <span
2340
+ style={{
2341
+ fontFamily: FONT,
2342
+ fontSize: 24,
2343
+ fontWeight: 500,
2344
+ color: C.inkSoft,
2345
+ letterSpacing: "-0.02em",
2346
+ }}
2347
+ >
2348
+ community models running on it
2349
+ </span>
2350
+ </div>
2351
+ </div>
2352
+
2353
+ {/* Closing line "blowing up fast" */}
2354
+ <div
2355
+ style={{
2356
+ position: "absolute",
2357
+ left: 0,
2358
+ right: 0,
2359
+ top: 1320,
2360
+ textAlign: "center",
2361
+ opacity: interpolate(local, [200, 230], [0, 1], {
2362
+ extrapolateLeft: "clamp",
2363
+ extrapolateRight: "clamp",
2364
+ }),
2365
+ transform: `scale(${spring({
2366
+ frame: local - 200,
2367
+ fps: 30,
2368
+ config: { damping: 9, stiffness: 130 },
2369
+ from: 0.8,
2370
+ to: 1,
2371
+ })})`,
2372
+ }}
2373
+ >
2374
+ <div
2375
+ style={{
2376
+ fontFamily: FONT,
2377
+ fontSize: 86,
2378
+ fontWeight: 800,
2379
+ color: C.ink,
2380
+ letterSpacing: "-0.04em",
2381
+ lineHeight: 1,
2382
+ }}
2383
+ >
2384
+ Blowing up{" "}
2385
+ <span
2386
+ style={{
2387
+ background: `linear-gradient(135deg, ${C.ember}, ${C.crimson}, ${C.plasma})`,
2388
+ WebkitBackgroundClip: "text",
2389
+ WebkitTextFillColor: "transparent",
2390
+ backgroundClip: "text",
2391
+ }}
2392
+ >
2393
+ fast.
2394
+ </span>
2395
+ </div>
2396
+ </div>
2397
+ </AbsoluteFill>
2398
+ );
2399
+ };
2400
+
2401
+ // ═══════════════════════════════════════════════════════════════
2402
+ // CTA PILL — single glass capsule with icon + label
2403
+ // ═══════════════════════════════════════════════════════════════
2404
+ const CtaPill: React.FC<{
2405
+ iconNode: React.ReactNode;
2406
+ label: string;
2407
+ accent: string;
2408
+ startFrame: number;
2409
+ index: number;
2410
+ }> = ({ iconNode, label, accent, startFrame, index }) => {
2411
+ const frame = useCurrentFrame();
2412
+ const enter = startFrame + index * 6;
2413
+ const local = frame - enter;
2414
+ const op = interpolate(local, [0, 22], [0, 1], {
2415
+ extrapolateLeft: "clamp",
2416
+ extrapolateRight: "clamp",
2417
+ });
2418
+ const sc = spring({
2419
+ frame: local,
2420
+ fps: 30,
2421
+ config: { damping: 12, stiffness: 110 },
2422
+ from: 0.8,
2423
+ to: 1,
2424
+ });
2425
+ const pulse = 1 + Math.sin((frame + index * 22) * 0.05) * 0.012;
2426
+ return (
2427
+ <div
2428
+ style={{
2429
+ ...glassBase,
2430
+ background: C.glassFillStrong,
2431
+ borderRadius: 9999,
2432
+ padding: "20px 32px",
2433
+ display: "inline-flex",
2434
+ alignItems: "center",
2435
+ gap: 16,
2436
+ opacity: op,
2437
+ transform: `scale(${sc * pulse})`,
2438
+ willChange: "transform, opacity",
2439
+ }}
2440
+ >
2441
+ <div
2442
+ style={{
2443
+ width: 48,
2444
+ height: 48,
2445
+ borderRadius: 14,
2446
+ background: accent,
2447
+ display: "flex",
2448
+ alignItems: "center",
2449
+ justifyContent: "center",
2450
+ boxShadow: `0 0 18px ${accent}aa`,
2451
+ }}
2452
+ >
2453
+ {iconNode}
2454
+ </div>
2455
+ <div
2456
+ style={{
2457
+ fontFamily: FONT,
2458
+ fontSize: 30,
2459
+ fontWeight: 700,
2460
+ color: C.ink,
2461
+ letterSpacing: "-0.025em",
2462
+ }}
2463
+ >
2464
+ {label}
2465
+ </div>
2466
+ </div>
2467
+ );
2468
+ };
2469
+
2470
+ // ═══════════════════════════════════════════════════════════════
2471
+ // SCENE 7 — CTA (1500–1639, 4.6s)
2472
+ // "Like, subscribe, and check pinned comment for resources."
2473
+ // ═══════════════════════════════════════════════════════════════
2474
+ const CtaScene: React.FC = () => {
2475
+ const frame = useCurrentFrame();
2476
+ const local = frame - HBEAT.cta;
2477
+ const heroOp = interpolate(local, [0, 24], [0, 1], { extrapolateRight: "clamp" });
2478
+ const heroY = interpolate(local, [0, 30], [30, 0], {
2479
+ extrapolateRight: "clamp",
2480
+ easing: ease.expoOut,
2481
+ });
2482
+ return (
2483
+ <AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
2484
+ {/* Behind-scene halo */}
2485
+ <div
2486
+ style={{
2487
+ position: "absolute",
2488
+ width: 1100,
2489
+ height: 1100,
2490
+ borderRadius: "50%",
2491
+ background: `conic-gradient(from ${frame * 0.4}deg, ${C.ember}, ${C.crimson}, ${C.ultraviolet}, ${C.plasma}, ${C.ember})`,
2492
+ filter: "blur(120px)",
2493
+ opacity: 0.45,
2494
+ }}
2495
+ />
2496
+
2497
+ {/* Headline */}
2498
+ <div
2499
+ style={{
2500
+ opacity: heroOp,
2501
+ transform: `translateY(${heroY}px)`,
2502
+ textAlign: "center",
2503
+ position: "relative",
2504
+ }}
2505
+ >
2506
+ <div
2507
+ style={{
2508
+ fontFamily: MONO,
2509
+ fontSize: 22,
2510
+ color: C.inkMuted,
2511
+ letterSpacing: "0.22em",
2512
+ textTransform: "uppercase",
2513
+ marginBottom: 18,
2514
+ }}
2515
+ >
2516
+ resources in pinned
2517
+ </div>
2518
+ <div
2519
+ style={{
2520
+ fontFamily: FONT,
2521
+ fontSize: 124,
2522
+ fontWeight: 800,
2523
+ color: C.ink,
2524
+ letterSpacing: "-0.06em",
2525
+ lineHeight: 0.92,
2526
+ }}
2527
+ >
2528
+ Like.{" "}
2529
+ <span
2530
+ style={{
2531
+ background: `linear-gradient(135deg, ${C.ember}, ${C.crimson}, ${C.plasma})`,
2532
+ WebkitBackgroundClip: "text",
2533
+ WebkitTextFillColor: "transparent",
2534
+ backgroundClip: "text",
2535
+ }}
2536
+ >
2537
+ Subscribe.
2538
+ </span>
2539
+ </div>
2540
+ </div>
2541
+
2542
+ {/* Three glass pill buttons */}
2543
+ <div
2544
+ style={{
2545
+ marginTop: 64,
2546
+ display: "flex",
2547
+ gap: 18,
2548
+ flexDirection: "column",
2549
+ alignItems: "center",
2550
+ position: "relative",
2551
+ }}
2552
+ >
2553
+ <CtaPill
2554
+ iconNode={
2555
+ <svg width="26" height="26" viewBox="0 0 24 24" fill="white">
2556
+ <path d="M12 21s-7-4.35-7-10a4 4 0 0 1 7-2.65A4 4 0 0 1 19 11c0 5.65-7 10-7 10z" />
2557
+ </svg>
2558
+ }
2559
+ label="Like"
2560
+ accent={C.ember}
2561
+ startFrame={HBEAT.cta + 22}
2562
+ index={0}
2563
+ />
2564
+ <CtaPill
2565
+ iconNode={
2566
+ <Img
2567
+ src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
2568
+ style={{ width: 28, height: 28 }}
2569
+ />
2570
+ }
2571
+ label="Subscribe"
2572
+ accent={C.crimson}
2573
+ startFrame={HBEAT.cta + 22}
2574
+ index={1}
2575
+ />
2576
+ <CtaPill
2577
+ iconNode={
2578
+ <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2">
2579
+ <path d="M5 4h14v17l-7-4-7 4z" />
2580
+ </svg>
2581
+ }
2582
+ label="Pinned Comment"
2583
+ accent={C.ultraviolet}
2584
+ startFrame={HBEAT.cta + 22}
2585
+ index={2}
2586
+ />
2587
+ </div>
2588
+ </AbsoluteFill>
2589
+ );
2590
+ };
2591
+
2592
+ // ═══════════════════════════════════════════════════════════════
2593
+ // MAIN — orchestrate scenes, audio, and persistent ambient layers
2594
+ // ═══════════════════════════════════════════════════════════════
2595
+ export const HereticReel: React.FC = () => {
2596
+ const { width, height } = useVideoConfig();
2597
+ const frame = useCurrentFrame();
2598
+
2599
+ return (
2600
+ <AbsoluteFill
2601
+ style={{
2602
+ background: `radial-gradient(ellipse at 30% 20%, ${C.bgWarm} 0%, ${C.bg} 50%, ${C.bgCool} 100%)`,
2603
+ width,
2604
+ height,
2605
+ overflow: "hidden",
2606
+ }}
2607
+ >
2608
+ {/* Perpetual ambient layers — drift across entire reel */}
2609
+ <CausticBlobs />
2610
+ <HairlineGrid opacity={0.04} />
2611
+
2612
+ {/* Film-grain noise (fixed, pointer-events none) */}
2613
+ <AbsoluteFill
2614
+ style={{
2615
+ backgroundImage:
2616
+ "url(\"data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E\")",
2617
+ opacity: 0.06,
2618
+ pointerEvents: "none",
2619
+ mixBlendMode: "multiply",
2620
+ }}
2621
+ />
2622
+
2623
+ {/* Conditional scene render so useCurrentFrame() inside each scene
2624
+ returns the GLOBAL frame, matching `local = frame - HBEAT.x`. */}
2625
+ {frame >= HBEAT.hook && frame < HBEAT.refusal && <HookScene />}
2626
+ {frame >= HBEAT.refusal && frame < HBEAT.reveal && <RefusalScene />}
2627
+ {frame >= HBEAT.reveal && frame < HBEAT.mechanism && <RevealScene />}
2628
+ {frame >= HBEAT.mechanism && frame < HBEAT.brains && <MechanismScene />}
2629
+ {frame >= HBEAT.brains && frame < HBEAT.stars && <BrainsScene />}
2630
+ {frame >= HBEAT.stars && frame < HBEAT.cta && <StarsScene />}
2631
+ {frame >= HBEAT.cta && frame < HBEAT.end && <CtaScene />}
2632
+
2633
+ {/* REFERENCE-STRIP: <Audio> tag removed — bring your own voiceover */}
2634
+ </AbsoluteFill>
2635
+ );
2636
+ };