@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.
- package/LICENSE +128 -0
- package/README.md +125 -0
- package/cli/beats.js +124 -0
- package/cli/bootstrap.js +124 -0
- package/cli/capture.js +34 -0
- package/cli/direction.js +114 -0
- package/cli/icons.js +49 -0
- package/cli/index.js +101 -0
- package/cli/init.js +253 -0
- package/cli/license.js +168 -0
- package/cli/lint.js +865 -0
- package/cli/preview.js +59 -0
- package/cli/render.js +404 -0
- package/cli/scaffold.js +239 -0
- package/cli/smoke.js +76 -0
- package/cli/update.js +26 -0
- package/cli/utils.js +184 -0
- package/docs/buyers-guide.md +220 -0
- package/docs/design-discipline.md +130 -0
- package/docs/family-galleries/dark.md +95 -0
- package/docs/family-galleries/forbidden.md +78 -0
- package/docs/family-galleries/glass.md +98 -0
- package/docs/family-galleries/paper.md +82 -0
- package/docs/family-galleries/warm.md +86 -0
- package/docs/superpowers/plans/2026-05-09-reelstack-init-readiness-gate.md +1166 -0
- package/docs/superpowers/specs/2026-05-09-reelstack-init-readiness-gate-design.md +233 -0
- package/families/dark/components/DriftingSpotlights.tsx +59 -0
- package/families/dark/components/FilmGrain.tsx +44 -0
- package/families/dark/components/ForestCard.tsx +43 -0
- package/families/dark/components/GridBackground.tsx +29 -0
- package/families/dark/components/RadialVignette.tsx +21 -0
- package/families/dark/components/Scanlines.tsx +35 -0
- package/families/dark/components/SegmentOpacity.ts +37 -0
- package/families/dark/components/index.ts +13 -0
- package/families/dark/index.ts +31 -0
- package/families/dark/palette.ts +98 -0
- package/families/dark/presets/claudedispatch.ts +46 -0
- package/families/dark/presets/codedrop.ts +37 -0
- package/families/dark/presets/gpt55.ts +54 -0
- package/families/dark/presets/notebooklm.ts +50 -0
- package/families/dark/presets/resourcescta.ts +35 -0
- package/families/dark/presets/skills.ts +40 -0
- package/families/dark/presets/stitch.ts +46 -0
- package/families/dark/presets/stitch2.ts +43 -0
- package/families/dark/typography.ts +16 -0
- package/families/forbidden/components/ForbiddenCausticBlobs.tsx +52 -0
- package/families/forbidden/components/NewsprintTexture.tsx +28 -0
- package/families/forbidden/components/TintedShadow.tsx +36 -0
- package/families/forbidden/components/index.ts +38 -0
- package/families/forbidden/index.ts +17 -0
- package/families/forbidden/palette.ts +88 -0
- package/families/forbidden/presets/heretic.ts +44 -0
- package/families/forbidden/typography.ts +18 -0
- package/families/glass/components/BreakdownCard.tsx +158 -0
- package/families/glass/components/CausticBlobs.tsx +49 -0
- package/families/glass/components/Counter.tsx +72 -0
- package/families/glass/components/EyebrowPill.tsx +59 -0
- package/families/glass/components/FilmStrip.tsx +202 -0
- package/families/glass/components/FloatingGlyphs.tsx +78 -0
- package/families/glass/components/GlassCard.tsx +58 -0
- package/families/glass/components/GlassCardBezel.tsx +45 -0
- package/families/glass/components/HairlineGrid.tsx +30 -0
- package/families/glass/components/IridescentRing.tsx +114 -0
- package/families/glass/components/IridescentText.tsx +98 -0
- package/families/glass/components/LightBeam.tsx +46 -0
- package/families/glass/components/ParticleBurst.tsx +62 -0
- package/families/glass/components/SonarRings.tsx +81 -0
- package/families/glass/components/StaggeredWords.tsx +74 -0
- package/families/glass/components/index.ts +20 -0
- package/families/glass/index.ts +31 -0
- package/families/glass/palette.ts +93 -0
- package/families/glass/presets/claudewatch.ts +64 -0
- package/families/glass/presets/claudewatchcta.ts +43 -0
- package/families/glass/presets/graphify.ts +45 -0
- package/families/glass/presets/gstack.ts +48 -0
- package/families/glass/presets/jcode.ts +50 -0
- package/families/glass/presets/lilagents.ts +52 -0
- package/families/glass/presets/paperclip.ts +43 -0
- package/families/glass/typography.ts +15 -0
- package/families/index.ts +49 -0
- package/families/paper/components/CardSpring.tsx +42 -0
- package/families/paper/components/CreamGrid.tsx +26 -0
- package/families/paper/components/EditorialSerifText.tsx +51 -0
- package/families/paper/components/GreenAccentCard.tsx +10 -0
- package/families/paper/components/PaperShadow.tsx +30 -0
- package/families/paper/components/ScaleBlurText.tsx +40 -0
- package/families/paper/components/index.ts +11 -0
- package/families/paper/index.ts +23 -0
- package/families/paper/palette.ts +102 -0
- package/families/paper/presets/designreel.ts +32 -0
- package/families/paper/presets/devini3d.ts +45 -0
- package/families/paper/presets/justdrop.ts +39 -0
- package/families/paper/presets/opus.ts +48 -0
- package/families/paper/typography.ts +17 -0
- package/families/warm/components/AccentGlow.tsx +60 -0
- package/families/warm/components/BentoCell.tsx +56 -0
- package/families/warm/components/BentoGrid.tsx +30 -0
- package/families/warm/components/FilmGrain.tsx +36 -0
- package/families/warm/components/ScaleBlurCounter.tsx +71 -0
- package/families/warm/components/WarmSurface.tsx +35 -0
- package/families/warm/components/index.ts +11 -0
- package/families/warm/index.ts +19 -0
- package/families/warm/palette.ts +81 -0
- package/families/warm/presets/huashu.ts +49 -0
- package/families/warm/presets/mempalace.ts +51 -0
- package/families/warm/typography.ts +17 -0
- package/package.json +85 -0
- package/reference/dark/claudedispatch.tsx +2441 -0
- package/reference/dark/notebooklm.tsx +2316 -0
- package/reference/dark/stitch.tsx +3040 -0
- package/reference/forbidden/heretic.tsx +2636 -0
- package/reference/glass/claudewatch.tsx +3827 -0
- package/reference/glass/graphify.tsx +2418 -0
- package/reference/glass/paperclip.tsx +2218 -0
- package/reference/paper/designreel.tsx +883 -0
- package/reference/paper/justdrop.tsx +1898 -0
- package/reference/paper/opus.tsx +1770 -0
- package/reference/warm/huashu.tsx +3413 -0
- package/reference/warm/mempalace.tsx +2909 -0
- package/skill/SKILL.md +229 -0
- package/skill/commands/reelstack-beats.md +20 -0
- package/skill/commands/reelstack-capture.md +24 -0
- package/skill/commands/reelstack-critique.md +15 -0
- package/skill/commands/reelstack-dark.md +40 -0
- package/skill/commands/reelstack-direction.md +17 -0
- package/skill/commands/reelstack-forbidden.md +25 -0
- package/skill/commands/reelstack-glass.md +39 -0
- package/skill/commands/reelstack-icons.md +22 -0
- package/skill/commands/reelstack-init.md +17 -0
- package/skill/commands/reelstack-lint.md +22 -0
- package/skill/commands/reelstack-paper.md +36 -0
- package/skill/commands/reelstack-render.md +20 -0
- package/skill/commands/reelstack-warm.md +36 -0
- package/templates/dark/template.tsx +115 -0
- package/templates/forbidden/template.tsx +111 -0
- package/templates/glass/template.tsx +201 -0
- package/templates/paper/template.tsx +133 -0
- package/templates/warm/template.tsx +210 -0
- package/utils/ai-purple-blocklist.ts +13 -0
- package/utils/banned-fonts.ts +11 -0
- package/utils/cubic-bezier.ts +36 -0
- package/utils/easing.ts +84 -0
- package/utils/grid.ts +13 -0
- package/utils/render-presets.json +56 -0
- package/utils/safe-zones.tsx +57 -0
|
@@ -0,0 +1,2909 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REFERENCE — MemPalaceReel (Family: warm)
|
|
3
|
+
*
|
|
4
|
+
* Canonical example of the warm 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/MemPalaceReel.tsx
|
|
15
|
+
* Bundled at: 2026-05-08T18:50:39.538Z
|
|
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
|
+
// CONSTANTS — 9:16 reel, 30 fps, ~84 s
|
|
35
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
36
|
+
|
|
37
|
+
const H = 1920;
|
|
38
|
+
|
|
39
|
+
// IG safe zones per project memory: top ~280, bottom ~410
|
|
40
|
+
const SAFE_TOP = 280;
|
|
41
|
+
const SAFE_BOT_Y = 1510;
|
|
42
|
+
|
|
43
|
+
export const MEMPALACE_TOTAL = 2520;
|
|
44
|
+
|
|
45
|
+
const SCENES = {
|
|
46
|
+
S1: { from: 0, dur: 225 }, // 7.5s — cold-open hook
|
|
47
|
+
S2: { from: 225, dur: 330 }, // 11s — pain (Gone.)
|
|
48
|
+
S3: { from: 555, dur: 225 }, // 7.5s — Mem0 / "AI decides" wall
|
|
49
|
+
S4: { from: 780, dur: 135 }, // 4.5s — MemPalace flip
|
|
50
|
+
S5: { from: 915, dur: 480 }, // 16s — Architecture (Aristotle/Cicero, wings/rooms/drawers)
|
|
51
|
+
S6: { from: 1395, dur: 420 }, // 14s — Hook magic + screen recording
|
|
52
|
+
S7: { from: 1815, dur: 390 }, // 13s — Social proof
|
|
53
|
+
S8: { from: 2205, dur: 315 }, // 10.5s— CTA
|
|
54
|
+
} as const;
|
|
55
|
+
|
|
56
|
+
// Palette — dark zinc base + warm parchment palace + emerald success.
|
|
57
|
+
// One accent rule (palace gold) keeps the LLM-generic look out.
|
|
58
|
+
const C = {
|
|
59
|
+
bg: "#09090b",
|
|
60
|
+
bgLift: "#111114",
|
|
61
|
+
surface: "#15151c",
|
|
62
|
+
border: "rgba(255,255,255,0.08)",
|
|
63
|
+
borderLoud: "rgba(255,255,255,0.16)",
|
|
64
|
+
fg: "#fafafa",
|
|
65
|
+
fgSoft: "#d4d4d8",
|
|
66
|
+
fgMuted: "#9f9fa9",
|
|
67
|
+
fgDim: "#6b6b75",
|
|
68
|
+
|
|
69
|
+
// Palace warm tones
|
|
70
|
+
paper: "#efe7d6",
|
|
71
|
+
paperWarm: "#e7dcc4",
|
|
72
|
+
paperDeep: "#d8c8a0",
|
|
73
|
+
ink: "#1a1410",
|
|
74
|
+
inkSoft: "#3a2f24",
|
|
75
|
+
gold: "#b8893d",
|
|
76
|
+
goldDeep: "#8a6429",
|
|
77
|
+
goldGlow: "rgba(184,137,61,0.22)",
|
|
78
|
+
|
|
79
|
+
// Tech accents
|
|
80
|
+
emerald: "#00d294",
|
|
81
|
+
emeraldDeep: "#00875a",
|
|
82
|
+
indigo: "#625fff",
|
|
83
|
+
red: "#ef4444",
|
|
84
|
+
redDeep: "#7f1d1d",
|
|
85
|
+
} as const;
|
|
86
|
+
|
|
87
|
+
const FONT = ds.font.sans;
|
|
88
|
+
const MONO = ds.font.mono;
|
|
89
|
+
const SERIF = "ui-serif, 'Iowan Old Style', 'Charter', 'Source Serif Pro', Georgia, serif";
|
|
90
|
+
|
|
91
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
92
|
+
// MOTION HELPERS — GSAP-style timeline ergonomics on top of Remotion springs
|
|
93
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
94
|
+
|
|
95
|
+
type SpringKind = "smooth" | "snappy" | "gentle" | "bouncy" | "glass";
|
|
96
|
+
|
|
97
|
+
const sp = (
|
|
98
|
+
frame: number,
|
|
99
|
+
fps: number,
|
|
100
|
+
delaySec: number,
|
|
101
|
+
kind: SpringKind = "snappy",
|
|
102
|
+
) =>
|
|
103
|
+
spring({ frame, fps, delay: Math.round(delaySec * fps), config: ds.spring[kind] });
|
|
104
|
+
|
|
105
|
+
const fadeIn = (f: number, at: number, len = 12) =>
|
|
106
|
+
interpolate(f, [at, at + len], [0, 1], {
|
|
107
|
+
extrapolateLeft: "clamp",
|
|
108
|
+
extrapolateRight: "clamp",
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const fadeOut = (f: number, at: number, len = 12) =>
|
|
112
|
+
interpolate(f, [at, at + len], [1, 0], {
|
|
113
|
+
extrapolateLeft: "clamp",
|
|
114
|
+
extrapolateRight: "clamp",
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// GSAP power3.out feel
|
|
118
|
+
const expoOut = Easing.bezier(0.16, 1, 0.3, 1);
|
|
119
|
+
|
|
120
|
+
// "tween" — like gsap.to({duration, ease}) — clamp by default
|
|
121
|
+
const tween = (
|
|
122
|
+
f: number,
|
|
123
|
+
startFrame: number,
|
|
124
|
+
durFrames: number,
|
|
125
|
+
from: number,
|
|
126
|
+
to: number,
|
|
127
|
+
easing: ReturnType<typeof Easing.bezier> = expoOut,
|
|
128
|
+
) =>
|
|
129
|
+
interpolate(f, [startFrame, startFrame + durFrames], [from, to], {
|
|
130
|
+
extrapolateLeft: "clamp",
|
|
131
|
+
extrapolateRight: "clamp",
|
|
132
|
+
easing,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Letter-by-letter stagger helper — returns per-char {opacity, y}
|
|
136
|
+
const letterStagger = (
|
|
137
|
+
chars: string,
|
|
138
|
+
frame: number,
|
|
139
|
+
fps: number,
|
|
140
|
+
startSec: number,
|
|
141
|
+
perCharSec = 0.04,
|
|
142
|
+
) =>
|
|
143
|
+
chars.split("").map((ch, i) => {
|
|
144
|
+
const s = sp(frame, fps, startSec + i * perCharSec, "snappy");
|
|
145
|
+
return {
|
|
146
|
+
ch,
|
|
147
|
+
opacity: interpolate(s, [0, 0.4], [0, 1], {
|
|
148
|
+
extrapolateLeft: "clamp",
|
|
149
|
+
extrapolateRight: "clamp",
|
|
150
|
+
}),
|
|
151
|
+
y: interpolate(s, [0, 1], [40, 0]),
|
|
152
|
+
scale: interpolate(s, [0, 0.6, 1], [0.85, 1.05, 1]),
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
157
|
+
// BACKGROUNDS
|
|
158
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
159
|
+
|
|
160
|
+
const NoiseGrain: React.FC<{ opacity?: number }> = ({ opacity = 0.06 }) => (
|
|
161
|
+
<AbsoluteFill
|
|
162
|
+
style={{
|
|
163
|
+
pointerEvents: "none",
|
|
164
|
+
opacity,
|
|
165
|
+
mixBlendMode: "overlay",
|
|
166
|
+
backgroundImage: `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'/></filter><rect width='200' height='200' filter='url(%23n)' opacity='0.7'/></svg>")`,
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const Vignette: React.FC<{ frame: number; tone?: "dark" | "warm" }> = ({
|
|
172
|
+
frame,
|
|
173
|
+
tone = "dark",
|
|
174
|
+
}) => {
|
|
175
|
+
const pulse = 0.42 + Math.sin(frame * 0.012) * 0.05;
|
|
176
|
+
const col =
|
|
177
|
+
tone === "warm"
|
|
178
|
+
? `rgba(80,55,15,${pulse})`
|
|
179
|
+
: `rgba(0,0,0,${pulse})`;
|
|
180
|
+
return (
|
|
181
|
+
<AbsoluteFill
|
|
182
|
+
style={{
|
|
183
|
+
background: `radial-gradient(ellipse at 50% 50%, transparent 38%, ${col} 100%)`,
|
|
184
|
+
}}
|
|
185
|
+
/>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const DarkBg: React.FC<{ frame: number; tint?: "indigo" | "emerald" | "red" }> = ({
|
|
190
|
+
frame,
|
|
191
|
+
tint = "indigo",
|
|
192
|
+
}) => {
|
|
193
|
+
const drift = (Math.sin(frame * 0.0028) + 1) * 0.5;
|
|
194
|
+
const drift2 = (Math.cos(frame * 0.0021) + 1) * 0.5;
|
|
195
|
+
const tintRgb =
|
|
196
|
+
tint === "indigo"
|
|
197
|
+
? "98,95,255"
|
|
198
|
+
: tint === "emerald"
|
|
199
|
+
? "0,210,148"
|
|
200
|
+
: "239,68,68";
|
|
201
|
+
return (
|
|
202
|
+
<AbsoluteFill>
|
|
203
|
+
<div style={{ width: "100%", height: "100%", background: C.bg }} />
|
|
204
|
+
<div
|
|
205
|
+
style={{
|
|
206
|
+
position: "absolute",
|
|
207
|
+
inset: 0,
|
|
208
|
+
background: `radial-gradient(ellipse 800px 1000px at ${20 + drift * 60}% ${15 + drift2 * 40}%, rgba(${tintRgb},0.10) 0%, transparent 60%)`,
|
|
209
|
+
}}
|
|
210
|
+
/>
|
|
211
|
+
<div
|
|
212
|
+
style={{
|
|
213
|
+
position: "absolute",
|
|
214
|
+
inset: 0,
|
|
215
|
+
background: `radial-gradient(ellipse 700px 900px at ${85 - drift * 55}% ${78 + drift2 * 15}%, rgba(${tintRgb},0.05) 0%, transparent 55%)`,
|
|
216
|
+
}}
|
|
217
|
+
/>
|
|
218
|
+
{/* fine grid */}
|
|
219
|
+
<div
|
|
220
|
+
style={{
|
|
221
|
+
position: "absolute",
|
|
222
|
+
inset: 0,
|
|
223
|
+
backgroundImage: `linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px)`,
|
|
224
|
+
backgroundSize: "72px 72px",
|
|
225
|
+
maskImage: "radial-gradient(ellipse at 50% 50%, black 30%, transparent 85%)",
|
|
226
|
+
WebkitMaskImage: "radial-gradient(ellipse at 50% 50%, black 30%, transparent 85%)",
|
|
227
|
+
}}
|
|
228
|
+
/>
|
|
229
|
+
<NoiseGrain />
|
|
230
|
+
<Vignette frame={frame} tone="dark" />
|
|
231
|
+
</AbsoluteFill>
|
|
232
|
+
);
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const PaperBg: React.FC<{ frame: number }> = ({ frame }) => {
|
|
236
|
+
const drift = (Math.sin(frame * 0.0025) + 1) * 0.5;
|
|
237
|
+
return (
|
|
238
|
+
<AbsoluteFill>
|
|
239
|
+
<div style={{ width: "100%", height: "100%", background: C.paper }} />
|
|
240
|
+
<div
|
|
241
|
+
style={{
|
|
242
|
+
position: "absolute",
|
|
243
|
+
inset: 0,
|
|
244
|
+
background: `radial-gradient(ellipse 900px 1200px at ${30 + drift * 40}% 20%, rgba(255,245,220,0.7) 0%, transparent 60%)`,
|
|
245
|
+
}}
|
|
246
|
+
/>
|
|
247
|
+
<div
|
|
248
|
+
style={{
|
|
249
|
+
position: "absolute",
|
|
250
|
+
inset: 0,
|
|
251
|
+
background: `radial-gradient(ellipse 700px 700px at 80% 90%, ${C.paperDeep} 0%, transparent 55%)`,
|
|
252
|
+
opacity: 0.55,
|
|
253
|
+
}}
|
|
254
|
+
/>
|
|
255
|
+
{/* horizontal blueprint lines */}
|
|
256
|
+
<div
|
|
257
|
+
style={{
|
|
258
|
+
position: "absolute",
|
|
259
|
+
inset: 0,
|
|
260
|
+
backgroundImage: `linear-gradient(rgba(58,47,36,0.06) 1px, transparent 1px)`,
|
|
261
|
+
backgroundSize: "100% 56px",
|
|
262
|
+
maskImage: "linear-gradient(to bottom, transparent 0%, black 12%, black 88%, transparent 100%)",
|
|
263
|
+
WebkitMaskImage: "linear-gradient(to bottom, transparent 0%, black 12%, black 88%, transparent 100%)",
|
|
264
|
+
}}
|
|
265
|
+
/>
|
|
266
|
+
{/* paper grain */}
|
|
267
|
+
<div
|
|
268
|
+
style={{
|
|
269
|
+
position: "absolute",
|
|
270
|
+
inset: 0,
|
|
271
|
+
opacity: 0.18,
|
|
272
|
+
mixBlendMode: "multiply",
|
|
273
|
+
backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.72'/></filter><rect width='240' height='240' filter='url(%23n)' opacity='0.55'/></svg>")`,
|
|
274
|
+
}}
|
|
275
|
+
/>
|
|
276
|
+
<Vignette frame={frame} tone="warm" />
|
|
277
|
+
</AbsoluteFill>
|
|
278
|
+
);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
282
|
+
// REUSABLE PRIMITIVES
|
|
283
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
284
|
+
|
|
285
|
+
const Pill: React.FC<{
|
|
286
|
+
children: React.ReactNode;
|
|
287
|
+
bg: string;
|
|
288
|
+
fg: string;
|
|
289
|
+
border?: string;
|
|
290
|
+
dot?: string;
|
|
291
|
+
mono?: boolean;
|
|
292
|
+
size?: number;
|
|
293
|
+
}> = ({ children, bg, fg, border, dot, mono = true, size = 22 }) => (
|
|
294
|
+
<div
|
|
295
|
+
style={{
|
|
296
|
+
display: "inline-flex",
|
|
297
|
+
alignItems: "center",
|
|
298
|
+
gap: 12,
|
|
299
|
+
padding: "12px 22px",
|
|
300
|
+
borderRadius: 9999,
|
|
301
|
+
background: bg,
|
|
302
|
+
border: border ? `1px solid ${border}` : undefined,
|
|
303
|
+
color: fg,
|
|
304
|
+
fontFamily: mono ? MONO : FONT,
|
|
305
|
+
fontSize: size,
|
|
306
|
+
fontWeight: 600,
|
|
307
|
+
letterSpacing: "0.08em",
|
|
308
|
+
}}
|
|
309
|
+
>
|
|
310
|
+
{dot ? (
|
|
311
|
+
<span
|
|
312
|
+
style={{
|
|
313
|
+
width: 8,
|
|
314
|
+
height: 8,
|
|
315
|
+
borderRadius: 999,
|
|
316
|
+
background: dot,
|
|
317
|
+
boxShadow: `0 0 12px ${dot}`,
|
|
318
|
+
}}
|
|
319
|
+
/>
|
|
320
|
+
) : null}
|
|
321
|
+
{children}
|
|
322
|
+
</div>
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
326
|
+
// SCENE 1 — COLD OPEN HOOK
|
|
327
|
+
// "Your Claude Code forgets your entire project every session.
|
|
328
|
+
// This 1-line install gives it permanent memory — and it's free."
|
|
329
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
330
|
+
|
|
331
|
+
const Scene1: React.FC = () => {
|
|
332
|
+
const frame = useCurrentFrame();
|
|
333
|
+
const { fps } = useVideoConfig();
|
|
334
|
+
|
|
335
|
+
// Terminal window slides up
|
|
336
|
+
const winSpring = sp(frame, fps, 0.05, "snappy");
|
|
337
|
+
const winY = interpolate(winSpring, [0, 1], [60, 0]);
|
|
338
|
+
const winOp = interpolate(winSpring, [0, 0.5], [0, 1], {
|
|
339
|
+
extrapolateLeft: "clamp",
|
|
340
|
+
extrapolateRight: "clamp",
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Typewriter — "How do we handle auth tokens?"
|
|
344
|
+
const typed = "> How do we handle auth tokens?";
|
|
345
|
+
const startTypeF = 12;
|
|
346
|
+
const charPerFrame = 1.4;
|
|
347
|
+
const charsShown = Math.max(
|
|
348
|
+
0,
|
|
349
|
+
Math.min(typed.length, Math.floor((frame - startTypeF) * charPerFrame)),
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
// After ~2.6s — single deterministic glitch beat instead of per-frame strobe
|
|
353
|
+
const expireAt = 78;
|
|
354
|
+
// Two short dropouts at expireAt+2 and expireAt+10, each lasting 2 frames.
|
|
355
|
+
// Looks like a CRT signal hiccup, not a flickering bulb.
|
|
356
|
+
const inDropout =
|
|
357
|
+
(frame >= expireAt + 2 && frame < expireAt + 4) ||
|
|
358
|
+
(frame >= expireAt + 10 && frame < expireAt + 12);
|
|
359
|
+
const flicker = inDropout ? 0.55 : 1;
|
|
360
|
+
const expiredOp = fadeIn(frame, expireAt + 18, 8);
|
|
361
|
+
const expiredY = interpolate(frame, [expireAt + 18, expireAt + 30], [10, 0], {
|
|
362
|
+
extrapolateLeft: "clamp",
|
|
363
|
+
extrapolateRight: "clamp",
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Headline slam — at 4.0s (frame 120)
|
|
367
|
+
const slamAt = 120;
|
|
368
|
+
const slamSpring = sp(frame, fps, slamAt / fps, "bouncy");
|
|
369
|
+
const slamScale = interpolate(slamSpring, [0, 0.6, 1], [0.7, 1.06, 1]);
|
|
370
|
+
|
|
371
|
+
// Two lines of headline letter-stagger
|
|
372
|
+
const line1 = "FORGETS EVERY";
|
|
373
|
+
|
|
374
|
+
// Line 2 — "SESSION." gradient slam, animated as a single unit
|
|
375
|
+
// (gradient + WebkitBackgroundClip do not propagate to per-letter child spans,
|
|
376
|
+
// so we don't split it letter-by-letter)
|
|
377
|
+
const line2Spring = sp(frame, fps, slamAt / fps + 0.22, "bouncy");
|
|
378
|
+
const line2Op = interpolate(line2Spring, [0, 0.4], [0, 1], {
|
|
379
|
+
extrapolateLeft: "clamp",
|
|
380
|
+
extrapolateRight: "clamp",
|
|
381
|
+
});
|
|
382
|
+
const line2Y = interpolate(line2Spring, [0, 1], [50, 0]);
|
|
383
|
+
const line2Scale = interpolate(line2Spring, [0, 0.55, 1], [0.7, 1.1, 1]);
|
|
384
|
+
|
|
385
|
+
// CTA strip — "1-line install · permanent memory · free"
|
|
386
|
+
const stripOp = fadeIn(frame, 165);
|
|
387
|
+
const stripY = interpolate(frame, [165, 185], [16, 0], {
|
|
388
|
+
extrapolateLeft: "clamp",
|
|
389
|
+
extrapolateRight: "clamp",
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const exit = fadeOut(frame, SCENES.S1.dur - 16, 12);
|
|
393
|
+
|
|
394
|
+
return (
|
|
395
|
+
<AbsoluteFill style={{ fontFamily: FONT, opacity: exit }}>
|
|
396
|
+
<DarkBg frame={frame} tint="red" />
|
|
397
|
+
|
|
398
|
+
{/* TOP CONTEXT TAG */}
|
|
399
|
+
<div
|
|
400
|
+
style={{
|
|
401
|
+
position: "absolute",
|
|
402
|
+
top: SAFE_TOP,
|
|
403
|
+
left: 0,
|
|
404
|
+
right: 0,
|
|
405
|
+
display: "flex",
|
|
406
|
+
justifyContent: "center",
|
|
407
|
+
opacity: fadeIn(frame, 0, 10),
|
|
408
|
+
}}
|
|
409
|
+
>
|
|
410
|
+
<Pill
|
|
411
|
+
bg="rgba(239,68,68,0.10)"
|
|
412
|
+
fg="#fca5a5"
|
|
413
|
+
border="rgba(239,68,68,0.35)"
|
|
414
|
+
dot={C.red}
|
|
415
|
+
>
|
|
416
|
+
AMNESIA · CTX RESET
|
|
417
|
+
</Pill>
|
|
418
|
+
</div>
|
|
419
|
+
|
|
420
|
+
{/* TERMINAL WINDOW */}
|
|
421
|
+
<div
|
|
422
|
+
style={{
|
|
423
|
+
position: "absolute",
|
|
424
|
+
left: 60,
|
|
425
|
+
right: 60,
|
|
426
|
+
top: 460,
|
|
427
|
+
opacity: winOp * flicker,
|
|
428
|
+
transform: `translateY(${winY}px)`,
|
|
429
|
+
}}
|
|
430
|
+
>
|
|
431
|
+
<div
|
|
432
|
+
style={{
|
|
433
|
+
background: C.surface,
|
|
434
|
+
border: `1px solid ${C.borderLoud}`,
|
|
435
|
+
borderRadius: 22,
|
|
436
|
+
overflow: "hidden",
|
|
437
|
+
boxShadow:
|
|
438
|
+
"0 30px 80px -20px rgba(0,0,0,0.7), inset 0 1px 0 rgba(255,255,255,0.08)",
|
|
439
|
+
}}
|
|
440
|
+
>
|
|
441
|
+
{/* title bar */}
|
|
442
|
+
<div
|
|
443
|
+
style={{
|
|
444
|
+
display: "flex",
|
|
445
|
+
alignItems: "center",
|
|
446
|
+
gap: 10,
|
|
447
|
+
padding: "16px 22px",
|
|
448
|
+
background: "rgba(255,255,255,0.03)",
|
|
449
|
+
borderBottom: `1px solid ${C.border}`,
|
|
450
|
+
}}
|
|
451
|
+
>
|
|
452
|
+
<div style={{ width: 12, height: 12, borderRadius: 999, background: "#ff5f57" }} />
|
|
453
|
+
<div style={{ width: 12, height: 12, borderRadius: 999, background: "#febc2e" }} />
|
|
454
|
+
<div style={{ width: 12, height: 12, borderRadius: 999, background: "#28c840" }} />
|
|
455
|
+
<div
|
|
456
|
+
style={{
|
|
457
|
+
marginLeft: 18,
|
|
458
|
+
fontFamily: MONO,
|
|
459
|
+
fontSize: 18,
|
|
460
|
+
color: C.fgMuted,
|
|
461
|
+
letterSpacing: "0.05em",
|
|
462
|
+
}}
|
|
463
|
+
>
|
|
464
|
+
claude-code · ~/project
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
|
|
468
|
+
{/* body */}
|
|
469
|
+
<div
|
|
470
|
+
style={{
|
|
471
|
+
padding: "32px 28px 60px",
|
|
472
|
+
fontFamily: MONO,
|
|
473
|
+
fontSize: 30,
|
|
474
|
+
lineHeight: 1.6,
|
|
475
|
+
color: C.fgSoft,
|
|
476
|
+
minHeight: 380,
|
|
477
|
+
}}
|
|
478
|
+
>
|
|
479
|
+
<div style={{ color: C.fgDim, marginBottom: 10 }}>
|
|
480
|
+
[session-7423] connected
|
|
481
|
+
</div>
|
|
482
|
+
<div>
|
|
483
|
+
{typed.slice(0, charsShown)}
|
|
484
|
+
{/* cursor — visible only while typing; hides once context is lost */}
|
|
485
|
+
{frame < expireAt ? (
|
|
486
|
+
<span
|
|
487
|
+
style={{
|
|
488
|
+
display: "inline-block",
|
|
489
|
+
width: 14,
|
|
490
|
+
height: 30,
|
|
491
|
+
marginLeft: 4,
|
|
492
|
+
background: C.fg,
|
|
493
|
+
verticalAlign: "-4px",
|
|
494
|
+
// Slower, eased blink: ~530ms cycle, smooth opacity not hard cut
|
|
495
|
+
opacity:
|
|
496
|
+
0.35 +
|
|
497
|
+
0.65 *
|
|
498
|
+
Math.pow(
|
|
499
|
+
Math.cos((frame * Math.PI) / 16),
|
|
500
|
+
2,
|
|
501
|
+
),
|
|
502
|
+
}}
|
|
503
|
+
/>
|
|
504
|
+
) : null}
|
|
505
|
+
</div>
|
|
506
|
+
{/* expired line */}
|
|
507
|
+
{frame >= expireAt + 6 ? (
|
|
508
|
+
<div
|
|
509
|
+
style={{
|
|
510
|
+
marginTop: 22,
|
|
511
|
+
opacity: expiredOp,
|
|
512
|
+
transform: `translateY(${expiredY}px)`,
|
|
513
|
+
color: C.red,
|
|
514
|
+
fontWeight: 600,
|
|
515
|
+
fontSize: 26,
|
|
516
|
+
letterSpacing: "0.04em",
|
|
517
|
+
}}
|
|
518
|
+
>
|
|
519
|
+
✗ context lost · 0 memory carried over
|
|
520
|
+
</div>
|
|
521
|
+
) : null}
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
</div>
|
|
525
|
+
|
|
526
|
+
{/* HEADLINE SLAM */}
|
|
527
|
+
{frame >= slamAt - 4 ? (
|
|
528
|
+
<div
|
|
529
|
+
style={{
|
|
530
|
+
position: "absolute",
|
|
531
|
+
top: 1010,
|
|
532
|
+
left: 0,
|
|
533
|
+
right: 0,
|
|
534
|
+
textAlign: "center",
|
|
535
|
+
padding: "0 50px",
|
|
536
|
+
transform: `scale(${slamScale})`,
|
|
537
|
+
}}
|
|
538
|
+
>
|
|
539
|
+
{/* line 1 */}
|
|
540
|
+
<div
|
|
541
|
+
style={{
|
|
542
|
+
display: "flex",
|
|
543
|
+
justifyContent: "center",
|
|
544
|
+
flexWrap: "nowrap",
|
|
545
|
+
gap: 0,
|
|
546
|
+
fontSize: 100,
|
|
547
|
+
fontWeight: 800,
|
|
548
|
+
color: C.fg,
|
|
549
|
+
letterSpacing: "-0.05em",
|
|
550
|
+
lineHeight: 0.95,
|
|
551
|
+
whiteSpace: "nowrap",
|
|
552
|
+
}}
|
|
553
|
+
>
|
|
554
|
+
{letterStagger(line1, frame, fps, slamAt / fps, 0.025).map((s, i) => (
|
|
555
|
+
<span
|
|
556
|
+
key={`l1-${i}`}
|
|
557
|
+
style={{
|
|
558
|
+
display: "inline-block",
|
|
559
|
+
opacity: s.opacity,
|
|
560
|
+
transform: `translateY(${s.y}px) scale(${s.scale})`,
|
|
561
|
+
width: s.ch === " " ? 24 : "auto",
|
|
562
|
+
}}
|
|
563
|
+
>
|
|
564
|
+
{s.ch === " " ? "\u00A0" : s.ch}
|
|
565
|
+
</span>
|
|
566
|
+
))}
|
|
567
|
+
</div>
|
|
568
|
+
{/* line 2 — gradient slam (animated as single span) */}
|
|
569
|
+
<div
|
|
570
|
+
style={{
|
|
571
|
+
marginTop: 4,
|
|
572
|
+
opacity: line2Op,
|
|
573
|
+
transform: `translateY(${line2Y}px) scale(${line2Scale})`,
|
|
574
|
+
fontSize: 184,
|
|
575
|
+
fontWeight: 800,
|
|
576
|
+
letterSpacing: "-0.06em",
|
|
577
|
+
lineHeight: 0.95,
|
|
578
|
+
background: `linear-gradient(135deg, ${C.red} 0%, #fb7185 100%)`,
|
|
579
|
+
WebkitBackgroundClip: "text",
|
|
580
|
+
backgroundClip: "text",
|
|
581
|
+
WebkitTextFillColor: "transparent",
|
|
582
|
+
filter: "drop-shadow(0 0 32px rgba(239,68,68,0.45))",
|
|
583
|
+
}}
|
|
584
|
+
>
|
|
585
|
+
SESSION.
|
|
586
|
+
</div>
|
|
587
|
+
</div>
|
|
588
|
+
) : null}
|
|
589
|
+
|
|
590
|
+
{/* INSTALL CTA STRIP */}
|
|
591
|
+
<div
|
|
592
|
+
style={{
|
|
593
|
+
position: "absolute",
|
|
594
|
+
left: 0,
|
|
595
|
+
right: 0,
|
|
596
|
+
bottom: H - SAFE_BOT_Y + 50,
|
|
597
|
+
display: "flex",
|
|
598
|
+
justifyContent: "center",
|
|
599
|
+
opacity: stripOp,
|
|
600
|
+
transform: `translateY(${stripY}px)`,
|
|
601
|
+
}}
|
|
602
|
+
>
|
|
603
|
+
<div
|
|
604
|
+
style={{
|
|
605
|
+
display: "flex",
|
|
606
|
+
alignItems: "center",
|
|
607
|
+
gap: 18,
|
|
608
|
+
padding: "20px 30px",
|
|
609
|
+
background: "rgba(255,255,255,0.05)",
|
|
610
|
+
border: `1px solid ${C.borderLoud}`,
|
|
611
|
+
borderRadius: 999,
|
|
612
|
+
backdropFilter: "blur(20px)",
|
|
613
|
+
fontFamily: MONO,
|
|
614
|
+
fontSize: 26,
|
|
615
|
+
fontWeight: 600,
|
|
616
|
+
color: C.fg,
|
|
617
|
+
letterSpacing: "0.04em",
|
|
618
|
+
}}
|
|
619
|
+
>
|
|
620
|
+
<span style={{ color: C.emerald }}>$</span>
|
|
621
|
+
<span>1 line · permanent memory · free</span>
|
|
622
|
+
</div>
|
|
623
|
+
</div>
|
|
624
|
+
</AbsoluteFill>
|
|
625
|
+
);
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
629
|
+
// SCENE 2 — WHAT'S LOST
|
|
630
|
+
// "every decision, every back-and-forth, every reason behind your reasoning?
|
|
631
|
+
// Gone. The second you start a new session."
|
|
632
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
633
|
+
|
|
634
|
+
const FloatingMemoryCard: React.FC<{
|
|
635
|
+
frame: number;
|
|
636
|
+
index: number;
|
|
637
|
+
startFrame: number;
|
|
638
|
+
shredAt: number;
|
|
639
|
+
label: string;
|
|
640
|
+
body: string;
|
|
641
|
+
x: number;
|
|
642
|
+
y: number;
|
|
643
|
+
rot: number;
|
|
644
|
+
tint: string;
|
|
645
|
+
}> = ({ frame, index, startFrame, shredAt, label, body, x, y, rot, tint }) => {
|
|
646
|
+
// Enter
|
|
647
|
+
const enterT = tween(frame, startFrame + index * 8, 24, 0, 1);
|
|
648
|
+
const op = enterT;
|
|
649
|
+
const fy = (Math.sin((frame + index * 14) * 0.04) - 0.5) * 8;
|
|
650
|
+
|
|
651
|
+
// Shred
|
|
652
|
+
const shredT = tween(frame, shredAt, 22, 0, 1);
|
|
653
|
+
const shredOp = 1 - shredT;
|
|
654
|
+
const shredX = shredT * (60 + index * 14) * (index % 2 === 0 ? 1 : -1);
|
|
655
|
+
const shredY = shredT * 90;
|
|
656
|
+
const shredScale = 1 - shredT * 0.18;
|
|
657
|
+
const shredBlur = shredT * 6;
|
|
658
|
+
|
|
659
|
+
return (
|
|
660
|
+
<div
|
|
661
|
+
style={{
|
|
662
|
+
position: "absolute",
|
|
663
|
+
left: x,
|
|
664
|
+
top: y + fy,
|
|
665
|
+
width: 540,
|
|
666
|
+
opacity: op * shredOp,
|
|
667
|
+
transform: `translate(${shredX}px, ${shredY}px) rotate(${rot + shredT * (index % 2 === 0 ? 6 : -6)}deg) scale(${shredScale})`,
|
|
668
|
+
filter: `blur(${shredBlur}px)`,
|
|
669
|
+
}}
|
|
670
|
+
>
|
|
671
|
+
<div
|
|
672
|
+
style={{
|
|
673
|
+
background: C.surface,
|
|
674
|
+
border: `1px solid ${C.border}`,
|
|
675
|
+
borderRadius: 18,
|
|
676
|
+
padding: "20px 22px",
|
|
677
|
+
fontFamily: FONT,
|
|
678
|
+
color: C.fgSoft,
|
|
679
|
+
boxShadow: "0 20px 60px -10px rgba(0,0,0,0.55), inset 0 1px 0 rgba(255,255,255,0.05)",
|
|
680
|
+
}}
|
|
681
|
+
>
|
|
682
|
+
<div
|
|
683
|
+
style={{
|
|
684
|
+
display: "flex",
|
|
685
|
+
alignItems: "center",
|
|
686
|
+
gap: 10,
|
|
687
|
+
marginBottom: 12,
|
|
688
|
+
}}
|
|
689
|
+
>
|
|
690
|
+
<div
|
|
691
|
+
style={{
|
|
692
|
+
width: 8,
|
|
693
|
+
height: 8,
|
|
694
|
+
borderRadius: 999,
|
|
695
|
+
background: tint,
|
|
696
|
+
boxShadow: `0 0 10px ${tint}`,
|
|
697
|
+
}}
|
|
698
|
+
/>
|
|
699
|
+
<div
|
|
700
|
+
style={{
|
|
701
|
+
fontFamily: MONO,
|
|
702
|
+
fontSize: 17,
|
|
703
|
+
color: tint,
|
|
704
|
+
letterSpacing: "0.1em",
|
|
705
|
+
fontWeight: 600,
|
|
706
|
+
}}
|
|
707
|
+
>
|
|
708
|
+
{label}
|
|
709
|
+
</div>
|
|
710
|
+
</div>
|
|
711
|
+
<div style={{ fontSize: 27, fontWeight: 500, lineHeight: 1.35, color: C.fg }}>
|
|
712
|
+
{body}
|
|
713
|
+
</div>
|
|
714
|
+
</div>
|
|
715
|
+
</div>
|
|
716
|
+
);
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
const Scene2: React.FC = () => {
|
|
720
|
+
const frame = useCurrentFrame();
|
|
721
|
+
const { fps } = useVideoConfig();
|
|
722
|
+
|
|
723
|
+
const titleOp = fadeIn(frame, 0, 14);
|
|
724
|
+
const titleY = interpolate(frame, [0, 18], [22, 0], {
|
|
725
|
+
extrapolateLeft: "clamp",
|
|
726
|
+
extrapolateRight: "clamp",
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
// 4 cards stagger in across ~1s
|
|
730
|
+
// Shred at frame ~210 (when "Gone." hits)
|
|
731
|
+
const shredAt = 210;
|
|
732
|
+
|
|
733
|
+
// GONE slam
|
|
734
|
+
const goneAt = 220;
|
|
735
|
+
const goneSpring = sp(frame, fps, goneAt / fps, "bouncy");
|
|
736
|
+
const goneOp = interpolate(goneSpring, [0, 0.4], [0, 1], {
|
|
737
|
+
extrapolateLeft: "clamp",
|
|
738
|
+
extrapolateRight: "clamp",
|
|
739
|
+
});
|
|
740
|
+
const goneScale = interpolate(goneSpring, [0, 0.5, 1], [0.5, 1.15, 1]);
|
|
741
|
+
const goneRot = interpolate(goneSpring, [0, 1], [-6, -2]);
|
|
742
|
+
const goneShake = goneOp * Math.sin(frame * 0.6) * 1.5;
|
|
743
|
+
|
|
744
|
+
// sub line
|
|
745
|
+
const subOp = fadeIn(frame, 270);
|
|
746
|
+
const subY = interpolate(frame, [270, 295], [18, 0], {
|
|
747
|
+
extrapolateLeft: "clamp",
|
|
748
|
+
extrapolateRight: "clamp",
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
const exit = fadeOut(frame, SCENES.S2.dur - 16, 12);
|
|
752
|
+
|
|
753
|
+
return (
|
|
754
|
+
<AbsoluteFill style={{ fontFamily: FONT, opacity: exit }}>
|
|
755
|
+
<DarkBg frame={frame} tint="red" />
|
|
756
|
+
|
|
757
|
+
{/* Title */}
|
|
758
|
+
<div
|
|
759
|
+
style={{
|
|
760
|
+
position: "absolute",
|
|
761
|
+
top: SAFE_TOP - 10,
|
|
762
|
+
left: 0,
|
|
763
|
+
right: 0,
|
|
764
|
+
textAlign: "center",
|
|
765
|
+
opacity: titleOp,
|
|
766
|
+
transform: `translateY(${titleY}px)`,
|
|
767
|
+
padding: "0 60px",
|
|
768
|
+
}}
|
|
769
|
+
>
|
|
770
|
+
<Pill bg="rgba(255,255,255,0.05)" fg={C.fgSoft} border={C.border}>
|
|
771
|
+
WHAT'S LOST AT SESSION RESET
|
|
772
|
+
</Pill>
|
|
773
|
+
<div
|
|
774
|
+
style={{
|
|
775
|
+
marginTop: 28,
|
|
776
|
+
fontSize: 78,
|
|
777
|
+
fontWeight: 700,
|
|
778
|
+
color: C.fg,
|
|
779
|
+
letterSpacing: "-0.04em",
|
|
780
|
+
lineHeight: 1.02,
|
|
781
|
+
}}
|
|
782
|
+
>
|
|
783
|
+
Every decision.<br />
|
|
784
|
+
<span style={{ color: C.fgMuted, fontWeight: 600 }}>
|
|
785
|
+
Every back-and-forth.
|
|
786
|
+
</span><br />
|
|
787
|
+
<span style={{ color: C.fgDim, fontWeight: 600 }}>
|
|
788
|
+
Every reason behind it.
|
|
789
|
+
</span>
|
|
790
|
+
</div>
|
|
791
|
+
</div>
|
|
792
|
+
|
|
793
|
+
{/* FLOATING MEMORY CARDS */}
|
|
794
|
+
<FloatingMemoryCard
|
|
795
|
+
frame={frame}
|
|
796
|
+
index={0}
|
|
797
|
+
startFrame={50}
|
|
798
|
+
shredAt={shredAt}
|
|
799
|
+
label="DECISION · 14:32"
|
|
800
|
+
body={"\u201CWe chose Postgres over\nDynamo because of joins.\u201D"}
|
|
801
|
+
x={120}
|
|
802
|
+
y={830}
|
|
803
|
+
rot={-3}
|
|
804
|
+
tint={C.indigo}
|
|
805
|
+
/>
|
|
806
|
+
<FloatingMemoryCard
|
|
807
|
+
frame={frame}
|
|
808
|
+
index={1}
|
|
809
|
+
startFrame={50}
|
|
810
|
+
shredAt={shredAt}
|
|
811
|
+
label="REASONING · 14:48"
|
|
812
|
+
body={"\u201CRetry on 502 only — 503\nmeans pool is exhausted.\u201D"}
|
|
813
|
+
x={420}
|
|
814
|
+
y={970}
|
|
815
|
+
rot={4}
|
|
816
|
+
tint={C.emerald}
|
|
817
|
+
/>
|
|
818
|
+
<FloatingMemoryCard
|
|
819
|
+
frame={frame}
|
|
820
|
+
index={2}
|
|
821
|
+
startFrame={50}
|
|
822
|
+
shredAt={shredAt}
|
|
823
|
+
label="BACK-AND-FORTH · 15:11"
|
|
824
|
+
body={"\u201CDon\u2019t mock the DB in\ntests \u2014 burned us last Q.\u201D"}
|
|
825
|
+
x={130}
|
|
826
|
+
y={1110}
|
|
827
|
+
rot={2}
|
|
828
|
+
tint="#fcbb00"
|
|
829
|
+
/>
|
|
830
|
+
<FloatingMemoryCard
|
|
831
|
+
frame={frame}
|
|
832
|
+
index={3}
|
|
833
|
+
startFrame={50}
|
|
834
|
+
shredAt={shredAt}
|
|
835
|
+
label="CONSTRAINT · 15:24"
|
|
836
|
+
body={"\u201CMobile freeze starts\nThu \u2014 critical merges only.\u201D"}
|
|
837
|
+
x={420}
|
|
838
|
+
y={1255}
|
|
839
|
+
rot={-2}
|
|
840
|
+
tint="#fb7185"
|
|
841
|
+
/>
|
|
842
|
+
|
|
843
|
+
{/* GONE. — slam */}
|
|
844
|
+
{frame >= goneAt - 4 ? (
|
|
845
|
+
<div
|
|
846
|
+
style={{
|
|
847
|
+
position: "absolute",
|
|
848
|
+
left: 0,
|
|
849
|
+
right: 0,
|
|
850
|
+
top: 1340,
|
|
851
|
+
textAlign: "center",
|
|
852
|
+
opacity: goneOp,
|
|
853
|
+
}}
|
|
854
|
+
>
|
|
855
|
+
<div
|
|
856
|
+
style={{
|
|
857
|
+
display: "inline-block",
|
|
858
|
+
fontSize: 240,
|
|
859
|
+
fontWeight: 800,
|
|
860
|
+
letterSpacing: "-0.07em",
|
|
861
|
+
color: C.fg,
|
|
862
|
+
transform: `scale(${goneScale}) rotate(${goneRot}deg) translateX(${goneShake}px)`,
|
|
863
|
+
filter: "drop-shadow(0 0 60px rgba(239,68,68,0.45))",
|
|
864
|
+
}}
|
|
865
|
+
>
|
|
866
|
+
<span style={{ color: C.red }}>GONE</span>
|
|
867
|
+
<span style={{ color: C.fg }}>.</span>
|
|
868
|
+
</div>
|
|
869
|
+
</div>
|
|
870
|
+
) : null}
|
|
871
|
+
|
|
872
|
+
{/* sub */}
|
|
873
|
+
<div
|
|
874
|
+
style={{
|
|
875
|
+
position: "absolute",
|
|
876
|
+
left: 0,
|
|
877
|
+
right: 0,
|
|
878
|
+
top: 1420,
|
|
879
|
+
textAlign: "center",
|
|
880
|
+
opacity: subOp,
|
|
881
|
+
transform: `translateY(${subY}px)`,
|
|
882
|
+
fontSize: 30,
|
|
883
|
+
fontWeight: 500,
|
|
884
|
+
color: C.fgMuted,
|
|
885
|
+
letterSpacing: "-0.01em",
|
|
886
|
+
}}
|
|
887
|
+
>
|
|
888
|
+
the second you start a new session
|
|
889
|
+
</div>
|
|
890
|
+
</AbsoluteFill>
|
|
891
|
+
);
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
895
|
+
// SCENE 3 — MEM0 / "AI DECIDES" WALL
|
|
896
|
+
// "Mem zero charges nineteen a month. But they all hit the same wall —
|
|
897
|
+
// they let AI decide what's worth keeping."
|
|
898
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
899
|
+
|
|
900
|
+
const Scene3: React.FC = () => {
|
|
901
|
+
const frame = useCurrentFrame();
|
|
902
|
+
const { fps } = useVideoConfig();
|
|
903
|
+
|
|
904
|
+
// Pricing card flip in
|
|
905
|
+
const cardSpring = sp(frame, fps, 0.1, "snappy");
|
|
906
|
+
const cardScale = interpolate(cardSpring, [0, 1], [0.88, 1]);
|
|
907
|
+
const cardOp = interpolate(cardSpring, [0, 0.5], [0, 1], {
|
|
908
|
+
extrapolateLeft: "clamp",
|
|
909
|
+
extrapolateRight: "clamp",
|
|
910
|
+
});
|
|
911
|
+
const cardY = interpolate(cardSpring, [0, 1], [40, 0]);
|
|
912
|
+
|
|
913
|
+
// Price counter — counts up from 0 to 19
|
|
914
|
+
const priceCount = Math.round(tween(frame, 12, 30, 0, 19));
|
|
915
|
+
|
|
916
|
+
// Title
|
|
917
|
+
const titleOp = fadeIn(frame, 0, 12);
|
|
918
|
+
|
|
919
|
+
// VS divider
|
|
920
|
+
const dividerOp = fadeIn(frame, 70);
|
|
921
|
+
|
|
922
|
+
// Right card — "AI decides" with strikethrough
|
|
923
|
+
const rightSpring = sp(frame, fps, 2.4, "snappy");
|
|
924
|
+
const rightOp = interpolate(rightSpring, [0, 0.4], [0, 1], {
|
|
925
|
+
extrapolateLeft: "clamp",
|
|
926
|
+
extrapolateRight: "clamp",
|
|
927
|
+
});
|
|
928
|
+
const rightY = interpolate(rightSpring, [0, 1], [40, 0]);
|
|
929
|
+
|
|
930
|
+
// Strikethrough draws on top of "AI DECIDES"
|
|
931
|
+
const strikeAt = 105;
|
|
932
|
+
const strikeT = tween(frame, strikeAt, 18, 0, 1);
|
|
933
|
+
|
|
934
|
+
// "SAME WALL" — bricks build up
|
|
935
|
+
const wallStartAt = 140;
|
|
936
|
+
const exit = fadeOut(frame, SCENES.S3.dur - 16, 12);
|
|
937
|
+
|
|
938
|
+
return (
|
|
939
|
+
<AbsoluteFill style={{ fontFamily: FONT, opacity: exit }}>
|
|
940
|
+
<DarkBg frame={frame} tint="red" />
|
|
941
|
+
|
|
942
|
+
{/* Title */}
|
|
943
|
+
<div
|
|
944
|
+
style={{
|
|
945
|
+
position: "absolute",
|
|
946
|
+
top: SAFE_TOP,
|
|
947
|
+
left: 0,
|
|
948
|
+
right: 0,
|
|
949
|
+
textAlign: "center",
|
|
950
|
+
opacity: titleOp,
|
|
951
|
+
padding: "0 60px",
|
|
952
|
+
}}
|
|
953
|
+
>
|
|
954
|
+
<Pill bg="rgba(239,68,68,0.10)" fg="#fca5a5" border="rgba(239,68,68,0.30)">
|
|
955
|
+
THE SAME CEILING
|
|
956
|
+
</Pill>
|
|
957
|
+
<div
|
|
958
|
+
style={{
|
|
959
|
+
marginTop: 24,
|
|
960
|
+
fontSize: 64,
|
|
961
|
+
fontWeight: 700,
|
|
962
|
+
color: C.fg,
|
|
963
|
+
letterSpacing: "-0.035em",
|
|
964
|
+
lineHeight: 1.05,
|
|
965
|
+
}}
|
|
966
|
+
>
|
|
967
|
+
They charge you,<br />
|
|
968
|
+
then <span style={{ color: C.red }}>throw most of it away.</span>
|
|
969
|
+
</div>
|
|
970
|
+
</div>
|
|
971
|
+
|
|
972
|
+
{/* PRICING CARD */}
|
|
973
|
+
<div
|
|
974
|
+
style={{
|
|
975
|
+
position: "absolute",
|
|
976
|
+
top: 720,
|
|
977
|
+
left: 80,
|
|
978
|
+
width: 420,
|
|
979
|
+
opacity: cardOp,
|
|
980
|
+
transform: `translateY(${cardY}px) scale(${cardScale})`,
|
|
981
|
+
}}
|
|
982
|
+
>
|
|
983
|
+
<div
|
|
984
|
+
style={{
|
|
985
|
+
background: C.surface,
|
|
986
|
+
border: `1px solid ${C.borderLoud}`,
|
|
987
|
+
borderRadius: 24,
|
|
988
|
+
padding: "32px 30px",
|
|
989
|
+
boxShadow:
|
|
990
|
+
"0 30px 60px -10px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.06)",
|
|
991
|
+
fontFamily: FONT,
|
|
992
|
+
}}
|
|
993
|
+
>
|
|
994
|
+
<div
|
|
995
|
+
style={{
|
|
996
|
+
fontFamily: MONO,
|
|
997
|
+
fontSize: 18,
|
|
998
|
+
color: C.fgMuted,
|
|
999
|
+
letterSpacing: "0.12em",
|
|
1000
|
+
fontWeight: 600,
|
|
1001
|
+
}}
|
|
1002
|
+
>
|
|
1003
|
+
MEM0 · BASIC
|
|
1004
|
+
</div>
|
|
1005
|
+
<div
|
|
1006
|
+
style={{
|
|
1007
|
+
marginTop: 18,
|
|
1008
|
+
display: "flex",
|
|
1009
|
+
alignItems: "baseline",
|
|
1010
|
+
gap: 6,
|
|
1011
|
+
}}
|
|
1012
|
+
>
|
|
1013
|
+
<span style={{ fontSize: 38, color: C.fgMuted, fontWeight: 600 }}>$</span>
|
|
1014
|
+
<span
|
|
1015
|
+
style={{
|
|
1016
|
+
fontSize: 124,
|
|
1017
|
+
fontWeight: 800,
|
|
1018
|
+
letterSpacing: "-0.06em",
|
|
1019
|
+
color: C.fg,
|
|
1020
|
+
lineHeight: 0.9,
|
|
1021
|
+
}}
|
|
1022
|
+
>
|
|
1023
|
+
{priceCount}
|
|
1024
|
+
</span>
|
|
1025
|
+
<span style={{ fontSize: 30, color: C.fgMuted, marginLeft: 6 }}>/mo</span>
|
|
1026
|
+
</div>
|
|
1027
|
+
<div
|
|
1028
|
+
style={{
|
|
1029
|
+
marginTop: 18,
|
|
1030
|
+
display: "flex",
|
|
1031
|
+
flexDirection: "column",
|
|
1032
|
+
gap: 12,
|
|
1033
|
+
}}
|
|
1034
|
+
>
|
|
1035
|
+
{["AI-curated retention", "What it deems important", "Vendor lock-in"].map(
|
|
1036
|
+
(txt, i) => {
|
|
1037
|
+
const lineT = tween(frame, 50 + i * 8, 18, 0, 1);
|
|
1038
|
+
return (
|
|
1039
|
+
<div
|
|
1040
|
+
key={txt}
|
|
1041
|
+
style={{
|
|
1042
|
+
opacity: lineT,
|
|
1043
|
+
display: "flex",
|
|
1044
|
+
alignItems: "center",
|
|
1045
|
+
gap: 12,
|
|
1046
|
+
fontSize: 22,
|
|
1047
|
+
color: C.fgSoft,
|
|
1048
|
+
fontFamily: MONO,
|
|
1049
|
+
}}
|
|
1050
|
+
>
|
|
1051
|
+
<Img
|
|
1052
|
+
src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
|
|
1053
|
+
style={{ width: 22, height: 22, filter: "brightness(0) saturate(100%) invert(45%) sepia(85%) saturate(2900%) hue-rotate(335deg)" }}
|
|
1054
|
+
/>
|
|
1055
|
+
{txt}
|
|
1056
|
+
</div>
|
|
1057
|
+
);
|
|
1058
|
+
},
|
|
1059
|
+
)}
|
|
1060
|
+
</div>
|
|
1061
|
+
</div>
|
|
1062
|
+
</div>
|
|
1063
|
+
|
|
1064
|
+
{/* VS DIVIDER */}
|
|
1065
|
+
<div
|
|
1066
|
+
style={{
|
|
1067
|
+
position: "absolute",
|
|
1068
|
+
top: 840,
|
|
1069
|
+
left: 510,
|
|
1070
|
+
width: 60,
|
|
1071
|
+
opacity: dividerOp,
|
|
1072
|
+
textAlign: "center",
|
|
1073
|
+
}}
|
|
1074
|
+
>
|
|
1075
|
+
<div
|
|
1076
|
+
style={{
|
|
1077
|
+
fontFamily: MONO,
|
|
1078
|
+
fontWeight: 800,
|
|
1079
|
+
fontSize: 30,
|
|
1080
|
+
color: C.fgMuted,
|
|
1081
|
+
letterSpacing: "0.1em",
|
|
1082
|
+
}}
|
|
1083
|
+
>
|
|
1084
|
+
·
|
|
1085
|
+
</div>
|
|
1086
|
+
</div>
|
|
1087
|
+
|
|
1088
|
+
{/* RIGHT — "AI DECIDES" stamp */}
|
|
1089
|
+
<div
|
|
1090
|
+
style={{
|
|
1091
|
+
position: "absolute",
|
|
1092
|
+
top: 760,
|
|
1093
|
+
right: 80,
|
|
1094
|
+
width: 420,
|
|
1095
|
+
opacity: rightOp,
|
|
1096
|
+
transform: `translateY(${rightY}px)`,
|
|
1097
|
+
}}
|
|
1098
|
+
>
|
|
1099
|
+
<div
|
|
1100
|
+
style={{
|
|
1101
|
+
fontFamily: MONO,
|
|
1102
|
+
fontSize: 18,
|
|
1103
|
+
color: "#fca5a5",
|
|
1104
|
+
letterSpacing: "0.12em",
|
|
1105
|
+
fontWeight: 600,
|
|
1106
|
+
marginBottom: 18,
|
|
1107
|
+
}}
|
|
1108
|
+
>
|
|
1109
|
+
THE WALL
|
|
1110
|
+
</div>
|
|
1111
|
+
<div
|
|
1112
|
+
style={{
|
|
1113
|
+
position: "relative",
|
|
1114
|
+
display: "inline-block",
|
|
1115
|
+
fontSize: 96,
|
|
1116
|
+
fontWeight: 800,
|
|
1117
|
+
color: C.fg,
|
|
1118
|
+
letterSpacing: "-0.04em",
|
|
1119
|
+
lineHeight: 0.95,
|
|
1120
|
+
}}
|
|
1121
|
+
>
|
|
1122
|
+
AI DECIDES<br />
|
|
1123
|
+
<span style={{ color: C.fgDim }}>WHAT TO KEEP.</span>
|
|
1124
|
+
{/* Red strike line */}
|
|
1125
|
+
<svg
|
|
1126
|
+
width={400}
|
|
1127
|
+
height={220}
|
|
1128
|
+
style={{
|
|
1129
|
+
position: "absolute",
|
|
1130
|
+
top: 0,
|
|
1131
|
+
left: -10,
|
|
1132
|
+
pointerEvents: "none",
|
|
1133
|
+
overflow: "visible",
|
|
1134
|
+
}}
|
|
1135
|
+
>
|
|
1136
|
+
<line
|
|
1137
|
+
x1={20}
|
|
1138
|
+
y1={30}
|
|
1139
|
+
x2={20 + strikeT * 380}
|
|
1140
|
+
y2={30 + strikeT * 170}
|
|
1141
|
+
stroke={C.red}
|
|
1142
|
+
strokeWidth={10}
|
|
1143
|
+
strokeLinecap="round"
|
|
1144
|
+
style={{
|
|
1145
|
+
filter: `drop-shadow(0 0 10px rgba(239,68,68,0.6))`,
|
|
1146
|
+
}}
|
|
1147
|
+
/>
|
|
1148
|
+
</svg>
|
|
1149
|
+
</div>
|
|
1150
|
+
</div>
|
|
1151
|
+
|
|
1152
|
+
{/* Wall bricks at bottom */}
|
|
1153
|
+
<div
|
|
1154
|
+
style={{
|
|
1155
|
+
position: "absolute",
|
|
1156
|
+
left: 60,
|
|
1157
|
+
right: 60,
|
|
1158
|
+
top: 1280,
|
|
1159
|
+
height: 230,
|
|
1160
|
+
display: "grid",
|
|
1161
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
1162
|
+
gridTemplateRows: "repeat(4, 1fr)",
|
|
1163
|
+
gap: 6,
|
|
1164
|
+
}}
|
|
1165
|
+
>
|
|
1166
|
+
{Array.from({ length: 32 }).map((_, i) => {
|
|
1167
|
+
const t = tween(frame, wallStartAt + i * 1.6, 14, 0, 1);
|
|
1168
|
+
const offsetRow = Math.floor(i / 8) % 2 === 0 ? 0 : 14;
|
|
1169
|
+
return (
|
|
1170
|
+
<div
|
|
1171
|
+
key={i}
|
|
1172
|
+
style={{
|
|
1173
|
+
background: `rgba(${48 + (i % 4) * 4},${28 + (i % 3) * 2},${28 + (i % 5) * 3},${0.85 * t})`,
|
|
1174
|
+
border: `1px solid rgba(239,68,68,${0.18 * t})`,
|
|
1175
|
+
borderRadius: 4,
|
|
1176
|
+
opacity: t,
|
|
1177
|
+
transform: `translate(${offsetRow}px, ${(1 - t) * -14}px)`,
|
|
1178
|
+
}}
|
|
1179
|
+
/>
|
|
1180
|
+
);
|
|
1181
|
+
})}
|
|
1182
|
+
</div>
|
|
1183
|
+
</AbsoluteFill>
|
|
1184
|
+
);
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1188
|
+
// SCENE 4 — MEMPALACE FLIP
|
|
1189
|
+
// "MemPalace flipped it. It saves everything. No AI deciding."
|
|
1190
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1191
|
+
|
|
1192
|
+
const Scene4: React.FC = () => {
|
|
1193
|
+
const frame = useCurrentFrame();
|
|
1194
|
+
const { fps } = useVideoConfig();
|
|
1195
|
+
|
|
1196
|
+
// Hard cut to PaperBg — feels like flipping a coin from dark to light
|
|
1197
|
+
// Logo emerges with bouncy spring
|
|
1198
|
+
const logoSpring = sp(frame, fps, 0.05, "bouncy");
|
|
1199
|
+
const logoScale = interpolate(logoSpring, [0, 0.55, 1], [0.3, 1.1, 1]);
|
|
1200
|
+
const logoOp = interpolate(logoSpring, [0, 0.45], [0, 1], {
|
|
1201
|
+
extrapolateLeft: "clamp",
|
|
1202
|
+
extrapolateRight: "clamp",
|
|
1203
|
+
});
|
|
1204
|
+
const logoRot = interpolate(logoSpring, [0, 1], [-180, 0]);
|
|
1205
|
+
|
|
1206
|
+
// Wordmark letter-by-letter
|
|
1207
|
+
const wordChars = "MEMPALACE";
|
|
1208
|
+
|
|
1209
|
+
// Underline
|
|
1210
|
+
const underlineT = tween(frame, 50, 20, 0, 1);
|
|
1211
|
+
|
|
1212
|
+
// Tagline: SAVES EVERYTHING
|
|
1213
|
+
const taglineOp = fadeIn(frame, 75);
|
|
1214
|
+
const taglineY = interpolate(frame, [75, 95], [16, 0], {
|
|
1215
|
+
extrapolateLeft: "clamp",
|
|
1216
|
+
extrapolateRight: "clamp",
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
return (
|
|
1220
|
+
<AbsoluteFill style={{ fontFamily: FONT }}>
|
|
1221
|
+
<PaperBg frame={frame} />
|
|
1222
|
+
|
|
1223
|
+
{/* Crest / seal */}
|
|
1224
|
+
<div
|
|
1225
|
+
style={{
|
|
1226
|
+
position: "absolute",
|
|
1227
|
+
top: 540,
|
|
1228
|
+
left: 0,
|
|
1229
|
+
right: 0,
|
|
1230
|
+
display: "flex",
|
|
1231
|
+
justifyContent: "center",
|
|
1232
|
+
opacity: logoOp,
|
|
1233
|
+
transform: `scale(${logoScale}) rotate(${logoRot}deg)`,
|
|
1234
|
+
}}
|
|
1235
|
+
>
|
|
1236
|
+
<svg width={260} height={260} viewBox="0 0 200 200">
|
|
1237
|
+
{/* outer ring */}
|
|
1238
|
+
<circle cx={100} cy={100} r={92} fill="none" stroke={C.gold} strokeWidth={3} />
|
|
1239
|
+
<circle cx={100} cy={100} r={84} fill="none" stroke={C.goldDeep} strokeWidth={1.2} strokeDasharray="2 6" />
|
|
1240
|
+
{/* pediment */}
|
|
1241
|
+
<path
|
|
1242
|
+
d="M40 110 L100 50 L160 110 Z"
|
|
1243
|
+
fill="none"
|
|
1244
|
+
stroke={C.goldDeep}
|
|
1245
|
+
strokeWidth={3}
|
|
1246
|
+
/>
|
|
1247
|
+
{/* columns */}
|
|
1248
|
+
<rect x={56} y={110} width={8} height={42} fill={C.goldDeep} />
|
|
1249
|
+
<rect x={84} y={110} width={8} height={42} fill={C.goldDeep} />
|
|
1250
|
+
<rect x={108} y={110} width={8} height={42} fill={C.goldDeep} />
|
|
1251
|
+
<rect x={136} y={110} width={8} height={42} fill={C.goldDeep} />
|
|
1252
|
+
{/* base */}
|
|
1253
|
+
<rect x={48} y={154} width={104} height={6} fill={C.goldDeep} />
|
|
1254
|
+
{/* steps */}
|
|
1255
|
+
<rect x={42} y={162} width={116} height={3} fill={C.gold} />
|
|
1256
|
+
{/* pediment dot */}
|
|
1257
|
+
<circle cx={100} cy={84} r={4} fill={C.gold} />
|
|
1258
|
+
</svg>
|
|
1259
|
+
</div>
|
|
1260
|
+
|
|
1261
|
+
{/* Wordmark */}
|
|
1262
|
+
<div
|
|
1263
|
+
style={{
|
|
1264
|
+
position: "absolute",
|
|
1265
|
+
top: 820,
|
|
1266
|
+
left: 0,
|
|
1267
|
+
right: 0,
|
|
1268
|
+
display: "flex",
|
|
1269
|
+
justifyContent: "center",
|
|
1270
|
+
fontFamily: SERIF,
|
|
1271
|
+
}}
|
|
1272
|
+
>
|
|
1273
|
+
<div
|
|
1274
|
+
style={{
|
|
1275
|
+
display: "flex",
|
|
1276
|
+
fontSize: 140,
|
|
1277
|
+
fontWeight: 700,
|
|
1278
|
+
color: C.ink,
|
|
1279
|
+
letterSpacing: "-0.04em",
|
|
1280
|
+
lineHeight: 1,
|
|
1281
|
+
}}
|
|
1282
|
+
>
|
|
1283
|
+
{letterStagger(wordChars, frame, fps, 0.4, 0.04).map((s, i) => (
|
|
1284
|
+
<span
|
|
1285
|
+
key={`w-${i}`}
|
|
1286
|
+
style={{
|
|
1287
|
+
display: "inline-block",
|
|
1288
|
+
opacity: s.opacity,
|
|
1289
|
+
transform: `translateY(${s.y}px) scale(${s.scale})`,
|
|
1290
|
+
}}
|
|
1291
|
+
>
|
|
1292
|
+
{s.ch}
|
|
1293
|
+
</span>
|
|
1294
|
+
))}
|
|
1295
|
+
</div>
|
|
1296
|
+
</div>
|
|
1297
|
+
|
|
1298
|
+
{/* Underline */}
|
|
1299
|
+
<div
|
|
1300
|
+
style={{
|
|
1301
|
+
position: "absolute",
|
|
1302
|
+
top: 985,
|
|
1303
|
+
left: 0,
|
|
1304
|
+
right: 0,
|
|
1305
|
+
display: "flex",
|
|
1306
|
+
justifyContent: "center",
|
|
1307
|
+
}}
|
|
1308
|
+
>
|
|
1309
|
+
<div
|
|
1310
|
+
style={{
|
|
1311
|
+
width: underlineT * 540,
|
|
1312
|
+
height: 4,
|
|
1313
|
+
background: `linear-gradient(90deg, transparent, ${C.gold}, transparent)`,
|
|
1314
|
+
borderRadius: 999,
|
|
1315
|
+
}}
|
|
1316
|
+
/>
|
|
1317
|
+
</div>
|
|
1318
|
+
|
|
1319
|
+
{/* Tagline */}
|
|
1320
|
+
<div
|
|
1321
|
+
style={{
|
|
1322
|
+
position: "absolute",
|
|
1323
|
+
top: 1080,
|
|
1324
|
+
left: 0,
|
|
1325
|
+
right: 0,
|
|
1326
|
+
textAlign: "center",
|
|
1327
|
+
opacity: taglineOp,
|
|
1328
|
+
transform: `translateY(${taglineY}px)`,
|
|
1329
|
+
padding: "0 80px",
|
|
1330
|
+
}}
|
|
1331
|
+
>
|
|
1332
|
+
<div
|
|
1333
|
+
style={{
|
|
1334
|
+
fontSize: 70,
|
|
1335
|
+
fontWeight: 700,
|
|
1336
|
+
color: C.ink,
|
|
1337
|
+
letterSpacing: "-0.03em",
|
|
1338
|
+
lineHeight: 1.05,
|
|
1339
|
+
}}
|
|
1340
|
+
>
|
|
1341
|
+
Saves <span style={{ color: C.goldDeep, fontStyle: "italic", fontFamily: SERIF }}>everything.</span>
|
|
1342
|
+
</div>
|
|
1343
|
+
<div
|
|
1344
|
+
style={{
|
|
1345
|
+
marginTop: 14,
|
|
1346
|
+
fontSize: 36,
|
|
1347
|
+
color: C.inkSoft,
|
|
1348
|
+
fontWeight: 500,
|
|
1349
|
+
}}
|
|
1350
|
+
>
|
|
1351
|
+
No AI deciding.
|
|
1352
|
+
</div>
|
|
1353
|
+
</div>
|
|
1354
|
+
</AbsoluteFill>
|
|
1355
|
+
);
|
|
1356
|
+
};
|
|
1357
|
+
|
|
1358
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1359
|
+
// SCENE 5 — ARCHITECTURE
|
|
1360
|
+
// "ancient Greek memory palace technique. Aristotle used it. Cicero used it.
|
|
1361
|
+
// Projects become wings. Topics become rooms. Every memory lives word-for-word
|
|
1362
|
+
// in a drawer Claude can open on demand."
|
|
1363
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
1364
|
+
|
|
1365
|
+
const ArchitectureDiagram: React.FC<{ frame: number; fps: number }> = ({
|
|
1366
|
+
frame,
|
|
1367
|
+
}) => {
|
|
1368
|
+
// Build layered hierarchy: PALACE → WINGS → ROOMS → DRAWERS
|
|
1369
|
+
// Reveal layer by layer with stagger.
|
|
1370
|
+
const sFacade = tween(frame, 80, 30, 0, 1);
|
|
1371
|
+
const sWings = tween(frame, 130, 26, 0, 1);
|
|
1372
|
+
const sRooms = tween(frame, 180, 28, 0, 1);
|
|
1373
|
+
const sDrawers = tween(frame, 240, 32, 0, 1);
|
|
1374
|
+
const sLines = tween(frame, 200, 26, 0, 1);
|
|
1375
|
+
|
|
1376
|
+
// Subtle window-glow pulse — gives the buildings a "living" feel
|
|
1377
|
+
const winPulse = 0.78 + Math.sin(frame * 0.05) * 0.18;
|
|
1378
|
+
// Animated dash-flow on connectors (signal traveling down the hierarchy)
|
|
1379
|
+
const dashOffset = -(frame * 0.6) % 16;
|
|
1380
|
+
|
|
1381
|
+
// Wing data
|
|
1382
|
+
const wings = [
|
|
1383
|
+
{ cx: 160, label: "claude-code" },
|
|
1384
|
+
{ cx: 460, label: "my-saas" },
|
|
1385
|
+
{ cx: 760, label: "agent-sdk" },
|
|
1386
|
+
];
|
|
1387
|
+
// Room data
|
|
1388
|
+
const rooms = [
|
|
1389
|
+
{ cx: 160, label: "auth" },
|
|
1390
|
+
{ cx: 460, label: "billing" },
|
|
1391
|
+
{ cx: 760, label: "ui-design" },
|
|
1392
|
+
];
|
|
1393
|
+
// Drawers — each drawer carries a real memory snippet (echoes Scene 2)
|
|
1394
|
+
// 4 cards × 156 wide + 3 × 18 gap = 678 → centered in 920 (margin 121)
|
|
1395
|
+
const drawers = [
|
|
1396
|
+
{ cx: 121, time: "14:32", body: "postgres > dynamo", tag: "joins" },
|
|
1397
|
+
{ cx: 295, time: "14:48", body: "retry 502 only", tag: "503 = pool" },
|
|
1398
|
+
{ cx: 469, time: "15:11", body: "no DB mocks", tag: "burned us" },
|
|
1399
|
+
{ cx: 643, time: "15:24", body: "mobile freeze Thu", tag: "critical" },
|
|
1400
|
+
];
|
|
1401
|
+
|
|
1402
|
+
return (
|
|
1403
|
+
<svg
|
|
1404
|
+
width={920}
|
|
1405
|
+
height={820}
|
|
1406
|
+
viewBox="0 0 920 820"
|
|
1407
|
+
style={{ position: "absolute", left: 80, top: 580 }}
|
|
1408
|
+
>
|
|
1409
|
+
<defs>
|
|
1410
|
+
{/* Pediment marble gradient */}
|
|
1411
|
+
<linearGradient id="marble" x1="0" y1="0" x2="0" y2="1">
|
|
1412
|
+
<stop offset="0%" stopColor={C.paper} />
|
|
1413
|
+
<stop offset="100%" stopColor={C.paperDeep} />
|
|
1414
|
+
</linearGradient>
|
|
1415
|
+
{/* Column shading: lit on left, shadow on right */}
|
|
1416
|
+
<linearGradient id="column" x1="0" y1="0" x2="1" y2="0">
|
|
1417
|
+
<stop offset="0%" stopColor={C.paper} />
|
|
1418
|
+
<stop offset="55%" stopColor={C.paperWarm} />
|
|
1419
|
+
<stop offset="100%" stopColor={C.paperDeep} />
|
|
1420
|
+
</linearGradient>
|
|
1421
|
+
{/* Building front shading */}
|
|
1422
|
+
<linearGradient id="wall" x1="0" y1="0" x2="1" y2="0">
|
|
1423
|
+
<stop offset="0%" stopColor={C.paper} />
|
|
1424
|
+
<stop offset="100%" stopColor={C.paperWarm} />
|
|
1425
|
+
</linearGradient>
|
|
1426
|
+
{/* Roof front face */}
|
|
1427
|
+
<linearGradient id="roof" x1="0" y1="0" x2="0" y2="1">
|
|
1428
|
+
<stop offset="0%" stopColor={C.gold} />
|
|
1429
|
+
<stop offset="100%" stopColor={C.goldDeep} />
|
|
1430
|
+
</linearGradient>
|
|
1431
|
+
{/* Lit window — gold light glowing from inside */}
|
|
1432
|
+
<radialGradient id="window-glow" cx="0.5" cy="0.5" r="0.7">
|
|
1433
|
+
<stop offset="0%" stopColor="#f9e1a8" />
|
|
1434
|
+
<stop offset="60%" stopColor={C.gold} />
|
|
1435
|
+
<stop offset="100%" stopColor={C.goldDeep} />
|
|
1436
|
+
</radialGradient>
|
|
1437
|
+
{/* Plaque shading */}
|
|
1438
|
+
<linearGradient id="plaque" x1="0" y1="0" x2="0" y2="1">
|
|
1439
|
+
<stop offset="0%" stopColor={C.paper} />
|
|
1440
|
+
<stop offset="100%" stopColor={C.paperDeep} />
|
|
1441
|
+
</linearGradient>
|
|
1442
|
+
{/* Drawer body */}
|
|
1443
|
+
<linearGradient id="drawer-body" x1="0" y1="0" x2="0" y2="1">
|
|
1444
|
+
<stop offset="0%" stopColor={C.paperWarm} />
|
|
1445
|
+
<stop offset="100%" stopColor={C.paperDeep} />
|
|
1446
|
+
</linearGradient>
|
|
1447
|
+
{/* Connector stroke */}
|
|
1448
|
+
<linearGradient id="connector" x1="0" y1="0" x2="0" y2="1">
|
|
1449
|
+
<stop offset="0%" stopColor={C.gold} stopOpacity="0.85" />
|
|
1450
|
+
<stop offset="100%" stopColor={C.goldDeep} stopOpacity="0.55" />
|
|
1451
|
+
</linearGradient>
|
|
1452
|
+
|
|
1453
|
+
{/* Soft cast-shadow filter */}
|
|
1454
|
+
<filter id="soft-shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
1455
|
+
<feGaussianBlur in="SourceAlpha" stdDeviation="2.4" />
|
|
1456
|
+
<feOffset dx="0" dy="3" result="offset" />
|
|
1457
|
+
<feComponentTransfer>
|
|
1458
|
+
<feFuncA type="linear" slope="0.35" />
|
|
1459
|
+
</feComponentTransfer>
|
|
1460
|
+
<feMerge>
|
|
1461
|
+
<feMergeNode />
|
|
1462
|
+
<feMergeNode in="SourceGraphic" />
|
|
1463
|
+
</feMerge>
|
|
1464
|
+
</filter>
|
|
1465
|
+
</defs>
|
|
1466
|
+
|
|
1467
|
+
{/* Corner ornaments — small classical filigree */}
|
|
1468
|
+
<g opacity={sFacade * 0.45} fill={C.goldDeep}>
|
|
1469
|
+
<circle cx={6} cy={6} r={2.5} />
|
|
1470
|
+
<circle cx={20} cy={6} r={1.2} />
|
|
1471
|
+
<circle cx={6} cy={20} r={1.2} />
|
|
1472
|
+
<circle cx={914} cy={6} r={2.5} />
|
|
1473
|
+
<circle cx={900} cy={6} r={1.2} />
|
|
1474
|
+
<circle cx={914} cy={20} r={1.2} />
|
|
1475
|
+
</g>
|
|
1476
|
+
|
|
1477
|
+
{/* ───────────────── PALACE FACADE ───────────────── */}
|
|
1478
|
+
<g
|
|
1479
|
+
opacity={sFacade}
|
|
1480
|
+
transform={`translate(${360}, ${10 + (1 - sFacade) * 20})`}
|
|
1481
|
+
>
|
|
1482
|
+
{/* Soft platform shadow */}
|
|
1483
|
+
<ellipse cx={100} cy={210} rx={130} ry={5} fill="rgba(26,20,16,0.18)" />
|
|
1484
|
+
|
|
1485
|
+
{/* Stepped base — three tiers, widening toward bottom */}
|
|
1486
|
+
<rect x={-10} y={195} width={220} height={11} fill={C.goldDeep} />
|
|
1487
|
+
<rect x={-4} y={186} width={208} height={9} fill={C.gold} />
|
|
1488
|
+
<rect x={2} y={178} width={196} height={8} fill={C.goldDeep} />
|
|
1489
|
+
|
|
1490
|
+
{/* 5 columns with subtle shading (lit left / shadow right) */}
|
|
1491
|
+
{[18, 56, 94, 132, 170].map((x) => (
|
|
1492
|
+
<g key={x}>
|
|
1493
|
+
{/* Capital (top flare) */}
|
|
1494
|
+
<rect x={x - 2} y={94} width={18} height={5} fill={C.goldDeep} />
|
|
1495
|
+
{/* Shaft */}
|
|
1496
|
+
<rect
|
|
1497
|
+
x={x}
|
|
1498
|
+
y={99}
|
|
1499
|
+
width={14}
|
|
1500
|
+
height={76}
|
|
1501
|
+
fill="url(#column)"
|
|
1502
|
+
stroke={C.goldDeep}
|
|
1503
|
+
strokeWidth={1}
|
|
1504
|
+
/>
|
|
1505
|
+
{/* Vertical fluting line */}
|
|
1506
|
+
<line
|
|
1507
|
+
x1={x + 7}
|
|
1508
|
+
y1={102}
|
|
1509
|
+
x2={x + 7}
|
|
1510
|
+
y2={172}
|
|
1511
|
+
stroke={C.goldDeep}
|
|
1512
|
+
strokeOpacity="0.35"
|
|
1513
|
+
strokeWidth={0.8}
|
|
1514
|
+
/>
|
|
1515
|
+
{/* Base */}
|
|
1516
|
+
<rect x={x - 2} y={175} width={18} height={3} fill={C.goldDeep} />
|
|
1517
|
+
</g>
|
|
1518
|
+
))}
|
|
1519
|
+
|
|
1520
|
+
{/* Architrave (horizontal beam above columns) */}
|
|
1521
|
+
<rect x={2} y={84} width={196} height={11} fill={C.goldDeep} />
|
|
1522
|
+
<rect x={6} y={86} width={188} height={1.5} fill={C.gold} />
|
|
1523
|
+
|
|
1524
|
+
{/* Pediment (triangular gable) */}
|
|
1525
|
+
<path
|
|
1526
|
+
d="M2 84 L100 4 L198 84 Z"
|
|
1527
|
+
fill="url(#marble)"
|
|
1528
|
+
stroke={C.goldDeep}
|
|
1529
|
+
strokeWidth={2}
|
|
1530
|
+
/>
|
|
1531
|
+
{/* Inner pediment line — echoes the silhouette */}
|
|
1532
|
+
<path
|
|
1533
|
+
d="M16 80 L100 12 L184 80"
|
|
1534
|
+
fill="none"
|
|
1535
|
+
stroke={C.gold}
|
|
1536
|
+
strokeOpacity="0.55"
|
|
1537
|
+
strokeWidth={1}
|
|
1538
|
+
/>
|
|
1539
|
+
{/* Acroteria (small ornaments on pediment corners) */}
|
|
1540
|
+
<circle cx={2} cy={84} r={3} fill={C.goldDeep} />
|
|
1541
|
+
<circle cx={198} cy={84} r={3} fill={C.goldDeep} />
|
|
1542
|
+
<circle cx={100} cy={4} r={3.5} fill={C.goldDeep} />
|
|
1543
|
+
|
|
1544
|
+
{/* Central medallion / laurel */}
|
|
1545
|
+
<circle cx={100} cy={56} r={11} fill={C.paper} stroke={C.goldDeep} strokeWidth={1.4} />
|
|
1546
|
+
<circle cx={100} cy={56} r={6} fill={C.goldDeep} opacity={0.18} />
|
|
1547
|
+
<path
|
|
1548
|
+
d="M94 56 L106 56 M100 50 L100 62"
|
|
1549
|
+
stroke={C.goldDeep}
|
|
1550
|
+
strokeWidth={1.2}
|
|
1551
|
+
/>
|
|
1552
|
+
|
|
1553
|
+
{/* Label below */}
|
|
1554
|
+
<text
|
|
1555
|
+
x={100}
|
|
1556
|
+
y={234}
|
|
1557
|
+
fill={C.inkSoft}
|
|
1558
|
+
fontFamily={MONO}
|
|
1559
|
+
fontSize={15}
|
|
1560
|
+
fontWeight={700}
|
|
1561
|
+
letterSpacing="0.22em"
|
|
1562
|
+
textAnchor="middle"
|
|
1563
|
+
>
|
|
1564
|
+
THE PALACE
|
|
1565
|
+
</text>
|
|
1566
|
+
</g>
|
|
1567
|
+
|
|
1568
|
+
{/* ───── Curved bezier connectors — palace → wings ───── */}
|
|
1569
|
+
<g
|
|
1570
|
+
fill="none"
|
|
1571
|
+
stroke="url(#connector)"
|
|
1572
|
+
strokeWidth={1.6}
|
|
1573
|
+
strokeDasharray="4 6"
|
|
1574
|
+
strokeDashoffset={dashOffset}
|
|
1575
|
+
opacity={sLines * 0.85}
|
|
1576
|
+
>
|
|
1577
|
+
<path d="M460 220 C460 270, 200 270, 160 320" />
|
|
1578
|
+
<path d="M460 220 C460 280, 460 280, 460 320" />
|
|
1579
|
+
<path d="M460 220 C460 270, 720 270, 760 320" />
|
|
1580
|
+
</g>
|
|
1581
|
+
|
|
1582
|
+
{/* ───────────────── WINGS ───────────────── */}
|
|
1583
|
+
{wings.map((wing) => (
|
|
1584
|
+
<g
|
|
1585
|
+
key={wing.label}
|
|
1586
|
+
opacity={sWings}
|
|
1587
|
+
transform={`translate(${wing.cx}, ${330 + (1 - sWings) * 16})`}
|
|
1588
|
+
>
|
|
1589
|
+
{/* Ground shadow */}
|
|
1590
|
+
<ellipse cx={6} cy={142} rx={92} ry={4} fill="rgba(26,20,16,0.18)" />
|
|
1591
|
+
|
|
1592
|
+
{/* Right side panel — perspective hint (back face peeking) */}
|
|
1593
|
+
<path d="M76 0 L88 6 L88 134 L76 140 Z" fill={C.paperDeep} />
|
|
1594
|
+
|
|
1595
|
+
{/* Roof — front face + side shadow */}
|
|
1596
|
+
<path d="M-82 0 L0 -34 L82 0 Z" fill="url(#roof)" stroke={C.goldDeep} strokeWidth={1.4} />
|
|
1597
|
+
<path d="M82 0 L88 6 L0 -28 L0 -34 Z" fill={C.goldDeep} opacity={0.85} />
|
|
1598
|
+
{/* Roof crest line */}
|
|
1599
|
+
<line x1={0} y1={-34} x2={0} y2={-30} stroke={C.paperDeep} strokeWidth={1.5} />
|
|
1600
|
+
|
|
1601
|
+
{/* Building wall — front face */}
|
|
1602
|
+
<rect
|
|
1603
|
+
x={-78}
|
|
1604
|
+
y={0}
|
|
1605
|
+
width={156}
|
|
1606
|
+
height={136}
|
|
1607
|
+
fill="url(#wall)"
|
|
1608
|
+
stroke={C.goldDeep}
|
|
1609
|
+
strokeWidth={1.6}
|
|
1610
|
+
/>
|
|
1611
|
+
|
|
1612
|
+
{/* Cornice line under roof */}
|
|
1613
|
+
<line x1={-78} y1={6} x2={78} y2={6} stroke={C.goldDeep} strokeOpacity="0.4" strokeWidth={0.8} />
|
|
1614
|
+
|
|
1615
|
+
{/* Two LIT windows with radial gold glow */}
|
|
1616
|
+
{[-42, 42].map((wx) => (
|
|
1617
|
+
<g key={wx} transform={`translate(${wx - 18}, 22)`} opacity={winPulse}>
|
|
1618
|
+
{/* Frame */}
|
|
1619
|
+
<rect width={36} height={36} rx={1} fill="url(#window-glow)" stroke={C.goldDeep} strokeWidth={1.4} />
|
|
1620
|
+
{/* Mullions */}
|
|
1621
|
+
<line x1={18} y1={0} x2={18} y2={36} stroke={C.goldDeep} strokeOpacity="0.7" strokeWidth={1.1} />
|
|
1622
|
+
<line x1={0} y1={18} x2={36} y2={18} stroke={C.goldDeep} strokeOpacity="0.7" strokeWidth={1.1} />
|
|
1623
|
+
{/* Sill */}
|
|
1624
|
+
<rect x={-2} y={36} width={40} height={2.4} fill={C.goldDeep} />
|
|
1625
|
+
</g>
|
|
1626
|
+
))}
|
|
1627
|
+
|
|
1628
|
+
{/* Door */}
|
|
1629
|
+
<rect x={-12} y={88} width={24} height={48} fill={C.inkSoft} stroke={C.goldDeep} strokeWidth={1.2} />
|
|
1630
|
+
<circle cx={6} cy={113} r={1.6} fill={C.gold} />
|
|
1631
|
+
{/* Step under door */}
|
|
1632
|
+
<rect x={-16} y={134} width={32} height={2.4} fill={C.goldDeep} />
|
|
1633
|
+
|
|
1634
|
+
{/* Roof-side small chimney (right) */}
|
|
1635
|
+
<rect x={36} y={-18} width={6} height={10} fill={C.goldDeep} />
|
|
1636
|
+
|
|
1637
|
+
{/* Foundation line */}
|
|
1638
|
+
<line x1={-86} y1={138} x2={94} y2={138} stroke={C.goldDeep} strokeWidth={1} />
|
|
1639
|
+
|
|
1640
|
+
{/* Label below */}
|
|
1641
|
+
<text
|
|
1642
|
+
x={4}
|
|
1643
|
+
y={166}
|
|
1644
|
+
fill={C.inkSoft}
|
|
1645
|
+
fontFamily={MONO}
|
|
1646
|
+
fontSize={13}
|
|
1647
|
+
fontWeight={700}
|
|
1648
|
+
letterSpacing="0.16em"
|
|
1649
|
+
textAnchor="middle"
|
|
1650
|
+
>
|
|
1651
|
+
WING · {wing.label}
|
|
1652
|
+
</text>
|
|
1653
|
+
</g>
|
|
1654
|
+
))}
|
|
1655
|
+
|
|
1656
|
+
{/* ───── Connectors — middle wing → rooms ───── */}
|
|
1657
|
+
<g
|
|
1658
|
+
fill="none"
|
|
1659
|
+
stroke="url(#connector)"
|
|
1660
|
+
strokeWidth={1.4}
|
|
1661
|
+
strokeDasharray="3 5"
|
|
1662
|
+
strokeDashoffset={dashOffset * 0.7}
|
|
1663
|
+
opacity={sLines * 0.75}
|
|
1664
|
+
>
|
|
1665
|
+
<path d="M460 502 C460 540, 200 540, 160 568" />
|
|
1666
|
+
<path d="M460 502 C460 545, 460 545, 460 568" />
|
|
1667
|
+
<path d="M460 502 C460 540, 720 540, 760 568" />
|
|
1668
|
+
</g>
|
|
1669
|
+
|
|
1670
|
+
{/* ───────────────── ROOMS — engraved nameplates ───────────────── */}
|
|
1671
|
+
{rooms.map((room, i) => (
|
|
1672
|
+
<g
|
|
1673
|
+
key={room.label}
|
|
1674
|
+
opacity={sRooms}
|
|
1675
|
+
transform={`translate(${room.cx}, ${574 + (1 - sRooms) * 12})`}
|
|
1676
|
+
>
|
|
1677
|
+
{/* Drop shadow */}
|
|
1678
|
+
<ellipse cx={0} cy={70} rx={88} ry={3} fill="rgba(26,20,16,0.16)" />
|
|
1679
|
+
{/* Plaque body */}
|
|
1680
|
+
<rect
|
|
1681
|
+
x={-92}
|
|
1682
|
+
y={0}
|
|
1683
|
+
width={184}
|
|
1684
|
+
height={66}
|
|
1685
|
+
rx={6}
|
|
1686
|
+
fill="url(#plaque)"
|
|
1687
|
+
stroke={C.goldDeep}
|
|
1688
|
+
strokeWidth={1.8}
|
|
1689
|
+
/>
|
|
1690
|
+
{/* Inner inset border */}
|
|
1691
|
+
<rect
|
|
1692
|
+
x={-86}
|
|
1693
|
+
y={5}
|
|
1694
|
+
width={172}
|
|
1695
|
+
height={56}
|
|
1696
|
+
rx={4}
|
|
1697
|
+
fill="none"
|
|
1698
|
+
stroke={C.gold}
|
|
1699
|
+
strokeOpacity="0.6"
|
|
1700
|
+
strokeWidth={0.8}
|
|
1701
|
+
/>
|
|
1702
|
+
{/* Tiny corner studs */}
|
|
1703
|
+
{[
|
|
1704
|
+
[-82, 10],
|
|
1705
|
+
[82, 10],
|
|
1706
|
+
[-82, 56],
|
|
1707
|
+
[82, 56],
|
|
1708
|
+
].map(([x, y]) => (
|
|
1709
|
+
<circle key={`${x}-${y}`} cx={x} cy={y} r={1.6} fill={C.goldDeep} />
|
|
1710
|
+
))}
|
|
1711
|
+
{/* Room name in serif italic */}
|
|
1712
|
+
<text
|
|
1713
|
+
x={0}
|
|
1714
|
+
y={40}
|
|
1715
|
+
fill={C.ink}
|
|
1716
|
+
fontFamily={SERIF}
|
|
1717
|
+
fontSize={26}
|
|
1718
|
+
fontWeight={600}
|
|
1719
|
+
textAnchor="middle"
|
|
1720
|
+
fontStyle="italic"
|
|
1721
|
+
>
|
|
1722
|
+
{room.label}
|
|
1723
|
+
</text>
|
|
1724
|
+
{/* Gold underscore ornament */}
|
|
1725
|
+
<line x1={-22} y1={50} x2={22} y2={50} stroke={C.goldDeep} strokeWidth={1.4} />
|
|
1726
|
+
<circle cx={0} cy={50} r={2} fill={C.goldDeep} />
|
|
1727
|
+
{/* Tiny mono label below plaque */}
|
|
1728
|
+
<text
|
|
1729
|
+
x={0}
|
|
1730
|
+
y={86}
|
|
1731
|
+
fill={C.inkSoft}
|
|
1732
|
+
fontFamily={MONO}
|
|
1733
|
+
fontSize={11}
|
|
1734
|
+
fontWeight={700}
|
|
1735
|
+
letterSpacing="0.22em"
|
|
1736
|
+
textAnchor="middle"
|
|
1737
|
+
>
|
|
1738
|
+
ROOM · {String(i + 1).padStart(2, "0")}
|
|
1739
|
+
</text>
|
|
1740
|
+
</g>
|
|
1741
|
+
))}
|
|
1742
|
+
|
|
1743
|
+
{/* ───── Connectors — middle room → drawers (target each drawer cx + 78 mid) ───── */}
|
|
1744
|
+
<g
|
|
1745
|
+
fill="none"
|
|
1746
|
+
stroke="url(#connector)"
|
|
1747
|
+
strokeWidth={1.2}
|
|
1748
|
+
strokeDasharray="2 4"
|
|
1749
|
+
strokeDashoffset={dashOffset * 0.5}
|
|
1750
|
+
opacity={sLines * 0.65}
|
|
1751
|
+
>
|
|
1752
|
+
<path d="M460 670 C460 690, 220 690, 199 712" />
|
|
1753
|
+
<path d="M460 670 C460 695, 373 695, 373 712" />
|
|
1754
|
+
<path d="M460 670 C460 695, 547 695, 547 712" />
|
|
1755
|
+
<path d="M460 670 C460 690, 700 690, 721 712" />
|
|
1756
|
+
</g>
|
|
1757
|
+
|
|
1758
|
+
{/* ───────────────── DRAWERS — readable memory cards ───────────────── */}
|
|
1759
|
+
<g opacity={sDrawers}>
|
|
1760
|
+
{drawers.map((d, i) => (
|
|
1761
|
+
<g
|
|
1762
|
+
key={d.time}
|
|
1763
|
+
transform={`translate(${d.cx}, ${712 + (1 - sDrawers) * 8})`}
|
|
1764
|
+
>
|
|
1765
|
+
{/* Shadow */}
|
|
1766
|
+
<ellipse cx={78} cy={92} rx={76} ry={3} fill="rgba(26,20,16,0.18)" />
|
|
1767
|
+
{/* Drawer body */}
|
|
1768
|
+
<rect
|
|
1769
|
+
x={0}
|
|
1770
|
+
y={0}
|
|
1771
|
+
width={156}
|
|
1772
|
+
height={88}
|
|
1773
|
+
rx={5}
|
|
1774
|
+
fill="url(#drawer-body)"
|
|
1775
|
+
stroke={C.goldDeep}
|
|
1776
|
+
strokeWidth={1.5}
|
|
1777
|
+
/>
|
|
1778
|
+
{/* Top tab — gold strip */}
|
|
1779
|
+
<rect x={0} y={0} width={156} height={20} rx={5} fill={C.goldDeep} />
|
|
1780
|
+
<rect x={0} y={14} width={156} height={6} fill={C.goldDeep} />
|
|
1781
|
+
{/* Tab inner highlight */}
|
|
1782
|
+
<line x1={4} y1={3} x2={152} y2={3} stroke={C.gold} strokeOpacity="0.7" strokeWidth={0.8} />
|
|
1783
|
+
{/* Time label inside tab */}
|
|
1784
|
+
<text
|
|
1785
|
+
x={10}
|
|
1786
|
+
y={14}
|
|
1787
|
+
fill={C.paper}
|
|
1788
|
+
fontFamily={MONO}
|
|
1789
|
+
fontSize={10}
|
|
1790
|
+
fontWeight={700}
|
|
1791
|
+
letterSpacing="0.1em"
|
|
1792
|
+
>
|
|
1793
|
+
{d.time}
|
|
1794
|
+
</text>
|
|
1795
|
+
{/* Two pull rings */}
|
|
1796
|
+
<circle cx={56} cy={11} r={2.4} fill={C.paper} opacity={0.55} />
|
|
1797
|
+
<circle cx={108} cy={11} r={2.4} fill={C.paper} opacity={0.55} />
|
|
1798
|
+
{/* Memory body — primary line */}
|
|
1799
|
+
<text
|
|
1800
|
+
x={10}
|
|
1801
|
+
y={44}
|
|
1802
|
+
fill={C.ink}
|
|
1803
|
+
fontFamily={MONO}
|
|
1804
|
+
fontSize={12}
|
|
1805
|
+
fontWeight={700}
|
|
1806
|
+
>
|
|
1807
|
+
{d.body}
|
|
1808
|
+
</text>
|
|
1809
|
+
{/* Memory body — secondary tag */}
|
|
1810
|
+
<text
|
|
1811
|
+
x={10}
|
|
1812
|
+
y={64}
|
|
1813
|
+
fill={C.inkSoft}
|
|
1814
|
+
fontFamily={MONO}
|
|
1815
|
+
fontSize={10}
|
|
1816
|
+
fontWeight={500}
|
|
1817
|
+
opacity={0.85}
|
|
1818
|
+
>
|
|
1819
|
+
· {d.tag}
|
|
1820
|
+
</text>
|
|
1821
|
+
{/* Bottom hairline */}
|
|
1822
|
+
<line x1={6} y1={78} x2={150} y2={78} stroke={C.goldDeep} strokeOpacity="0.35" strokeWidth={0.8} />
|
|
1823
|
+
{/* Index marker */}
|
|
1824
|
+
<text
|
|
1825
|
+
x={148}
|
|
1826
|
+
y={64}
|
|
1827
|
+
fill={C.goldDeep}
|
|
1828
|
+
fontFamily={MONO}
|
|
1829
|
+
fontSize={9}
|
|
1830
|
+
fontWeight={700}
|
|
1831
|
+
textAnchor="end"
|
|
1832
|
+
opacity={0.55}
|
|
1833
|
+
>
|
|
1834
|
+
#{String(i + 1).padStart(2, "0")}
|
|
1835
|
+
</text>
|
|
1836
|
+
</g>
|
|
1837
|
+
))}
|
|
1838
|
+
{/* Caption beneath drawer row */}
|
|
1839
|
+
<g transform="translate(460, 815)">
|
|
1840
|
+
<line x1={-80} y1={0} x2={-26} y2={0} stroke={C.goldDeep} strokeOpacity="0.4" strokeWidth={1} />
|
|
1841
|
+
<line x1={26} y1={0} x2={80} y2={0} stroke={C.goldDeep} strokeOpacity="0.4" strokeWidth={1} />
|
|
1842
|
+
<text
|
|
1843
|
+
x={0}
|
|
1844
|
+
y={5}
|
|
1845
|
+
fill={C.inkSoft}
|
|
1846
|
+
fontFamily={MONO}
|
|
1847
|
+
fontSize={13}
|
|
1848
|
+
fontWeight={700}
|
|
1849
|
+
letterSpacing="0.22em"
|
|
1850
|
+
textAnchor="middle"
|
|
1851
|
+
>
|
|
1852
|
+
DRAWERS · MEMORIES
|
|
1853
|
+
</text>
|
|
1854
|
+
</g>
|
|
1855
|
+
</g>
|
|
1856
|
+
</svg>
|
|
1857
|
+
);
|
|
1858
|
+
};
|
|
1859
|
+
|
|
1860
|
+
const Scene5: React.FC = () => {
|
|
1861
|
+
const frame = useCurrentFrame();
|
|
1862
|
+
const { fps } = useVideoConfig();
|
|
1863
|
+
|
|
1864
|
+
// Pill in top
|
|
1865
|
+
const pillOp = fadeIn(frame, 0, 14);
|
|
1866
|
+
|
|
1867
|
+
// Aristotle / Cicero quote block — type each name in
|
|
1868
|
+
const aristotleOp = fadeIn(frame, 12);
|
|
1869
|
+
const ciceroOp = fadeIn(frame, 30);
|
|
1870
|
+
|
|
1871
|
+
// Headline
|
|
1872
|
+
const headOp = fadeIn(frame, 48, 18);
|
|
1873
|
+
const headY = interpolate(frame, [48, 70], [22, 0], {
|
|
1874
|
+
extrapolateLeft: "clamp",
|
|
1875
|
+
extrapolateRight: "clamp",
|
|
1876
|
+
});
|
|
1877
|
+
|
|
1878
|
+
// bottom caption — "word-for-word"
|
|
1879
|
+
const capOp = fadeIn(frame, 320);
|
|
1880
|
+
const capY = interpolate(frame, [320, 350], [16, 0], {
|
|
1881
|
+
extrapolateLeft: "clamp",
|
|
1882
|
+
extrapolateRight: "clamp",
|
|
1883
|
+
});
|
|
1884
|
+
|
|
1885
|
+
const exit = fadeOut(frame, SCENES.S5.dur - 16, 12);
|
|
1886
|
+
|
|
1887
|
+
return (
|
|
1888
|
+
<AbsoluteFill style={{ fontFamily: FONT, opacity: exit }}>
|
|
1889
|
+
<PaperBg frame={frame} />
|
|
1890
|
+
|
|
1891
|
+
{/* Pill */}
|
|
1892
|
+
<div
|
|
1893
|
+
style={{
|
|
1894
|
+
position: "absolute",
|
|
1895
|
+
top: SAFE_TOP - 20,
|
|
1896
|
+
left: 0,
|
|
1897
|
+
right: 0,
|
|
1898
|
+
textAlign: "center",
|
|
1899
|
+
opacity: pillOp,
|
|
1900
|
+
}}
|
|
1901
|
+
>
|
|
1902
|
+
<Pill bg="rgba(184,137,61,0.14)" fg={C.goldDeep} border="rgba(184,137,61,0.40)">
|
|
1903
|
+
ANCIENT GREEK · 500 BC
|
|
1904
|
+
</Pill>
|
|
1905
|
+
</div>
|
|
1906
|
+
|
|
1907
|
+
{/* Quote attributions */}
|
|
1908
|
+
<div
|
|
1909
|
+
style={{
|
|
1910
|
+
position: "absolute",
|
|
1911
|
+
top: SAFE_TOP + 40,
|
|
1912
|
+
left: 0,
|
|
1913
|
+
right: 0,
|
|
1914
|
+
textAlign: "center",
|
|
1915
|
+
fontFamily: SERIF,
|
|
1916
|
+
}}
|
|
1917
|
+
>
|
|
1918
|
+
<div
|
|
1919
|
+
style={{
|
|
1920
|
+
display: "flex",
|
|
1921
|
+
justifyContent: "center",
|
|
1922
|
+
gap: 48,
|
|
1923
|
+
fontSize: 38,
|
|
1924
|
+
color: C.inkSoft,
|
|
1925
|
+
fontStyle: "italic",
|
|
1926
|
+
}}
|
|
1927
|
+
>
|
|
1928
|
+
<span style={{ opacity: aristotleOp }}>
|
|
1929
|
+
<span style={{ color: C.gold }}>— </span>Aristotle
|
|
1930
|
+
</span>
|
|
1931
|
+
<span style={{ opacity: ciceroOp }}>
|
|
1932
|
+
<span style={{ color: C.gold }}>— </span>Cicero
|
|
1933
|
+
</span>
|
|
1934
|
+
</div>
|
|
1935
|
+
<div
|
|
1936
|
+
style={{
|
|
1937
|
+
marginTop: 4,
|
|
1938
|
+
fontSize: 22,
|
|
1939
|
+
color: C.inkSoft,
|
|
1940
|
+
opacity: aristotleOp * 0.7,
|
|
1941
|
+
fontFamily: MONO,
|
|
1942
|
+
letterSpacing: "0.12em",
|
|
1943
|
+
}}
|
|
1944
|
+
>
|
|
1945
|
+
USED THIS · 2,400 YEARS
|
|
1946
|
+
</div>
|
|
1947
|
+
</div>
|
|
1948
|
+
|
|
1949
|
+
{/* Headline */}
|
|
1950
|
+
<div
|
|
1951
|
+
style={{
|
|
1952
|
+
position: "absolute",
|
|
1953
|
+
top: 460,
|
|
1954
|
+
left: 0,
|
|
1955
|
+
right: 0,
|
|
1956
|
+
textAlign: "center",
|
|
1957
|
+
padding: "0 60px",
|
|
1958
|
+
opacity: headOp,
|
|
1959
|
+
transform: `translateY(${headY}px)`,
|
|
1960
|
+
}}
|
|
1961
|
+
>
|
|
1962
|
+
<div
|
|
1963
|
+
style={{
|
|
1964
|
+
fontSize: 64,
|
|
1965
|
+
fontWeight: 700,
|
|
1966
|
+
color: C.ink,
|
|
1967
|
+
letterSpacing: "-0.035em",
|
|
1968
|
+
lineHeight: 1.0,
|
|
1969
|
+
}}
|
|
1970
|
+
>
|
|
1971
|
+
Your projects become<br />
|
|
1972
|
+
<span style={{ fontFamily: SERIF, fontStyle: "italic", color: C.goldDeep }}>
|
|
1973
|
+
a building you can walk.
|
|
1974
|
+
</span>
|
|
1975
|
+
</div>
|
|
1976
|
+
</div>
|
|
1977
|
+
|
|
1978
|
+
{/* Architecture diagram */}
|
|
1979
|
+
<ArchitectureDiagram frame={frame} fps={fps} />
|
|
1980
|
+
|
|
1981
|
+
{/* Bottom caption — "word-for-word" */}
|
|
1982
|
+
<div
|
|
1983
|
+
style={{
|
|
1984
|
+
position: "absolute",
|
|
1985
|
+
left: 0,
|
|
1986
|
+
right: 0,
|
|
1987
|
+
top: 1410,
|
|
1988
|
+
textAlign: "center",
|
|
1989
|
+
opacity: capOp,
|
|
1990
|
+
transform: `translateY(${capY}px)`,
|
|
1991
|
+
padding: "0 60px",
|
|
1992
|
+
}}
|
|
1993
|
+
>
|
|
1994
|
+
<div
|
|
1995
|
+
style={{
|
|
1996
|
+
display: "inline-block",
|
|
1997
|
+
padding: "20px 32px",
|
|
1998
|
+
background: "rgba(26,20,16,0.06)",
|
|
1999
|
+
border: `1px solid rgba(184,137,61,0.30)`,
|
|
2000
|
+
borderRadius: 16,
|
|
2001
|
+
fontFamily: MONO,
|
|
2002
|
+
fontSize: 28,
|
|
2003
|
+
color: C.ink,
|
|
2004
|
+
fontWeight: 600,
|
|
2005
|
+
letterSpacing: "-0.01em",
|
|
2006
|
+
}}
|
|
2007
|
+
>
|
|
2008
|
+
word-for-word · <span style={{ color: C.goldDeep }}>open on demand</span>
|
|
2009
|
+
</div>
|
|
2010
|
+
</div>
|
|
2011
|
+
</AbsoluteFill>
|
|
2012
|
+
);
|
|
2013
|
+
};
|
|
2014
|
+
|
|
2015
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2016
|
+
// SCENE 6 — THE HOOK MAGIC (with screen recording)
|
|
2017
|
+
// "There's a hook that fires right before context compaction.
|
|
2018
|
+
// this setup already saved it. Locally."
|
|
2019
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2020
|
+
|
|
2021
|
+
const Scene6: React.FC = () => {
|
|
2022
|
+
const frame = useCurrentFrame();
|
|
2023
|
+
const { fps } = useVideoConfig();
|
|
2024
|
+
|
|
2025
|
+
// Title
|
|
2026
|
+
const titleOp = fadeIn(frame, 0, 14);
|
|
2027
|
+
const titleY = interpolate(frame, [0, 18], [22, 0], {
|
|
2028
|
+
extrapolateLeft: "clamp",
|
|
2029
|
+
extrapolateRight: "clamp",
|
|
2030
|
+
});
|
|
2031
|
+
|
|
2032
|
+
// Hook diagram pop in
|
|
2033
|
+
const hookSpring = sp(frame, fps, 1.5, "snappy");
|
|
2034
|
+
const hookOp = interpolate(hookSpring, [0, 0.4], [0, 1], {
|
|
2035
|
+
extrapolateLeft: "clamp",
|
|
2036
|
+
extrapolateRight: "clamp",
|
|
2037
|
+
});
|
|
2038
|
+
const hookY = interpolate(hookSpring, [0, 1], [40, 0]);
|
|
2039
|
+
|
|
2040
|
+
// Locally pill — 7s
|
|
2041
|
+
const localOp = fadeIn(frame, 230);
|
|
2042
|
+
const localY = interpolate(frame, [230, 255], [22, 0], {
|
|
2043
|
+
extrapolateLeft: "clamp",
|
|
2044
|
+
extrapolateRight: "clamp",
|
|
2045
|
+
});
|
|
2046
|
+
|
|
2047
|
+
// Pulse on the hook arrow
|
|
2048
|
+
const pulse = (Math.sin(frame * 0.18) + 1) * 0.5;
|
|
2049
|
+
|
|
2050
|
+
const exit = fadeOut(frame, SCENES.S6.dur - 16, 12);
|
|
2051
|
+
|
|
2052
|
+
return (
|
|
2053
|
+
<AbsoluteFill style={{ fontFamily: FONT, opacity: exit }}>
|
|
2054
|
+
<DarkBg frame={frame} tint="emerald" />
|
|
2055
|
+
|
|
2056
|
+
{/* Title */}
|
|
2057
|
+
<div
|
|
2058
|
+
style={{
|
|
2059
|
+
position: "absolute",
|
|
2060
|
+
top: SAFE_TOP - 8,
|
|
2061
|
+
left: 0,
|
|
2062
|
+
right: 0,
|
|
2063
|
+
textAlign: "center",
|
|
2064
|
+
opacity: titleOp,
|
|
2065
|
+
transform: `translateY(${titleY}px)`,
|
|
2066
|
+
padding: "0 60px",
|
|
2067
|
+
}}
|
|
2068
|
+
>
|
|
2069
|
+
<Pill bg="rgba(0,210,148,0.10)" fg={C.emerald} border="rgba(0,210,148,0.35)" dot={C.emerald}>
|
|
2070
|
+
THE PRE-COMPACTION HOOK
|
|
2071
|
+
</Pill>
|
|
2072
|
+
<div
|
|
2073
|
+
style={{
|
|
2074
|
+
marginTop: 22,
|
|
2075
|
+
fontSize: 60,
|
|
2076
|
+
fontWeight: 700,
|
|
2077
|
+
color: C.fg,
|
|
2078
|
+
letterSpacing: "-0.035em",
|
|
2079
|
+
lineHeight: 1.05,
|
|
2080
|
+
}}
|
|
2081
|
+
>
|
|
2082
|
+
Fires the second Claude<br />
|
|
2083
|
+
is <span style={{ color: C.emerald }}>about to forget.</span>
|
|
2084
|
+
</div>
|
|
2085
|
+
</div>
|
|
2086
|
+
|
|
2087
|
+
{/* Hook flow diagram */}
|
|
2088
|
+
<Sequence from={50} durationInFrames={SCENES.S6.dur}>
|
|
2089
|
+
<AbsoluteFill style={{ opacity: hookOp, transform: `translateY(${hookY}px)` }}>
|
|
2090
|
+
<HookFlowDiagram frame={frame - 50} pulse={pulse} />
|
|
2091
|
+
</AbsoluteFill>
|
|
2092
|
+
</Sequence>
|
|
2093
|
+
|
|
2094
|
+
{/* Screen recording */}
|
|
2095
|
+
<Sequence from={120} durationInFrames={SCENES.S6.dur - 120}>
|
|
2096
|
+
<ScreenRecording />
|
|
2097
|
+
</Sequence>
|
|
2098
|
+
|
|
2099
|
+
{/* Bottom locally pill */}
|
|
2100
|
+
<div
|
|
2101
|
+
style={{
|
|
2102
|
+
position: "absolute",
|
|
2103
|
+
left: 0,
|
|
2104
|
+
right: 0,
|
|
2105
|
+
bottom: H - SAFE_BOT_Y + 40,
|
|
2106
|
+
display: "flex",
|
|
2107
|
+
justifyContent: "center",
|
|
2108
|
+
gap: 16,
|
|
2109
|
+
opacity: localOp,
|
|
2110
|
+
transform: `translateY(${localY}px)`,
|
|
2111
|
+
}}
|
|
2112
|
+
>
|
|
2113
|
+
<Pill bg="rgba(0,210,148,0.12)" fg={C.emerald} border="rgba(0,210,148,0.40)" dot={C.emerald} size={24}>
|
|
2114
|
+
SAVED LOCALLY · 0 NETWORK
|
|
2115
|
+
</Pill>
|
|
2116
|
+
</div>
|
|
2117
|
+
</AbsoluteFill>
|
|
2118
|
+
);
|
|
2119
|
+
};
|
|
2120
|
+
|
|
2121
|
+
const HookFlowDiagram: React.FC<{ frame: number; pulse: number }> = ({
|
|
2122
|
+
frame,
|
|
2123
|
+
pulse,
|
|
2124
|
+
}) => {
|
|
2125
|
+
// 3-step pipe diagram: [CTX FULL] → [HOOK FIRES] → [SAVED]
|
|
2126
|
+
const t1 = tween(frame, 0, 16, 0, 1);
|
|
2127
|
+
const t2 = tween(frame, 24, 16, 0, 1);
|
|
2128
|
+
const t3 = tween(frame, 50, 16, 0, 1);
|
|
2129
|
+
|
|
2130
|
+
return (
|
|
2131
|
+
<div
|
|
2132
|
+
style={{
|
|
2133
|
+
position: "absolute",
|
|
2134
|
+
top: 540,
|
|
2135
|
+
left: 60,
|
|
2136
|
+
right: 60,
|
|
2137
|
+
display: "flex",
|
|
2138
|
+
flexDirection: "column",
|
|
2139
|
+
gap: 18,
|
|
2140
|
+
}}
|
|
2141
|
+
>
|
|
2142
|
+
{/* Row 1 — CTX FULL */}
|
|
2143
|
+
<div
|
|
2144
|
+
style={{
|
|
2145
|
+
opacity: t1,
|
|
2146
|
+
transform: `translateY(${(1 - t1) * 14}px)`,
|
|
2147
|
+
background: C.surface,
|
|
2148
|
+
border: `1px solid ${C.borderLoud}`,
|
|
2149
|
+
borderRadius: 18,
|
|
2150
|
+
padding: "20px 24px",
|
|
2151
|
+
display: "flex",
|
|
2152
|
+
alignItems: "center",
|
|
2153
|
+
gap: 16,
|
|
2154
|
+
fontFamily: MONO,
|
|
2155
|
+
color: C.fgSoft,
|
|
2156
|
+
}}
|
|
2157
|
+
>
|
|
2158
|
+
<div
|
|
2159
|
+
style={{
|
|
2160
|
+
width: 12,
|
|
2161
|
+
height: 12,
|
|
2162
|
+
borderRadius: 999,
|
|
2163
|
+
background: "#fcbb00",
|
|
2164
|
+
boxShadow: "0 0 14px rgba(252,187,0,0.45)",
|
|
2165
|
+
}}
|
|
2166
|
+
/>
|
|
2167
|
+
<div style={{ fontSize: 22, fontWeight: 600, letterSpacing: "0.04em" }}>
|
|
2168
|
+
context window · 98% full
|
|
2169
|
+
</div>
|
|
2170
|
+
<div
|
|
2171
|
+
style={{
|
|
2172
|
+
marginLeft: "auto",
|
|
2173
|
+
display: "flex",
|
|
2174
|
+
alignItems: "center",
|
|
2175
|
+
gap: 6,
|
|
2176
|
+
color: "#fcbb00",
|
|
2177
|
+
fontSize: 18,
|
|
2178
|
+
fontWeight: 600,
|
|
2179
|
+
}}
|
|
2180
|
+
>
|
|
2181
|
+
<span style={{ width: 80, height: 6, borderRadius: 999, background: "rgba(255,255,255,0.06)", overflow: "hidden", display: "inline-block" }}>
|
|
2182
|
+
<span
|
|
2183
|
+
style={{
|
|
2184
|
+
display: "block",
|
|
2185
|
+
width: "98%",
|
|
2186
|
+
height: "100%",
|
|
2187
|
+
background: "linear-gradient(90deg, #fcbb00, #ef4444)",
|
|
2188
|
+
}}
|
|
2189
|
+
/>
|
|
2190
|
+
</span>
|
|
2191
|
+
</div>
|
|
2192
|
+
</div>
|
|
2193
|
+
|
|
2194
|
+
{/* Arrow + HOOK */}
|
|
2195
|
+
<div
|
|
2196
|
+
style={{
|
|
2197
|
+
opacity: t2,
|
|
2198
|
+
display: "flex",
|
|
2199
|
+
flexDirection: "column",
|
|
2200
|
+
alignItems: "center",
|
|
2201
|
+
gap: 10,
|
|
2202
|
+
transform: `translateY(${(1 - t2) * 14}px)`,
|
|
2203
|
+
}}
|
|
2204
|
+
>
|
|
2205
|
+
<div
|
|
2206
|
+
style={{
|
|
2207
|
+
width: 4,
|
|
2208
|
+
height: 36,
|
|
2209
|
+
background: `linear-gradient(${C.fgDim}, ${C.emerald})`,
|
|
2210
|
+
borderRadius: 999,
|
|
2211
|
+
}}
|
|
2212
|
+
/>
|
|
2213
|
+
<div
|
|
2214
|
+
style={{
|
|
2215
|
+
display: "flex",
|
|
2216
|
+
alignItems: "center",
|
|
2217
|
+
gap: 14,
|
|
2218
|
+
padding: "16px 28px",
|
|
2219
|
+
background: `linear-gradient(135deg, rgba(0,210,148,0.18), rgba(0,135,90,0.12))`,
|
|
2220
|
+
border: `1px solid rgba(0,210,148,${0.4 + pulse * 0.3})`,
|
|
2221
|
+
borderRadius: 999,
|
|
2222
|
+
fontFamily: MONO,
|
|
2223
|
+
color: C.emerald,
|
|
2224
|
+
fontWeight: 700,
|
|
2225
|
+
fontSize: 24,
|
|
2226
|
+
letterSpacing: "0.05em",
|
|
2227
|
+
boxShadow: `0 0 ${30 + pulse * 30}px rgba(0,210,148,${0.18 + pulse * 0.12})`,
|
|
2228
|
+
}}
|
|
2229
|
+
>
|
|
2230
|
+
{/* Inline hook icon — emerald, no external file */}
|
|
2231
|
+
<svg width={26} height={26} viewBox="0 0 24 24" fill="none">
|
|
2232
|
+
<path
|
|
2233
|
+
d="M12 3 L12 13 A4 4 0 1 1 8 17"
|
|
2234
|
+
stroke={C.emerald}
|
|
2235
|
+
strokeWidth={2.4}
|
|
2236
|
+
strokeLinecap="round"
|
|
2237
|
+
strokeLinejoin="round"
|
|
2238
|
+
/>
|
|
2239
|
+
<circle cx={12} cy={3} r={1.6} fill={C.emerald} />
|
|
2240
|
+
</svg>
|
|
2241
|
+
PRE-COMPACTION HOOK FIRES
|
|
2242
|
+
</div>
|
|
2243
|
+
<div
|
|
2244
|
+
style={{
|
|
2245
|
+
width: 4,
|
|
2246
|
+
height: 36,
|
|
2247
|
+
background: `linear-gradient(${C.emerald}, ${C.fgDim})`,
|
|
2248
|
+
borderRadius: 999,
|
|
2249
|
+
}}
|
|
2250
|
+
/>
|
|
2251
|
+
</div>
|
|
2252
|
+
|
|
2253
|
+
{/* SAVED */}
|
|
2254
|
+
<div
|
|
2255
|
+
style={{
|
|
2256
|
+
opacity: t3,
|
|
2257
|
+
transform: `translateY(${(1 - t3) * 14}px)`,
|
|
2258
|
+
background: `linear-gradient(135deg, rgba(0,210,148,0.08), rgba(0,135,90,0.04))`,
|
|
2259
|
+
border: `1px solid rgba(0,210,148,0.35)`,
|
|
2260
|
+
borderRadius: 18,
|
|
2261
|
+
padding: "20px 24px",
|
|
2262
|
+
display: "flex",
|
|
2263
|
+
alignItems: "center",
|
|
2264
|
+
gap: 16,
|
|
2265
|
+
fontFamily: MONO,
|
|
2266
|
+
color: C.fg,
|
|
2267
|
+
}}
|
|
2268
|
+
>
|
|
2269
|
+
<Img
|
|
2270
|
+
src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
|
|
2271
|
+
style={{
|
|
2272
|
+
width: 28,
|
|
2273
|
+
height: 28,
|
|
2274
|
+
filter: "brightness(0) saturate(100%) invert(72%) sepia(76%) saturate(363%) hue-rotate(95deg) brightness(91%) contrast(86%)",
|
|
2275
|
+
}}
|
|
2276
|
+
/>
|
|
2277
|
+
<div style={{ fontSize: 22, fontWeight: 600, letterSpacing: "0.04em" }}>
|
|
2278
|
+
memory persisted · ~/.mempalace/
|
|
2279
|
+
</div>
|
|
2280
|
+
</div>
|
|
2281
|
+
</div>
|
|
2282
|
+
);
|
|
2283
|
+
};
|
|
2284
|
+
|
|
2285
|
+
// Screen recording placed in stylized terminal frame
|
|
2286
|
+
const ScreenRecording: React.FC = () => {
|
|
2287
|
+
const frame = useCurrentFrame();
|
|
2288
|
+
|
|
2289
|
+
// mempalace.mov is 7.15s × 60fps = 545 native frames; we'll loop using OffthreadVideo
|
|
2290
|
+
const op = fadeIn(frame, 0, 18);
|
|
2291
|
+
const enterY = interpolate(frame, [0, 24], [40, 0], {
|
|
2292
|
+
extrapolateLeft: "clamp",
|
|
2293
|
+
extrapolateRight: "clamp",
|
|
2294
|
+
});
|
|
2295
|
+
|
|
2296
|
+
return (
|
|
2297
|
+
<AbsoluteFill
|
|
2298
|
+
style={{
|
|
2299
|
+
opacity: op,
|
|
2300
|
+
transform: `translateY(${enterY}px)`,
|
|
2301
|
+
}}
|
|
2302
|
+
>
|
|
2303
|
+
<div
|
|
2304
|
+
style={{
|
|
2305
|
+
position: "absolute",
|
|
2306
|
+
top: 1010,
|
|
2307
|
+
left: 80,
|
|
2308
|
+
right: 80,
|
|
2309
|
+
height: 460,
|
|
2310
|
+
borderRadius: 22,
|
|
2311
|
+
overflow: "hidden",
|
|
2312
|
+
background: C.surface,
|
|
2313
|
+
border: `1px solid ${C.borderLoud}`,
|
|
2314
|
+
boxShadow:
|
|
2315
|
+
"0 30px 80px -10px rgba(0,0,0,0.6), inset 0 1px 0 rgba(255,255,255,0.06)",
|
|
2316
|
+
}}
|
|
2317
|
+
>
|
|
2318
|
+
{/* title bar */}
|
|
2319
|
+
<div
|
|
2320
|
+
style={{
|
|
2321
|
+
display: "flex",
|
|
2322
|
+
alignItems: "center",
|
|
2323
|
+
gap: 10,
|
|
2324
|
+
padding: "14px 20px",
|
|
2325
|
+
background: "rgba(255,255,255,0.04)",
|
|
2326
|
+
borderBottom: `1px solid ${C.border}`,
|
|
2327
|
+
}}
|
|
2328
|
+
>
|
|
2329
|
+
<div style={{ width: 11, height: 11, borderRadius: 999, background: "#ff5f57" }} />
|
|
2330
|
+
<div style={{ width: 11, height: 11, borderRadius: 999, background: "#febc2e" }} />
|
|
2331
|
+
<div style={{ width: 11, height: 11, borderRadius: 999, background: "#28c840" }} />
|
|
2332
|
+
<div
|
|
2333
|
+
style={{
|
|
2334
|
+
marginLeft: 14,
|
|
2335
|
+
fontFamily: MONO,
|
|
2336
|
+
fontSize: 16,
|
|
2337
|
+
color: C.fgMuted,
|
|
2338
|
+
letterSpacing: "0.05em",
|
|
2339
|
+
}}
|
|
2340
|
+
>
|
|
2341
|
+
~/.mempalace · live
|
|
2342
|
+
</div>
|
|
2343
|
+
<div
|
|
2344
|
+
style={{
|
|
2345
|
+
marginLeft: "auto",
|
|
2346
|
+
display: "flex",
|
|
2347
|
+
alignItems: "center",
|
|
2348
|
+
gap: 6,
|
|
2349
|
+
fontFamily: MONO,
|
|
2350
|
+
fontSize: 14,
|
|
2351
|
+
color: C.emerald,
|
|
2352
|
+
letterSpacing: "0.1em",
|
|
2353
|
+
fontWeight: 600,
|
|
2354
|
+
}}
|
|
2355
|
+
>
|
|
2356
|
+
<span
|
|
2357
|
+
style={{
|
|
2358
|
+
width: 6,
|
|
2359
|
+
height: 6,
|
|
2360
|
+
borderRadius: 999,
|
|
2361
|
+
background: C.emerald,
|
|
2362
|
+
boxShadow: `0 0 8px ${C.emerald}`,
|
|
2363
|
+
}}
|
|
2364
|
+
/>
|
|
2365
|
+
REC
|
|
2366
|
+
</div>
|
|
2367
|
+
</div>
|
|
2368
|
+
{/* video */}
|
|
2369
|
+
<div style={{ position: "relative", width: "100%", height: "100%", background: "#000" }}>
|
|
2370
|
+
{/* REFERENCE-STRIP: <OffthreadVideo> removed — bring your own clip */}
|
|
2371
|
+
{/* subtle scanline overlay for "screen rec" feel */}
|
|
2372
|
+
<div
|
|
2373
|
+
style={{
|
|
2374
|
+
position: "absolute",
|
|
2375
|
+
inset: 0,
|
|
2376
|
+
backgroundImage: `repeating-linear-gradient(0deg, rgba(255,255,255,0.03) 0px, rgba(255,255,255,0.03) 1px, transparent 1px, transparent 3px)`,
|
|
2377
|
+
pointerEvents: "none",
|
|
2378
|
+
mixBlendMode: "overlay",
|
|
2379
|
+
}}
|
|
2380
|
+
/>
|
|
2381
|
+
</div>
|
|
2382
|
+
</div>
|
|
2383
|
+
</AbsoluteFill>
|
|
2384
|
+
);
|
|
2385
|
+
};
|
|
2386
|
+
|
|
2387
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2388
|
+
// SCENE 7 — SOCIAL PROOF
|
|
2389
|
+
// "Zero-Human Company · 79 employees · USC professor · locally · 0 API · 0 sub · MIT"
|
|
2390
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2391
|
+
|
|
2392
|
+
const Scene7: React.FC = () => {
|
|
2393
|
+
const frame = useCurrentFrame();
|
|
2394
|
+
const { fps } = useVideoConfig();
|
|
2395
|
+
|
|
2396
|
+
// Pill in
|
|
2397
|
+
const titleOp = fadeIn(frame, 0, 14);
|
|
2398
|
+
const titleY = interpolate(frame, [0, 18], [22, 0], {
|
|
2399
|
+
extrapolateLeft: "clamp",
|
|
2400
|
+
extrapolateRight: "clamp",
|
|
2401
|
+
});
|
|
2402
|
+
|
|
2403
|
+
// 79 counter
|
|
2404
|
+
const seventyNineCount = Math.round(tween(frame, 30, 40, 0, 79));
|
|
2405
|
+
|
|
2406
|
+
// Stagger the 6 stat cards
|
|
2407
|
+
const cards = [
|
|
2408
|
+
{
|
|
2409
|
+
kicker: "DEPLOYED AT",
|
|
2410
|
+
head: "Zero-Human Co.",
|
|
2411
|
+
sub: `${seventyNineCount} employees`,
|
|
2412
|
+
tint: C.emerald,
|
|
2413
|
+
delay: 0.5,
|
|
2414
|
+
mono: false,
|
|
2415
|
+
},
|
|
2416
|
+
{
|
|
2417
|
+
kicker: "ARCHITECTURE",
|
|
2418
|
+
head: "USC professor",
|
|
2419
|
+
sub: "blessed",
|
|
2420
|
+
tint: "#fcbb00",
|
|
2421
|
+
delay: 1.0,
|
|
2422
|
+
mono: false,
|
|
2423
|
+
},
|
|
2424
|
+
{
|
|
2425
|
+
kicker: "RUNTIME",
|
|
2426
|
+
head: "100% local",
|
|
2427
|
+
sub: "no cloud",
|
|
2428
|
+
tint: C.emerald,
|
|
2429
|
+
delay: 1.5,
|
|
2430
|
+
mono: false,
|
|
2431
|
+
},
|
|
2432
|
+
{
|
|
2433
|
+
kicker: "API CALLS",
|
|
2434
|
+
head: "0",
|
|
2435
|
+
sub: "zero outbound",
|
|
2436
|
+
tint: C.emerald,
|
|
2437
|
+
delay: 2.0,
|
|
2438
|
+
mono: true,
|
|
2439
|
+
},
|
|
2440
|
+
{
|
|
2441
|
+
kicker: "SUBSCRIPTION",
|
|
2442
|
+
head: "$0",
|
|
2443
|
+
sub: "forever",
|
|
2444
|
+
tint: C.emerald,
|
|
2445
|
+
delay: 2.5,
|
|
2446
|
+
mono: true,
|
|
2447
|
+
},
|
|
2448
|
+
{
|
|
2449
|
+
kicker: "LICENSE",
|
|
2450
|
+
head: "MIT",
|
|
2451
|
+
sub: "fork it",
|
|
2452
|
+
tint: C.indigo,
|
|
2453
|
+
delay: 3.0,
|
|
2454
|
+
mono: true,
|
|
2455
|
+
},
|
|
2456
|
+
];
|
|
2457
|
+
|
|
2458
|
+
const exit = fadeOut(frame, SCENES.S7.dur - 16, 12);
|
|
2459
|
+
|
|
2460
|
+
return (
|
|
2461
|
+
<AbsoluteFill style={{ fontFamily: FONT, opacity: exit }}>
|
|
2462
|
+
<DarkBg frame={frame} tint="emerald" />
|
|
2463
|
+
|
|
2464
|
+
{/* Title */}
|
|
2465
|
+
<div
|
|
2466
|
+
style={{
|
|
2467
|
+
position: "absolute",
|
|
2468
|
+
top: SAFE_TOP - 8,
|
|
2469
|
+
left: 0,
|
|
2470
|
+
right: 0,
|
|
2471
|
+
textAlign: "center",
|
|
2472
|
+
opacity: titleOp,
|
|
2473
|
+
transform: `translateY(${titleY}px)`,
|
|
2474
|
+
padding: "0 60px",
|
|
2475
|
+
}}
|
|
2476
|
+
>
|
|
2477
|
+
<Pill bg="rgba(0,210,148,0.10)" fg={C.emerald} border="rgba(0,210,148,0.35)" dot={C.emerald}>
|
|
2478
|
+
SHIPPED · APPROVED · OPEN
|
|
2479
|
+
</Pill>
|
|
2480
|
+
<div
|
|
2481
|
+
style={{
|
|
2482
|
+
marginTop: 22,
|
|
2483
|
+
fontSize: 64,
|
|
2484
|
+
fontWeight: 700,
|
|
2485
|
+
color: C.fg,
|
|
2486
|
+
letterSpacing: "-0.035em",
|
|
2487
|
+
lineHeight: 1.05,
|
|
2488
|
+
}}
|
|
2489
|
+
>
|
|
2490
|
+
Already in production.<br />
|
|
2491
|
+
<span style={{ color: C.fgMuted }}>Reviewed.</span>
|
|
2492
|
+
<span style={{ color: C.fg }}> Free.</span>
|
|
2493
|
+
</div>
|
|
2494
|
+
</div>
|
|
2495
|
+
|
|
2496
|
+
{/* Stat grid 2x3 */}
|
|
2497
|
+
<div
|
|
2498
|
+
style={{
|
|
2499
|
+
position: "absolute",
|
|
2500
|
+
top: 660,
|
|
2501
|
+
left: 60,
|
|
2502
|
+
right: 60,
|
|
2503
|
+
display: "grid",
|
|
2504
|
+
gridTemplateColumns: "1fr 1fr",
|
|
2505
|
+
gap: 16,
|
|
2506
|
+
}}
|
|
2507
|
+
>
|
|
2508
|
+
{cards.map((c, i) => {
|
|
2509
|
+
const cs = sp(frame, fps, c.delay, "snappy");
|
|
2510
|
+
const op = interpolate(cs, [0, 0.4], [0, 1], {
|
|
2511
|
+
extrapolateLeft: "clamp",
|
|
2512
|
+
extrapolateRight: "clamp",
|
|
2513
|
+
});
|
|
2514
|
+
const y = interpolate(cs, [0, 1], [40, 0]);
|
|
2515
|
+
return (
|
|
2516
|
+
<div
|
|
2517
|
+
key={c.kicker}
|
|
2518
|
+
style={{
|
|
2519
|
+
opacity: op,
|
|
2520
|
+
transform: `translateY(${y}px)`,
|
|
2521
|
+
background: C.surface,
|
|
2522
|
+
border: `1px solid ${C.borderLoud}`,
|
|
2523
|
+
borderRadius: 22,
|
|
2524
|
+
padding: "26px 26px",
|
|
2525
|
+
position: "relative",
|
|
2526
|
+
overflow: "hidden",
|
|
2527
|
+
boxShadow: "0 18px 50px -10px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.05)",
|
|
2528
|
+
}}
|
|
2529
|
+
>
|
|
2530
|
+
{/* tint bar */}
|
|
2531
|
+
<div
|
|
2532
|
+
style={{
|
|
2533
|
+
position: "absolute",
|
|
2534
|
+
left: 0,
|
|
2535
|
+
top: 0,
|
|
2536
|
+
bottom: 0,
|
|
2537
|
+
width: 4,
|
|
2538
|
+
background: c.tint,
|
|
2539
|
+
}}
|
|
2540
|
+
/>
|
|
2541
|
+
<div
|
|
2542
|
+
style={{
|
|
2543
|
+
fontFamily: MONO,
|
|
2544
|
+
fontSize: 14,
|
|
2545
|
+
color: c.tint,
|
|
2546
|
+
letterSpacing: "0.16em",
|
|
2547
|
+
fontWeight: 600,
|
|
2548
|
+
}}
|
|
2549
|
+
>
|
|
2550
|
+
{c.kicker}
|
|
2551
|
+
</div>
|
|
2552
|
+
<div
|
|
2553
|
+
style={{
|
|
2554
|
+
marginTop: 10,
|
|
2555
|
+
fontSize: c.mono ? 84 : 44,
|
|
2556
|
+
fontFamily: c.mono ? MONO : FONT,
|
|
2557
|
+
fontWeight: c.mono ? 700 : 700,
|
|
2558
|
+
color: C.fg,
|
|
2559
|
+
letterSpacing: "-0.04em",
|
|
2560
|
+
lineHeight: 1,
|
|
2561
|
+
}}
|
|
2562
|
+
>
|
|
2563
|
+
{c.head}
|
|
2564
|
+
</div>
|
|
2565
|
+
<div
|
|
2566
|
+
style={{
|
|
2567
|
+
marginTop: 10,
|
|
2568
|
+
fontSize: 22,
|
|
2569
|
+
color: C.fgMuted,
|
|
2570
|
+
fontWeight: 500,
|
|
2571
|
+
letterSpacing: "-0.01em",
|
|
2572
|
+
}}
|
|
2573
|
+
>
|
|
2574
|
+
{c.sub}
|
|
2575
|
+
</div>
|
|
2576
|
+
</div>
|
|
2577
|
+
);
|
|
2578
|
+
})}
|
|
2579
|
+
</div>
|
|
2580
|
+
</AbsoluteFill>
|
|
2581
|
+
);
|
|
2582
|
+
};
|
|
2583
|
+
|
|
2584
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2585
|
+
// SCENE 8 — CTA
|
|
2586
|
+
// "Comment 'AI' below and I'll share the official GitHub repo plus
|
|
2587
|
+
// the Claude Code setup. Once Claude actually remembers what you taught it...
|
|
2588
|
+
// you're done with every other memory tool."
|
|
2589
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2590
|
+
|
|
2591
|
+
const Scene8: React.FC = () => {
|
|
2592
|
+
const frame = useCurrentFrame();
|
|
2593
|
+
const { fps } = useVideoConfig();
|
|
2594
|
+
|
|
2595
|
+
// Headline letters
|
|
2596
|
+
const head = "COMMENT";
|
|
2597
|
+
|
|
2598
|
+
// 'AI' — gradient + WebkitBackgroundClip do not propagate to per-letter
|
|
2599
|
+
// child spans, so animate as a single unit via parent transform
|
|
2600
|
+
const aiSpring = sp(frame, fps, 0.55, "bouncy");
|
|
2601
|
+
const aiOp = interpolate(aiSpring, [0, 0.4], [0, 1], {
|
|
2602
|
+
extrapolateLeft: "clamp",
|
|
2603
|
+
extrapolateRight: "clamp",
|
|
2604
|
+
});
|
|
2605
|
+
const aiY = interpolate(aiSpring, [0, 1], [50, 0]);
|
|
2606
|
+
const aiScale = interpolate(aiSpring, [0, 0.55, 1], [0.7, 1.1, 1]);
|
|
2607
|
+
|
|
2608
|
+
// Big CTA in
|
|
2609
|
+
const subOp = fadeIn(frame, 36);
|
|
2610
|
+
const subY = interpolate(frame, [36, 60], [22, 0], {
|
|
2611
|
+
extrapolateLeft: "clamp",
|
|
2612
|
+
extrapolateRight: "clamp",
|
|
2613
|
+
});
|
|
2614
|
+
|
|
2615
|
+
// payload chips
|
|
2616
|
+
const c1 = sp(frame, fps, 1.6, "snappy");
|
|
2617
|
+
const c2 = sp(frame, fps, 1.9, "snappy");
|
|
2618
|
+
|
|
2619
|
+
// closer line
|
|
2620
|
+
const closerOp = fadeIn(frame, 96);
|
|
2621
|
+
const closerY = interpolate(frame, [96, 124], [22, 0], {
|
|
2622
|
+
extrapolateLeft: "clamp",
|
|
2623
|
+
extrapolateRight: "clamp",
|
|
2624
|
+
});
|
|
2625
|
+
|
|
2626
|
+
// arrow bounce — points to comment area
|
|
2627
|
+
const arrowAt = 150;
|
|
2628
|
+
const arrowOp = fadeIn(frame, arrowAt, 12);
|
|
2629
|
+
const arrowBounce = (Math.sin((frame - arrowAt) * 0.18) + 1) * 0.5;
|
|
2630
|
+
const arrowY = arrowBounce * 14;
|
|
2631
|
+
|
|
2632
|
+
return (
|
|
2633
|
+
<AbsoluteFill style={{ fontFamily: FONT }}>
|
|
2634
|
+
<DarkBg frame={frame} tint="indigo" />
|
|
2635
|
+
|
|
2636
|
+
{/* Top context */}
|
|
2637
|
+
<div
|
|
2638
|
+
style={{
|
|
2639
|
+
position: "absolute",
|
|
2640
|
+
top: SAFE_TOP - 10,
|
|
2641
|
+
left: 0,
|
|
2642
|
+
right: 0,
|
|
2643
|
+
textAlign: "center",
|
|
2644
|
+
opacity: fadeIn(frame, 0, 12),
|
|
2645
|
+
}}
|
|
2646
|
+
>
|
|
2647
|
+
<Pill bg="rgba(98,95,255,0.12)" fg="#a4b3ff" border="rgba(98,95,255,0.40)" dot={C.indigo}>
|
|
2648
|
+
GET THE REPO
|
|
2649
|
+
</Pill>
|
|
2650
|
+
</div>
|
|
2651
|
+
|
|
2652
|
+
{/* Big "COMMENT 'AI'" */}
|
|
2653
|
+
<div
|
|
2654
|
+
style={{
|
|
2655
|
+
position: "absolute",
|
|
2656
|
+
top: 480,
|
|
2657
|
+
left: 0,
|
|
2658
|
+
right: 0,
|
|
2659
|
+
textAlign: "center",
|
|
2660
|
+
padding: "0 50px",
|
|
2661
|
+
}}
|
|
2662
|
+
>
|
|
2663
|
+
<div
|
|
2664
|
+
style={{
|
|
2665
|
+
display: "flex",
|
|
2666
|
+
justifyContent: "center",
|
|
2667
|
+
fontSize: 156,
|
|
2668
|
+
fontWeight: 800,
|
|
2669
|
+
color: C.fg,
|
|
2670
|
+
letterSpacing: "-0.06em",
|
|
2671
|
+
lineHeight: 0.95,
|
|
2672
|
+
}}
|
|
2673
|
+
>
|
|
2674
|
+
{letterStagger(head, frame, fps, 0.05, 0.04).map((s, i) => (
|
|
2675
|
+
<span
|
|
2676
|
+
key={`h-${i}`}
|
|
2677
|
+
style={{
|
|
2678
|
+
display: "inline-block",
|
|
2679
|
+
opacity: s.opacity,
|
|
2680
|
+
transform: `translateY(${s.y}px) scale(${s.scale})`,
|
|
2681
|
+
}}
|
|
2682
|
+
>
|
|
2683
|
+
{s.ch}
|
|
2684
|
+
</span>
|
|
2685
|
+
))}
|
|
2686
|
+
</div>
|
|
2687
|
+
<div
|
|
2688
|
+
style={{
|
|
2689
|
+
marginTop: 16,
|
|
2690
|
+
fontSize: 240,
|
|
2691
|
+
fontWeight: 800,
|
|
2692
|
+
letterSpacing: "-0.07em",
|
|
2693
|
+
lineHeight: 0.92,
|
|
2694
|
+
background: `linear-gradient(135deg, ${C.indigo} 0%, #a4b3ff 100%)`,
|
|
2695
|
+
WebkitBackgroundClip: "text",
|
|
2696
|
+
backgroundClip: "text",
|
|
2697
|
+
WebkitTextFillColor: "transparent",
|
|
2698
|
+
filter: `drop-shadow(0 0 40px rgba(98,95,255,0.45))`,
|
|
2699
|
+
opacity: aiOp,
|
|
2700
|
+
transform: `translateY(${aiY}px) scale(${aiScale})`,
|
|
2701
|
+
transformOrigin: "center",
|
|
2702
|
+
}}
|
|
2703
|
+
>
|
|
2704
|
+
'AI'
|
|
2705
|
+
</div>
|
|
2706
|
+
</div>
|
|
2707
|
+
|
|
2708
|
+
{/* Sub: "I'll DM you the repo" */}
|
|
2709
|
+
<div
|
|
2710
|
+
style={{
|
|
2711
|
+
position: "absolute",
|
|
2712
|
+
top: 980,
|
|
2713
|
+
left: 0,
|
|
2714
|
+
right: 0,
|
|
2715
|
+
textAlign: "center",
|
|
2716
|
+
opacity: subOp,
|
|
2717
|
+
transform: `translateY(${subY}px)`,
|
|
2718
|
+
padding: "0 70px",
|
|
2719
|
+
}}
|
|
2720
|
+
>
|
|
2721
|
+
<div
|
|
2722
|
+
style={{
|
|
2723
|
+
fontSize: 36,
|
|
2724
|
+
color: C.fgSoft,
|
|
2725
|
+
fontWeight: 500,
|
|
2726
|
+
letterSpacing: "-0.01em",
|
|
2727
|
+
lineHeight: 1.3,
|
|
2728
|
+
}}
|
|
2729
|
+
>
|
|
2730
|
+
and I'll send you the repo +<br />
|
|
2731
|
+
one-line setup
|
|
2732
|
+
</div>
|
|
2733
|
+
</div>
|
|
2734
|
+
|
|
2735
|
+
{/* Payload chips */}
|
|
2736
|
+
<div
|
|
2737
|
+
style={{
|
|
2738
|
+
position: "absolute",
|
|
2739
|
+
top: 1130,
|
|
2740
|
+
left: 0,
|
|
2741
|
+
right: 0,
|
|
2742
|
+
display: "flex",
|
|
2743
|
+
justifyContent: "center",
|
|
2744
|
+
gap: 14,
|
|
2745
|
+
}}
|
|
2746
|
+
>
|
|
2747
|
+
<div
|
|
2748
|
+
style={{
|
|
2749
|
+
opacity: interpolate(c1, [0, 0.4], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }),
|
|
2750
|
+
transform: `translateY(${interpolate(c1, [0, 1], [20, 0])}px) scale(${interpolate(c1, [0, 0.6, 1], [0.9, 1.04, 1])})`,
|
|
2751
|
+
}}
|
|
2752
|
+
>
|
|
2753
|
+
<div
|
|
2754
|
+
style={{
|
|
2755
|
+
display: "inline-flex",
|
|
2756
|
+
alignItems: "center",
|
|
2757
|
+
gap: 12,
|
|
2758
|
+
padding: "14px 22px",
|
|
2759
|
+
background: "rgba(255,255,255,0.06)",
|
|
2760
|
+
border: `1px solid ${C.borderLoud}`,
|
|
2761
|
+
borderRadius: 999,
|
|
2762
|
+
fontFamily: MONO,
|
|
2763
|
+
fontSize: 22,
|
|
2764
|
+
color: C.fg,
|
|
2765
|
+
fontWeight: 600,
|
|
2766
|
+
}}
|
|
2767
|
+
>
|
|
2768
|
+
<Img
|
|
2769
|
+
src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
|
|
2770
|
+
style={{ width: 22, height: 22, filter: "brightness(0) invert(1)" }}
|
|
2771
|
+
/>
|
|
2772
|
+
github repo
|
|
2773
|
+
</div>
|
|
2774
|
+
</div>
|
|
2775
|
+
<div
|
|
2776
|
+
style={{
|
|
2777
|
+
opacity: interpolate(c2, [0, 0.4], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }),
|
|
2778
|
+
transform: `translateY(${interpolate(c2, [0, 1], [20, 0])}px) scale(${interpolate(c2, [0, 0.6, 1], [0.9, 1.04, 1])})`,
|
|
2779
|
+
}}
|
|
2780
|
+
>
|
|
2781
|
+
<div
|
|
2782
|
+
style={{
|
|
2783
|
+
display: "inline-flex",
|
|
2784
|
+
alignItems: "center",
|
|
2785
|
+
gap: 12,
|
|
2786
|
+
padding: "14px 22px",
|
|
2787
|
+
background: "rgba(98,95,255,0.10)",
|
|
2788
|
+
border: `1px solid rgba(98,95,255,0.40)`,
|
|
2789
|
+
borderRadius: 999,
|
|
2790
|
+
fontFamily: MONO,
|
|
2791
|
+
fontSize: 22,
|
|
2792
|
+
color: "#a4b3ff",
|
|
2793
|
+
fontWeight: 600,
|
|
2794
|
+
}}
|
|
2795
|
+
>
|
|
2796
|
+
<Img
|
|
2797
|
+
src={staticFile("captures/your-asset.png" /* REFERENCE-STRIP */)}
|
|
2798
|
+
style={{
|
|
2799
|
+
width: 22,
|
|
2800
|
+
height: 22,
|
|
2801
|
+
filter: "brightness(0) saturate(100%) invert(70%) sepia(15%) saturate(2300%) hue-rotate(214deg) brightness(108%) contrast(101%)",
|
|
2802
|
+
}}
|
|
2803
|
+
/>
|
|
2804
|
+
claude-code setup
|
|
2805
|
+
</div>
|
|
2806
|
+
</div>
|
|
2807
|
+
</div>
|
|
2808
|
+
|
|
2809
|
+
{/* Closer */}
|
|
2810
|
+
<div
|
|
2811
|
+
style={{
|
|
2812
|
+
position: "absolute",
|
|
2813
|
+
top: 1280,
|
|
2814
|
+
left: 0,
|
|
2815
|
+
right: 0,
|
|
2816
|
+
textAlign: "center",
|
|
2817
|
+
padding: "0 80px",
|
|
2818
|
+
opacity: closerOp,
|
|
2819
|
+
transform: `translateY(${closerY}px)`,
|
|
2820
|
+
}}
|
|
2821
|
+
>
|
|
2822
|
+
<div
|
|
2823
|
+
style={{
|
|
2824
|
+
fontSize: 32,
|
|
2825
|
+
fontFamily: SERIF,
|
|
2826
|
+
fontStyle: "italic",
|
|
2827
|
+
color: C.fgMuted,
|
|
2828
|
+
letterSpacing: "-0.01em",
|
|
2829
|
+
lineHeight: 1.35,
|
|
2830
|
+
}}
|
|
2831
|
+
>
|
|
2832
|
+
Once Claude remembers what you taught it…<br />
|
|
2833
|
+
<span style={{ color: C.fg, fontWeight: 600 }}>
|
|
2834
|
+
you're done with every other memory tool.
|
|
2835
|
+
</span>
|
|
2836
|
+
</div>
|
|
2837
|
+
</div>
|
|
2838
|
+
|
|
2839
|
+
{/* Arrow pointing down to comment field */}
|
|
2840
|
+
<div
|
|
2841
|
+
style={{
|
|
2842
|
+
position: "absolute",
|
|
2843
|
+
left: 0,
|
|
2844
|
+
right: 0,
|
|
2845
|
+
bottom: H - SAFE_BOT_Y - 60,
|
|
2846
|
+
display: "flex",
|
|
2847
|
+
justifyContent: "center",
|
|
2848
|
+
opacity: arrowOp,
|
|
2849
|
+
transform: `translateY(${arrowY}px)`,
|
|
2850
|
+
}}
|
|
2851
|
+
>
|
|
2852
|
+
<svg width={92} height={92} viewBox="0 0 92 92">
|
|
2853
|
+
<defs>
|
|
2854
|
+
<linearGradient id="arr-grad" x1="0" y1="0" x2="0" y2="1">
|
|
2855
|
+
<stop offset="0%" stopColor={C.indigo} />
|
|
2856
|
+
<stop offset="100%" stopColor="#a4b3ff" />
|
|
2857
|
+
</linearGradient>
|
|
2858
|
+
</defs>
|
|
2859
|
+
<circle cx={46} cy={46} r={42} fill="rgba(98,95,255,0.12)" stroke="rgba(98,95,255,0.4)" strokeWidth={1.5} />
|
|
2860
|
+
<path
|
|
2861
|
+
d="M46 22 L46 64 M28 50 L46 68 L64 50"
|
|
2862
|
+
stroke="url(#arr-grad)"
|
|
2863
|
+
strokeWidth={5}
|
|
2864
|
+
strokeLinecap="round"
|
|
2865
|
+
strokeLinejoin="round"
|
|
2866
|
+
fill="none"
|
|
2867
|
+
/>
|
|
2868
|
+
</svg>
|
|
2869
|
+
</div>
|
|
2870
|
+
</AbsoluteFill>
|
|
2871
|
+
);
|
|
2872
|
+
};
|
|
2873
|
+
|
|
2874
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2875
|
+
// COMPOSITION ROOT
|
|
2876
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2877
|
+
|
|
2878
|
+
export const MemPalaceReel: React.FC = () => {
|
|
2879
|
+
return (
|
|
2880
|
+
<AbsoluteFill style={{ background: C.bg }}>
|
|
2881
|
+
{/* REFERENCE-STRIP: <Audio> tag removed — bring your own voiceover */}
|
|
2882
|
+
|
|
2883
|
+
<Sequence from={SCENES.S1.from} durationInFrames={SCENES.S1.dur}>
|
|
2884
|
+
<Scene1 />
|
|
2885
|
+
</Sequence>
|
|
2886
|
+
<Sequence from={SCENES.S2.from} durationInFrames={SCENES.S2.dur}>
|
|
2887
|
+
<Scene2 />
|
|
2888
|
+
</Sequence>
|
|
2889
|
+
<Sequence from={SCENES.S3.from} durationInFrames={SCENES.S3.dur}>
|
|
2890
|
+
<Scene3 />
|
|
2891
|
+
</Sequence>
|
|
2892
|
+
<Sequence from={SCENES.S4.from} durationInFrames={SCENES.S4.dur}>
|
|
2893
|
+
<Scene4 />
|
|
2894
|
+
</Sequence>
|
|
2895
|
+
<Sequence from={SCENES.S5.from} durationInFrames={SCENES.S5.dur}>
|
|
2896
|
+
<Scene5 />
|
|
2897
|
+
</Sequence>
|
|
2898
|
+
<Sequence from={SCENES.S6.from} durationInFrames={SCENES.S6.dur}>
|
|
2899
|
+
<Scene6 />
|
|
2900
|
+
</Sequence>
|
|
2901
|
+
<Sequence from={SCENES.S7.from} durationInFrames={SCENES.S7.dur}>
|
|
2902
|
+
<Scene7 />
|
|
2903
|
+
</Sequence>
|
|
2904
|
+
<Sequence from={SCENES.S8.from} durationInFrames={SCENES.S8.dur}>
|
|
2905
|
+
<Scene8 />
|
|
2906
|
+
</Sequence>
|
|
2907
|
+
</AbsoluteFill>
|
|
2908
|
+
);
|
|
2909
|
+
};
|