hyperframes 0.1.1 → 0.1.4

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 (31) hide show
  1. package/README.md +121 -0
  2. package/dist/cli.js +2755 -1167
  3. package/dist/docs/compositions.md +8 -1
  4. package/dist/docs/data-attributes.md +4 -0
  5. package/dist/docs/gsap.md +3 -0
  6. package/dist/docs/rendering.md +4 -0
  7. package/dist/docs/templates.md +4 -0
  8. package/dist/docs/troubleshooting.md +7 -0
  9. package/dist/hyperframe-runtime.js +4 -3
  10. package/dist/hyperframe.manifest.json +22 -0
  11. package/dist/hyperframe.runtime.iife.js +13 -0
  12. package/dist/studio/index.html +11 -11
  13. package/dist/templates/blank/compositions/captions.html +92 -0
  14. package/dist/templates/blank/index.html +44 -0
  15. package/dist/templates/play-mode/compositions/captions.html +96 -30
  16. package/dist/templates/play-mode/compositions/intro.html +90 -71
  17. package/dist/templates/play-mode/compositions/stats.html +210 -74
  18. package/dist/templates/play-mode/index.html +214 -148
  19. package/dist/templates/swiss-grid/compositions/captions.html +70 -17
  20. package/dist/templates/swiss-grid/compositions/graphics.html +52 -43
  21. package/dist/templates/swiss-grid/compositions/intro.html +42 -25
  22. package/dist/templates/swiss-grid/index.html +227 -165
  23. package/dist/templates/vignelli/compositions/captions.html +87 -28
  24. package/dist/templates/vignelli/compositions/overlays.html +83 -31
  25. package/dist/templates/vignelli/index.html +183 -164
  26. package/dist/templates/warm-grain/compositions/captions.html +80 -66
  27. package/dist/templates/warm-grain/compositions/graphics.html +29 -22
  28. package/dist/templates/warm-grain/compositions/intro.html +29 -20
  29. package/dist/templates/warm-grain/index.html +278 -179
  30. package/package.json +16 -15
  31. package/LICENSE +0 -21
@@ -33,7 +33,7 @@
33
33
  <div class="overlay-item editing-skills-stat" id="stat-3-4">
34
34
  <div class="text-block">
35
35
  <span class="highlight">3 out of 4</span>
36
- <br>lack editing skills
36
+ <br />lack editing skills
37
37
  </div>
38
38
  <div class="side-bar"></div>
39
39
  </div>
@@ -51,7 +51,7 @@
51
51
  position: relative;
52
52
  width: 1080px;
53
53
  height: 1920px;
54
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
54
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
55
55
  color: #000000;
56
56
  overflow: hidden;
57
57
  pointer-events: none;
@@ -87,13 +87,13 @@
87
87
  left: 0;
88
88
  width: 540px; /* 3 columns */
89
89
  height: 240px;
90
- background: #FFFFFF;
90
+ background: #ffffff;
91
91
  flex-direction: row;
92
92
  align-items: stretch;
93
93
  }
94
94
  [data-composition-id="overlays"] #stat-47 .red-bar {
95
95
  width: 20px;
96
- background: #CC0000;
96
+ background: #cc0000;
97
97
  }
98
98
  [data-composition-id="overlays"] #stat-47 .stat-content {
99
99
  padding: 40px;
@@ -128,7 +128,7 @@
128
128
  left: 0;
129
129
  width: 100%;
130
130
  height: 100%;
131
- background: #1A1A1A;
131
+ background: #1a1a1a;
132
132
  }
133
133
  [data-composition-id="overlays"] #stat-62 .full-content {
134
134
  position: relative;
@@ -142,14 +142,14 @@
142
142
  [data-composition-id="overlays"] #stat-62 .large-number {
143
143
  font-size: 400px;
144
144
  font-weight: 900;
145
- color: #FFFFFF;
145
+ color: #ffffff;
146
146
  line-height: 0.8;
147
147
  letter-spacing: -10px;
148
148
  }
149
149
  [data-composition-id="overlays"] #stat-62 .large-label {
150
150
  font-size: 80px;
151
151
  font-weight: 700;
152
- color: #FFFFFF;
152
+ color: #ffffff;
153
153
  text-transform: uppercase;
154
154
  margin-top: 20px;
155
155
  max-width: 600px;
@@ -160,7 +160,7 @@
160
160
  right: 0;
161
161
  width: 180px; /* 1 column */
162
162
  height: 100%;
163
- background: #CC0000;
163
+ background: #cc0000;
164
164
  }
165
165
 
166
166
  /* 3. 3 out of 4 Stat Styles */
@@ -168,7 +168,7 @@
168
168
  top: 400px;
169
169
  right: 0;
170
170
  width: 360px; /* 2 columns */
171
- background: #FFFFFF;
171
+ background: #ffffff;
172
172
  padding: 40px;
173
173
  flex-direction: row-reverse;
174
174
  }
@@ -179,7 +179,7 @@
179
179
  text-align: right;
180
180
  }
181
181
  [data-composition-id="overlays"] #stat-3-4 .highlight {
182
- color: #CC0000;
182
+ color: #cc0000;
183
183
  font-size: 64px;
184
184
  font-weight: 900;
185
185
  }
@@ -216,7 +216,7 @@
216
216
  [data-composition-id="overlays"] #branding .logo-underline {
217
217
  width: 100%;
218
218
  height: 8px;
219
- background: #CC0000;
219
+ background: #cc0000;
220
220
  margin-top: 10px;
221
221
  transform-origin: left;
222
222
  }
@@ -224,47 +224,99 @@
224
224
 
225
225
  <script>
226
226
  const tl = gsap.timeline({ paused: true });
227
- const TRANSCRIPT = [{'text': 'We', 'start': 0.14, 'end': 0.239}, {'text': 'asked', 'start': 0.28, 'end': 0.459}, {'text': 'what', 'start': 0.5, 'end': 0.619}, {'text': 'you', 'start': 0.659, 'end': 0.779}, {'text': 'needed.', 'start': 0.8, 'end': 1.179}, {'text': 'Forty-seven', 'start': 1.199, 'end': 1.619}, {'text': 'percent', 'start': 1.699, 'end': 1.96}, {'text': 'of', 'start': 1.979, 'end': 2.059}, {'text': 'you', 'start': 2.099, 'end': 2.299}, {'text': 'said', 'start': 2.319, 'end': 2.499}, {'text': 'motion', 'start': 2.559, 'end': 2.839}, {'text': 'graphics,', 'start': 2.899, 'end': 3.759}, {'text': 'sixty-two', 'start': 3.799, 'end': 4.159}, {'text': 'percent', 'start': 4.239, 'end': 4.559}, {'text': 'said', 'start': 4.639, 'end': 4.799}, {'text': 'static', 'start': 4.859, 'end': 5.199}, {'text': 'content', 'start': 5.239, 'end': 5.639}, {'text': 'was', 'start': 5.679, 'end': 5.779}, {'text': 'costing', 'start': 5.859, 'end': 6.219}, {'text': 'you', 'start': 6.259, 'end': 6.339}, {'text': 'attention,', 'start': 6.379, 'end': 7.299}, {'text': 'and', 'start': 7.319, 'end': 7.439}, {'text': 'three', 'start': 7.48, 'end': 7.599}, {'text': 'out', 'start': 7.679, 'end': 7.779}, {'text': 'of', 'start': 7.799, 'end': 7.879}, {'text': 'four', 'start': 7.94, 'end': 8.139}, {'text': 'said', 'start': 8.279, 'end': 8.46}, {'text': 'you', 'start': 8.519, 'end': 8.6}, {'text': 'know', 'start': 8.619, 'end': 8.739}, {'text': 'the', 'start': 8.8, 'end': 8.88}, {'text': 'look', 'start': 8.92, 'end': 9.079}, {'text': 'you', 'start': 9.119, 'end': 9.259}, {'text': 'want', 'start': 9.279, 'end': 9.619}, {'text': 'but', 'start': 9.779, 'end': 9.88}, {'text': "don't", 'start': 9.92, 'end': 10.1}, {'text': 'have', 'start': 10.159, 'end': 10.3}, {'text': 'the', 'start': 10.3, 'end': 10.42}, {'text': 'editing', 'start': 10.5, 'end': 10.779}, {'text': 'skills', 'start': 10.86, 'end': 11.139}, {'text': 'to', 'start': 11.159, 'end': 11.239}, {'text': 'get', 'start': 11.279, 'end': 11.439}, {'text': 'there.', 'start': 11.46, 'end': 12.239}, {'text': 'So', 'start': 12.3, 'end': 12.38}, {'text': 'we', 'start': 12.399, 'end': 12.519}, {'text': 'built', 'start': 12.539, 'end': 12.759}, {'text': 'Hyperframes', 'start': 12.84, 'end': 13.119}];
227
+ const TRANSCRIPT = [
228
+ { text: "We", start: 0.14, end: 0.239 },
229
+ { text: "asked", start: 0.28, end: 0.459 },
230
+ { text: "what", start: 0.5, end: 0.619 },
231
+ { text: "you", start: 0.659, end: 0.779 },
232
+ { text: "needed.", start: 0.8, end: 1.179 },
233
+ { text: "Forty-seven", start: 1.199, end: 1.619 },
234
+ { text: "percent", start: 1.699, end: 1.96 },
235
+ { text: "of", start: 1.979, end: 2.059 },
236
+ { text: "you", start: 2.099, end: 2.299 },
237
+ { text: "said", start: 2.319, end: 2.499 },
238
+ { text: "motion", start: 2.559, end: 2.839 },
239
+ { text: "graphics,", start: 2.899, end: 3.759 },
240
+ { text: "sixty-two", start: 3.799, end: 4.159 },
241
+ { text: "percent", start: 4.239, end: 4.559 },
242
+ { text: "said", start: 4.639, end: 4.799 },
243
+ { text: "static", start: 4.859, end: 5.199 },
244
+ { text: "content", start: 5.239, end: 5.639 },
245
+ { text: "was", start: 5.679, end: 5.779 },
246
+ { text: "costing", start: 5.859, end: 6.219 },
247
+ { text: "you", start: 6.259, end: 6.339 },
248
+ { text: "attention,", start: 6.379, end: 7.299 },
249
+ { text: "and", start: 7.319, end: 7.439 },
250
+ { text: "three", start: 7.48, end: 7.599 },
251
+ { text: "out", start: 7.679, end: 7.779 },
252
+ { text: "of", start: 7.799, end: 7.879 },
253
+ { text: "four", start: 7.94, end: 8.139 },
254
+ { text: "said", start: 8.279, end: 8.46 },
255
+ { text: "you", start: 8.519, end: 8.6 },
256
+ { text: "know", start: 8.619, end: 8.739 },
257
+ { text: "the", start: 8.8, end: 8.88 },
258
+ { text: "look", start: 8.92, end: 9.079 },
259
+ { text: "you", start: 9.119, end: 9.259 },
260
+ { text: "want", start: 9.279, end: 9.619 },
261
+ { text: "but", start: 9.779, end: 9.88 },
262
+ { text: "don't", start: 9.92, end: 10.1 },
263
+ { text: "have", start: 10.159, end: 10.3 },
264
+ { text: "the", start: 10.3, end: 10.42 },
265
+ { text: "editing", start: 10.5, end: 10.779 },
266
+ { text: "skills", start: 10.86, end: 11.139 },
267
+ { text: "to", start: 11.159, end: 11.239 },
268
+ { text: "get", start: 11.279, end: 11.439 },
269
+ { text: "there.", start: 11.46, end: 12.239 },
270
+ { text: "So", start: 12.3, end: 12.38 },
271
+ { text: "we", start: 12.399, end: 12.519 },
272
+ { text: "built", start: 12.539, end: 12.759 },
273
+ { text: "Hyperframes", start: 12.84, end: 13.119 },
274
+ ];
228
275
 
229
276
  // Requirement 1: "47% Motion Graphics" (Start: 1.199, End: 3.759)
230
277
  // Positioned in bottom half, columns 1-3.
231
- tl.fromTo("#stat-47",
232
- { x: -540, opacity: 1 },
233
- { x: 0, duration: 0.8, ease: "expo.out" },
234
- 1.199
235
- );
236
- tl.to("#stat-47",
237
- { x: -540, duration: 0.6, ease: "expo.in" },
238
- 3.759 - 0.6
278
+ tl.fromTo(
279
+ "#stat-47",
280
+ { x: -540, opacity: 1 },
281
+ { x: 0, duration: 0.8, ease: "expo.out" },
282
+ 1.199,
239
283
  );
284
+ tl.to("#stat-47", { x: -540, duration: 0.6, ease: "expo.in" }, 3.759 - 0.6);
240
285
 
241
286
  // Requirement 2: "62% Static Content" (Start: 3.799, End: 7.299)
242
287
  // Full canvas moment. Large bold typography across columns.
243
288
  tl.set("#stat-62", { opacity: 1 }, 3.799);
244
289
  tl.from("#stat-62 .bg-charcoal", { x: "100%", duration: 0.8, ease: "expo.out" }, 3.799);
245
290
  tl.from("#stat-62 .red-accent", { x: "100%", duration: 0.8, ease: "expo.out" }, 3.899);
246
- tl.from("#stat-62 .large-number", { y: 100, opacity: 0, duration: 1, ease: "expo.out" }, 4.099);
291
+ tl.from(
292
+ "#stat-62 .large-number",
293
+ { y: 100, opacity: 0, duration: 1, ease: "expo.out" },
294
+ 4.099,
295
+ );
247
296
  tl.from("#stat-62 .large-label", { y: 50, opacity: 0, duration: 1, ease: "expo.out" }, 4.299);
248
-
297
+
249
298
  tl.to("#stat-62", { x: "-100%", duration: 0.8, ease: "expo.in" }, 7.299 - 0.8);
250
299
 
251
300
  // Requirement 3: "3 out of 4 lack editing skills" (Start: 7.319, End: 12.239)
252
301
  // Positioned in columns 5-6 (right side) to avoid face (x: 300-776)
253
- tl.fromTo("#stat-3-4",
254
- { x: 360, opacity: 1 },
255
- { x: 0, duration: 0.8, ease: "expo.out" },
256
- 7.319
257
- );
258
- tl.to("#stat-3-4",
259
- { x: 360, duration: 0.6, ease: "expo.in" },
260
- 12.239 - 0.6
302
+ tl.fromTo(
303
+ "#stat-3-4",
304
+ { x: 360, opacity: 1 },
305
+ { x: 0, duration: 0.8, ease: "expo.out" },
306
+ 7.319,
261
307
  );
308
+ tl.to("#stat-3-4", { x: 360, duration: 0.6, ease: "expo.in" }, 12.239 - 0.6);
262
309
 
263
310
  // Requirement 4: "Hyperframes" (Start: 12.84, End: 13.84)
264
311
  tl.set("#branding", { opacity: 1 }, 12.84);
265
- tl.from("#branding .logo-text", { y: 20, opacity: 0, duration: 0.6, ease: "expo.out" }, 12.84);
312
+ tl.from(
313
+ "#branding .logo-text",
314
+ { y: 20, opacity: 0, duration: 0.6, ease: "expo.out" },
315
+ 12.84,
316
+ );
266
317
  tl.from("#branding .logo-underline", { scaleX: 0, duration: 0.8, ease: "expo.out" }, 13.04);
267
318
 
319
+ window.__timelines = window.__timelines || {};
268
320
  window.__timelines["overlays"] = tl;
269
321
  </script>
270
322
  </div>
@@ -1,171 +1,190 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
5
  <title>Massimo Vignelli Video</title>
6
6
  <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
7
7
  <style>
8
- body,
9
- html {
10
- margin: 0;
11
- padding: 0;
12
- background: #FFFFFF;
13
- overflow: hidden;
14
- width: 1080px;
15
- height: 1920px;
16
- font-family: 'Helvetica', Arial, sans-serif;
17
- }
18
-
19
- /* 6-Column Grid System */
20
- .grid-container {
21
- position: absolute;
22
- top: 0;
23
- left: 0;
24
- width: 1080px;
25
- height: 1920px;
26
- display: grid;
27
- grid-template-columns: repeat(6, 1fr);
28
- pointer-events: none;
29
- z-index: 1000;
30
- opacity: 0; /* Keep grid invisible but present for layout references */
31
- }
32
-
33
- .grid-column {
34
- border-right: 1px solid rgba(204, 0, 0, 0.2); /* Vignelli Red accent */
35
- }
36
-
37
- #main-composition {
38
- position: relative;
39
- width: 1080px;
40
- height: 1920px;
41
- background: #FFFFFF;
42
- overflow: hidden;
43
- }
44
-
45
- /* Layer Hosts */
46
- #a-roll-wrapper {
47
- position: absolute;
48
- top: 0;
49
- left: 0;
50
- width: 100%;
51
- height: 100%;
52
- z-index: 10;
53
- overflow: hidden;
54
- }
55
-
56
- #a-roll,
57
- #a-roll-wrapper img.__render_frame__,
58
- #a-roll-wrapper img.__preview_render_frame__ {
59
- position: absolute;
60
- inset: 0;
61
- width: 100%;
62
- height: 100%;
63
- object-fit: cover;
64
- }
65
-
66
- #overlays-comp,
67
- #captions-comp {
68
- position: absolute;
69
- top: 0;
70
- left: 0;
71
- width: 1080px;
72
- height: 1920px;
73
- pointer-events: none;
74
- }
75
-
76
- #overlays-comp {
77
- z-index: 20;
78
- }
79
-
80
- #captions-comp {
81
- z-index: 30;
82
- }
83
-
84
- /* Curtain Transition Layer */
85
- .curtain {
86
- position: absolute;
87
- top: 0;
88
- left: -100%;
89
- width: 100%;
90
- height: 100%;
91
- background: #1A1A1A;
92
- z-index: 25;
93
- pointer-events: none;
94
- }
95
-
96
- .curtain.red {
97
- background: #CC0000;
98
- z-index: 26;
99
- }
100
-
8
+ body,
9
+ html {
10
+ margin: 0;
11
+ padding: 0;
12
+ background: #ffffff;
13
+ overflow: hidden;
14
+ width: 1080px;
15
+ height: 1920px;
16
+ font-family: "Helvetica", Arial, sans-serif;
17
+ }
18
+
19
+ /* 6-Column Grid System */
20
+ .grid-container {
21
+ position: absolute;
22
+ top: 0;
23
+ left: 0;
24
+ width: 1080px;
25
+ height: 1920px;
26
+ display: grid;
27
+ grid-template-columns: repeat(6, 1fr);
28
+ pointer-events: none;
29
+ z-index: 1000;
30
+ opacity: 0; /* Keep grid invisible but present for layout references */
31
+ }
32
+
33
+ .grid-column {
34
+ border-right: 1px solid rgba(204, 0, 0, 0.2); /* Vignelli Red accent */
35
+ }
36
+
37
+ #main-composition {
38
+ position: relative;
39
+ width: 1080px;
40
+ height: 1920px;
41
+ background: #ffffff;
42
+ overflow: hidden;
43
+ }
44
+
45
+ /* Layer Hosts */
46
+ #a-roll-wrapper {
47
+ position: absolute;
48
+ top: 0;
49
+ left: 0;
50
+ width: 100%;
51
+ height: 100%;
52
+ z-index: 10;
53
+ overflow: hidden;
54
+ }
55
+
56
+ #a-roll,
57
+ #a-roll-wrapper img.__render_frame__,
58
+ #a-roll-wrapper img.__preview_render_frame__ {
59
+ position: absolute;
60
+ inset: 0;
61
+ width: 100%;
62
+ height: 100%;
63
+ object-fit: cover;
64
+ }
65
+
66
+ #overlays-comp,
67
+ #captions-comp {
68
+ position: absolute;
69
+ top: 0;
70
+ left: 0;
71
+ width: 1080px;
72
+ height: 1920px;
73
+ pointer-events: none;
74
+ }
75
+
76
+ #overlays-comp {
77
+ z-index: 20;
78
+ }
79
+
80
+ #captions-comp {
81
+ z-index: 30;
82
+ }
83
+
84
+ /* Curtain Transition Layer */
85
+ .curtain {
86
+ position: absolute;
87
+ top: 0;
88
+ left: -100%;
89
+ width: 100%;
90
+ height: 100%;
91
+ background: #1a1a1a;
92
+ z-index: 25;
93
+ pointer-events: none;
94
+ }
95
+
96
+ .curtain.red {
97
+ background: #cc0000;
98
+ z-index: 26;
99
+ }
101
100
  </style>
102
- </head>
103
- <body>
104
- <div id="main-composition" data-composition-id="main-comp" data-width="1080" data-height="1920" data-duration="13.88">
105
-
106
- <!-- A-Roll -->
107
- <div id="a-roll-wrapper">
108
- <video id="a-roll"
109
- src="__VIDEO_SRC__"
110
- data-start="0"
111
- data-duration="13.88"
112
- data-track-index="0">
113
- </video>
114
- </div>
115
-
116
- <!-- Transitions -->
117
- <div id="curtain-black" class="curtain"></div>
118
- <div id="curtain-red" class="curtain red"></div>
119
-
120
- <!-- Overlays Composition -->
121
- <div id="overlays-comp"
122
- data-composition-id="overlays"
123
- data-composition-src="compositions/overlays.html"
124
- data-start="0"
125
- data-duration="13.88"
126
- data-track-index="2">
127
- </div>
128
-
129
- <!-- Captions Composition -->
130
- <div id="captions-comp"
131
- data-composition-id="captions"
132
- data-composition-src="compositions/captions.html"
133
- data-start="0"
134
- data-duration="13.88"
135
- data-track-index="3">
136
- </div>
137
-
138
- <!-- Grid Visualization -->
139
- <div class="grid-container">
140
- <div class="grid-column"></div>
141
- <div class="grid-column"></div>
142
- <div class="grid-column"></div>
143
- <div class="grid-column"></div>
144
- <div class="grid-column"></div>
145
- <div class="grid-column"></div>
146
- </div>
147
-
148
- <script>
149
- const tl = gsap.timeline({ paused: true });
150
-
151
- // Transition: Curtain Pull logic
152
- // A-roll leaves the screen at least once.
153
- // Timing: Let's do a curtain pull at 3.7s (transitioning to the 62% stat)
154
- // and return at 7.3s (end of attention stat).
155
-
156
- // Curtain Out (A-roll hidden)
157
- tl.to("#curtain-black", { left: "0%", duration: 0.2, ease: "power2.inOut" }, 3.5);
158
- tl.to("#a-roll-wrapper", { opacity: 0, duration: 0 }, 3.7);
159
- tl.to("#curtain-black", { left: "100%", duration: 0.4, ease: "power2.inOut" }, 3.7);
160
-
161
- // Curtain In (A-roll return)
162
- tl.set("#curtain-red", { left: "-100%" }, 7.1);
163
- tl.to("#curtain-red", { left: "0%", duration: 0.2, ease: "power2.inOut" }, 7.1);
164
- tl.to("#a-roll-wrapper", { opacity: 1, duration: 0 }, 7.3);
165
- tl.to("#curtain-red", { left: "100%", duration: 0.4, ease: "power2.inOut" }, 7.3);
166
-
167
- window.__timelines["main-comp"] = tl;
168
- </script>
101
+ </head>
102
+ <body>
103
+ <div
104
+ id="main-composition"
105
+ data-composition-id="main-comp"
106
+ data-width="1080"
107
+ data-height="1920"
108
+ data-start="0"
109
+ data-duration="__VIDEO_DURATION__"
110
+ >
111
+ <!-- A-Roll -->
112
+ <div id="a-roll-wrapper">
113
+ <video
114
+ id="a-roll"
115
+ src="__VIDEO_SRC__"
116
+ muted
117
+ playsinline
118
+ data-start="0"
119
+ data-duration="__VIDEO_DURATION__"
120
+ data-track-index="0"
121
+ ></video>
122
+ </div>
123
+ <audio
124
+ id="a-roll-audio"
125
+ src="__VIDEO_SRC__"
126
+ data-start="0"
127
+ data-duration="__VIDEO_DURATION__"
128
+ data-track-index="5"
129
+ data-volume="1"
130
+ ></audio>
131
+
132
+ <!-- Transitions -->
133
+ <div id="curtain-black" class="curtain"></div>
134
+ <div id="curtain-red" class="curtain red"></div>
135
+
136
+ <!-- Overlays Composition -->
137
+ <div
138
+ id="overlays-comp"
139
+ data-composition-id="overlays"
140
+ data-composition-src="compositions/overlays.html"
141
+ data-start="0"
142
+ data-duration="__VIDEO_DURATION__"
143
+ data-track-index="2"
144
+ ></div>
145
+
146
+ <!-- Captions Composition -->
147
+ <div
148
+ id="captions-comp"
149
+ data-composition-id="captions"
150
+ data-composition-src="compositions/captions.html"
151
+ data-start="0"
152
+ data-duration="__VIDEO_DURATION__"
153
+ data-track-index="3"
154
+ ></div>
155
+
156
+ <!-- Grid Visualization -->
157
+ <div class="grid-container">
158
+ <div class="grid-column"></div>
159
+ <div class="grid-column"></div>
160
+ <div class="grid-column"></div>
161
+ <div class="grid-column"></div>
162
+ <div class="grid-column"></div>
163
+ <div class="grid-column"></div>
164
+ </div>
165
+
166
+ <script>
167
+ const tl = gsap.timeline({ paused: true });
168
+
169
+ // Transition: Curtain Pull logic
170
+ // A-roll leaves the screen at least once.
171
+ // Timing: Let's do a curtain pull at 3.7s (transitioning to the 62% stat)
172
+ // and return at 7.3s (end of attention stat).
173
+
174
+ // Curtain Out (A-roll hidden)
175
+ tl.to("#curtain-black", { left: "0%", duration: 0.2, ease: "power2.inOut" }, 3.5);
176
+ tl.to("#a-roll-wrapper", { opacity: 0, duration: 0 }, 3.7);
177
+ tl.to("#curtain-black", { left: "100%", duration: 0.4, ease: "power2.inOut" }, 3.7);
178
+
179
+ // Curtain In (A-roll return)
180
+ tl.set("#curtain-red", { left: "-100%" }, 7.1);
181
+ tl.to("#curtain-red", { left: "0%", duration: 0.2, ease: "power2.inOut" }, 7.1);
182
+ tl.to("#a-roll-wrapper", { opacity: 1, duration: 0 }, 7.3);
183
+ tl.to("#curtain-red", { left: "100%", duration: 0.4, ease: "power2.inOut" }, 7.3);
184
+
185
+ window.__timelines = window.__timelines || {};
186
+ window.__timelines["main-comp"] = tl;
187
+ </script>
169
188
  </div>
170
- </body>
189
+ </body>
171
190
  </html>