hyperframes 0.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 (34) hide show
  1. package/dist/cli.js +22905 -0
  2. package/dist/docs/compositions.md +26 -0
  3. package/dist/docs/data-attributes.md +22 -0
  4. package/dist/docs/gsap.md +23 -0
  5. package/dist/docs/rendering.md +23 -0
  6. package/dist/docs/templates.md +15 -0
  7. package/dist/docs/troubleshooting.md +22 -0
  8. package/dist/hyperframe-runtime.js +12 -0
  9. package/dist/studio/assets/index-B1830ANq.js +78 -0
  10. package/dist/studio/assets/index-KoBceNoU.css +1 -0
  11. package/dist/studio/icons/timeline/audio.svg +7 -0
  12. package/dist/studio/icons/timeline/captions.svg +5 -0
  13. package/dist/studio/icons/timeline/composition.svg +12 -0
  14. package/dist/studio/icons/timeline/image.svg +18 -0
  15. package/dist/studio/icons/timeline/music.svg +10 -0
  16. package/dist/studio/icons/timeline/text.svg +3 -0
  17. package/dist/studio/index.html +13 -0
  18. package/dist/templates/play-mode/compositions/captions.html +97 -0
  19. package/dist/templates/play-mode/compositions/intro.html +88 -0
  20. package/dist/templates/play-mode/compositions/stats.html +252 -0
  21. package/dist/templates/play-mode/index.html +173 -0
  22. package/dist/templates/swiss-grid/assets/swiss-grid.svg +116 -0
  23. package/dist/templates/swiss-grid/compositions/captions.html +95 -0
  24. package/dist/templates/swiss-grid/compositions/graphics.html +198 -0
  25. package/dist/templates/swiss-grid/compositions/intro.html +114 -0
  26. package/dist/templates/swiss-grid/index.html +172 -0
  27. package/dist/templates/vignelli/compositions/captions.html +122 -0
  28. package/dist/templates/vignelli/compositions/overlays.html +271 -0
  29. package/dist/templates/vignelli/index.html +171 -0
  30. package/dist/templates/warm-grain/compositions/captions.html +133 -0
  31. package/dist/templates/warm-grain/compositions/graphics.html +157 -0
  32. package/dist/templates/warm-grain/compositions/intro.html +77 -0
  33. package/dist/templates/warm-grain/index.html +195 -0
  34. package/package.json +54 -0
@@ -0,0 +1,114 @@
1
+ <template id="intro-template">
2
+ <div data-composition-id="intro" data-width="1920" data-height="1080" data-duration="1.86">
3
+ <div class="container">
4
+ <div class="grid-line"></div>
5
+ <div class="text-wrapper">
6
+ <h1 class="title">HYPERFRAMES</h1>
7
+ <h2 class="subtitle">THE SURVEY FINDINGS</h2>
8
+ </div>
9
+ </div>
10
+
11
+ <style>
12
+ [data-composition-id="intro"] {
13
+ background-color: #F5F5F5; /* Off-white */
14
+ width: 1920px;
15
+ height: 1080px;
16
+ display: flex;
17
+ align-items: center;
18
+ justify-content: center;
19
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
20
+ overflow: hidden;
21
+ }
22
+
23
+ [data-composition-id="intro"] .container {
24
+ position: relative;
25
+ width: 100%;
26
+ height: 100%;
27
+ display: flex;
28
+ flex-direction: column;
29
+ justify-content: center;
30
+ padding-left: 160px; /* Swiss grid alignment */
31
+ }
32
+
33
+ [data-composition-id="intro"] .grid-line {
34
+ position: absolute;
35
+ left: 160px;
36
+ top: 50%;
37
+ width: 0px;
38
+ height: 12px;
39
+ background-color: #0A1E3D; /* Navy */
40
+ transform: translateY(-180px); /* Positioned above the text */
41
+ }
42
+
43
+ [data-composition-id="intro"] .text-wrapper {
44
+ display: flex;
45
+ flex-direction: column;
46
+ gap: 0;
47
+ overflow: hidden;
48
+ }
49
+
50
+ [data-composition-id="intro"] .title {
51
+ color: #0A1E3D;
52
+ font-size: 180px;
53
+ font-weight: 900; /* Black weight */
54
+ line-height: 0.9;
55
+ margin: 0;
56
+ letter-spacing: -0.04em;
57
+ text-transform: uppercase;
58
+ transform: translateX(-100%); /* Start off-screen left */
59
+ }
60
+
61
+ [data-composition-id="intro"] .subtitle {
62
+ color: #0A1E3D;
63
+ font-size: 64px;
64
+ font-weight: 300; /* Lighter weight for contrast */
65
+ line-height: 1.2;
66
+ margin: 0;
67
+ letter-spacing: 0.1em;
68
+ text-transform: uppercase;
69
+ transform: translateX(-100%); /* Start off-screen left */
70
+ margin-top: 20px;
71
+ }
72
+ </style>
73
+
74
+ <script>
75
+ (function() {
76
+ const tl = gsap.timeline({ paused: true });
77
+
78
+ // Mechanical timing: 200ms (0.2s)
79
+ const MECHANICAL_DURATION = 0.2;
80
+ const STAGGER = 0.1;
81
+
82
+ // 1. Animate the grid line first
83
+ tl.to('.grid-line', {
84
+ width: '1200px',
85
+ duration: 0.4,
86
+ ease: 'power4.out'
87
+ }, 0.2);
88
+
89
+ // 2. Slide in the title
90
+ tl.to('.title', {
91
+ x: 0,
92
+ duration: MECHANICAL_DURATION,
93
+ ease: 'power2.inOut'
94
+ }, 0.5);
95
+
96
+ // 3. Slide in the subtitle with a slight stagger
97
+ tl.to('.subtitle', {
98
+ x: 0,
99
+ duration: MECHANICAL_DURATION,
100
+ ease: 'power2.inOut'
101
+ }, 0.5 + STAGGER);
102
+
103
+ // 4. Subtle ambient motion (slow drift) to keep it alive
104
+ tl.to('.text-wrapper', {
105
+ x: 30,
106
+ duration: 1.16, // Adjusted to fit 1.86s total
107
+ ease: 'none'
108
+ }, 0.7);
109
+
110
+ window.__timelines["intro"] = tl;
111
+ })();
112
+ </script>
113
+ </div>
114
+ </template>
@@ -0,0 +1,172 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Swiss Grid - Hyperframes</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
8
+ <style>
9
+ body, html {
10
+ margin: 0;
11
+ padding: 0;
12
+ width: 1920px;
13
+ height: 1080px;
14
+ background-color: #F2F2F2;
15
+ overflow: hidden;
16
+ font-family: 'Helvetica', Arial, sans-serif;
17
+ }
18
+
19
+ #master-root {
20
+ width: 1920px;
21
+ height: 1080px;
22
+ position: relative;
23
+ }
24
+
25
+ .background-grid {
26
+ position: absolute;
27
+ top: 0;
28
+ left: 0;
29
+ width: 100%;
30
+ height: 100%;
31
+ z-index: 0;
32
+ }
33
+
34
+ /* A-roll styling */
35
+ #short_mag_cut_frame {
36
+ position: absolute;
37
+ border-radius: 8px; /* Required */
38
+ z-index: 1;
39
+ box-shadow: 0 20px 40px rgba(0,0,0,0.3);
40
+ overflow: hidden;
41
+ background: #000;
42
+ }
43
+
44
+ #short_mag_cut,
45
+ #short_mag_cut_frame > img.__render_frame__,
46
+ #short_mag_cut_frame > img.__preview_render_frame__ {
47
+ position: absolute;
48
+ inset: 0;
49
+ width: 100%;
50
+ height: 100%;
51
+ object-fit: cover;
52
+ object-position: center;
53
+ display: block;
54
+ }
55
+
56
+ /* Overlay layers */
57
+ .overlay-layer {
58
+ position: absolute;
59
+ top: 0;
60
+ left: 0;
61
+ width: 100%;
62
+ height: 100%;
63
+ pointer-events: none;
64
+ }
65
+
66
+ #intro-comp { z-index: 2; }
67
+ #graphics-comp { z-index: 3; }
68
+ #captions-comp { z-index: 4; }
69
+ </style>
70
+ </head>
71
+ <body>
72
+ <div id="master-root" data-composition-id="master" data-width="1920" data-height="1080" data-duration="16.04">
73
+
74
+ <!-- Background Grid -->
75
+ <img id="bg-grid"
76
+ class="background-grid"
77
+ src="assets/swiss-grid.svg"
78
+ alt="Grid"
79
+ data-start="0"
80
+ data-duration="16.04"
81
+ data-track-index="0">
82
+
83
+ <!-- A-roll Video -->
84
+ <div id="short_mag_cut_frame">
85
+ <video id="short_mag_cut"
86
+ src="__VIDEO_SRC__"
87
+ data-start="0"
88
+ data-duration="16.04"
89
+ data-track-index="1">
90
+ </video>
91
+ </div>
92
+
93
+ <!-- Intro Sub-composition -->
94
+ <div id="intro-comp"
95
+ class="overlay-layer"
96
+ data-composition-id="intro"
97
+ data-composition-src="compositions/intro.html"
98
+ data-start="0"
99
+ data-duration="1.86"
100
+ data-track-index="2">
101
+ </div>
102
+
103
+ <!-- Graphics Sub-composition -->
104
+ <div id="graphics-comp"
105
+ class="overlay-layer"
106
+ data-composition-id="graphics"
107
+ data-composition-src="compositions/graphics.html"
108
+ data-start="0"
109
+ data-duration="16.04"
110
+ data-track-index="3">
111
+ </div>
112
+
113
+ <!-- Captions Sub-composition -->
114
+ <div id="captions-comp"
115
+ class="overlay-layer"
116
+ data-composition-id="captions"
117
+ data-composition-src="compositions/captions.html"
118
+ data-start="0"
119
+ data-duration="16.04"
120
+ data-track-index="4">
121
+ </div>
122
+
123
+ <!-- Sound Effects -->
124
+ <audio id="sfx-intro" data-start="0" data-track-index="5" data-duration="1" src=""></audio>
125
+ <audio id="sfx-stat1" data-start="1.86" data-track-index="5" data-duration="1" src=""></audio>
126
+ <audio id="sfx-stat2" data-start="4.68" data-track-index="5" data-duration="1" src=""></audio>
127
+ <audio id="sfx-stat3" data-start="8.88" data-track-index="5" data-duration="1" src=""></audio>
128
+
129
+ <script>
130
+ window.__timelines = window.__timelines || {};
131
+
132
+ const masterTL = gsap.timeline({ paused: true });
133
+ const v = document.getElementById('short_mag_cut_frame');
134
+
135
+ // --- A-ROLL MOVEMENT (Structured Swiss Layout) ---
136
+
137
+ // 1. Entrance (0-1.86s): Slide in from left, settle centered for Intro
138
+ masterTL.fromTo(v,
139
+ { x: -1000, y: 120, width: 960, height: 840 },
140
+ { x: 480, y: 120, width: 960, height: 840, duration: 0.8, ease: "power2.out" },
141
+ 0
142
+ );
143
+
144
+ // 2. Stat 1 (1.86s - 4.68s): Move to right side (Graphic is on left)
145
+ masterTL.to(v, {
146
+ x: 1080, y: 120, width: 720, height: 720,
147
+ duration: 0.25, ease: "expo.out"
148
+ }, 1.86);
149
+
150
+ // 3. Stat 2 (4.68s - 8.88s): Stay right, zoom in slightly
151
+ masterTL.to(v, {
152
+ x: 1080, y: 60, width: 780, height: 780,
153
+ duration: 0.25, ease: "expo.out"
154
+ }, 4.68);
155
+
156
+ // 4. Stat 3 (8.88s - 14.2s): Move to left side (Graphic is on right)
157
+ masterTL.to(v, {
158
+ x: 120, y: 120, width: 720, height: 720,
159
+ duration: 0.25, ease: "expo.out"
160
+ }, 8.88);
161
+
162
+ // 5. Conclusion (14.2s - 16.04s): Center large
163
+ masterTL.to(v, {
164
+ x: 240, y: 60, width: 1440, height: 810,
165
+ duration: 0.5, ease: "expo.out"
166
+ }, 14.2);
167
+
168
+ window.__timelines["master"] = masterTL;
169
+ </script>
170
+ </div>
171
+ </body>
172
+ </html>
@@ -0,0 +1,122 @@
1
+ <template id="captions-template">
2
+ <div data-composition-id="captions" data-width="1080" data-height="1920" data-duration="13.88">
3
+ <div id="captions-container"></div>
4
+
5
+ <style>
6
+ [data-composition-id="captions"] {
7
+ position: absolute;
8
+ top: 0;
9
+ left: 0;
10
+ width: 1080px;
11
+ height: 1920px;
12
+ font-family: "Helvetica", "Helvetica Neue", Arial, sans-serif;
13
+ font-weight: 900; /* Helvetica Black/Bold */
14
+ text-transform: uppercase;
15
+ pointer-events: none;
16
+ }
17
+
18
+ [data-composition-id="captions"] #captions-container {
19
+ position: absolute;
20
+ inset: 0;
21
+ }
22
+
23
+ [data-composition-id="captions"] .caption-group {
24
+ position: absolute;
25
+ left: 50%;
26
+ transform: translateX(-50%);
27
+ width: auto;
28
+ max-width: 920px; /* 1080 - 2*80 */
29
+ bottom: 672px;
30
+ display: flex;
31
+ justify-content: center;
32
+ align-items: center;
33
+ text-align: center;
34
+ opacity: 0;
35
+ z-index: 10;
36
+ }
37
+
38
+ [data-composition-id="captions"] .caption-text {
39
+ font-size: 64px;
40
+ line-height: 1.1;
41
+ color: #000000;
42
+ background-color: #FFFFFF;
43
+ padding: 15px 30px;
44
+ border-top: 8px solid #CC0000; /* Vignelli Red top border accent */
45
+ display: inline-block;
46
+ letter-spacing: -0.02em; /* Tight Helvetica spacing */
47
+ white-space: nowrap; /* Prevent wrapping at the element level */
48
+ }
49
+ </style>
50
+
51
+ <script>
52
+ (function() {
53
+ 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}];
54
+ const tl = gsap.timeline({ paused: true });
55
+ const container = document.getElementById('captions-container');
56
+
57
+ // Group words into single lines (max words or based on pauses/sentence ends)
58
+ function groupTranscript(transcript, maxWords = 3) {
59
+ const groups = [];
60
+ let currentGroup = [];
61
+
62
+ transcript.forEach((word, index) => {
63
+ currentGroup.push(word);
64
+
65
+ const nextWord = transcript[index + 1];
66
+ const isPause = nextWord && (nextWord.start - word.end > 0.15);
67
+ const isSentenceEnd = word.text.includes('.') || word.text.includes('?') || word.text.includes('!');
68
+
69
+ if (currentGroup.length >= maxWords || isPause || isSentenceEnd || !nextWord) {
70
+ groups.push({
71
+ words: currentGroup,
72
+ start: currentGroup[0].start,
73
+ end: currentGroup[currentGroup.length - 1].end,
74
+ text: currentGroup.map(w => w.text).join(' ')
75
+ });
76
+ currentGroup = [];
77
+ }
78
+ });
79
+ return groups;
80
+ }
81
+
82
+ const captionGroups = groupTranscript(TRANSCRIPT);
83
+
84
+ captionGroups.forEach((group, index) => {
85
+ const div = document.createElement('div');
86
+ div.className = 'caption-group';
87
+ div.id = `group-${index}`;
88
+
89
+ const textSpan = document.createElement('span');
90
+ textSpan.className = 'caption-text';
91
+ textSpan.innerText = group.text;
92
+
93
+ div.appendChild(textSpan);
94
+ container.appendChild(div);
95
+
96
+ // Animation: Modern "expo.out" transitions
97
+ // Entrance
98
+ tl.fromTo(div,
99
+ { opacity: 0, y: 20 },
100
+ {
101
+ opacity: 1,
102
+ y: 0,
103
+ duration: 0.4,
104
+ ease: "expo.out"
105
+ },
106
+ group.start
107
+ );
108
+
109
+ // Exit
110
+ tl.to(div, {
111
+ opacity: 0,
112
+ y: -10,
113
+ duration: 0.3,
114
+ ease: "expo.out"
115
+ }, group.end - 0.3);
116
+ });
117
+
118
+ window.__timelines["captions"] = tl;
119
+ })();
120
+ </script>
121
+ </div>
122
+ </template>
@@ -0,0 +1,271 @@
1
+ <template id="overlays-template">
2
+ <div data-composition-id="overlays" data-width="1080" data-height="1920" data-duration="16.88">
3
+ <!-- 6-Column Grid Overlay (for visual reference during development, hidden by default) -->
4
+ <div class="vignelli-grid">
5
+ <div class="col"></div>
6
+ <div class="col"></div>
7
+ <div class="col"></div>
8
+ <div class="col"></div>
9
+ <div class="col"></div>
10
+ <div class="col"></div>
11
+ </div>
12
+
13
+ <!-- 1. 47% Motion Graphics -->
14
+ <div class="overlay-item motion-graphics-stat" id="stat-47">
15
+ <div class="red-bar"></div>
16
+ <div class="stat-content">
17
+ <div class="number">47%</div>
18
+ <div class="label">Motion Graphics</div>
19
+ </div>
20
+ </div>
21
+
22
+ <!-- 2. 62% Static Content (Full Canvas) -->
23
+ <div class="overlay-item static-content-stat" id="stat-62">
24
+ <div class="bg-charcoal"></div>
25
+ <div class="full-content">
26
+ <div class="large-number">62%</div>
27
+ <div class="large-label">Static Content</div>
28
+ <div class="red-accent"></div>
29
+ </div>
30
+ </div>
31
+
32
+ <!-- 3. 3 out of 4 lack editing skills -->
33
+ <div class="overlay-item editing-skills-stat" id="stat-3-4">
34
+ <div class="text-block">
35
+ <span class="highlight">3 out of 4</span>
36
+ <br>lack editing skills
37
+ </div>
38
+ <div class="side-bar"></div>
39
+ </div>
40
+
41
+ <!-- 4. Hyperframes Branding -->
42
+ <div class="overlay-item branding-reveal" id="branding">
43
+ <div class="logo-container">
44
+ <div class="logo-text"><span class="heavy">HYPERFRAMES</span></div>
45
+ <div class="logo-underline"></div>
46
+ </div>
47
+ </div>
48
+
49
+ <style>
50
+ [data-composition-id="overlays"] {
51
+ position: relative;
52
+ width: 1080px;
53
+ height: 1920px;
54
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
55
+ color: #000000;
56
+ overflow: hidden;
57
+ pointer-events: none;
58
+ }
59
+
60
+ /* Grid System */
61
+ [data-composition-id="overlays"] .vignelli-grid {
62
+ position: absolute;
63
+ top: 0;
64
+ left: 0;
65
+ width: 100%;
66
+ height: 100%;
67
+ display: grid;
68
+ grid-template-columns: repeat(6, 1fr);
69
+ pointer-events: none;
70
+ z-index: 100;
71
+ opacity: 0; /* Hidden */
72
+ }
73
+ [data-composition-id="overlays"] .vignelli-grid .col {
74
+ border-right: 1px solid rgba(204, 0, 0, 0.1);
75
+ }
76
+
77
+ [data-composition-id="overlays"] .overlay-item {
78
+ position: absolute;
79
+ opacity: 0;
80
+ display: flex;
81
+ z-index: 10;
82
+ }
83
+
84
+ /* 1. 47% Stat Styles */
85
+ [data-composition-id="overlays"] #stat-47 {
86
+ bottom: 200px;
87
+ left: 0;
88
+ width: 540px; /* 3 columns */
89
+ height: 240px;
90
+ background: #FFFFFF;
91
+ flex-direction: row;
92
+ align-items: stretch;
93
+ }
94
+ [data-composition-id="overlays"] #stat-47 .red-bar {
95
+ width: 20px;
96
+ background: #CC0000;
97
+ }
98
+ [data-composition-id="overlays"] #stat-47 .stat-content {
99
+ padding: 40px;
100
+ display: flex;
101
+ flex-direction: column;
102
+ justify-content: center;
103
+ }
104
+ [data-composition-id="overlays"] #stat-47 .number {
105
+ font-size: 120px;
106
+ font-weight: 900;
107
+ line-height: 1;
108
+ letter-spacing: -2px;
109
+ }
110
+ [data-composition-id="overlays"] #stat-47 .label {
111
+ font-size: 32px;
112
+ font-weight: 700;
113
+ text-transform: uppercase;
114
+ margin-top: 10px;
115
+ }
116
+
117
+ /* 2. 62% Stat Styles (Full Canvas) */
118
+ [data-composition-id="overlays"] #stat-62 {
119
+ top: 0;
120
+ left: 0;
121
+ width: 1080px;
122
+ height: 1920px;
123
+ z-index: 50;
124
+ }
125
+ [data-composition-id="overlays"] #stat-62 .bg-charcoal {
126
+ position: absolute;
127
+ top: 0;
128
+ left: 0;
129
+ width: 100%;
130
+ height: 100%;
131
+ background: #1A1A1A;
132
+ }
133
+ [data-composition-id="overlays"] #stat-62 .full-content {
134
+ position: relative;
135
+ width: 100%;
136
+ height: 100%;
137
+ display: flex;
138
+ flex-direction: column;
139
+ justify-content: center;
140
+ padding: 0 90px; /* Align with grid */
141
+ }
142
+ [data-composition-id="overlays"] #stat-62 .large-number {
143
+ font-size: 400px;
144
+ font-weight: 900;
145
+ color: #FFFFFF;
146
+ line-height: 0.8;
147
+ letter-spacing: -10px;
148
+ }
149
+ [data-composition-id="overlays"] #stat-62 .large-label {
150
+ font-size: 80px;
151
+ font-weight: 700;
152
+ color: #FFFFFF;
153
+ text-transform: uppercase;
154
+ margin-top: 20px;
155
+ max-width: 600px;
156
+ }
157
+ [data-composition-id="overlays"] #stat-62 .red-accent {
158
+ position: absolute;
159
+ top: 0;
160
+ right: 0;
161
+ width: 180px; /* 1 column */
162
+ height: 100%;
163
+ background: #CC0000;
164
+ }
165
+
166
+ /* 3. 3 out of 4 Stat Styles */
167
+ [data-composition-id="overlays"] #stat-3-4 {
168
+ top: 400px;
169
+ right: 0;
170
+ width: 360px; /* 2 columns */
171
+ background: #FFFFFF;
172
+ padding: 40px;
173
+ flex-direction: row-reverse;
174
+ }
175
+ [data-composition-id="overlays"] #stat-3-4 .text-block {
176
+ font-size: 48px;
177
+ font-weight: 700;
178
+ line-height: 1.1;
179
+ text-align: right;
180
+ }
181
+ [data-composition-id="overlays"] #stat-3-4 .highlight {
182
+ color: #CC0000;
183
+ font-size: 64px;
184
+ font-weight: 900;
185
+ }
186
+ [data-composition-id="overlays"] #stat-3-4 .side-bar {
187
+ width: 10px;
188
+ background: #000000;
189
+ margin-left: 20px;
190
+ }
191
+
192
+ /* 4. Branding Styles */
193
+ [data-composition-id="overlays"] #branding {
194
+ bottom: 100px;
195
+ left: 90px;
196
+ width: 900px;
197
+ justify-content: center;
198
+ z-index: 60;
199
+ }
200
+ [data-composition-id="overlays"] #branding .logo-container {
201
+ display: flex;
202
+ flex-direction: column;
203
+ align-items: center;
204
+ }
205
+ [data-composition-id="overlays"] #branding .logo-text {
206
+ font-size: 64px;
207
+ letter-spacing: 10px;
208
+ color: #000000;
209
+ }
210
+ [data-composition-id="overlays"] #branding .logo-text .heavy {
211
+ font-weight: 900;
212
+ }
213
+ [data-composition-id="overlays"] #branding .logo-text .light {
214
+ font-weight: 300;
215
+ }
216
+ [data-composition-id="overlays"] #branding .logo-underline {
217
+ width: 100%;
218
+ height: 8px;
219
+ background: #CC0000;
220
+ margin-top: 10px;
221
+ transform-origin: left;
222
+ }
223
+ </style>
224
+
225
+ <script>
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}];
228
+
229
+ // Requirement 1: "47% Motion Graphics" (Start: 1.199, End: 3.759)
230
+ // 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
239
+ );
240
+
241
+ // Requirement 2: "62% Static Content" (Start: 3.799, End: 7.299)
242
+ // Full canvas moment. Large bold typography across columns.
243
+ tl.set("#stat-62", { opacity: 1 }, 3.799);
244
+ tl.from("#stat-62 .bg-charcoal", { x: "100%", duration: 0.8, ease: "expo.out" }, 3.799);
245
+ 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);
247
+ tl.from("#stat-62 .large-label", { y: 50, opacity: 0, duration: 1, ease: "expo.out" }, 4.299);
248
+
249
+ tl.to("#stat-62", { x: "-100%", duration: 0.8, ease: "expo.in" }, 7.299 - 0.8);
250
+
251
+ // Requirement 3: "3 out of 4 lack editing skills" (Start: 7.319, End: 12.239)
252
+ // 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
261
+ );
262
+
263
+ // Requirement 4: "Hyperframes" (Start: 12.84, End: 13.84)
264
+ 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);
266
+ tl.from("#branding .logo-underline", { scaleX: 0, duration: 0.8, ease: "expo.out" }, 13.04);
267
+
268
+ window.__timelines["overlays"] = tl;
269
+ </script>
270
+ </div>
271
+ </template>