flomotion 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/CHANGELOG.md +58 -2
  2. package/LICENSE +1 -1
  3. package/README.md +29 -20
  4. package/dist/bin.mjs +6279 -2582
  5. package/dist/chunks/{chunk-QG2MOGKO.mjs → chunk-IGG2VZB6.mjs} +178 -14
  6. package/dist/chunks/{chunk-AVP5XX4G.mjs → chunk-PEC2UVQY.mjs} +138 -108
  7. package/dist/chunks/{chunk-IUSYVGP6.mjs → chunk-TTHAZGRG.mjs} +7 -7
  8. package/dist/chunks/{chunk-JCLRAREG.mjs → chunk-XWY6CUY6.mjs} +16 -16
  9. package/dist/chunks/{lock-MLQUU7X3.mjs → lock-WGPR7CJ2.mjs} +3 -3
  10. package/dist/components.mjs +19 -13
  11. package/dist/core.mjs +12 -12
  12. package/dist/hooks.mjs +8 -12
  13. package/dist/jsx-dev-runtime.mjs +1 -1
  14. package/dist/jsx-runtime.mjs +1 -1
  15. package/docs/components/Adjustment.md +2 -2
  16. package/docs/components/Audio.md +2 -2
  17. package/docs/components/B.md +3 -3
  18. package/docs/components/Captions.md +2 -2
  19. package/docs/components/Card.md +2 -2
  20. package/docs/components/Center.md +2 -2
  21. package/docs/components/Chart.md +2 -2
  22. package/docs/components/Chip.md +2 -2
  23. package/docs/components/Circle.md +2 -2
  24. package/docs/components/Clip.md +2 -2
  25. package/docs/components/CodeBlock.md +2 -2
  26. package/docs/components/Composition.md +2 -2
  27. package/docs/components/Counter.md +2 -2
  28. package/docs/components/Cursor.md +2 -2
  29. package/docs/components/Fonts.md +2 -2
  30. package/docs/components/GlassCard.md +2 -2
  31. package/docs/components/Grid.md +2 -2
  32. package/docs/components/Group.md +2 -2
  33. package/docs/components/Highlight.md +3 -3
  34. package/docs/components/I.md +3 -3
  35. package/docs/components/Image.md +2 -2
  36. package/docs/components/Line.md +2 -2
  37. package/docs/components/Marker.md +2 -2
  38. package/docs/components/Path.md +2 -2
  39. package/docs/components/Polygon.md +2 -2
  40. package/docs/components/Precomp.md +2 -2
  41. package/docs/components/ProgressRing.md +2 -2
  42. package/docs/components/Rect.md +2 -2
  43. package/docs/components/RoundRect.md +2 -2
  44. package/docs/components/SafeArea.md +2 -2
  45. package/docs/components/Scene.md +2 -2
  46. package/docs/components/Sequence.md +2 -2
  47. package/docs/components/Span.md +3 -3
  48. package/docs/components/SplitText.md +2 -2
  49. package/docs/components/Stack.md +2 -2
  50. package/docs/components/Stagger.md +2 -2
  51. package/docs/components/Strike.md +3 -3
  52. package/docs/components/Svg.md +2 -2
  53. package/docs/components/Text.md +2 -2
  54. package/docs/components/Title.md +2 -2
  55. package/docs/components/Track.md +2 -2
  56. package/docs/components/UIMock.md +2 -2
  57. package/docs/components/Underline.md +3 -3
  58. package/docs/components/Video.md +2 -2
  59. package/docs/gate2-manual-checklist.md +10 -9
  60. package/docs/hyperframes-notes.md +20 -20
  61. package/docs/later.md +23 -16
  62. package/docs/spec.md +83 -22
  63. package/package.json +1 -2
  64. package/skills/flomotion-studio/CHANGELOG.md +39 -0
  65. package/skills/flomotion-studio/README.md +81 -0
  66. package/skills/flomotion-studio/SKILL.md +90 -0
  67. package/skills/flomotion-studio/config/thresholds.md +191 -0
  68. package/skills/flomotion-studio/dataset/annotations/ansarada.md +53 -0
  69. package/skills/flomotion-studio/dataset/annotations/canva.md +49 -0
  70. package/skills/flomotion-studio/dataset/annotations/clickup.md +60 -0
  71. package/skills/flomotion-studio/dataset/annotations/gemini-stub.md +39 -0
  72. package/skills/flomotion-studio/dataset/annotations/monday.md +51 -0
  73. package/skills/flomotion-studio/dataset/annotations/phantom.md +53 -0
  74. package/skills/flomotion-studio/dataset/annotations/slack.md +54 -0
  75. package/skills/flomotion-studio/dataset/annotations/unknown-7.md +39 -0
  76. package/skills/flomotion-studio/dataset/annotations/vaylens.md +53 -0
  77. package/skills/flomotion-studio/dataset/brief-template.md +110 -0
  78. package/skills/flomotion-studio/dataset/rating-sheet.md +28 -0
  79. package/skills/flomotion-studio/dataset/schema.md +44 -0
  80. package/skills/flomotion-studio/evals/README.md +33 -0
  81. package/skills/flomotion-studio/evals/briefs/briefs.md +25 -0
  82. package/skills/{motion-studio/looks → flomotion-studio/examples/engine-looks}/kinetic.scene.tsx +1 -1
  83. package/skills/{motion-studio/looks → flomotion-studio/examples/engine-looks}/minimal.scene.tsx +1 -1
  84. package/skills/{motion-studio/looks → flomotion-studio/examples/engine-looks}/sketch.scene.tsx +1 -1
  85. package/skills/flomotion-studio/examples/flomotion-ad/LOG.md +39 -0
  86. package/skills/flomotion-studio/examples/flomotion-ad/brief.md +41 -0
  87. package/skills/flomotion-studio/examples/flomotion-ad/ideas.md +12 -0
  88. package/skills/flomotion-studio/examples/flomotion-ad/project.tsx +1694 -0
  89. package/skills/flomotion-studio/examples/flomotion-ad/script.md +28 -0
  90. package/skills/flomotion-studio/examples/flomotion-ad/storyboard.md +93 -0
  91. package/skills/{motion-studio → flomotion-studio}/examples/saas-promo/README.md +1 -1
  92. package/skills/{motion-studio → flomotion-studio}/examples/saas-promo/make-assets.sh +1 -1
  93. package/skills/{motion-studio → flomotion-studio}/examples/saas-promo/project.tsx +3 -3
  94. package/skills/flomotion-studio/looks/bold-kinetic.md +122 -0
  95. package/skills/flomotion-studio/looks/clean-light.md +122 -0
  96. package/skills/flomotion-studio/looks/dark-product.md +120 -0
  97. package/skills/flomotion-studio/references/anti-patterns.md +36 -0
  98. package/skills/flomotion-studio/references/assets.md +42 -0
  99. package/skills/flomotion-studio/references/block-recipes.md +249 -0
  100. package/skills/flomotion-studio/references/blocks.md +114 -0
  101. package/skills/flomotion-studio/references/catalogue.md +53 -0
  102. package/skills/flomotion-studio/references/checks.md +87 -0
  103. package/skills/flomotion-studio/references/clean-styles.md +56 -0
  104. package/skills/{motion-studio → flomotion-studio}/references/components.md +94 -94
  105. package/skills/flomotion-studio/references/copywriting.md +64 -0
  106. package/skills/flomotion-studio/references/decision-tables.md +80 -0
  107. package/skills/flomotion-studio/references/interview.md +145 -0
  108. package/skills/flomotion-studio/references/looks.md +45 -0
  109. package/skills/flomotion-studio/references/mcp-tools.md +70 -0
  110. package/skills/flomotion-studio/references/motion.md +68 -0
  111. package/skills/flomotion-studio/references/patterns.md +45 -0
  112. package/skills/flomotion-studio/references/review.md +56 -0
  113. package/skills/flomotion-studio/references/script-craft.md +59 -0
  114. package/skills/flomotion-studio/references/sound.md +57 -0
  115. package/skills/flomotion-studio/references/story-templates.md +52 -0
  116. package/skills/flomotion-studio/references/storyboard.md +62 -0
  117. package/skills/flomotion-studio/references/styles.md +70 -0
  118. package/skills/flomotion-studio/references/transitions.md +62 -0
  119. package/skills/flomotion-studio/references/typography.md +46 -0
  120. package/skills/flomotion-studio/references/workflow.md +96 -0
  121. package/skills/motion-studio/SKILL.md +0 -87
  122. package/skills/motion-studio/looks/kinetic.json +0 -89
  123. package/skills/motion-studio/looks/minimal.json +0 -91
  124. package/skills/motion-studio/looks/sketch.json +0 -83
  125. package/skills/motion-studio/references/motion.md +0 -73
  126. package/skills/motion-studio/references/review.md +0 -32
  127. package/skills/motion-studio/references/saas-promo.md +0 -29
  128. package/skills/motion-studio/references/sound.md +0 -47
  129. package/skills/motion-studio/references/typography.md +0 -50
@@ -0,0 +1,1694 @@
1
+ import {
2
+ Composition,
3
+ Track,
4
+ Scene,
5
+ Marker,
6
+ SafeArea,
7
+ Rect,
8
+ RoundRect,
9
+ Circle,
10
+ Title,
11
+ Text,
12
+ Span,
13
+ Highlight,
14
+ Counter,
15
+ Chip,
16
+ Card,
17
+ UIMock,
18
+ Image,
19
+ CodeBlock,
20
+ Mask,
21
+ Shake,
22
+ Thud,
23
+ PunchZoom,
24
+ Glitch,
25
+ RGBSplit,
26
+ Pulse,
27
+ Grain,
28
+ Sound,
29
+ Voiceover,
30
+ Audio,
31
+ Captions,
32
+ } from "@flomotion/components";
33
+
34
+ const POP = "back.out(1.6)";
35
+
36
+ /**
37
+ * flomotion, 30 s, 9:16, 128 bpm: one beat = 0.46875 s, 64 beats = 30 s.
38
+ * Beats per scene: hook 7, pain 8 (four words, 2 beats each), turn 4, promise 6, product 7, props 7, checks 6,
39
+ * licences 7, proof 6, cta 6. Every cut is on a beat and has its own transition; words land on the voice's own
40
+ * word times. The turn is two big dots that converge into one small dot, split in two, and grow into the next
41
+ * slide; the vault door that opens there (and closes over the ledger later) is built from circles.
42
+ */
43
+ export default (
44
+ <Composition
45
+ id="flomotion-ad"
46
+ size={[1080, 1920]}
47
+ fps={30}
48
+ duration="30s"
49
+ theme="$look.bold-kinetic"
50
+ background="$brand.bg"
51
+ >
52
+ <Track id="v1" kind="video">
53
+ {/* 1. HOOK 0 - 3.28 s */}
54
+ <Scene
55
+ id="hook"
56
+ start="0s"
57
+ duration="3.28125s"
58
+ scale={[
59
+ [0, 1.06],
60
+ [0.35, 1, "expo.out"],
61
+ ]}
62
+ >
63
+ <Rect id="hook-bg" width={1080} height={1920} fill="$brand.block4" />
64
+ <Circle
65
+ id="hook-blob"
66
+ at={[400, 1000]}
67
+ width={760}
68
+ fill="$brand.accent"
69
+ scale={[
70
+ [0.2, 0],
71
+ [0.9, 1, POP],
72
+ ]}
73
+ />
74
+ <SafeArea id="hook-safe" preset="reels">
75
+ <Title
76
+ id="hook-1"
77
+ at={[0, 40]}
78
+ text="Stop editing."
79
+ size={176}
80
+ align="left"
81
+ maxWidth="100%"
82
+ fill="$brand.text"
83
+ font="$type.display"
84
+ strike={{
85
+ thickness: 18,
86
+ color: "$brand.accent",
87
+ progress: [
88
+ [0.8, 0],
89
+ [1.1, 1, "expo.out"],
90
+ ],
91
+ }}
92
+ enter={{ from: "s", distance: 260, ease: POP, duration: 0.5, delay: 0.05 }}
93
+ />
94
+ <Text
95
+ id="hook-2"
96
+ at={[0, 450]}
97
+ align="left"
98
+ maxWidth="100%"
99
+ size={164}
100
+ weight={800}
101
+ font="$type.display"
102
+ fill="$brand.text"
103
+ enter={{ from: "e", distance: 500, ease: "back.out(1.4)", duration: 0.45, delay: 1.6 }}
104
+ >
105
+ <Span id="hook-2a">Start </Span>
106
+ <Highlight
107
+ id="hook-2b"
108
+ color="$brand.accent"
109
+ padding={10}
110
+ radius={14}
111
+ progress={[
112
+ [2.0, 0],
113
+ [2.3, 1, "expo.out"],
114
+ ]}
115
+ >
116
+ describing.
117
+ </Highlight>
118
+ </Text>
119
+ <CodeBlock
120
+ id="hook-prompt"
121
+ at={[0, 880]}
122
+ width={952}
123
+ size={44}
124
+ padding={44}
125
+ theme="light"
126
+ code="> a 30 s ad for flomotion"
127
+ reveal={[
128
+ [2.3, 0],
129
+ [3.05, 1, "none"],
130
+ ]}
131
+ enter={{ from: "s", distance: 220, ease: POP, duration: 0.45, delay: 2.15 }}
132
+ />
133
+ </SafeArea>
134
+ <Sound
135
+ id="s-hook-whip"
136
+ src="freesound:460469"
137
+ at="1.6s"
138
+ peak="whip"
139
+ gain={-14}
140
+ tag="move/whip"
141
+ />
142
+ <Sound id="s-hook-hit" src="local:hit" at="1.7s" peak="boom" gain={-6} tag="hit/boom" />
143
+ <Sound id="s-hook-t1" src="local:type" at="2.4s" peak="type" gain={-10} tag="ui/type" />
144
+ <Sound id="s-hook-t2" src="local:type" at="2.55s" peak="type" gain={-11} tag="ui/type" />
145
+ <Sound id="s-hook-t3" src="local:type" at="2.7s" peak="type" gain={-10} tag="ui/type" />
146
+ <Sound id="s-hook-t4" src="local:type" at="2.85s" peak="type" gain={-11} tag="ui/type" />
147
+ </Scene>
148
+
149
+ {/* 2. PAIN 3.28 - 7.03 s: four hard-cut words, 2 beats each */}
150
+ <Scene
151
+ id="pain-1"
152
+ start="3.28125s"
153
+ duration="0.9375s"
154
+ scale={[
155
+ [0, 1.08],
156
+ [0.3, 1, "expo.out"],
157
+ ]}
158
+ >
159
+ <Rect id="p1-bg" width={1080} height={1920} fill="$brand.block3" />
160
+ <SafeArea id="p1-safe" preset="reels">
161
+ <Title
162
+ id="p1-word"
163
+ at={[0, 300]}
164
+ text="Timelines."
165
+ size={172}
166
+ align="left"
167
+ maxWidth="100%"
168
+ fill="$brand.text"
169
+ font="$type.display"
170
+ enter={{ from: "w", distance: 700, ease: "expo.out", duration: 0.35 }}
171
+ />
172
+ <RoundRect
173
+ id="p1-a"
174
+ at={[0, 760]}
175
+ width={640}
176
+ height={96}
177
+ radius={26}
178
+ fill="$brand.text"
179
+ anchor={[0, 50]}
180
+ scale={[
181
+ [0.1, [0, 1]],
182
+ [0.5, [1, 1], "expo.out"],
183
+ ]}
184
+ />
185
+ <RoundRect
186
+ id="p1-b"
187
+ at={[200, 890]}
188
+ width={752}
189
+ height={96}
190
+ radius={26}
191
+ fill="$brand.surface"
192
+ anchor={[0, 50]}
193
+ scale={[
194
+ [0.2, [0, 1]],
195
+ [0.6, [1, 1], "expo.out"],
196
+ ]}
197
+ />
198
+ <RoundRect
199
+ id="p1-c"
200
+ at={[60, 1020]}
201
+ width={420}
202
+ height={96}
203
+ radius={26}
204
+ fill="$brand.accent"
205
+ anchor={[0, 50]}
206
+ scale={[
207
+ [0.3, [0, 1]],
208
+ [0.7, [1, 1], "expo.out"],
209
+ ]}
210
+ />
211
+ </SafeArea>
212
+ </Scene>
213
+ <Scene
214
+ id="pain-2"
215
+ start="4.21875s"
216
+ duration="0.9375s"
217
+ scale={[
218
+ [0, 1.08],
219
+ [0.3, 1, "expo.out"],
220
+ ]}
221
+ >
222
+ <Rect id="p2-bg" width={1080} height={1920} fill="$brand.block2" />
223
+ <SafeArea id="p2-safe" preset="reels">
224
+ <Title
225
+ id="p2-word"
226
+ at={[0, 300]}
227
+ text="Dragging."
228
+ size={172}
229
+ align="left"
230
+ maxWidth="100%"
231
+ fill="$brand.text"
232
+ font="$type.display"
233
+ enter={{ from: "e", distance: 700, ease: "expo.out", duration: 0.35 }}
234
+ />
235
+ <RoundRect
236
+ id="p2-a"
237
+ at={[0, 780]}
238
+ width={560}
239
+ height={110}
240
+ radius={28}
241
+ fill="$brand.text"
242
+ position={[
243
+ [0.1, [0, 0]],
244
+ [0.75, [380, 0], "power3.inOut"],
245
+ ]}
246
+ />
247
+ <RoundRect
248
+ id="p2-b"
249
+ at={[0, 930]}
250
+ width={420}
251
+ height={110}
252
+ radius={28}
253
+ fill="$brand.surface"
254
+ />
255
+ </SafeArea>
256
+ </Scene>
257
+ <Scene
258
+ id="pain-3"
259
+ start="5.15625s"
260
+ duration="0.9375s"
261
+ scale={[
262
+ [0, 1.08],
263
+ [0.3, 1, "expo.out"],
264
+ ]}
265
+ >
266
+ <Rect id="p3-bg" width={1080} height={1920} fill="$brand.block5" />
267
+ <SafeArea id="p3-safe" preset="reels">
268
+ <Title
269
+ id="p3-word"
270
+ at={[0, 300]}
271
+ text="Exporting."
272
+ size={172}
273
+ align="left"
274
+ maxWidth="100%"
275
+ fill="$brand.text"
276
+ font="$type.display"
277
+ enter={{ from: "w", distance: 700, ease: "expo.out", duration: 0.35 }}
278
+ />
279
+ <RoundRect
280
+ id="p3-track"
281
+ at={[0, 800]}
282
+ width={952}
283
+ height={48}
284
+ radius={24}
285
+ fill="$brand.surface"
286
+ opacity={0.4}
287
+ />
288
+ <RoundRect
289
+ id="p3-bar"
290
+ at={[0, 800]}
291
+ anchor={[0, 50]}
292
+ width={952}
293
+ height={48}
294
+ radius={24}
295
+ fill="$brand.signal"
296
+ scale={[
297
+ [0.1, [0, 1]],
298
+ [0.85, [0.94, 1], "power2.inOut"],
299
+ ]}
300
+ />
301
+ </SafeArea>
302
+ <Sound id="s-p3-tick" src="local:tick" at="0.7s" peak="tick" gain={-9} tag="ui/tick" />
303
+ </Scene>
304
+ <Scene
305
+ id="pain-4"
306
+ start="6.09375s"
307
+ duration="0.9375s"
308
+ scale={[
309
+ [0, 1.1],
310
+ [0.3, 1, "expo.out"],
311
+ ]}
312
+ >
313
+ <Rect id="p4-bg" width={1080} height={1920} fill="$brand.negative" />
314
+ <SafeArea id="p4-safe" preset="reels">
315
+ <Title
316
+ id="p4-word"
317
+ at={[0, 260]}
318
+ text="Again."
319
+ size={270}
320
+ align="left"
321
+ maxWidth="100%"
322
+ fill="$brand.text"
323
+ font="$type.display"
324
+ enter={{ from: "s", distance: 400, ease: "expo.out", duration: 0.3 }}
325
+ >
326
+ <Glitch id="p4-glitch" start="0.05s" duration="0.55s" />
327
+ <RGBSplit id="p4-rgb" start="0.05s" duration="0.6s" />
328
+ <Shake id="p4-shake" amp={14} freq={18} decay={7} start="0.05s" sound="" />
329
+ </Title>
330
+ <RoundRect
331
+ id="p4-bar"
332
+ at={[0, 800]}
333
+ anchor={[0, 50]}
334
+ width={952}
335
+ height={48}
336
+ radius={24}
337
+ fill="$brand.surface"
338
+ opacity={0.5}
339
+ scale={[
340
+ [0.05, [0.94, 1]],
341
+ [0.4, [0, 1], "expo.in"],
342
+ ]}
343
+ />
344
+ </SafeArea>
345
+ </Scene>
346
+
347
+ {/* 3. TURN 7.03 - 8.91 s: two big dots converge into one small dot, split in two, and grow into the next slide */}
348
+ <Scene id="turn" start="7.03125s" duration="1.875s">
349
+ <Rect id="turn-bg" width={1080} height={1920} fill="$brand.text" />
350
+ <Circle
351
+ id="turn-a"
352
+ at={[-170, 650]}
353
+ width={620}
354
+ fill="$brand.accent"
355
+ position={[
356
+ [0, [0, 0]],
357
+ [0.8, [400, 0], "power3.inOut"],
358
+ ]}
359
+ scale={[
360
+ [0, 1],
361
+ [0.8, 0.16, "power3.inOut"],
362
+ [0.86, 0],
363
+ ]}
364
+ />
365
+ <Circle
366
+ id="turn-b"
367
+ at={[630, 650]}
368
+ width={620}
369
+ fill="$brand.signal"
370
+ position={[
371
+ [0, [0, 0]],
372
+ [0.8, [-400, 0], "power3.inOut"],
373
+ ]}
374
+ scale={[
375
+ [0, 1],
376
+ [0.8, 0.16, "power3.inOut"],
377
+ [0.86, 0],
378
+ ]}
379
+ />
380
+ <Circle
381
+ id="turn-core"
382
+ at={[490, 910]}
383
+ width={100}
384
+ fill="$brand.text"
385
+ stroke={{ width: 8, color: "$brand.surface" }}
386
+ scale={[
387
+ [0.78, 0],
388
+ [0.9, 1.2, POP],
389
+ [0.98, 1],
390
+ [1.0, 1],
391
+ [1.05, 0],
392
+ ]}
393
+ />
394
+ <Circle
395
+ id="turn-c"
396
+ at={[490, 910]}
397
+ width={100}
398
+ fill="$brand.accent"
399
+ position={[
400
+ [1.0, [0, 0]],
401
+ [1.3, [-170, 0], "back.out(1.8)"],
402
+ ]}
403
+ scale={[
404
+ [1.0, 0],
405
+ [1.06, 1],
406
+ [1.3, 1],
407
+ [1.875, 28, "power3.in"],
408
+ ]}
409
+ />
410
+ <Circle
411
+ id="turn-d"
412
+ at={[490, 910]}
413
+ width={100}
414
+ fill="$brand.accent"
415
+ position={[
416
+ [1.0, [0, 0]],
417
+ [1.3, [170, 0], "back.out(1.8)"],
418
+ ]}
419
+ scale={[
420
+ [1.0, 0],
421
+ [1.06, 1],
422
+ [1.3, 1],
423
+ [1.875, 28, "power3.in"],
424
+ ]}
425
+ />
426
+ <Sound id="s-turn-merge" src="local:hit" at="0.85s" peak="boom" gain={-8} tag="hit/boom" />
427
+ <Sound id="s-turn-split" src="local:pop" at="1.02s" peak="pop" gain={-6} tag="ui/pop" />
428
+ </Scene>
429
+
430
+ {/* 4. PROMISE 8.91 - 11.72 s: a vault door (match cut on the circle) opens onto the name */}
431
+ <Scene id="promise" start="8.90625s" duration="2.8125s">
432
+ <Rect id="promise-bg" width={1080} height={1920} fill="$brand.accent" />
433
+ <Rect
434
+ id="promise-white"
435
+ width={1080}
436
+ height={1920}
437
+ fill="$brand.surface"
438
+ opacity={[
439
+ [1.0, 0],
440
+ [1.5, 1],
441
+ ]}
442
+ />
443
+ <Circle
444
+ id="promise-disc"
445
+ at={[260, 680]}
446
+ width={560}
447
+ fill="$brand.signal"
448
+ scale={[
449
+ [0.9, 0.2],
450
+ [1.5, 1, POP],
451
+ ]}
452
+ />
453
+ <SafeArea id="promise-safe" preset="reels">
454
+ <Text
455
+ id="promise-meet"
456
+ at={[0, 0]}
457
+ text="Meet"
458
+ size={120}
459
+ weight={800}
460
+ fill="$brand.text"
461
+ align="left"
462
+ maxWidth="100%"
463
+ font="$type.display"
464
+ enter={{ from: "w", distance: 400, ease: "back.out(1.4)", duration: 0.4 }}
465
+ />
466
+ <Title
467
+ id="promise-name"
468
+ at={[0, 150]}
469
+ text="flomotion"
470
+ size={176}
471
+ align="left"
472
+ maxWidth="100%"
473
+ fill="$brand.text"
474
+ font="$type.display"
475
+ enter={{ from: "s", distance: 500, ease: POP, duration: 0.5, delay: 0.2 }}
476
+ >
477
+ <PunchZoom id="promise-punch" start="0.25s" amount={0.06} sound="" />
478
+ </Title>
479
+ <Card
480
+ id="door-open"
481
+ at={[136, 370]}
482
+ layout="absolute"
483
+ width={680}
484
+ height={680}
485
+ padding={0}
486
+ radius={0}
487
+ fill="rgba(0,0,0,0)"
488
+ shadow={false}
489
+ scale={[
490
+ [0, 0.3],
491
+ [0.45, 1, "back.out(1.4)"],
492
+ [1.0, 1],
493
+ [1.6, 0.001, "power3.in"],
494
+ ]}
495
+ rotation={[
496
+ [1.0, 0],
497
+ [1.6, -70, "power3.in"],
498
+ ]}
499
+ >
500
+ <Circle
501
+ id="door-open-body"
502
+ at={[0, 0]}
503
+ width={680}
504
+ fill="$brand.accent"
505
+ stroke={{ width: 12, color: "$brand.text" }}
506
+ />
507
+ <Circle
508
+ id="door-open-ring"
509
+ at={[75, 75]}
510
+ width={530}
511
+ fill="rgba(0,0,0,0)"
512
+ stroke={{ width: 8, color: "$brand.text" }}
513
+ />
514
+ <Circle
515
+ id="door-open-plate"
516
+ at={[170, 170]}
517
+ width={340}
518
+ fill="$brand.signal"
519
+ stroke={{ width: 8, color: "$brand.text" }}
520
+ />
521
+ <Circle id="door-open-bolt0" at={[622, 323]} width={34} fill="$brand.text" />
522
+ <Circle id="door-open-bolt1" at={[535, 535]} width={34} fill="$brand.text" />
523
+ <Circle id="door-open-bolt2" at={[323, 622]} width={34} fill="$brand.text" />
524
+ <Circle id="door-open-bolt3" at={[111, 535]} width={34} fill="$brand.text" />
525
+ <Circle id="door-open-bolt4" at={[24, 323]} width={34} fill="$brand.text" />
526
+ <Circle id="door-open-bolt5" at={[111, 111]} width={34} fill="$brand.text" />
527
+ <Circle id="door-open-bolt6" at={[323, 24]} width={34} fill="$brand.text" />
528
+ <Circle id="door-open-bolt7" at={[535, 111]} width={34} fill="$brand.text" />
529
+ <Card
530
+ id="door-open-spokes"
531
+ at={[170, 170]}
532
+ layout="absolute"
533
+ width={340}
534
+ height={340}
535
+ padding={0}
536
+ radius={0}
537
+ fill="rgba(0,0,0,0)"
538
+ shadow={false}
539
+ rotation={[
540
+ [0.25, 0],
541
+ [0.95, 120, "power3.inOut"],
542
+ ]}
543
+ >
544
+ <RoundRect
545
+ id="door-open-spoke-h"
546
+ at={[14, 144]}
547
+ width={313}
548
+ height={51}
549
+ radius={26}
550
+ fill="$brand.text"
551
+ />
552
+ <RoundRect
553
+ id="door-open-spoke-v"
554
+ at={[144, 14]}
555
+ width={51}
556
+ height={313}
557
+ radius={26}
558
+ fill="$brand.text"
559
+ />
560
+ <Circle
561
+ id="door-open-hub"
562
+ at={[122, 122]}
563
+ width={95}
564
+ fill="$brand.surface"
565
+ stroke={{ width: 8, color: "$brand.text" }}
566
+ />
567
+ </Card>
568
+ </Card>
569
+ <Chip
570
+ id="promise-file"
571
+ at={[160, 640]}
572
+ label="One TSX file."
573
+ fill="$brand.text"
574
+ textColor="$brand.surface"
575
+ font="$type.display"
576
+ size={88}
577
+ weight={800}
578
+ paddingX={46}
579
+ paddingY={28}
580
+ rotation={-3}
581
+ enter={{ from: "e", distance: 800, ease: POP, duration: 0.45, delay: 1.2 }}
582
+ />
583
+ </SafeArea>
584
+ <Sound id="s-prom-land" src="local:hit" at="0.4s" peak="boom" gain={-7} tag="hit/boom" />
585
+ <Sound id="s-prom-unlock" src="local:tick" at="0.95s" peak="tick" gain={-6} tag="ui/tick" />
586
+ <Sound
587
+ id="s-prom-open"
588
+ src="freesound:460469"
589
+ at="1.35s"
590
+ peak="whip"
591
+ gain={-11}
592
+ tag="move/whip"
593
+ />
594
+ <Sound id="s-prom-pop" src="local:pop" at="1.45s" peak="pop" gain={-8} tag="ui/pop" />
595
+ </Scene>
596
+
597
+ {/* 5. PRODUCT 11.72 - 15.0 s: the real live view */}
598
+ <Scene
599
+ id="product"
600
+ start="11.71875s"
601
+ duration="3.28125s"
602
+ scale={[
603
+ [0, 1.06],
604
+ [0.35, 1, "expo.out"],
605
+ ]}
606
+ >
607
+ <Rect id="product-bg" width={1080} height={1920} fill="$brand.block5" />
608
+ <SafeArea id="product-safe" preset="reels">
609
+ <Title
610
+ id="product-1"
611
+ at={[0, 0]}
612
+ text="Claude builds."
613
+ size={128}
614
+ align="left"
615
+ maxWidth="100%"
616
+ fill="$brand.text"
617
+ font="$type.display"
618
+ enter={{ from: "s", distance: 200, ease: POP, duration: 0.45, delay: 0.02 }}
619
+ />
620
+ <Title
621
+ id="product-2"
622
+ at={[0, 140]}
623
+ text="You watch."
624
+ size={128}
625
+ align="left"
626
+ maxWidth="100%"
627
+ fill="$brand.text"
628
+ font="$type.display"
629
+ enter={{ from: "s", distance: 200, ease: POP, duration: 0.45, delay: 1.4 }}
630
+ />
631
+ <UIMock
632
+ id="product-browser"
633
+ at={[0, 340]}
634
+ device="browser"
635
+ url="localhost:4399"
636
+ width={952}
637
+ height={690}
638
+ rotation={-2}
639
+ screenColor="$brand.surface"
640
+ enter={{ from: "s", distance: 900, ease: "back.out(1.3)", duration: 0.7, delay: 0.15 }}
641
+ >
642
+ <Image
643
+ id="product-shot"
644
+ src="./assets/captures/live-full.png"
645
+ alt="flomotion live view: progress, Claude's activity, the preview and the outline"
646
+ fit="cover"
647
+ />
648
+ </UIMock>
649
+ <Card
650
+ id="product-inset"
651
+ at={[150, 560]}
652
+ layout="absolute"
653
+ width={780}
654
+ height={520}
655
+ padding={0}
656
+ radius={28}
657
+ rotation={2}
658
+ fill="$brand.surface"
659
+ stroke={{ width: 6, color: "$brand.text" }}
660
+ enter={{ from: "s", distance: 600, ease: POP, duration: 0.6, delay: 1.5 }}
661
+ >
662
+ <Image
663
+ id="product-feed"
664
+ src="./assets/captures/live-activity-tall.png"
665
+ alt="flomotion live view: Claude's activity feed, one tool call per row"
666
+ at={[0, 0]}
667
+ width={780}
668
+ height={2340}
669
+ fit="cover"
670
+ position={[
671
+ [2.0, [0, 0]],
672
+ [3.2, [0, -420], "power1.inOut"],
673
+ ]}
674
+ />
675
+ <Mask id="product-inset-mask" shape="roundrect" radius={0.05} />
676
+ </Card>
677
+ <Chip
678
+ id="product-alive"
679
+ at={[690, 262]}
680
+ label="alive"
681
+ dot="$brand.signal"
682
+ fill="$brand.text"
683
+ textColor="$brand.surface"
684
+ size={44}
685
+ enter={{ from: "s", distance: 60, ease: POP, duration: 0.4, delay: 2.05 }}
686
+ >
687
+ <Pulse
688
+ id="product-alive-pulse"
689
+ start="2.5s"
690
+ amp={0.07}
691
+ freq={2.133}
692
+ count={0}
693
+ sound=""
694
+ />
695
+ </Chip>
696
+ </SafeArea>
697
+ <Sound id="s-prod-hit" src="local:hit" at="1.41s" peak="boom" gain={-9} tag="hit/boom" />
698
+ <Sound id="s-prod-pop1" src="local:pop" at="1.62s" peak="pop" gain={-9} tag="ui/pop" />
699
+ <Sound
700
+ id="s-prod-chime"
701
+ src="local:chime"
702
+ at="2.1s"
703
+ peak="main"
704
+ gain={-12}
705
+ tag="tech/success"
706
+ />
707
+ </Scene>
708
+
709
+ {/* 6a. FEATURE: every control is a typed prop 15.0 - 18.28 s */}
710
+ <Scene
711
+ id="feature-props"
712
+ start="15s"
713
+ duration="3.28125s"
714
+ scale={[
715
+ [0, 1.06],
716
+ [0.35, 1, "expo.out"],
717
+ ]}
718
+ >
719
+ <Rect id="fp-bg" width={1080} height={1920} fill="$brand.block2" />
720
+ <SafeArea id="fp-safe" preset="reels">
721
+ <Title
722
+ id="fp-title"
723
+ at={[0, 0]}
724
+ text="Every control is a typed prop."
725
+ size={108}
726
+ align="left"
727
+ maxWidth="100%"
728
+ fill="$brand.text"
729
+ font="$type.display"
730
+ enter={{ from: "w", distance: 500, ease: POP, duration: 0.45, delay: 0.02 }}
731
+ />
732
+ <CodeBlock
733
+ id="fp-code"
734
+ at={[0, 290]}
735
+ width={952}
736
+ size={36}
737
+ code={
738
+ '<SplitText\n id="hook-line1"\n text="Describe the video."\n size={140}\n fill="$brand.text"\n/>'
739
+ }
740
+ reveal={[
741
+ [0.25, 0],
742
+ [1.0, 1, "power2.out"],
743
+ ]}
744
+ enter={{ from: "s", distance: 240, ease: POP, duration: 0.45, delay: 0.1 }}
745
+ />
746
+ <RoundRect
747
+ id="fp-ring"
748
+ at={[8, 486]}
749
+ width={270}
750
+ height={60}
751
+ radius={14}
752
+ fill="rgba(0,0,0,0)"
753
+ stroke={{ width: 5, color: "$brand.signal" }}
754
+ opacity={[
755
+ [1.3, 0],
756
+ [1.35, 1],
757
+ ]}
758
+ scale={[
759
+ [1.3, 1.25],
760
+ [1.6, 1, "expo.out"],
761
+ ]}
762
+ />
763
+ <Card
764
+ id="fp-preview"
765
+ at={[0, 750]}
766
+ layout="absolute"
767
+ width={952}
768
+ height={360}
769
+ padding={0}
770
+ radius={28}
771
+ fill="$brand.surface"
772
+ stroke={{ width: 6, color: "$brand.text" }}
773
+ enter={{ from: "s", distance: 300, ease: POP, duration: 0.5, delay: 0.4 }}
774
+ >
775
+ <Text
776
+ id="fp-preview-text"
777
+ at={[40, 18]}
778
+ text="Describe the video."
779
+ size={[
780
+ [0, 86],
781
+ [1.4, 86],
782
+ [1.75, 140, "back.out(1.8)"],
783
+ ]}
784
+ weight={800}
785
+ fill="$brand.text"
786
+ align="left"
787
+ maxWidth={870}
788
+ font="$type.display"
789
+ />
790
+ </Card>
791
+ <Chip
792
+ id="fp-chip"
793
+ at={[470, 688]}
794
+ label="element_set size 140"
795
+ dot="$brand.signal"
796
+ fill="$brand.text"
797
+ textColor="$brand.surface"
798
+ font="$type.mono"
799
+ size={34}
800
+ enter={{ from: "s", distance: 50, ease: POP, duration: 0.4, delay: 1.45 }}
801
+ />
802
+ </SafeArea>
803
+ <Sound id="s-fp-t1" src="local:type" at="0.35s" peak="type" gain={-10} tag="ui/type" />
804
+ <Sound id="s-fp-t2" src="local:type" at="0.55s" peak="type" gain={-11} tag="ui/type" />
805
+ <Sound id="s-fp-t3" src="local:type" at="0.75s" peak="type" gain={-10} tag="ui/type" />
806
+ <Sound id="s-fp-ring" src="local:tick" at="1.35s" peak="tick" gain={-8} tag="ui/tick" />
807
+ <Sound id="s-fp-pop" src="local:pop" at="1.45s" peak="pop" gain={-7} tag="ui/pop" />
808
+ </Scene>
809
+
810
+ {/* 6b. FEATURE: 17 checks 18.28 - 21.09 s */}
811
+ <Scene
812
+ id="feature-checks"
813
+ start="18.28125s"
814
+ duration="2.8125s"
815
+ scale={[
816
+ [0, 1.06],
817
+ [0.35, 1, "expo.out"],
818
+ ]}
819
+ >
820
+ <Rect id="fc-bg" width={1080} height={1920} fill="$brand.block3" />
821
+ <SafeArea id="fc-safe" preset="reels">
822
+ <Counter
823
+ id="fc-count"
824
+ at={[0, 0]}
825
+ from={0}
826
+ to={17}
827
+ over={0.9}
828
+ delay="0.05s"
829
+ size={330}
830
+ align="left"
831
+ maxWidth="100%"
832
+ fill="$brand.text"
833
+ font="$type.numerals"
834
+ >
835
+ <Thud id="fc-thud" amp={14} start="1.0s" sound="" />
836
+ </Counter>
837
+ <Text
838
+ id="fc-label"
839
+ at={[0, 350]}
840
+ text="automatic checks"
841
+ size={80}
842
+ weight={800}
843
+ fill="$brand.text"
844
+ align="left"
845
+ maxWidth="100%"
846
+ font="$type.display"
847
+ enter={{ from: "s", distance: 80, ease: POP, duration: 0.45, delay: 0.5 }}
848
+ />
849
+ <Card
850
+ id="fc-clip"
851
+ at={[76, 500]}
852
+ layout="absolute"
853
+ width={800}
854
+ height={560}
855
+ padding={0}
856
+ radius={0}
857
+ fill="rgba(0,0,0,0)"
858
+ shadow={false}
859
+ rotation={-1.5}
860
+ enter={{ from: "s", distance: 500, ease: POP, duration: 0.55, delay: 0.3 }}
861
+ >
862
+ <Image
863
+ id="fc-shot"
864
+ src="./assets/captures/live-review-tall.png"
865
+ alt="flomotion live view: the review panel listing 17 checks"
866
+ at={[0, 0]}
867
+ width={800}
868
+ height={2994}
869
+ fit="cover"
870
+ position={[
871
+ [0.6, [0, 0]],
872
+ [2.5, [0, -2434], "power2.inOut"],
873
+ ]}
874
+ />
875
+ <Mask id="fc-mask" shape="roundrect" radius={0.04} />
876
+ </Card>
877
+ </SafeArea>
878
+ <Sound id="s-fc-t1" src="local:tick" at="0.25s" peak="tick" gain={-9} tag="ui/tick" />
879
+ <Sound id="s-fc-t2" src="local:tick" at="0.5s" peak="tick" gain={-9} tag="ui/tick" />
880
+ <Sound id="s-fc-t3" src="local:tick" at="0.75s" peak="tick" gain={-9} tag="ui/tick" />
881
+ <Sound id="s-fc-t4" src="local:pop" at="1.0s" peak="pop" gain={-7} tag="ui/pop" />
882
+ </Scene>
883
+
884
+ {/* 6c. FEATURE: licensed, logged, locked 21.09 - 24.375 s: the vault door closes over the ledger */}
885
+ <Scene
886
+ id="feature-licences"
887
+ start="21.09375s"
888
+ duration="3.28125s"
889
+ scale={[
890
+ [0, 1.06],
891
+ [0.35, 1, "expo.out"],
892
+ ]}
893
+ >
894
+ <Rect id="fl-bg" width={1080} height={1920} fill="$brand.block4" />
895
+ <SafeArea id="fl-safe" preset="reels">
896
+ <Text
897
+ id="fl-lead"
898
+ at={[0, 0]}
899
+ text="Every sound and font:"
900
+ size={64}
901
+ weight={800}
902
+ fill="$brand.text"
903
+ align="left"
904
+ maxWidth="100%"
905
+ font="$type.display"
906
+ enter={{ from: "w", distance: 400, ease: POP, duration: 0.4, delay: 0.02 }}
907
+ />
908
+ <Title
909
+ id="fl-1"
910
+ at={[0, 70]}
911
+ text="Licensed."
912
+ size={124}
913
+ align="left"
914
+ maxWidth="100%"
915
+ fill="$brand.text"
916
+ font="$type.display"
917
+ enter={{ from: "e", distance: 600, ease: POP, duration: 0.4, delay: 1.2 }}
918
+ />
919
+ <Title
920
+ id="fl-2"
921
+ at={[0, 210]}
922
+ text="Logged."
923
+ size={124}
924
+ align="left"
925
+ maxWidth="100%"
926
+ fill="$brand.text"
927
+ font="$type.display"
928
+ enter={{ from: "w", distance: 600, ease: POP, duration: 0.4, delay: 1.9 }}
929
+ />
930
+ <Title
931
+ id="fl-3"
932
+ at={[0, 350]}
933
+ text="Locked."
934
+ size={124}
935
+ align="left"
936
+ maxWidth="100%"
937
+ fill="$brand.accent"
938
+ font="$type.display"
939
+ enter={{ from: "e", distance: 600, ease: POP, duration: 0.4, delay: 2.5 }}
940
+ />
941
+ <Card
942
+ id="fl-clip"
943
+ at={[36, 520]}
944
+ layout="absolute"
945
+ width={880}
946
+ height={560}
947
+ padding={0}
948
+ radius={0}
949
+ fill="rgba(0,0,0,0)"
950
+ shadow={false}
951
+ rotation={1.5}
952
+ enter={{ from: "s", distance: 600, ease: POP, duration: 0.55, delay: 0.25 }}
953
+ >
954
+ <Image
955
+ id="fl-shot"
956
+ src="./assets/captures/live-ledger.png"
957
+ alt="flomotion live view: the licence ledger of this very video"
958
+ at={[0, 0]}
959
+ width={880}
960
+ height={5102}
961
+ fit="cover"
962
+ position={[
963
+ [0.5, [0, 0]],
964
+ [2.3, [0, -2000], "power2.inOut"],
965
+ ]}
966
+ />
967
+ <Mask id="fl-mask" shape="roundrect" radius={0.03} />
968
+ </Card>
969
+ <Card
970
+ id="door-shut"
971
+ opacity={[
972
+ [2.44, 0],
973
+ [2.45, 1],
974
+ ]}
975
+ at={[216, 540]}
976
+ layout="absolute"
977
+ width={520}
978
+ height={520}
979
+ padding={0}
980
+ radius={0}
981
+ fill="rgba(0,0,0,0)"
982
+ shadow={false}
983
+ scale={[
984
+ [2.45, 0.2],
985
+ [2.85, 1, "back.out(1.5)"],
986
+ ]}
987
+ rotation={[[2.85, 0]]}
988
+ >
989
+ <Circle
990
+ id="door-shut-body"
991
+ at={[0, 0]}
992
+ width={520}
993
+ fill="$brand.accent"
994
+ stroke={{ width: 12, color: "$brand.text" }}
995
+ />
996
+ <Circle
997
+ id="door-shut-ring"
998
+ at={[57, 57]}
999
+ width={406}
1000
+ fill="rgba(0,0,0,0)"
1001
+ stroke={{ width: 8, color: "$brand.text" }}
1002
+ />
1003
+ <Circle
1004
+ id="door-shut-plate"
1005
+ at={[130, 130]}
1006
+ width={260}
1007
+ fill="$brand.signal"
1008
+ stroke={{ width: 8, color: "$brand.text" }}
1009
+ />
1010
+ <Circle id="door-shut-bolt0" at={[476, 247]} width={26} fill="$brand.text" />
1011
+ <Circle id="door-shut-bolt1" at={[409, 409]} width={26} fill="$brand.text" />
1012
+ <Circle id="door-shut-bolt2" at={[247, 476]} width={26} fill="$brand.text" />
1013
+ <Circle id="door-shut-bolt3" at={[85, 409]} width={26} fill="$brand.text" />
1014
+ <Circle id="door-shut-bolt4" at={[18, 247]} width={26} fill="$brand.text" />
1015
+ <Circle id="door-shut-bolt5" at={[85, 85]} width={26} fill="$brand.text" />
1016
+ <Circle id="door-shut-bolt6" at={[247, 18]} width={26} fill="$brand.text" />
1017
+ <Circle id="door-shut-bolt7" at={[409, 85]} width={26} fill="$brand.text" />
1018
+ <Card
1019
+ id="door-shut-spokes"
1020
+ at={[130, 130]}
1021
+ layout="absolute"
1022
+ width={260}
1023
+ height={260}
1024
+ padding={0}
1025
+ radius={0}
1026
+ fill="rgba(0,0,0,0)"
1027
+ shadow={false}
1028
+ rotation={[
1029
+ [2.45, 0],
1030
+ [3.1, 100, "power3.out"],
1031
+ ]}
1032
+ >
1033
+ <RoundRect
1034
+ id="door-shut-spoke-h"
1035
+ at={[10, 110]}
1036
+ width={239}
1037
+ height={39}
1038
+ radius={20}
1039
+ fill="$brand.text"
1040
+ />
1041
+ <RoundRect
1042
+ id="door-shut-spoke-v"
1043
+ at={[110, 10]}
1044
+ width={39}
1045
+ height={239}
1046
+ radius={20}
1047
+ fill="$brand.text"
1048
+ />
1049
+ <Circle
1050
+ id="door-shut-hub"
1051
+ at={[94, 94]}
1052
+ width={73}
1053
+ fill="$brand.surface"
1054
+ stroke={{ width: 8, color: "$brand.text" }}
1055
+ />
1056
+ </Card>
1057
+ </Card>
1058
+ </SafeArea>
1059
+ <Sound id="s-fl-pop1" src="local:pop" at="1.25s" peak="pop" gain={-9} tag="ui/pop" />
1060
+ <Sound id="s-fl-pop2" src="local:pop" at="1.95s" peak="pop" gain={-9} tag="ui/pop" />
1061
+ <Sound id="s-fl-slam" src="local:hit" at="2.85s" peak="boom" gain={-6} tag="hit/boom" />
1062
+ <Sound
1063
+ id="s-fl-chime"
1064
+ src="local:chime"
1065
+ at="2.95s"
1066
+ peak="main"
1067
+ gain={-10}
1068
+ tag="tech/success"
1069
+ />
1070
+ </Scene>
1071
+
1072
+ {/* 7. PROOF 24.375 - 27.19 s */}
1073
+ <Scene
1074
+ id="proof"
1075
+ start="24.375s"
1076
+ duration="2.8125s"
1077
+ scale={[
1078
+ [0, 1.1],
1079
+ [0.35, 1, "expo.out"],
1080
+ ]}
1081
+ >
1082
+ <Rect id="proof-bg" width={1080} height={1920} fill="$brand.accent" />
1083
+ <SafeArea id="proof-safe" preset="reels">
1084
+ <Counter
1085
+ id="proof-count"
1086
+ at={[0, 10]}
1087
+ from={0}
1088
+ to={39}
1089
+ over={0.8}
1090
+ delay="0.02s"
1091
+ size={460}
1092
+ align="left"
1093
+ maxWidth="100%"
1094
+ fill="$brand.text"
1095
+ font="$type.numerals"
1096
+ >
1097
+ <Thud id="proof-thud" amp={20} start="0.85s" sound="" />
1098
+ </Counter>
1099
+ <Text
1100
+ id="proof-label"
1101
+ at={[0, 500]}
1102
+ text="MCP tools"
1103
+ size={104}
1104
+ weight={800}
1105
+ fill="$brand.text"
1106
+ align="left"
1107
+ maxWidth="100%"
1108
+ font="$type.display"
1109
+ enter={{ from: "s", distance: 100, ease: POP, duration: 0.45, delay: 0.45 }}
1110
+ />
1111
+ <Title
1112
+ id="proof-same"
1113
+ at={[0, 690]}
1114
+ text="Diff it like code."
1115
+ size={112}
1116
+ align="left"
1117
+ maxWidth="100%"
1118
+ fill="$brand.text"
1119
+ font="$type.display"
1120
+ enter={{ from: "e", distance: 600, ease: POP, duration: 0.5, delay: 1.15 }}
1121
+ />
1122
+ <Chip
1123
+ id="proof-r1"
1124
+ at={[0, 900]}
1125
+ label="- size={120}"
1126
+ dot="$brand.negative"
1127
+ fill="$brand.text"
1128
+ textColor="$brand.surface"
1129
+ font="$type.mono"
1130
+ size={44}
1131
+ enter={{ from: "s", distance: 60, ease: POP, duration: 0.4, delay: 1.5 }}
1132
+ />
1133
+
1134
+ <Chip
1135
+ id="proof-r2"
1136
+ at={[0, 995]}
1137
+ label="+ size={140}"
1138
+ dot="$brand.positive"
1139
+ fill="$brand.text"
1140
+ textColor="$brand.surface"
1141
+ font="$type.mono"
1142
+ size={44}
1143
+ enter={{ from: "s", distance: 60, ease: POP, duration: 0.4, delay: 1.75 }}
1144
+ />
1145
+ </SafeArea>
1146
+ <Sound id="s-pr-t1" src="local:tick" at="0.25s" peak="tick" gain={-9} tag="ui/tick" />
1147
+ <Sound id="s-pr-t2" src="local:tick" at="0.5s" peak="tick" gain={-9} tag="ui/tick" />
1148
+ <Sound id="s-pr-t3" src="local:pop" at="0.85s" peak="pop" gain={-7} tag="ui/pop" />
1149
+ <Sound id="s-pr-hit" src="local:hit" at="1.2s" peak="boom" gain={-10} tag="hit/boom" />
1150
+ <Sound id="s-pr-r1" src="local:pop" at="1.55s" peak="pop" gain={-11} tag="ui/pop" />
1151
+ <Sound id="s-pr-r2" src="local:pop" at="1.8s" peak="pop" gain={-11} tag="ui/pop" />
1152
+ </Scene>
1153
+
1154
+ {/* 8. CTA 27.19 - 30 s: the hook's prompt comes back, rendered; and the reveal that the whole ad is one file */}
1155
+ <Scene
1156
+ id="cta"
1157
+ start="27.1875s"
1158
+ duration="2.8125s"
1159
+ scale={[
1160
+ [0, 1.1],
1161
+ [0.4, 1, "expo.out"],
1162
+ ]}
1163
+ >
1164
+ <Rect id="cta-bg" width={1080} height={1920} fill="$brand.surface" />
1165
+ <Circle
1166
+ id="cta-c1"
1167
+ at={[700, 150]}
1168
+ width={420}
1169
+ fill="$brand.block4"
1170
+ scale={[
1171
+ [0.1, 0],
1172
+ [0.7, 1, POP],
1173
+ ]}
1174
+ />
1175
+ <Circle
1176
+ id="cta-c2"
1177
+ at={[-200, 1420]}
1178
+ width={520}
1179
+ fill="$brand.accent"
1180
+ scale={[
1181
+ [0.2, 0],
1182
+ [0.9, 1, POP],
1183
+ ]}
1184
+ />
1185
+ <RoundRect
1186
+ id="cta-c3"
1187
+ at={[790, 1400]}
1188
+ width={230}
1189
+ height={230}
1190
+ radius={54}
1191
+ fill="$brand.block3"
1192
+ rotation={16}
1193
+ scale={[
1194
+ [0.35, 0],
1195
+ [1.0, 1, POP],
1196
+ ]}
1197
+ />
1198
+ <SafeArea id="cta-safe" preset="reels">
1199
+ <Title
1200
+ id="cta-start"
1201
+ at={[0, 300]}
1202
+ text="Start now."
1203
+ size={170}
1204
+ align="left"
1205
+ maxWidth="100%"
1206
+ fill="$brand.text"
1207
+ font="$type.display"
1208
+ enter={{ from: "s", distance: 400, ease: POP, duration: 0.5, delay: 0.05 }}
1209
+ >
1210
+ <PunchZoom id="cta-punch" start="0.1s" amount={0.05} sound="" />
1211
+ </Title>
1212
+ <CodeBlock
1213
+ id="cta-cmd"
1214
+ at={[0, 600]}
1215
+ width={952}
1216
+ size={76}
1217
+ padding={56}
1218
+ code="$ npx flomotion"
1219
+ reveal={[
1220
+ [0.95, 0],
1221
+ [1.75, 1, "none"],
1222
+ ]}
1223
+ enter={{ from: "s", distance: 400, ease: POP, duration: 0.5, delay: 0.25 }}
1224
+ />
1225
+ <Chip
1226
+ id="cta-done"
1227
+ at={[0, 880]}
1228
+ label="a 30 s ad for flomotion: rendered"
1229
+ dot="$brand.positive"
1230
+ fill="$brand.text"
1231
+ textColor="$brand.surface"
1232
+ font="$type.mono"
1233
+ size={36}
1234
+ enter={{ from: "s", distance: 60, ease: POP, duration: 0.45, delay: 1.85 }}
1235
+ />
1236
+ <Text
1237
+ id="cta-line"
1238
+ at={[0, 1010]}
1239
+ text="This whole ad is one TSX file."
1240
+ size={60}
1241
+ weight={800}
1242
+ fill="$brand.text"
1243
+ align="left"
1244
+ maxWidth="100%"
1245
+ font="$type.display"
1246
+ enter={{ from: "s", distance: 60, ease: POP, duration: 0.5, delay: 2.1 }}
1247
+ />
1248
+ </SafeArea>
1249
+ <Sound id="s-cta-t1" src="local:type" at="1.05s" peak="type" gain={-9} tag="ui/type" />
1250
+ <Sound id="s-cta-t2" src="local:type" at="1.2s" peak="type" gain={-10} tag="ui/type" />
1251
+ <Sound id="s-cta-t3" src="local:type" at="1.35s" peak="type" gain={-9} tag="ui/type" />
1252
+ <Sound id="s-cta-t4" src="local:type" at="1.5s" peak="type" gain={-10} tag="ui/type" />
1253
+ <Sound id="s-cta-t5" src="local:type" at="1.65s" peak="type" gain={-9} tag="ui/type" />
1254
+ <Sound
1255
+ id="s-cta-chime"
1256
+ src="local:chime"
1257
+ at="1.9s"
1258
+ peak="main"
1259
+ gain={-8}
1260
+ tag="tech/success"
1261
+ />
1262
+ </Scene>
1263
+ </Track>
1264
+
1265
+ {/* transitions: every cut has its own, ending on the beat in the colour of the scene that follows */}
1266
+ <Track id="wipes" kind="video">
1267
+ <Rect
1268
+ id="w1"
1269
+ start="3.03s"
1270
+ duration="0.3s"
1271
+ width={1080}
1272
+ height={1920}
1273
+ fill="$brand.block3"
1274
+ position={[
1275
+ [3.03, [-1080, 0]],
1276
+ [3.28125, [0, 0], "power4.out"],
1277
+ ]}
1278
+ />
1279
+ <Rect
1280
+ id="w2"
1281
+ start="3.97s"
1282
+ duration="0.3s"
1283
+ width={1080}
1284
+ height={1920}
1285
+ fill="$brand.block2"
1286
+ position={[
1287
+ [3.97, [0, 1920]],
1288
+ [4.21875, [0, 0], "power4.out"],
1289
+ ]}
1290
+ />
1291
+ <Circle
1292
+ id="w3"
1293
+ start="4.92s"
1294
+ duration="0.3s"
1295
+ at={[340, 760]}
1296
+ width={400}
1297
+ fill="$brand.block5"
1298
+ scale={[
1299
+ [4.92, 0],
1300
+ [5.15625, 7, "power3.in"],
1301
+ ]}
1302
+ />
1303
+ <Rect
1304
+ id="w4"
1305
+ start="5.84s"
1306
+ duration="0.3s"
1307
+ width={1080}
1308
+ height={1920}
1309
+ fill="$brand.negative"
1310
+ position={[
1311
+ [5.84, [1080, 0]],
1312
+ [6.09375, [0, 0], "power4.out"],
1313
+ ]}
1314
+ />
1315
+ <Rect
1316
+ id="w5"
1317
+ start="6.97s"
1318
+ duration="0.3s"
1319
+ width={1080}
1320
+ height={1920}
1321
+ fill="$brand.surface"
1322
+ opacity={[
1323
+ [6.97, 0],
1324
+ [7.03125, 1],
1325
+ [7.18, 0, "power2.out"],
1326
+ ]}
1327
+ />
1328
+ <Rect
1329
+ id="w6"
1330
+ start="11.45s"
1331
+ duration="0.4s"
1332
+ width={1080}
1333
+ height={1920}
1334
+ fill="$brand.block5"
1335
+ position={[
1336
+ [11.45, [0, -1920]],
1337
+ [11.71875, [0, 0], "power4.out"],
1338
+ ]}
1339
+ />
1340
+ <Rect
1341
+ id="w7"
1342
+ start="14.7s"
1343
+ duration="0.4s"
1344
+ at={[-1060, -640]}
1345
+ width={3200}
1346
+ height={3200}
1347
+ rotation={18}
1348
+ fill="$brand.block2"
1349
+ position={[
1350
+ [14.7, [-3000, 0]],
1351
+ [15, [0, 0], "power3.out"],
1352
+ ]}
1353
+ />
1354
+ <Rect
1355
+ id="w8a"
1356
+ start="17.98s"
1357
+ duration="0.4s"
1358
+ at={[0, 0]}
1359
+ width={220}
1360
+ height={1920}
1361
+ anchor={[50, 0]}
1362
+ fill="$brand.block3"
1363
+ scale={[
1364
+ [18.0, [1, 0]],
1365
+ [18.14, [1, 1], "power3.out"],
1366
+ ]}
1367
+ />
1368
+ <Rect
1369
+ id="w8b"
1370
+ start="17.98s"
1371
+ duration="0.4s"
1372
+ at={[216, 0]}
1373
+ width={220}
1374
+ height={1920}
1375
+ anchor={[50, 0]}
1376
+ fill="$brand.block3"
1377
+ scale={[
1378
+ [18.04, [1, 0]],
1379
+ [18.18, [1, 1], "power3.out"],
1380
+ ]}
1381
+ />
1382
+ <Rect
1383
+ id="w8c"
1384
+ start="17.98s"
1385
+ duration="0.4s"
1386
+ at={[432, 0]}
1387
+ width={220}
1388
+ height={1920}
1389
+ anchor={[50, 0]}
1390
+ fill="$brand.block3"
1391
+ scale={[
1392
+ [18.08, [1, 0]],
1393
+ [18.22, [1, 1], "power3.out"],
1394
+ ]}
1395
+ />
1396
+ <Rect
1397
+ id="w8d"
1398
+ start="17.98s"
1399
+ duration="0.4s"
1400
+ at={[648, 0]}
1401
+ width={220}
1402
+ height={1920}
1403
+ anchor={[50, 0]}
1404
+ fill="$brand.block3"
1405
+ scale={[
1406
+ [18.12, [1, 0]],
1407
+ [18.26, [1, 1], "power3.out"],
1408
+ ]}
1409
+ />
1410
+ <Rect
1411
+ id="w8e"
1412
+ start="17.98s"
1413
+ duration="0.4s"
1414
+ at={[864, 0]}
1415
+ width={220}
1416
+ height={1920}
1417
+ anchor={[50, 0]}
1418
+ fill="$brand.block3"
1419
+ scale={[
1420
+ [18.16, [1, 0]],
1421
+ [18.28125, [1, 1], "power3.out"],
1422
+ ]}
1423
+ />
1424
+ <Circle
1425
+ id="w9"
1426
+ start="20.85s"
1427
+ duration="0.4s"
1428
+ at={[340, 760]}
1429
+ width={400}
1430
+ fill="$brand.block4"
1431
+ scale={[
1432
+ [20.85, 0],
1433
+ [21.09375, 7, "power3.in"],
1434
+ ]}
1435
+ />
1436
+ <Rect
1437
+ id="w10a"
1438
+ start="24.1s"
1439
+ duration="0.4s"
1440
+ at={[0, 0]}
1441
+ width={540}
1442
+ height={1920}
1443
+ fill="$brand.accent"
1444
+ position={[
1445
+ [24.1, [-540, 0]],
1446
+ [24.375, [0, 0], "power3.out"],
1447
+ ]}
1448
+ />
1449
+ <Rect
1450
+ id="w10b"
1451
+ start="24.1s"
1452
+ duration="0.4s"
1453
+ at={[540, 0]}
1454
+ width={540}
1455
+ height={1920}
1456
+ fill="$brand.accent"
1457
+ position={[
1458
+ [24.1, [540, 0]],
1459
+ [24.375, [0, 0], "power3.out"],
1460
+ ]}
1461
+ />
1462
+ <Rect
1463
+ id="w11"
1464
+ start="27.08s"
1465
+ duration="0.3s"
1466
+ width={1080}
1467
+ height={1920}
1468
+ fill="$brand.surface"
1469
+ opacity={[
1470
+ [27.08, 0],
1471
+ [27.1875, 1],
1472
+ [27.35, 0, "power2.out"],
1473
+ ]}
1474
+ />
1475
+ </Track>
1476
+
1477
+ {/* captions: one word at a time, on the voice's own word times, from the product beat to the CTA */}
1478
+ <Track id="caps-track" kind="video">
1479
+ <SafeArea id="caps-safe" preset="reels">
1480
+ <Captions
1481
+ id="captions"
1482
+ start="11.71875s"
1483
+ duration="15.46875s"
1484
+ voice="#vo"
1485
+ at={[0, 1170]}
1486
+ captionStyle="word"
1487
+ size={96}
1488
+ weight={800}
1489
+ maxChars={12}
1490
+ maxWords={1}
1491
+ fill="$brand.text"
1492
+ font="$type.display"
1493
+ />
1494
+ </SafeArea>
1495
+ </Track>
1496
+
1497
+ {/* the mascot: one dot with eyes that carries across the film, reacts to the story and pulses on the beat after the drop */}
1498
+ <Track id="hero-track" kind="video">
1499
+ <Card
1500
+ id="flo"
1501
+ start="0s"
1502
+ duration="30s"
1503
+ at={[880, 110]}
1504
+ layout="absolute"
1505
+ width={110}
1506
+ height={110}
1507
+ padding={0}
1508
+ radius={0}
1509
+ fill="rgba(0,0,0,0)"
1510
+ shadow={false}
1511
+ scale={[
1512
+ [0, 1],
1513
+ [6.9, 1],
1514
+ [7.03, 0],
1515
+ [8.95, 0],
1516
+ [9.25, 1, POP],
1517
+ ]}
1518
+ rotation={[
1519
+ [6.1, 0],
1520
+ [6.95, 720, "power3.out"],
1521
+ ]}
1522
+ >
1523
+ <Circle
1524
+ id="flo-body"
1525
+ at={[0, 0]}
1526
+ width={110}
1527
+ fill="$brand.text"
1528
+ stroke={{ width: 7, color: "$brand.surface" }}
1529
+ />
1530
+ <Circle
1531
+ id="flo-eye-l"
1532
+ at={[20, 34]}
1533
+ width={34}
1534
+ fill="$brand.surface"
1535
+ scale={[
1536
+ [1.6, [1, 1]],
1537
+ [1.66, [1, 0.1]],
1538
+ [1.74, [1, 1]],
1539
+ [4.9, [1, 1]],
1540
+ [4.96, [1, 0.1]],
1541
+ [5.04, [1, 1]],
1542
+ [10.4, [1, 1]],
1543
+ [10.46, [1, 0.1]],
1544
+ [10.54, [1, 1]],
1545
+ [15.6, [1, 1]],
1546
+ [15.66, [1, 0.1]],
1547
+ [15.74, [1, 1]],
1548
+ [22.2, [1, 1]],
1549
+ [22.26, [1, 0.1]],
1550
+ [22.34, [1, 1]],
1551
+ ]}
1552
+ />
1553
+ <Circle
1554
+ id="flo-eye-r"
1555
+ at={[56, 34]}
1556
+ width={34}
1557
+ fill="$brand.surface"
1558
+ scale={[
1559
+ [1.6, [1, 1]],
1560
+ [1.66, [1, 0.1]],
1561
+ [1.74, [1, 1]],
1562
+ [4.9, [1, 1]],
1563
+ [4.96, [1, 0.1]],
1564
+ [5.04, [1, 1]],
1565
+ [10.4, [1, 1]],
1566
+ [10.46, [1, 0.1]],
1567
+ [10.54, [1, 1]],
1568
+ [15.6, [1, 1]],
1569
+ [15.66, [1, 0.1]],
1570
+ [15.74, [1, 1]],
1571
+ [22.2, [1, 1]],
1572
+ [22.26, [1, 0.1]],
1573
+ [22.34, [1, 1]],
1574
+ ]}
1575
+ />
1576
+ <Circle
1577
+ id="flo-pupil-l"
1578
+ at={[30, 44]}
1579
+ width={15}
1580
+ fill="$brand.text"
1581
+ position={[
1582
+ [0, [0, 0]],
1583
+ [11.7, [0, 0]],
1584
+ [12.1, [-5, 7], "power2.out"],
1585
+ [15, [-5, 7]],
1586
+ [15.3, [0, 0], "power2.out"],
1587
+ [24.3, [0, 0]],
1588
+ [24.6, [4, -2], "power2.out"],
1589
+ ]}
1590
+ />
1591
+ <Circle
1592
+ id="flo-pupil-r"
1593
+ at={[66, 44]}
1594
+ width={15}
1595
+ fill="$brand.text"
1596
+ position={[
1597
+ [0, [0, 0]],
1598
+ [11.7, [0, 0]],
1599
+ [12.1, [-5, 7], "power2.out"],
1600
+ [15, [-5, 7]],
1601
+ [15.3, [0, 0], "power2.out"],
1602
+ [24.3, [0, 0]],
1603
+ [24.6, [4, -2], "power2.out"],
1604
+ ]}
1605
+ />
1606
+ <Pulse id="flo-pulse" start="9.4s" amp={0.12} freq={2.133} count={0} sound="" />
1607
+ </Card>
1608
+ </Track>
1609
+
1610
+ {/* sounds on the cuts (absolute times; the peak of each lands on the cut) */}
1611
+ <Sound
1612
+ id="c-whip-1"
1613
+ src="freesound:460469"
1614
+ at="3.28125s"
1615
+ peak="whip"
1616
+ gain={-12}
1617
+ tag="move/whip"
1618
+ />
1619
+ <Sound
1620
+ id="c-whip-2"
1621
+ src="freesound:460469"
1622
+ at="4.21875s"
1623
+ peak="whip"
1624
+ gain={-13}
1625
+ tag="move/whip"
1626
+ />
1627
+ <Sound
1628
+ id="c-whip-3"
1629
+ src="freesound:460469"
1630
+ at="5.15625s"
1631
+ peak="whip"
1632
+ gain={-13}
1633
+ tag="move/whip"
1634
+ />
1635
+ <Sound
1636
+ id="c-glitch-4"
1637
+ src="freesound:856168"
1638
+ at="6.09375s"
1639
+ peak="glitch-whip"
1640
+ gain={-9}
1641
+ tag="move/glitch-whip"
1642
+ />
1643
+ <Sound
1644
+ id="c-riser-hit"
1645
+ src="freesound:757922"
1646
+ at="8.90625s"
1647
+ peak="riser-hit"
1648
+ gain={-4}
1649
+ tag="hit/riser-hit"
1650
+ />
1651
+ <Sound
1652
+ id="c-whip-6"
1653
+ src="freesound:460469"
1654
+ at="11.71875s"
1655
+ peak="whip"
1656
+ gain={-12}
1657
+ tag="move/whip"
1658
+ />
1659
+ <Sound id="c-whip-7" src="freesound:460469" at="15s" peak="whip" gain={-12} tag="move/whip" />
1660
+ <Sound
1661
+ id="c-whip-8"
1662
+ src="freesound:460469"
1663
+ at="18.28125s"
1664
+ peak="whip"
1665
+ gain={-12}
1666
+ tag="move/whip"
1667
+ />
1668
+ <Sound
1669
+ id="c-whip-9"
1670
+ src="freesound:460469"
1671
+ at="21.09375s"
1672
+ peak="whip"
1673
+ gain={-12}
1674
+ tag="move/whip"
1675
+ />
1676
+ <Sound
1677
+ id="c-whip-10"
1678
+ src="freesound:460469"
1679
+ at="24.375s"
1680
+ peak="whip"
1681
+ gain={-12}
1682
+ tag="move/whip"
1683
+ />
1684
+ <Sound id="c-boom-proof" src="local:hit" at="24.375s" peak="boom" gain={-8} tag="hit/boom" />
1685
+ <Sound id="c-boom-cta" src="local:hit" at="27.1875s" peak="boom" gain={-5} tag="hit/boom" />
1686
+
1687
+ <Marker id="turn-marker" at="8.90625s" label="Turn" />
1688
+ <Marker id="m-product" at="11.71875s" label="Product" />
1689
+ <Marker id="m-cta" at="27.1875s" label="CTA" />
1690
+ <Voiceover id="vo" src="./assets/voice/voice.wav" at="0s" gain={0} />
1691
+ <Audio id="music" src="local:music" gain={-9} fadeOut={0.8} />
1692
+ <Grain id="grain" amount={0.04} />
1693
+ </Composition>
1694
+ );