cinematic-scroll-skill 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/COMPATIBILITY.md +244 -0
  2. package/LICENSE +21 -0
  3. package/MODELS.md +92 -0
  4. package/README.md +250 -0
  5. package/SKILL.md +1003 -0
  6. package/audit-mode.md +497 -0
  7. package/bin/install.mjs +91 -0
  8. package/compile-choreography.mjs +296 -0
  9. package/decision-log.md +241 -0
  10. package/examples/GETTING_STARTED.md +279 -0
  11. package/examples/KNOWN_ISSUES.md +50 -0
  12. package/examples/PROMPTS.md +166 -0
  13. package/examples/luxe/README.md +88 -0
  14. package/examples/luxe/index.html +662 -0
  15. package/examples/noir/README.md +72 -0
  16. package/examples/noir/index.html +634 -0
  17. package/examples/pop/README.md +81 -0
  18. package/examples/pop/index.html +711 -0
  19. package/examples/renaissance/README.md +39 -0
  20. package/examples/renaissance/index.html +648 -0
  21. package/examples/studio/README.md +77 -0
  22. package/examples/studio/chapters.js +105 -0
  23. package/examples/studio/index.html +520 -0
  24. package/manifest.json +92 -0
  25. package/manifest.md +136 -0
  26. package/package.json +56 -0
  27. package/references/film-archetypes.md +211 -0
  28. package/references/performance-budget.md +499 -0
  29. package/references/scroll-patterns.md +693 -0
  30. package/scroll-choreography-compilation.md +543 -0
  31. package/scroll-choreography.json +1512 -0
  32. package/taste-guardrails.md +164 -0
  33. package/templates/nextjs/.env.example +41 -0
  34. package/templates/nextjs/app/api/fal/proxy/route.ts +33 -0
  35. package/templates/nextjs/app/api/fal/webhook/route.ts +132 -0
  36. package/templates/nextjs/app/api/generate-edition-asset/route.ts +66 -0
  37. package/templates/nextjs/app/globals.css +80 -0
  38. package/templates/nextjs/app/layout.tsx +21 -0
  39. package/templates/nextjs/app/page.tsx +10 -0
  40. package/templates/nextjs/components/ChapterDemoVisual.tsx +212 -0
  41. package/templates/nextjs/components/ChapterScene.tsx +373 -0
  42. package/templates/nextjs/components/EditionsPage.tsx +116 -0
  43. package/templates/nextjs/components/SmoothScrollProvider.tsx +8 -0
  44. package/templates/nextjs/lib/api-guard.ts +110 -0
  45. package/templates/nextjs/lib/editions-manifest.ts +224 -0
  46. package/templates/nextjs/lib/fal-client.ts +12 -0
  47. package/templates/nextjs/lib/fal-generate.ts +86 -0
  48. package/templates/nextjs/lib/fal-models.ts +213 -0
  49. package/templates/nextjs/lib/prompt-contract.ts +97 -0
  50. package/templates/nextjs/lib/use-device.ts +42 -0
  51. package/templates/nextjs/lib/use-lenis.ts +35 -0
  52. package/templates/nextjs/next.config.ts +29 -0
  53. package/templates/nextjs/package-lock.json +6455 -0
  54. package/templates/nextjs/package.json +41 -0
  55. package/templates/nextjs/package.patch.json +28 -0
  56. package/templates/nextjs/postcss.config.js +6 -0
  57. package/templates/nextjs/scripts/generate-chapter-assets.mjs +243 -0
  58. package/templates/nextjs/scripts/setup.mjs +170 -0
  59. package/templates/nextjs/tailwind.config.ts +37 -0
  60. package/templates/nextjs/tsconfig.json +23 -0
  61. package/troubleshooting.md +1284 -0
@@ -0,0 +1,1512 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "cinematic-scroll-choreography",
4
+ "title": "Cinematic Scroll Choreography",
5
+ "description": "Declarative scroll animation choreography that compiles to GSAP ScrollTrigger. Maps scroll position to cinematic camera moves through a typed, validatable schema.",
6
+ "version": "2.0.0",
7
+ "type": "object",
8
+ "required": [
9
+ "metadata",
10
+ "globals",
11
+ "chapters"
12
+ ],
13
+ "additionalProperties": false,
14
+ "definitions": {
15
+ "Metadata": {
16
+ "type": "object",
17
+ "required": [
18
+ "title",
19
+ "version",
20
+ "targetDevice",
21
+ "totalScrollRange"
22
+ ],
23
+ "properties": {
24
+ "title": {
25
+ "type": "string",
26
+ "description": "Human-readable choreography title"
27
+ },
28
+ "version": {
29
+ "type": "string",
30
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
31
+ "description": "Schema version this doc conforms to"
32
+ },
33
+ "targetDevice": {
34
+ "type": "string",
35
+ "enum": [
36
+ "desktop",
37
+ "tablet",
38
+ "mobile"
39
+ ],
40
+ "description": "Primary device target"
41
+ },
42
+ "totalScrollRange": {
43
+ "type": "integer",
44
+ "minimum": 500,
45
+ "maximum": 10000,
46
+ "description": "Total scroll height in vh units"
47
+ },
48
+ "author": {
49
+ "type": "string"
50
+ },
51
+ "created": {
52
+ "type": "string",
53
+ "format": "date"
54
+ },
55
+ "performanceTier": {
56
+ "type": "string",
57
+ "enum": [
58
+ "desktop",
59
+ "flagship",
60
+ "mid-range",
61
+ "budget",
62
+ "reduced"
63
+ ]
64
+ }
65
+ }
66
+ },
67
+ "Globals": {
68
+ "type": "object",
69
+ "description": "Default values applied to all chapters unless overridden.",
70
+ "properties": {
71
+ "defaultEasing": {
72
+ "type": "string",
73
+ "default": "power2.inOut",
74
+ "description": "GSAP easing name or cubic-bezier() string"
75
+ },
76
+ "defaultDuration": {
77
+ "type": "number",
78
+ "default": 1.0,
79
+ "minimum": 0.1,
80
+ "maximum": 5.0
81
+ },
82
+ "snapBehavior": {
83
+ "type": "string",
84
+ "enum": [
85
+ "none",
86
+ "section",
87
+ "progressive"
88
+ ],
89
+ "default": "none",
90
+ "description": "none=no snapping, section=snap to chapter centers, progressive=weighted snap based on scroll velocity"
91
+ },
92
+ "scrollSmoothing": {
93
+ "type": "number",
94
+ "default": 0.5,
95
+ "minimum": 0.1,
96
+ "maximum": 1.0,
97
+ "description": "Lenis/GSAP lerp factor"
98
+ },
99
+ "reducedMotionFallback": {
100
+ "type": "string",
101
+ "enum": [
102
+ "static",
103
+ "instant",
104
+ "minimal"
105
+ ],
106
+ "default": "static"
107
+ }
108
+ }
109
+ },
110
+ "PinConfig": {
111
+ "type": "object",
112
+ "description": "Pinning configuration.",
113
+ "required": [
114
+ "enabled"
115
+ ],
116
+ "properties": {
117
+ "enabled": {
118
+ "type": "boolean"
119
+ },
120
+ "pinDuration": {
121
+ "type": "integer",
122
+ "minimum": 150,
123
+ "maximum": 400,
124
+ "description": "Pin duration in vh. Range: 150-400 per taste-guardrails.md"
125
+ },
126
+ "pinSpacing": {
127
+ "type": "boolean",
128
+ "default": true
129
+ },
130
+ "anticipatorySettle": {
131
+ "type": "number",
132
+ "default": 0.05,
133
+ "minimum": 0.0,
134
+ "maximum": 0.15,
135
+ "description": "Fraction of pin duration before first animation starts"
136
+ }
137
+ }
138
+ },
139
+ "Layer": {
140
+ "type": "object",
141
+ "required": [
142
+ "id",
143
+ "depth",
144
+ "content"
145
+ ],
146
+ "properties": {
147
+ "id": {
148
+ "type": "string",
149
+ "pattern": "^[a-z][a-zA-Z0-9_-]*$"
150
+ },
151
+ "depth": {
152
+ "type": "number",
153
+ "minimum": 0.15,
154
+ "maximum": 1.4,
155
+ "description": "Parallax depth multiplier. 0.15=far background, 1.40=foreground overlay."
156
+ },
157
+ "content": {
158
+ "type": "object",
159
+ "required": [
160
+ "type"
161
+ ],
162
+ "properties": {
163
+ "type": {
164
+ "type": "string",
165
+ "enum": [
166
+ "image",
167
+ "text",
168
+ "svg",
169
+ "video"
170
+ ]
171
+ },
172
+ "src": {
173
+ "type": "string",
174
+ "description": "Asset URL or inline SVG string"
175
+ },
176
+ "alt": {
177
+ "type": "string",
178
+ "description": "Accessibility alt text (required for images)"
179
+ },
180
+ "text": {
181
+ "type": "string",
182
+ "description": "Text content for type=text layers"
183
+ },
184
+ "fontSize": {
185
+ "type": "string",
186
+ "description": "CSS font-size. Min 48px for display type."
187
+ }
188
+ }
189
+ },
190
+ "animation": {
191
+ "$ref": "#/definitions/Animation"
192
+ },
193
+ "mobileDegradation": {
194
+ "type": "string",
195
+ "enum": [
196
+ "full",
197
+ "reduce",
198
+ "static"
199
+ ],
200
+ "default": "reduce"
201
+ },
202
+ "willChange": {
203
+ "type": "boolean",
204
+ "default": false,
205
+ "description": "Max 3 per viewport enforced at compile time."
206
+ }
207
+ }
208
+ },
209
+ "AnimatedProperty": {
210
+ "type": "object",
211
+ "required": [
212
+ "property",
213
+ "from",
214
+ "to"
215
+ ],
216
+ "properties": {
217
+ "property": {
218
+ "type": "string",
219
+ "enum": [
220
+ "translateX",
221
+ "translateY",
222
+ "translateZ",
223
+ "scale",
224
+ "rotateX",
225
+ "rotateY",
226
+ "rotateZ",
227
+ "opacity"
228
+ ],
229
+ "description": "Only transform and opacity allowed per performance-budget.md"
230
+ },
231
+ "from": {
232
+ "type": [
233
+ "number",
234
+ "string"
235
+ ]
236
+ },
237
+ "to": {
238
+ "type": [
239
+ "number",
240
+ "string"
241
+ ]
242
+ },
243
+ "easing": {
244
+ "type": "string"
245
+ },
246
+ "relativeTo": {
247
+ "type": "string",
248
+ "enum": [
249
+ "viewport",
250
+ "parent",
251
+ "self"
252
+ ],
253
+ "default": "self"
254
+ },
255
+ "unit": {
256
+ "type": "string",
257
+ "enum": [
258
+ "px",
259
+ "vh",
260
+ "vw",
261
+ "deg",
262
+ "em",
263
+ ""
264
+ ],
265
+ "default": "px"
266
+ }
267
+ }
268
+ },
269
+ "ScrollTrigger": {
270
+ "type": "object",
271
+ "description": "GSAP ScrollTrigger configuration.",
272
+ "properties": {
273
+ "start": {
274
+ "type": "string",
275
+ "default": "top top"
276
+ },
277
+ "end": {
278
+ "type": "string",
279
+ "default": "bottom top"
280
+ },
281
+ "scrub": {
282
+ "type": [
283
+ "boolean",
284
+ "number"
285
+ ],
286
+ "default": 0.5,
287
+ "description": "0.3-0.8 recommended per performance-budget.md"
288
+ },
289
+ "markers": {
290
+ "type": "boolean",
291
+ "default": false,
292
+ "description": "NEVER true in production"
293
+ },
294
+ "pin": {
295
+ "type": "boolean",
296
+ "default": false
297
+ },
298
+ "fastScrollEnd": {
299
+ "type": "boolean",
300
+ "default": true
301
+ },
302
+ "invalidateOnRefresh": {
303
+ "type": "boolean",
304
+ "default": true
305
+ }
306
+ }
307
+ },
308
+ "Animation": {
309
+ "type": "object",
310
+ "description": "Animation config for a layer. Properties animate in parallel.",
311
+ "properties": {
312
+ "properties": {
313
+ "type": "array",
314
+ "items": {
315
+ "$ref": "#/definitions/AnimatedProperty"
316
+ }
317
+ },
318
+ "trigger": {
319
+ "$ref": "#/definitions/ScrollTrigger"
320
+ },
321
+ "stagger": {
322
+ "type": "object",
323
+ "properties": {
324
+ "offset": {
325
+ "type": "number",
326
+ "minimum": 0.01,
327
+ "maximum": 0.2
328
+ },
329
+ "maxElements": {
330
+ "type": "integer",
331
+ "minimum": 1,
332
+ "maximum": 5
333
+ }
334
+ }
335
+ }
336
+ }
337
+ },
338
+ "Chapter": {
339
+ "type": "object",
340
+ "required": [
341
+ "id",
342
+ "title",
343
+ "pattern",
344
+ "scrollRange",
345
+ "layers"
346
+ ],
347
+ "properties": {
348
+ "id": {
349
+ "type": "string",
350
+ "pattern": "^[a-z][a-zA-Z0-9_-]*$"
351
+ },
352
+ "title": {
353
+ "type": "string"
354
+ },
355
+ "pattern": {
356
+ "type": "string",
357
+ "enum": [
358
+ "pinnedHero",
359
+ "scrubbedTimeline",
360
+ "velocityReactive",
361
+ "stickyNarrative",
362
+ "chapteredRelease",
363
+ "parallaxGallery",
364
+ "3dProductOrbit",
365
+ "editorialLongread",
366
+ "dataStory",
367
+ "landingSequence",
368
+ "portfolioReveal",
369
+ "archiveExplorer"
370
+ ],
371
+ "description": "Reference to scroll-patterns.md pattern."
372
+ },
373
+ "scrollRange": {
374
+ "type": "object",
375
+ "required": [
376
+ "start",
377
+ "end"
378
+ ],
379
+ "properties": {
380
+ "start": {
381
+ "type": "integer",
382
+ "description": "Start position in vh from page top"
383
+ },
384
+ "end": {
385
+ "type": "integer",
386
+ "description": "End position in vh from page top"
387
+ }
388
+ }
389
+ },
390
+ "pin": {
391
+ "$ref": "#/definitions/PinConfig"
392
+ },
393
+ "layers": {
394
+ "type": "array",
395
+ "items": {
396
+ "$ref": "#/definitions/Layer"
397
+ },
398
+ "minItems": 1,
399
+ "maxItems": 7
400
+ },
401
+ "titleReveal": {
402
+ "$ref": "#/definitions/TitleReveal"
403
+ },
404
+ "atmosphere": {
405
+ "$ref": "#/definitions/Atmosphere"
406
+ },
407
+ "velocityNodes": {
408
+ "type": "array",
409
+ "items": {
410
+ "$ref": "#/definitions/VelocityNode"
411
+ }
412
+ }
413
+ }
414
+ },
415
+ "TitleReveal": {
416
+ "type": "object",
417
+ "required": [
418
+ "type"
419
+ ],
420
+ "properties": {
421
+ "type": {
422
+ "type": "string",
423
+ "enum": [
424
+ "maskReveal",
425
+ "wordStagger",
426
+ "letterStagger",
427
+ "clipPathWipe",
428
+ "letterSpacingScrub",
429
+ "verticalMask",
430
+ "scaleDownEntrance",
431
+ "blurCrossfade",
432
+ "typewriterReveal",
433
+ "splitLineRise"
434
+ ],
435
+ "description": "From taste-guardrails.md. Each chapter MUST use a different type."
436
+ },
437
+ "scrollRange": {
438
+ "type": "object",
439
+ "description": "As fraction of pin duration (0.0-1.0). Title must finish by 0.70.",
440
+ "properties": {
441
+ "start": {
442
+ "type": "number",
443
+ "minimum": 0.0,
444
+ "maximum": 1.0
445
+ },
446
+ "end": {
447
+ "type": "number",
448
+ "minimum": 0.0,
449
+ "maximum": 1.0
450
+ }
451
+ }
452
+ },
453
+ "stagger": {
454
+ "type": "object",
455
+ "properties": {
456
+ "offset": {
457
+ "type": "number",
458
+ "minimum": 0.01,
459
+ "maximum": 0.15
460
+ },
461
+ "maxElements": {
462
+ "type": "integer",
463
+ "minimum": 1,
464
+ "maximum": 5
465
+ }
466
+ }
467
+ },
468
+ "easing": {
469
+ "type": "string"
470
+ },
471
+ "text": {
472
+ "type": "string"
473
+ }
474
+ }
475
+ },
476
+ "Atmosphere": {
477
+ "type": "object",
478
+ "description": "Background and ambient effects. No filter animations allowed.",
479
+ "properties": {
480
+ "backgroundColor": {
481
+ "type": "string"
482
+ },
483
+ "backgroundGradient": {
484
+ "type": "object",
485
+ "properties": {
486
+ "from": {
487
+ "type": "string"
488
+ },
489
+ "to": {
490
+ "type": "string"
491
+ },
492
+ "angle": {
493
+ "type": "number",
494
+ "default": 180
495
+ }
496
+ }
497
+ },
498
+ "colorMorph": {
499
+ "type": "object",
500
+ "description": "Background color interpolation. Uses CSS custom properties, NOT filter.",
501
+ "properties": {
502
+ "from": {
503
+ "type": "string"
504
+ },
505
+ "to": {
506
+ "type": "string"
507
+ },
508
+ "scrollStart": {
509
+ "type": "number",
510
+ "minimum": 0.0,
511
+ "maximum": 1.0
512
+ },
513
+ "scrollEnd": {
514
+ "type": "number",
515
+ "minimum": 0.0,
516
+ "maximum": 1.0
517
+ },
518
+ "easing": {
519
+ "type": "string",
520
+ "default": "none"
521
+ }
522
+ }
523
+ },
524
+ "ambientDrift": {
525
+ "type": "object",
526
+ "description": "Subtle background movement. Max 2-3% of viewport.",
527
+ "properties": {
528
+ "translateX": {
529
+ "type": "number",
530
+ "description": "Max horizontal drift in vh"
531
+ },
532
+ "translateY": {
533
+ "type": "number",
534
+ "description": "Max vertical drift in vh"
535
+ },
536
+ "scale": {
537
+ "type": "number",
538
+ "description": "Scale range, e.g. 1.02 = 2% zoom drift"
539
+ }
540
+ }
541
+ }
542
+ }
543
+ },
544
+ "Transition": {
545
+ "type": "object",
546
+ "description": "Transition between chapters. Adjacent chapters MUST use different types per taste-guardrails.md.",
547
+ "required": [
548
+ "from",
549
+ "to",
550
+ "type"
551
+ ],
552
+ "properties": {
553
+ "from": {
554
+ "type": "string"
555
+ },
556
+ "to": {
557
+ "type": "string"
558
+ },
559
+ "type": {
560
+ "type": "string",
561
+ "enum": [
562
+ "craneShot",
563
+ "whipPan",
564
+ "matchCut",
565
+ "dissolve",
566
+ "pushIn",
567
+ "hardCut"
568
+ ]
569
+ },
570
+ "duration": {
571
+ "type": "integer",
572
+ "minimum": 20,
573
+ "maximum": 200,
574
+ "description": "Transition duration in vh"
575
+ },
576
+ "overlap": {
577
+ "type": "integer",
578
+ "minimum": 0,
579
+ "maximum": 100,
580
+ "description": "Chapter overlap during transition in vh"
581
+ },
582
+ "easing": {
583
+ "type": "string"
584
+ },
585
+ "properties": {
586
+ "type": "array",
587
+ "items": {
588
+ "$ref": "#/definitions/AnimatedProperty"
589
+ }
590
+ }
591
+ }
592
+ },
593
+ "VelocityNode": {
594
+ "type": "object",
595
+ "description": "Velocity-aware animation override.",
596
+ "required": [
597
+ "threshold"
598
+ ],
599
+ "properties": {
600
+ "threshold": {
601
+ "type": "number",
602
+ "minimum": 0.1,
603
+ "description": "Scroll velocity threshold in px/ms"
604
+ },
605
+ "comparison": {
606
+ "type": "string",
607
+ "enum": [
608
+ "above",
609
+ "below",
610
+ "equals"
611
+ ],
612
+ "default": "above"
613
+ },
614
+ "above": {
615
+ "type": "object",
616
+ "properties": {
617
+ "easing": {
618
+ "type": "string"
619
+ },
620
+ "opacity": {
621
+ "type": "number",
622
+ "minimum": 0,
623
+ "maximum": 1
624
+ },
625
+ "scale": {
626
+ "type": "number"
627
+ },
628
+ "skewX": {
629
+ "type": "number"
630
+ },
631
+ "letterSpacing": {
632
+ "type": "string"
633
+ }
634
+ }
635
+ },
636
+ "below": {
637
+ "type": "object",
638
+ "properties": {
639
+ "easing": {
640
+ "type": "string"
641
+ },
642
+ "opacity": {
643
+ "type": "number",
644
+ "minimum": 0,
645
+ "maximum": 1
646
+ },
647
+ "scale": {
648
+ "type": "number"
649
+ },
650
+ "skewX": {
651
+ "type": "number"
652
+ },
653
+ "letterSpacing": {
654
+ "type": "string"
655
+ }
656
+ }
657
+ },
658
+ "lerpFactor": {
659
+ "type": "number",
660
+ "default": 0.1,
661
+ "minimum": 0.01,
662
+ "maximum": 0.5
663
+ }
664
+ }
665
+ }
666
+ },
667
+ "properties": {
668
+ "metadata": {
669
+ "$ref": "#/definitions/Metadata"
670
+ },
671
+ "globals": {
672
+ "$ref": "#/definitions/Globals"
673
+ },
674
+ "chapters": {
675
+ "type": "array",
676
+ "items": {
677
+ "$ref": "#/definitions/Chapter"
678
+ },
679
+ "minItems": 1
680
+ },
681
+ "transitions": {
682
+ "type": "array",
683
+ "items": {
684
+ "$ref": "#/definitions/Transition"
685
+ }
686
+ }
687
+ },
688
+ "examples": [
689
+ {
690
+ "metadata": {
691
+ "title": "Maison Voss - Quiet Luxury Brand Launch",
692
+ "version": "2.0.0",
693
+ "targetDevice": "desktop",
694
+ "totalScrollRange": 2200,
695
+ "author": "cinematic-scroll-skill",
696
+ "created": "2025-01-15",
697
+ "performanceTier": "desktop"
698
+ },
699
+ "globals": {
700
+ "defaultEasing": "cubic-bezier(0.16, 1, 0.3, 1)",
701
+ "defaultDuration": 1.2,
702
+ "snapBehavior": "section",
703
+ "scrollSmoothing": 0.6,
704
+ "reducedMotionFallback": "static"
705
+ },
706
+ "chapters": [
707
+ {
708
+ "id": "hero-manifesto",
709
+ "title": "The Quiet Manifesto",
710
+ "pattern": "pinnedHero",
711
+ "scrollRange": {
712
+ "start": 0,
713
+ "end": 500
714
+ },
715
+ "pin": {
716
+ "enabled": true,
717
+ "pinDuration": 250,
718
+ "pinSpacing": true,
719
+ "anticipatorySettle": 0.08
720
+ },
721
+ "layers": [
722
+ {
723
+ "id": "hero-bg-gradient",
724
+ "depth": 0.15,
725
+ "content": {
726
+ "type": "svg",
727
+ "src": "<radialGradient id='hg'><stop offset='0%' stop-color='#1a1a1a'/><stop offset='100%' stop-color='#0d0d0d'/></radialGradient>",
728
+ "alt": "Dark radial gradient background"
729
+ },
730
+ "animation": {
731
+ "properties": [
732
+ {
733
+ "property": "scale",
734
+ "from": 1.0,
735
+ "to": 1.05,
736
+ "easing": "none",
737
+ "relativeTo": "self",
738
+ "unit": ""
739
+ }
740
+ ],
741
+ "trigger": {
742
+ "start": "top top",
743
+ "end": "bottom top",
744
+ "scrub": 0.5,
745
+ "markers": false,
746
+ "fastScrollEnd": true,
747
+ "invalidateOnRefresh": true
748
+ }
749
+ },
750
+ "mobileDegradation": "static",
751
+ "willChange": true
752
+ },
753
+ {
754
+ "id": "hero-texture-dust",
755
+ "depth": 0.3,
756
+ "content": {
757
+ "type": "image",
758
+ "src": "/assets/noise-texture.webp",
759
+ "alt": "Subtle grain texture overlay"
760
+ },
761
+ "animation": {
762
+ "properties": [
763
+ {
764
+ "property": "opacity",
765
+ "from": 0.0,
766
+ "to": 0.08,
767
+ "easing": "power2.out",
768
+ "unit": ""
769
+ },
770
+ {
771
+ "property": "translateY",
772
+ "from": 0,
773
+ "to": -15,
774
+ "easing": "none",
775
+ "unit": "px"
776
+ }
777
+ ],
778
+ "trigger": {
779
+ "start": "top top",
780
+ "end": "bottom top",
781
+ "scrub": 0.8,
782
+ "fastScrollEnd": true,
783
+ "invalidateOnRefresh": true
784
+ }
785
+ },
786
+ "mobileDegradation": "reduce",
787
+ "willChange": false
788
+ },
789
+ {
790
+ "id": "hero-product-hero",
791
+ "depth": 0.6,
792
+ "content": {
793
+ "type": "image",
794
+ "src": "/assets/voss-bottle-hero.webp",
795
+ "alt": "Maison Voss signature fragrance bottle on marble pedestal"
796
+ },
797
+ "animation": {
798
+ "properties": [
799
+ {
800
+ "property": "translateY",
801
+ "from": 80,
802
+ "to": -40,
803
+ "easing": "none",
804
+ "relativeTo": "viewport",
805
+ "unit": "vh"
806
+ },
807
+ {
808
+ "property": "scale",
809
+ "from": 0.85,
810
+ "to": 1.0,
811
+ "easing": "power2.out",
812
+ "unit": ""
813
+ },
814
+ {
815
+ "property": "rotateY",
816
+ "from": -8,
817
+ "to": 0,
818
+ "easing": "power2.out",
819
+ "unit": "deg"
820
+ }
821
+ ],
822
+ "trigger": {
823
+ "start": "top top",
824
+ "end": "bottom top",
825
+ "scrub": 0.5,
826
+ "fastScrollEnd": true,
827
+ "invalidateOnRefresh": true
828
+ }
829
+ },
830
+ "mobileDegradation": "reduce",
831
+ "willChange": true
832
+ },
833
+ {
834
+ "id": "hero-title-manifesto",
835
+ "depth": 1.0,
836
+ "content": {
837
+ "type": "text",
838
+ "text": "Quiet is the new luxury.",
839
+ "fontSize": "clamp(3rem, 8vw, 7rem)"
840
+ },
841
+ "animation": {
842
+ "properties": [
843
+ {
844
+ "property": "translateY",
845
+ "from": 60,
846
+ "to": 0,
847
+ "easing": "power3.out",
848
+ "unit": "px"
849
+ },
850
+ {
851
+ "property": "opacity",
852
+ "from": 0.0,
853
+ "to": 1.0,
854
+ "easing": "power2.out",
855
+ "unit": ""
856
+ }
857
+ ],
858
+ "trigger": {
859
+ "start": "top 80%",
860
+ "end": "top 30%",
861
+ "scrub": 0.3,
862
+ "fastScrollEnd": true,
863
+ "invalidateOnRefresh": true
864
+ }
865
+ },
866
+ "mobileDegradation": "static",
867
+ "willChange": true
868
+ },
869
+ {
870
+ "id": "hero-cta-scroll",
871
+ "depth": 1.2,
872
+ "content": {
873
+ "type": "text",
874
+ "text": "Scroll to discover",
875
+ "fontSize": "0.875rem"
876
+ },
877
+ "animation": {
878
+ "properties": [
879
+ {
880
+ "property": "opacity",
881
+ "from": 1.0,
882
+ "to": 0.0,
883
+ "easing": "power2.in",
884
+ "unit": ""
885
+ },
886
+ {
887
+ "property": "translateY",
888
+ "from": 0,
889
+ "to": -30,
890
+ "easing": "power2.in",
891
+ "unit": "px"
892
+ }
893
+ ],
894
+ "trigger": {
895
+ "start": "top 60%",
896
+ "end": "top 40%",
897
+ "scrub": 0.5,
898
+ "fastScrollEnd": true,
899
+ "invalidateOnRefresh": true
900
+ }
901
+ },
902
+ "mobileDegradation": "static",
903
+ "willChange": false
904
+ }
905
+ ],
906
+ "titleReveal": {
907
+ "type": "maskReveal",
908
+ "scrollRange": {
909
+ "start": 0.08,
910
+ "end": 0.45
911
+ },
912
+ "stagger": {
913
+ "offset": 0.06,
914
+ "maxElements": 5
915
+ },
916
+ "easing": "cubic-bezier(0.16, 1, 0.3, 1)",
917
+ "text": "Quiet is the new luxury."
918
+ },
919
+ "atmosphere": {
920
+ "backgroundColor": "#0d0d0d",
921
+ "backgroundGradient": {
922
+ "from": "#0d0d0d",
923
+ "to": "#1a1a1a",
924
+ "angle": 160
925
+ },
926
+ "ambientDrift": {
927
+ "translateX": 0,
928
+ "translateY": 2,
929
+ "scale": 1.02
930
+ }
931
+ },
932
+ "velocityNodes": [
933
+ {
934
+ "threshold": 1.5,
935
+ "comparison": "above",
936
+ "above": {
937
+ "opacity": 0.6,
938
+ "scale": 0.98,
939
+ "letterSpacing": "-0.02em"
940
+ },
941
+ "below": {
942
+ "opacity": 1.0,
943
+ "scale": 1.0,
944
+ "letterSpacing": "0em"
945
+ },
946
+ "lerpFactor": 0.1
947
+ }
948
+ ]
949
+ },
950
+ {
951
+ "id": "editorial-philosophy",
952
+ "title": "The Philosophy of Restraint",
953
+ "pattern": "editorialLongread",
954
+ "scrollRange": {
955
+ "start": 500,
956
+ "end": 1300
957
+ },
958
+ "pin": {
959
+ "enabled": false,
960
+ "pinDuration": 150,
961
+ "pinSpacing": true,
962
+ "anticipatorySettle": 0.0
963
+ },
964
+ "layers": [
965
+ {
966
+ "id": "ed-chapter-marker",
967
+ "depth": 0.2,
968
+ "content": {
969
+ "type": "text",
970
+ "text": "I",
971
+ "fontSize": "12rem"
972
+ },
973
+ "animation": {
974
+ "properties": [
975
+ {
976
+ "property": "translateY",
977
+ "from": 40,
978
+ "to": -20,
979
+ "easing": "none",
980
+ "unit": "px"
981
+ },
982
+ {
983
+ "property": "opacity",
984
+ "from": 0.04,
985
+ "to": 0.12,
986
+ "easing": "none",
987
+ "unit": ""
988
+ }
989
+ ],
990
+ "trigger": {
991
+ "start": "top bottom",
992
+ "end": "bottom top",
993
+ "scrub": 0.5,
994
+ "fastScrollEnd": true,
995
+ "invalidateOnRefresh": true
996
+ }
997
+ },
998
+ "mobileDegradation": "static",
999
+ "willChange": false
1000
+ },
1001
+ {
1002
+ "id": "ed-inline-image-1",
1003
+ "depth": 0.4,
1004
+ "content": {
1005
+ "type": "image",
1006
+ "src": "/assets/atelier-workbench.webp",
1007
+ "alt": "Artisan's workbench with raw fragrance materials arranged in golden light"
1008
+ },
1009
+ "animation": {
1010
+ "properties": [
1011
+ {
1012
+ "property": "translateY",
1013
+ "from": 60,
1014
+ "to": -30,
1015
+ "easing": "none",
1016
+ "relativeTo": "parent",
1017
+ "unit": "px"
1018
+ },
1019
+ {
1020
+ "property": "scale",
1021
+ "from": 1.0,
1022
+ "to": 1.03,
1023
+ "easing": "none",
1024
+ "unit": ""
1025
+ }
1026
+ ],
1027
+ "trigger": {
1028
+ "start": "top 90%",
1029
+ "end": "bottom 10%",
1030
+ "scrub": 0.6,
1031
+ "fastScrollEnd": true,
1032
+ "invalidateOnRefresh": true
1033
+ }
1034
+ },
1035
+ "mobileDegradation": "reduce",
1036
+ "willChange": true
1037
+ },
1038
+ {
1039
+ "id": "ed-pull-quote",
1040
+ "depth": 0.7,
1041
+ "content": {
1042
+ "type": "text",
1043
+ "text": "\"We do not perfume the body. We compose silence around it.\"",
1044
+ "fontSize": "clamp(1.5rem, 3vw, 2.5rem)"
1045
+ },
1046
+ "animation": {
1047
+ "properties": [
1048
+ {
1049
+ "property": "translateY",
1050
+ "from": 30,
1051
+ "to": -15,
1052
+ "easing": "none",
1053
+ "unit": "px"
1054
+ },
1055
+ {
1056
+ "property": "scale",
1057
+ "from": 0.98,
1058
+ "to": 1.0,
1059
+ "easing": "power2.out",
1060
+ "unit": ""
1061
+ },
1062
+ {
1063
+ "property": "opacity",
1064
+ "from": 0.5,
1065
+ "to": 1.0,
1066
+ "easing": "power2.out",
1067
+ "unit": ""
1068
+ }
1069
+ ],
1070
+ "trigger": {
1071
+ "start": "top 85%",
1072
+ "end": "top 30%",
1073
+ "scrub": 0.4,
1074
+ "fastScrollEnd": true,
1075
+ "invalidateOnRefresh": true
1076
+ }
1077
+ },
1078
+ "mobileDegradation": "reduce",
1079
+ "willChange": true
1080
+ },
1081
+ {
1082
+ "id": "ed-full-bleed-chapter",
1083
+ "depth": 0.9,
1084
+ "content": {
1085
+ "type": "image",
1086
+ "src": "/assets/ingredients-raw.webp",
1087
+ "alt": "Raw ingredients: bergamot, amber resin, and sandalwood shavings"
1088
+ },
1089
+ "animation": {
1090
+ "properties": [
1091
+ {
1092
+ "property": "translateY",
1093
+ "from": 0,
1094
+ "to": -80,
1095
+ "easing": "none",
1096
+ "relativeTo": "parent",
1097
+ "unit": "px"
1098
+ },
1099
+ {
1100
+ "property": "scale",
1101
+ "from": 1.08,
1102
+ "to": 1.0,
1103
+ "easing": "none",
1104
+ "unit": ""
1105
+ }
1106
+ ],
1107
+ "trigger": {
1108
+ "start": "top bottom",
1109
+ "end": "bottom top",
1110
+ "scrub": 0.5,
1111
+ "fastScrollEnd": true,
1112
+ "invalidateOnRefresh": true
1113
+ }
1114
+ },
1115
+ "mobileDegradation": "reduce",
1116
+ "willChange": true
1117
+ }
1118
+ ],
1119
+ "titleReveal": {
1120
+ "type": "wordStagger",
1121
+ "scrollRange": {
1122
+ "start": 0.0,
1123
+ "end": 0.35
1124
+ },
1125
+ "stagger": {
1126
+ "offset": 0.05,
1127
+ "maxElements": 5
1128
+ },
1129
+ "easing": "cubic-bezier(0.16, 1, 0.3, 1)",
1130
+ "text": "The Philosophy of Restraint"
1131
+ },
1132
+ "atmosphere": {
1133
+ "backgroundColor": "#f5f0e8",
1134
+ "backgroundGradient": {
1135
+ "from": "#f5f0e8",
1136
+ "to": "#ebe4d6",
1137
+ "angle": 180
1138
+ },
1139
+ "ambientDrift": {
1140
+ "translateX": 0.5,
1141
+ "translateY": 1.5,
1142
+ "scale": 1.01
1143
+ }
1144
+ },
1145
+ "velocityNodes": [
1146
+ {
1147
+ "threshold": 1.2,
1148
+ "comparison": "above",
1149
+ "above": {
1150
+ "opacity": 0.85,
1151
+ "letterSpacing": "-0.01em"
1152
+ },
1153
+ "below": {
1154
+ "opacity": 1.0,
1155
+ "letterSpacing": "0.01em"
1156
+ },
1157
+ "lerpFactor": 0.15
1158
+ }
1159
+ ]
1160
+ },
1161
+ {
1162
+ "id": "finale-collection",
1163
+ "title": "The Collection",
1164
+ "pattern": "chapteredRelease",
1165
+ "scrollRange": {
1166
+ "start": 1300,
1167
+ "end": 2200
1168
+ },
1169
+ "pin": {
1170
+ "enabled": true,
1171
+ "pinDuration": 300,
1172
+ "pinSpacing": true,
1173
+ "anticipatorySettle": 0.05
1174
+ },
1175
+ "layers": [
1176
+ {
1177
+ "id": "finale-bg-morph",
1178
+ "depth": 0.15,
1179
+ "content": {
1180
+ "type": "svg",
1181
+ "src": "<linearGradient id='gm'><stop offset='0%' stop-color='#c9a962'/><stop offset='100%' stop-color='#f5f0e8'/></linearGradient>",
1182
+ "alt": "Background gradient that morphs from gold to cream"
1183
+ },
1184
+ "animation": {
1185
+ "properties": [
1186
+ {
1187
+ "property": "scale",
1188
+ "from": 1.0,
1189
+ "to": 1.08,
1190
+ "easing": "none",
1191
+ "unit": ""
1192
+ }
1193
+ ],
1194
+ "trigger": {
1195
+ "start": "top top",
1196
+ "end": "bottom top",
1197
+ "scrub": 0.5,
1198
+ "fastScrollEnd": true,
1199
+ "invalidateOnRefresh": true
1200
+ }
1201
+ },
1202
+ "mobileDegradation": "static",
1203
+ "willChange": true
1204
+ },
1205
+ {
1206
+ "id": "finale-ambient-texture",
1207
+ "depth": 0.3,
1208
+ "content": {
1209
+ "type": "image",
1210
+ "src": "/assets/gold-vein-texture.webp",
1211
+ "alt": "Subtle gold vein texture overlay"
1212
+ },
1213
+ "animation": {
1214
+ "properties": [
1215
+ {
1216
+ "property": "opacity",
1217
+ "from": 0.15,
1218
+ "to": 0.05,
1219
+ "easing": "power2.inOut",
1220
+ "unit": ""
1221
+ },
1222
+ {
1223
+ "property": "translateY",
1224
+ "from": 0,
1225
+ "to": -25,
1226
+ "easing": "none",
1227
+ "unit": "px"
1228
+ }
1229
+ ],
1230
+ "trigger": {
1231
+ "start": "top top",
1232
+ "end": "bottom top",
1233
+ "scrub": 0.7,
1234
+ "fastScrollEnd": true,
1235
+ "invalidateOnRefresh": true
1236
+ }
1237
+ },
1238
+ "mobileDegradation": "static",
1239
+ "willChange": false
1240
+ },
1241
+ {
1242
+ "id": "finale-product-trio",
1243
+ "depth": 0.6,
1244
+ "content": {
1245
+ "type": "image",
1246
+ "src": "/assets/voss-collection-trio.webp",
1247
+ "alt": "Three fragrance bottles arranged in ascending composition"
1248
+ },
1249
+ "animation": {
1250
+ "properties": [
1251
+ {
1252
+ "property": "translateY",
1253
+ "from": 100,
1254
+ "to": -30,
1255
+ "easing": "none",
1256
+ "relativeTo": "viewport",
1257
+ "unit": "vh"
1258
+ },
1259
+ {
1260
+ "property": "scale",
1261
+ "from": 0.9,
1262
+ "to": 1.0,
1263
+ "easing": "power2.out",
1264
+ "unit": ""
1265
+ },
1266
+ {
1267
+ "property": "rotateX",
1268
+ "from": 6,
1269
+ "to": 0,
1270
+ "easing": "power2.out",
1271
+ "unit": "deg"
1272
+ }
1273
+ ],
1274
+ "trigger": {
1275
+ "start": "top top",
1276
+ "end": "bottom top",
1277
+ "scrub": 0.5,
1278
+ "fastScrollEnd": true,
1279
+ "invalidateOnRefresh": true
1280
+ }
1281
+ },
1282
+ "mobileDegradation": "reduce",
1283
+ "willChange": true
1284
+ },
1285
+ {
1286
+ "id": "finale-title-collection",
1287
+ "depth": 1.0,
1288
+ "content": {
1289
+ "type": "text",
1290
+ "text": "The Collection",
1291
+ "fontSize": "clamp(3rem, 7vw, 6rem)"
1292
+ },
1293
+ "animation": {
1294
+ "properties": [
1295
+ {
1296
+ "property": "translateX",
1297
+ "from": -40,
1298
+ "to": 0,
1299
+ "easing": "power3.out",
1300
+ "unit": "px"
1301
+ },
1302
+ {
1303
+ "property": "opacity",
1304
+ "from": 0.0,
1305
+ "to": 1.0,
1306
+ "easing": "power2.out",
1307
+ "unit": ""
1308
+ }
1309
+ ],
1310
+ "trigger": {
1311
+ "start": "top 75%",
1312
+ "end": "top 35%",
1313
+ "scrub": 0.3,
1314
+ "fastScrollEnd": true,
1315
+ "invalidateOnRefresh": true
1316
+ }
1317
+ },
1318
+ "mobileDegradation": "static",
1319
+ "willChange": true
1320
+ },
1321
+ {
1322
+ "id": "finale-product-labels",
1323
+ "depth": 1.15,
1324
+ "content": {
1325
+ "type": "text",
1326
+ "text": "Silence | Whisper | Presence",
1327
+ "fontSize": "1rem"
1328
+ },
1329
+ "animation": {
1330
+ "properties": [
1331
+ {
1332
+ "property": "translateY",
1333
+ "from": 20,
1334
+ "to": 0,
1335
+ "easing": "power2.out",
1336
+ "unit": "px"
1337
+ },
1338
+ {
1339
+ "property": "opacity",
1340
+ "from": 0.0,
1341
+ "to": 0.8,
1342
+ "easing": "power2.out",
1343
+ "unit": ""
1344
+ },
1345
+ {
1346
+ "property": "letterSpacing",
1347
+ "from": "0.3em",
1348
+ "to": "0.15em",
1349
+ "easing": "power2.out",
1350
+ "unit": ""
1351
+ }
1352
+ ],
1353
+ "trigger": {
1354
+ "start": "top 60%",
1355
+ "end": "top 40%",
1356
+ "scrub": 0.4,
1357
+ "fastScrollEnd": true,
1358
+ "invalidateOnRefresh": true
1359
+ }
1360
+ },
1361
+ "mobileDegradation": "static",
1362
+ "willChange": false
1363
+ },
1364
+ {
1365
+ "id": "finale-nav-dots",
1366
+ "depth": 1.3,
1367
+ "content": {
1368
+ "type": "svg",
1369
+ "src": "<svg width='60' height='200'><circle cx='30' cy='20' r='6' fill='currentColor'/><circle cx='30' cy='60' r='4' fill='currentColor' opacity='0.5'/><circle cx='30' cy='100' r='4' fill='currentColor' opacity='0.5'/></svg>",
1370
+ "alt": "Chapter navigation dots"
1371
+ },
1372
+ "animation": {
1373
+ "properties": [
1374
+ {
1375
+ "property": "opacity",
1376
+ "from": 0.0,
1377
+ "to": 0.6,
1378
+ "easing": "power2.out",
1379
+ "unit": ""
1380
+ }
1381
+ ],
1382
+ "trigger": {
1383
+ "start": "top 50%",
1384
+ "end": "top 30%",
1385
+ "scrub": 0.5,
1386
+ "fastScrollEnd": true,
1387
+ "invalidateOnRefresh": true
1388
+ }
1389
+ },
1390
+ "mobileDegradation": "static",
1391
+ "willChange": false
1392
+ }
1393
+ ],
1394
+ "titleReveal": {
1395
+ "type": "letterSpacingScrub",
1396
+ "scrollRange": {
1397
+ "start": 0.05,
1398
+ "end": 0.55
1399
+ },
1400
+ "stagger": {
1401
+ "offset": 0.02,
1402
+ "maxElements": 3
1403
+ },
1404
+ "easing": "none",
1405
+ "text": "The Collection"
1406
+ },
1407
+ "atmosphere": {
1408
+ "backgroundColor": "#c9a962",
1409
+ "backgroundGradient": {
1410
+ "from": "#c9a962",
1411
+ "to": "#f5f0e8",
1412
+ "angle": 145
1413
+ },
1414
+ "colorMorph": {
1415
+ "from": "#c9a962",
1416
+ "to": "#f5f0e8",
1417
+ "scrollStart": 0.2,
1418
+ "scrollEnd": 0.8,
1419
+ "easing": "power2.inOut"
1420
+ },
1421
+ "ambientDrift": {
1422
+ "translateX": 1,
1423
+ "translateY": 2.5,
1424
+ "scale": 1.03
1425
+ }
1426
+ },
1427
+ "velocityNodes": [
1428
+ {
1429
+ "threshold": 2.0,
1430
+ "comparison": "above",
1431
+ "above": {
1432
+ "opacity": 0.7,
1433
+ "scale": 0.97,
1434
+ "skewX": 1.5,
1435
+ "letterSpacing": "-0.03em"
1436
+ },
1437
+ "below": {
1438
+ "opacity": 1.0,
1439
+ "scale": 1.0,
1440
+ "skewX": 0,
1441
+ "letterSpacing": "0.05em"
1442
+ },
1443
+ "lerpFactor": 0.08
1444
+ },
1445
+ {
1446
+ "threshold": 0.5,
1447
+ "comparison": "below",
1448
+ "below": {
1449
+ "opacity": 1.0,
1450
+ "scale": 1.01,
1451
+ "letterSpacing": "0.08em"
1452
+ },
1453
+ "above": {
1454
+ "opacity": 0.95,
1455
+ "scale": 1.0,
1456
+ "letterSpacing": "0.03em"
1457
+ },
1458
+ "lerpFactor": 0.12
1459
+ }
1460
+ ]
1461
+ }
1462
+ ],
1463
+ "transitions": [
1464
+ {
1465
+ "from": "hero-manifesto",
1466
+ "to": "editorial-philosophy",
1467
+ "type": "craneShot",
1468
+ "duration": 100,
1469
+ "overlap": 30,
1470
+ "easing": "power4.inOut",
1471
+ "properties": [
1472
+ {
1473
+ "property": "translateY",
1474
+ "from": 0,
1475
+ "to": -100,
1476
+ "relativeTo": "viewport",
1477
+ "unit": "vh"
1478
+ },
1479
+ {
1480
+ "property": "rotateX",
1481
+ "from": 0,
1482
+ "to": 4,
1483
+ "unit": "deg"
1484
+ }
1485
+ ]
1486
+ },
1487
+ {
1488
+ "from": "editorial-philosophy",
1489
+ "to": "finale-collection",
1490
+ "type": "dissolve",
1491
+ "duration": 80,
1492
+ "overlap": 20,
1493
+ "easing": "power2.inOut",
1494
+ "properties": [
1495
+ {
1496
+ "property": "opacity",
1497
+ "from": 1.0,
1498
+ "to": 0.0,
1499
+ "unit": ""
1500
+ },
1501
+ {
1502
+ "property": "scale",
1503
+ "from": 1.0,
1504
+ "to": 0.97,
1505
+ "unit": ""
1506
+ }
1507
+ ]
1508
+ }
1509
+ ]
1510
+ }
1511
+ ]
1512
+ }