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
@@ -1,173 +1,239 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Hyperframes - Play Mode</title>
7
7
  <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
8
8
  <style>
9
- body, html {
10
- margin: 0;
11
- padding: 0;
12
- width: 1920px;
13
- height: 1080px;
14
- overflow: hidden;
15
- background-color: #FFFFFF;
16
- font-family: 'Nunito', sans-serif;
17
- }
9
+ body,
10
+ html {
11
+ margin: 0;
12
+ padding: 0;
13
+ width: 1920px;
14
+ height: 1080px;
15
+ overflow: hidden;
16
+ background-color: #ffffff;
17
+ font-family: "Nunito", sans-serif;
18
+ }
18
19
 
19
- #main-composition {
20
- width: 1920px;
21
- height: 1080px;
22
- position: relative;
23
- }
20
+ #main-composition {
21
+ width: 1920px;
22
+ height: 1080px;
23
+ position: relative;
24
+ }
24
25
 
25
- #bg-comp,
26
- #aroll-comp,
27
- #intro-comp,
28
- #stats-comp,
29
- #captions-comp {
30
- position: absolute;
31
- top: 0;
32
- left: 0;
33
- width: 100%;
34
- height: 100%;
35
- }
26
+ #bg-comp,
27
+ #aroll-comp,
28
+ #intro-comp,
29
+ #stats-comp,
30
+ #captions-comp {
31
+ position: absolute;
32
+ top: 0;
33
+ left: 0;
34
+ width: 100%;
35
+ height: 100%;
36
+ }
36
37
 
37
- #bg-comp {
38
- z-index: 1;
39
- }
38
+ #bg-comp {
39
+ z-index: 1;
40
+ }
40
41
 
41
- #aroll-comp {
42
- z-index: 10;
43
- }
42
+ #aroll-comp {
43
+ z-index: 10;
44
+ }
44
45
 
45
- #intro-comp {
46
- z-index: 100;
47
- }
46
+ #intro-comp {
47
+ z-index: 100;
48
+ }
48
49
 
49
- #stats-comp {
50
- z-index: 150;
51
- }
50
+ #stats-comp {
51
+ z-index: 150;
52
+ }
52
53
 
53
- #captions-comp {
54
- z-index: 200;
55
- }
54
+ #captions-comp {
55
+ z-index: 200;
56
+ }
56
57
 
57
- #aroll-container {
58
- position: absolute;
59
- width: 100%;
60
- height: 100%;
61
- display: flex;
62
- justify-content: center;
63
- align-items: center;
64
- z-index: 0;
65
- }
58
+ #aroll-container {
59
+ position: absolute;
60
+ width: 100%;
61
+ height: 100%;
62
+ display: flex;
63
+ justify-content: center;
64
+ align-items: center;
65
+ z-index: 0;
66
+ }
66
67
 
67
- #short_mag_cut {
68
- border-radius: 16px;
69
- box-shadow: 0 20px 60px rgba(0,0,0,0.4);
70
- border: 8px solid #FFFFFF;
71
- }
68
+ #short_mag_cut {
69
+ border-radius: 16px;
70
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
71
+ border: 8px solid #ffffff;
72
+ }
72
73
 
73
- #background-layer {
74
+ #background-layer {
75
+ position: absolute;
76
+ top: 0;
77
+ left: 0;
78
+ width: 100%;
79
+ height: 100%;
80
+ background-color: #ffffff;
81
+ z-index: 0;
82
+ }
83
+ </style>
84
+ <link
85
+ href="https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap"
86
+ rel="stylesheet"
87
+ />
88
+ </head>
89
+ <body>
90
+ <div
91
+ id="main-composition"
92
+ data-composition-id="main-video"
93
+ data-start="0"
94
+ data-duration="__VIDEO_DURATION__"
95
+ data-width="1920"
96
+ data-height="1080"
97
+ >
98
+ <!-- Background Layer Composition -->
99
+ <div
100
+ id="bg-comp"
101
+ data-composition-id="background"
102
+ data-start="0"
103
+ data-duration="__VIDEO_DURATION__"
104
+ data-width="1920"
105
+ data-height="1080"
106
+ data-track-index="1"
107
+ >
108
+ <div id="background-layer"></div>
109
+ <style>
110
+ #background-layer {
74
111
  position: absolute;
75
112
  top: 0;
76
113
  left: 0;
77
114
  width: 100%;
78
115
  height: 100%;
79
- background-color: #FFFFFF;
80
- z-index: 0;
81
- }
82
- </style>
83
- <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap" rel="stylesheet">
84
- </head>
85
- <body>
86
- <div id="main-composition" data-composition-id="main-video" data-start="0" data-duration="16.04" data-width="1920" data-height="1080">
87
- <!-- Background Layer Composition -->
88
- <div id="bg-comp" data-composition-id="background" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="1">
89
- <div id="background-layer"></div>
90
- <style>
91
- #background-layer {
92
- position: absolute;
93
- top: 0;
94
- left: 0;
95
- width: 100%;
96
- height: 100%;
97
- background-color: #FFFFFF;
98
- }
99
- </style>
100
- <script>
101
- (function() {
102
- const tl = gsap.timeline({ paused: true });
103
- const bg = document.getElementById('background-layer');
104
- // Sync with A-roll framing 3 (4.659s)
105
- tl.to(bg, { backgroundColor: "#0057FF", duration: 0.5 }, 4.659);
106
- // Sync with A-roll framing 4 (8.88s)
107
- tl.to(bg, { backgroundColor: "#FFFFFF", duration: 0.5 }, 8.88);
108
- window.__timelines["background"] = tl;
109
- })();
110
- </script>
111
- </div>
116
+ background-color: #ffffff;
117
+ }
118
+ </style>
119
+ <script>
120
+ (function () {
121
+ const tl = gsap.timeline({ paused: true });
122
+ const bg = document.getElementById("background-layer");
123
+ // Sync with A-roll framing 3 (4.659s)
124
+ tl.to(bg, { backgroundColor: "#0057FF", duration: 0.5 }, 4.659);
125
+ // Sync with A-roll framing 4 (8.88s)
126
+ tl.to(bg, { backgroundColor: "#FFFFFF", duration: 0.5 }, 8.88);
127
+ window.__timelines["background"] = tl;
128
+ })();
129
+ </script>
130
+ </div>
112
131
 
113
- <!-- A-roll Layer Composition -->
114
- <div id="aroll-comp" data-composition-id="aroll-layer" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="10">
115
- <div id="aroll-container">
116
- <video id="short_mag_cut"
117
- src="__VIDEO_SRC__"
118
- data-start="0"
119
- data-duration="16.04"
120
- data-track-index="1"
121
- style="width: 100%; height: auto;"></video>
122
- </div>
123
- <style>
124
- #aroll-container {
125
- position: absolute;
126
- width: 100%;
127
- height: 100%;
128
- display: flex;
129
- justify-content: center;
130
- align-items: center;
131
- }
132
- #short_mag_cut {
133
- border-radius: 16px;
134
- box-shadow: 0 20px 60px rgba(0,0,0,0.4);
135
- border: 8px solid #FFFFFF;
136
- }
137
- </style>
138
- <script>
139
- (function() {
140
- const tl = gsap.timeline({ paused: true });
141
- const container = document.getElementById('aroll-container');
142
- gsap.set(container, { y: -1100, scale: 0.8 });
143
- tl.to(container, { y: 0, duration: 1.2, ease: "elastic.out(1, 0.6)" }, 0);
144
- tl.to(container, { scale: 1.4, x: -300, duration: 1, ease: "back.out(1.7)" }, 1.839);
145
- tl.to(container, { scale: 0.7, x: 400, duration: 1, ease: "back.out(1.7)" }, 4.659);
146
- tl.to(container, { scale: 0.9, x: 0, duration: 1, ease: "back.out(1.7)" }, 8.88);
147
- window.__timelines["aroll-layer"] = tl;
148
- })();
149
- </script>
132
+ <!-- A-roll Layer Composition -->
133
+ <div
134
+ id="aroll-comp"
135
+ data-composition-id="aroll-layer"
136
+ data-start="0"
137
+ data-duration="__VIDEO_DURATION__"
138
+ data-width="1920"
139
+ data-height="1080"
140
+ data-track-index="10"
141
+ >
142
+ <div id="aroll-container">
143
+ <video
144
+ id="short_mag_cut"
145
+ src="__VIDEO_SRC__"
146
+ muted
147
+ playsinline
148
+ data-start="0"
149
+ data-duration="__VIDEO_DURATION__"
150
+ data-track-index="1"
151
+ style="width: 100%; height: auto"
152
+ ></video>
150
153
  </div>
151
-
152
- <!-- Compositions -->
153
- <div id="intro-comp" data-composition-id="intro" data-composition-src="compositions/intro.html" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="100"></div>
154
- <div id="captions-comp" data-composition-id="captions" data-composition-src="compositions/captions.html" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="200"></div>
155
- <div id="stats-comp" data-composition-id="stats" data-composition-src="compositions/stats.html" data-start="0" data-duration="16.04" data-width="1920" data-height="1080" data-track-index="150"></div>
156
-
157
- <!-- Audio Clips -->
158
- <audio id="sfx-bounce-0" src="" data-start="0" data-track-index="5"></audio>
159
- <audio id="sfx-whoosh-1" src="" data-start="1.839" data-track-index="6"></audio>
160
- <audio id="sfx-pop-1" src="" data-start="2.039" data-track-index="7"></audio>
161
- <audio id="sfx-whoosh-2" src="" data-start="4.659" data-track-index="6"></audio>
162
- <audio id="sfx-pop-2" src="" data-start="4.859" data-track-index="7"></audio>
163
- <audio id="sfx-whoosh-3" src="" data-start="8.88" data-track-index="6"></audio>
164
- <audio id="sfx-pop-3" src="" data-start="9.08" data-track-index="7"></audio>
165
-
154
+ <audio
155
+ id="a-roll-audio"
156
+ src="__VIDEO_SRC__"
157
+ data-start="0"
158
+ data-duration="__VIDEO_DURATION__"
159
+ data-track-index="5"
160
+ data-volume="1"
161
+ ></audio>
162
+ <style>
163
+ #aroll-container {
164
+ position: absolute;
165
+ width: 100%;
166
+ height: 100%;
167
+ display: flex;
168
+ justify-content: center;
169
+ align-items: center;
170
+ }
171
+ #short_mag_cut {
172
+ border-radius: 16px;
173
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
174
+ border: 8px solid #ffffff;
175
+ }
176
+ </style>
166
177
  <script>
167
- window.__timelines = window.__timelines || {};
178
+ (function () {
168
179
  const tl = gsap.timeline({ paused: true });
169
- window.__timelines["main-video"] = tl;
180
+ const container = document.getElementById("aroll-container");
181
+ gsap.set(container, { y: -1100, scale: 0.8 });
182
+ tl.to(container, { y: 0, duration: 1.2, ease: "elastic.out(1, 0.6)" }, 0);
183
+ tl.to(container, { scale: 1.4, x: -300, duration: 1, ease: "back.out(1.7)" }, 1.839);
184
+ tl.to(container, { scale: 0.7, x: 400, duration: 1, ease: "back.out(1.7)" }, 4.659);
185
+ tl.to(container, { scale: 0.9, x: 0, duration: 1, ease: "back.out(1.7)" }, 8.88);
186
+ window.__timelines["aroll-layer"] = tl;
187
+ })();
170
188
  </script>
189
+ </div>
190
+
191
+ <!-- Compositions -->
192
+ <div
193
+ id="intro-comp"
194
+ data-composition-id="intro"
195
+ data-composition-src="compositions/intro.html"
196
+ data-start="0"
197
+ data-duration="__VIDEO_DURATION__"
198
+ data-width="1920"
199
+ data-height="1080"
200
+ data-track-index="100"
201
+ ></div>
202
+ <div
203
+ id="captions-comp"
204
+ data-composition-id="captions"
205
+ data-composition-src="compositions/captions.html"
206
+ data-start="0"
207
+ data-duration="__VIDEO_DURATION__"
208
+ data-width="1920"
209
+ data-height="1080"
210
+ data-track-index="200"
211
+ ></div>
212
+ <div
213
+ id="stats-comp"
214
+ data-composition-id="stats"
215
+ data-composition-src="compositions/stats.html"
216
+ data-start="0"
217
+ data-duration="__VIDEO_DURATION__"
218
+ data-width="1920"
219
+ data-height="1080"
220
+ data-track-index="150"
221
+ ></div>
222
+
223
+ <!-- Audio Clips -->
224
+ <audio id="sfx-bounce-0" src="" data-start="0" data-track-index="5"></audio>
225
+ <audio id="sfx-whoosh-1" src="" data-start="1.839" data-track-index="6"></audio>
226
+ <audio id="sfx-pop-1" src="" data-start="2.039" data-track-index="7"></audio>
227
+ <audio id="sfx-whoosh-2" src="" data-start="4.659" data-track-index="6"></audio>
228
+ <audio id="sfx-pop-2" src="" data-start="4.859" data-track-index="7"></audio>
229
+ <audio id="sfx-whoosh-3" src="" data-start="8.88" data-track-index="6"></audio>
230
+ <audio id="sfx-pop-3" src="" data-start="9.08" data-track-index="7"></audio>
231
+
232
+ <script>
233
+ window.__timelines = window.__timelines || {};
234
+ const tl = gsap.timeline({ paused: true });
235
+ window.__timelines["main-video"] = tl;
236
+ </script>
171
237
  </div>
172
- </body>
173
- </html>
238
+ </body>
239
+ </html>
@@ -1,5 +1,10 @@
1
1
  <template id="captions-template">
2
- <div data-composition-id="captions" data-width="1920" data-height="1080" data-duration="16.04">
2
+ <div
3
+ data-composition-id="captions"
4
+ data-width="1920"
5
+ data-height="1080"
6
+ data-duration="__VIDEO_DURATION__"
7
+ >
3
8
  <div id="caption-container"></div>
4
9
 
5
10
  <style>
@@ -7,7 +12,7 @@
7
12
  width: 1920px;
8
13
  height: 1080px;
9
14
  position: relative;
10
- font-family: 'Helvetica', 'Arial', sans-serif;
15
+ font-family: "Helvetica", "Arial", sans-serif;
11
16
  font-weight: bold;
12
17
  overflow: hidden;
13
18
  }
@@ -24,7 +29,7 @@
24
29
  }
25
30
 
26
31
  [data-composition-id="captions"] .caption-box {
27
- background-color: #0A1E3D; /* Solid navy */
32
+ background-color: #0a1e3d; /* Solid navy */
28
33
  padding: 20px 40px;
29
34
  display: none; /* Hidden by default, shown via GSAP */
30
35
  justify-content: center;
@@ -33,7 +38,7 @@
33
38
  }
34
39
 
35
40
  [data-composition-id="captions"] .caption-text {
36
- color: #F2F2F2; /* Off-white */
41
+ color: #f2f2f2; /* Off-white */
37
42
  font-size: 72px;
38
43
  text-transform: uppercase; /* Swiss style often uses uppercase for impact */
39
44
  letter-spacing: -2px;
@@ -44,12 +49,60 @@
44
49
  </style>
45
50
 
46
51
  <script>
47
- (function() {
48
- const TRANSCRIPT = [{'text': 'We', 'start': 0.119, 'end': 0.259}, {'text': 'asked', 'start': 0.319, 'end': 0.479}, {'text': 'what', 'start': 0.519, 'end': 0.659}, {'text': 'you', 'start': 0.699, 'end': 0.819}, {'text': 'needed.', 'start': 0.859, 'end': 1.819}, {'text': 'Forty-seven', 'start': 1.86, 'end': 2.299}, {'text': 'percent', 'start': 2.399, 'end': 2.679}, {'text': 'of', 'start': 2.7, 'end': 2.799}, {'text': 'you', 'start': 2.839, 'end': 2.939}, {'text': 'said', 'start': 3.039, 'end': 3.179}, {'text': 'motion', 'start': 3.24, 'end': 3.559}, {'text': 'graphics,', 'start': 3.579, 'end': 4.599}, {'text': 'sixty-two', 'start': 4.679, 'end': 5.179}, {'text': 'percent', 'start': 5.299, 'end': 5.759}, {'text': 'said', 'start': 5.859, 'end': 5.98}, {'text': 'static', 'start': 6.079, 'end': 6.399}, {'text': 'content', 'start': 6.46, 'end': 6.879}, {'text': 'was', 'start': 6.92, 'end': 7.079}, {'text': 'costing', 'start': 7.099, 'end': 7.48}, {'text': 'you', 'start': 7.5, 'end': 7.579}, {'text': 'attention,', 'start': 7.679, 'end': 8.659}, {'text': 'and', 'start': 8.699, 'end': 8.86}, {'text': 'three', 'start': 8.88, 'end': 9.06}, {'text': 'out', 'start': 9.079, 'end': 9.18}, {'text': 'of', 'start': 9.199, 'end': 9.34}, {'text': 'four', 'start': 9.38, 'end': 9.799}, {'text': 'said', 'start': 9.84, 'end': 10.0}, {'text': 'you', 'start': 10.019, 'end': 10.159}, {'text': 'know', 'start': 10.179, 'end': 10.36}, {'text': 'the', 'start': 10.38, 'end': 10.42}, {'text': 'look', 'start': 10.519, 'end': 10.699}, {'text': 'you', 'start': 10.739, 'end': 10.859}, {'text': 'want', 'start': 10.98, 'end': 11.34}, {'text': 'but', 'start': 11.359, 'end': 11.52}, {'text': "don't", 'start': 11.56, 'end': 11.779}, {'text': 'have', 'start': 11.819, 'end': 11.94}, {'text': 'the', 'start': 11.96, 'end': 12.06}, {'text': 'editing', 'start': 12.079, 'end': 12.4}, {'text': 'skills', 'start': 12.52, 'end': 12.86}, {'text': 'to', 'start': 12.88, 'end': 13.0}, {'text': 'get', 'start': 13.019, 'end': 13.18}, {'text': 'there.', 'start': 13.22, 'end': 14.22}, {'text': 'So', 'start': 14.239, 'end': 14.399}, {'text': 'we', 'start': 14.42, 'end': 14.52}, {'text': 'built', 'start': 14.619, 'end': 14.88}, {'text': 'Hyperframes', 'start': 15.079, 'end': 15.42}];
49
- const container = document.getElementById('caption-container');
52
+ (function () {
53
+ const TRANSCRIPT = [
54
+ { text: "We", start: 0.119, end: 0.259 },
55
+ { text: "asked", start: 0.319, end: 0.479 },
56
+ { text: "what", start: 0.519, end: 0.659 },
57
+ { text: "you", start: 0.699, end: 0.819 },
58
+ { text: "needed.", start: 0.859, end: 1.819 },
59
+ { text: "Forty-seven", start: 1.86, end: 2.299 },
60
+ { text: "percent", start: 2.399, end: 2.679 },
61
+ { text: "of", start: 2.7, end: 2.799 },
62
+ { text: "you", start: 2.839, end: 2.939 },
63
+ { text: "said", start: 3.039, end: 3.179 },
64
+ { text: "motion", start: 3.24, end: 3.559 },
65
+ { text: "graphics,", start: 3.579, end: 4.599 },
66
+ { text: "sixty-two", start: 4.679, end: 5.179 },
67
+ { text: "percent", start: 5.299, end: 5.759 },
68
+ { text: "said", start: 5.859, end: 5.98 },
69
+ { text: "static", start: 6.079, end: 6.399 },
70
+ { text: "content", start: 6.46, end: 6.879 },
71
+ { text: "was", start: 6.92, end: 7.079 },
72
+ { text: "costing", start: 7.099, end: 7.48 },
73
+ { text: "you", start: 7.5, end: 7.579 },
74
+ { text: "attention,", start: 7.679, end: 8.659 },
75
+ { text: "and", start: 8.699, end: 8.86 },
76
+ { text: "three", start: 8.88, end: 9.06 },
77
+ { text: "out", start: 9.079, end: 9.18 },
78
+ { text: "of", start: 9.199, end: 9.34 },
79
+ { text: "four", start: 9.38, end: 9.799 },
80
+ { text: "said", start: 9.84, end: 10.0 },
81
+ { text: "you", start: 10.019, end: 10.159 },
82
+ { text: "know", start: 10.179, end: 10.36 },
83
+ { text: "the", start: 10.38, end: 10.42 },
84
+ { text: "look", start: 10.519, end: 10.699 },
85
+ { text: "you", start: 10.739, end: 10.859 },
86
+ { text: "want", start: 10.98, end: 11.34 },
87
+ { text: "but", start: 11.359, end: 11.52 },
88
+ { text: "don't", start: 11.56, end: 11.779 },
89
+ { text: "have", start: 11.819, end: 11.94 },
90
+ { text: "the", start: 11.96, end: 12.06 },
91
+ { text: "editing", start: 12.079, end: 12.4 },
92
+ { text: "skills", start: 12.52, end: 12.86 },
93
+ { text: "to", start: 12.88, end: 13.0 },
94
+ { text: "get", start: 13.019, end: 13.18 },
95
+ { text: "there.", start: 13.22, end: 14.22 },
96
+ { text: "So", start: 14.239, end: 14.399 },
97
+ { text: "we", start: 14.42, end: 14.52 },
98
+ { text: "built", start: 14.619, end: 14.88 },
99
+ { text: "Hyperframes", start: 15.079, end: 15.42 },
100
+ ];
101
+ const container = document.getElementById("caption-container");
50
102
  const tl = gsap.timeline({ paused: true });
51
103
 
52
104
  if (!TRANSCRIPT || TRANSCRIPT.length === 0) {
105
+ window.__timelines = window.__timelines || {};
53
106
  window.__timelines["captions"] = tl;
54
107
  return;
55
108
  }
@@ -57,7 +110,7 @@
57
110
  // Group transcript into max 5 words per group
58
111
  const groups = [];
59
112
  let currentGroup = [];
60
-
113
+
61
114
  TRANSCRIPT.forEach((word, index) => {
62
115
  currentGroup.push(word);
63
116
  // Group by 5 words OR if it's the last word
@@ -69,14 +122,14 @@
69
122
 
70
123
  // Create DOM elements and timeline for each group
71
124
  groups.forEach((group, i) => {
72
- const box = document.createElement('div');
73
- box.className = 'caption-box';
125
+ const box = document.createElement("div");
126
+ box.className = "caption-box";
74
127
  box.id = `group-${i}`;
75
-
76
- const text = document.createElement('div');
77
- text.className = 'caption-text';
78
- text.textContent = group.map(w => w.text).join(' ');
79
-
128
+
129
+ const text = document.createElement("div");
130
+ text.className = "caption-text";
131
+ text.textContent = group.map((w) => w.text).join(" ");
132
+
80
133
  box.appendChild(text);
81
134
  container.appendChild(box);
82
135
 
@@ -84,8 +137,8 @@
84
137
  const endTime = group[group.length - 1].end;
85
138
 
86
139
  // Hard cut animation (no fades) as requested
87
- tl.set(box, { display: 'flex' }, startTime);
88
- tl.set(box, { display: 'none' }, endTime);
140
+ tl.set(box, { display: "flex" }, startTime);
141
+ tl.set(box, { display: "none" }, endTime);
89
142
  });
90
143
 
91
144
  window.__timelines["captions"] = tl;