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
@@ -0,0 +1,92 @@
1
+ <template id="captions-template">
2
+ <div
3
+ data-composition-id="captions"
4
+ data-width="1920"
5
+ data-height="1080"
6
+ data-duration="__VIDEO_DURATION__"
7
+ >
8
+ <div id="captions-container"></div>
9
+
10
+ <style>
11
+ [data-composition-id="captions"] {
12
+ width: 1920px;
13
+ height: 1080px;
14
+ pointer-events: none;
15
+ }
16
+
17
+ [data-composition-id="captions"] #captions-container {
18
+ position: absolute;
19
+ bottom: 100px;
20
+ left: 50%;
21
+ transform: translateX(-50%);
22
+ display: flex;
23
+ justify-content: center;
24
+ align-items: center;
25
+ width: 100%;
26
+ height: 150px;
27
+ }
28
+
29
+ .caption-group {
30
+ position: absolute;
31
+ opacity: 0;
32
+ font-family: "Inter", sans-serif;
33
+ font-size: 48px;
34
+ font-weight: 700;
35
+ color: #ffffff;
36
+ text-shadow:
37
+ 0 2px 8px rgba(0, 0, 0, 0.8),
38
+ 0 0 2px rgba(0, 0, 0, 0.9);
39
+ white-space: nowrap;
40
+ }
41
+ </style>
42
+
43
+ <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
44
+ <script>
45
+ (function () {
46
+ window.__timelines = window.__timelines || {};
47
+ const tl = gsap.timeline({ paused: true });
48
+
49
+ const script = [];
50
+
51
+ if (script.length === 0) {
52
+ window.__timelines["captions"] = tl;
53
+ return;
54
+ }
55
+
56
+ const container = document.getElementById("captions-container");
57
+
58
+ // Group words into lines (max 5 words per line)
59
+ const lines = [];
60
+ for (let i = 0; i < script.length; i += 5) {
61
+ const lineWords = script.slice(i, i + 5);
62
+ lines.push({
63
+ text: lineWords.map((w) => w.text).join(" "),
64
+ start: lineWords[0].start,
65
+ end: lineWords[lineWords.length - 1].end,
66
+ });
67
+ }
68
+
69
+ lines.forEach((line, index) => {
70
+ const el = document.createElement("div");
71
+ el.className = "caption-group";
72
+ el.textContent = line.text;
73
+ container.appendChild(el);
74
+
75
+ tl.fromTo(
76
+ el,
77
+ { opacity: 0, y: 20 },
78
+ { opacity: 1, y: 0, duration: 0.3, ease: "power3.out" },
79
+ line.start,
80
+ );
81
+
82
+ const hideTime =
83
+ index < lines.length - 1 ? Math.min(line.end, lines[index + 1].start) : line.end;
84
+
85
+ tl.to(el, { opacity: 0, y: -10, duration: 0.25, ease: "power2.in" }, hideTime - 0.25);
86
+ });
87
+
88
+ window.__timelines["captions"] = tl;
89
+ })();
90
+ </script>
91
+ </div>
92
+ </template>
@@ -0,0 +1,44 @@
1
+ <div
2
+ id="root"
3
+ data-composition-id="main"
4
+ data-start="0"
5
+ data-duration="__VIDEO_DURATION__"
6
+ data-width="1920"
7
+ data-height="1080"
8
+ >
9
+ <video
10
+ id="a-roll"
11
+ src="__VIDEO_SRC__"
12
+ muted
13
+ playsinline
14
+ data-start="0"
15
+ data-duration="__VIDEO_DURATION__"
16
+ data-track-index="0"
17
+ ></video>
18
+ <audio
19
+ id="a-roll-audio"
20
+ src="__VIDEO_SRC__"
21
+ data-start="0"
22
+ data-duration="__VIDEO_DURATION__"
23
+ data-track-index="2"
24
+ data-volume="1"
25
+ ></audio>
26
+
27
+ <div
28
+ id="captions-comp"
29
+ data-composition-id="captions"
30
+ data-composition-src="compositions/captions.html"
31
+ data-start="0"
32
+ data-duration="__VIDEO_DURATION__"
33
+ data-track-index="3"
34
+ data-width="1920"
35
+ data-height="1080"
36
+ ></div>
37
+
38
+ <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
39
+ <script>
40
+ window.__timelines = window.__timelines || {};
41
+ const tl = gsap.timeline({ paused: true });
42
+ window.__timelines["main"] = tl;
43
+ </script>
44
+ </div>
@@ -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="captions-container"></div>
4
9
 
5
10
  <style>
@@ -23,11 +28,11 @@
23
28
 
24
29
  .caption-box {
25
30
  position: absolute; /* Stacked in the same place */
26
- background-color: #FF2D8A;
31
+ background-color: #ff2d8a;
27
32
  color: white;
28
33
  padding: 20px 40px;
29
34
  border-radius: 16px;
30
- font-family: 'Nunito', sans-serif;
35
+ font-family: "Nunito", sans-serif;
31
36
  font-weight: 900; /* Nunito Black */
32
37
  font-size: 64px;
33
38
  text-align: center;
@@ -41,9 +46,56 @@
41
46
  </style>
42
47
 
43
48
  <script>
44
- (function() {
45
- 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.839, '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.639}, {'text': 'Sixty-two', 'start': 4.659, 'end': 5.179}, {'text': 'percent', 'start': 5.299, 'end': 5.759}, {'text': 'said', 'start': 5.859, 'end': 5.98}, {'text': 'static', 'start': 6.099, '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.479}, {'text': 'look', 'start': 10.52, '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}];
46
- const container = document.getElementById('captions-container');
49
+ (function () {
50
+ const TRANSCRIPT = [
51
+ { text: "We", start: 0.119, end: 0.259 },
52
+ { text: "asked", start: 0.319, end: 0.479 },
53
+ { text: "what", start: 0.519, end: 0.659 },
54
+ { text: "you", start: 0.699, end: 0.819 },
55
+ { text: "needed.", start: 0.859, end: 1.819 },
56
+ { text: "Forty-seven", start: 1.839, end: 2.299 },
57
+ { text: "percent", start: 2.399, end: 2.679 },
58
+ { text: "of", start: 2.7, end: 2.799 },
59
+ { text: "you", start: 2.839, end: 2.939 },
60
+ { text: "said", start: 3.039, end: 3.179 },
61
+ { text: "motion", start: 3.24, end: 3.559 },
62
+ { text: "graphics.", start: 3.579, end: 4.639 },
63
+ { text: "Sixty-two", start: 4.659, end: 5.179 },
64
+ { text: "percent", start: 5.299, end: 5.759 },
65
+ { text: "said", start: 5.859, end: 5.98 },
66
+ { text: "static", start: 6.099, end: 6.399 },
67
+ { text: "content", start: 6.46, end: 6.879 },
68
+ { text: "was", start: 6.92, end: 7.079 },
69
+ { text: "costing", start: 7.099, end: 7.48 },
70
+ { text: "you", start: 7.5, end: 7.579 },
71
+ { text: "attention,", start: 7.679, end: 8.659 },
72
+ { text: "and", start: 8.699, end: 8.86 },
73
+ { text: "three", start: 8.88, end: 9.06 },
74
+ { text: "out", start: 9.079, end: 9.18 },
75
+ { text: "of", start: 9.199, end: 9.34 },
76
+ { text: "four", start: 9.38, end: 9.799 },
77
+ { text: "said", start: 9.84, end: 10.0 },
78
+ { text: "you", start: 10.019, end: 10.159 },
79
+ { text: "know", start: 10.179, end: 10.36 },
80
+ { text: "the", start: 10.38, end: 10.479 },
81
+ { text: "look", start: 10.52, end: 10.699 },
82
+ { text: "you", start: 10.739, end: 10.859 },
83
+ { text: "want", start: 10.98, end: 11.34 },
84
+ { text: "but", start: 11.359, end: 11.52 },
85
+ { text: "don't", start: 11.56, end: 11.779 },
86
+ { text: "have", start: 11.819, end: 11.94 },
87
+ { text: "the", start: 11.96, end: 12.06 },
88
+ { text: "editing", start: 12.079, end: 12.4 },
89
+ { text: "skills", start: 12.52, end: 12.86 },
90
+ { text: "to", start: 12.88, end: 13.0 },
91
+ { text: "get", start: 13.019, end: 13.18 },
92
+ { text: "there.", start: 13.22, end: 14.22 },
93
+ { text: "So", start: 14.239, end: 14.399 },
94
+ { text: "we", start: 14.42, end: 14.52 },
95
+ { text: "built", start: 14.619, end: 14.88 },
96
+ { text: "Hyperframes", start: 15.079, end: 15.42 },
97
+ ];
98
+ const container = document.getElementById("captions-container");
47
99
  const tl = gsap.timeline({ paused: true });
48
100
 
49
101
  // Group transcript into lines (max 5 words)
@@ -53,43 +105,57 @@
53
105
  }
54
106
 
55
107
  lines.forEach((lineWords, index) => {
56
- const lineText = lineWords.map(w => w.text).join(' ');
108
+ const lineText = lineWords.map((w) => w.text).join(" ");
57
109
  const startTime = lineWords[0].start;
58
110
  const endTime = lineWords[lineWords.length - 1].end;
59
-
111
+
60
112
  // Create element
61
- const el = document.createElement('div');
62
- el.className = 'caption-box';
113
+ const el = document.createElement("div");
114
+ el.className = "caption-box";
63
115
  el.textContent = lineText;
64
116
  el.id = `caption-line-${index}`;
65
117
  container.appendChild(el);
66
118
 
67
119
  // Animation: Pop in with scale-up bounce (0% to 110% to 100%)
68
- tl.to(el, {
69
- autoAlpha: 1,
70
- scale: 1.1,
71
- duration: 0.2,
72
- ease: "power2.out"
73
- }, startTime);
74
-
75
- tl.to(el, {
76
- scale: 1,
77
- duration: 0.1,
78
- ease: "power2.inOut"
79
- }, startTime + 0.2);
120
+ tl.to(
121
+ el,
122
+ {
123
+ autoAlpha: 1,
124
+ scale: 1.1,
125
+ duration: 0.2,
126
+ ease: "power2.out",
127
+ },
128
+ startTime,
129
+ );
130
+
131
+ tl.to(
132
+ el,
133
+ {
134
+ scale: 1,
135
+ duration: 0.1,
136
+ ease: "power2.inOut",
137
+ },
138
+ startTime + 0.2,
139
+ );
80
140
 
81
141
  // Stay visible until next line or end of its duration
82
142
  // We hide it when the next line starts or at its own end time
83
- const hideTime = (index < lines.length - 1) ? Math.min(endTime, lines[index+1][0].start) : endTime;
84
-
85
- tl.to(el, {
86
- autoAlpha: 0,
87
- scale: 0,
88
- duration: 0.15,
89
- ease: "power2.in"
90
- }, hideTime);
143
+ const hideTime =
144
+ index < lines.length - 1 ? Math.min(endTime, lines[index + 1][0].start) : endTime;
145
+
146
+ tl.to(
147
+ el,
148
+ {
149
+ autoAlpha: 0,
150
+ scale: 0,
151
+ duration: 0.15,
152
+ ease: "power2.in",
153
+ },
154
+ hideTime,
155
+ );
91
156
  });
92
157
 
158
+ window.__timelines = window.__timelines || {};
93
159
  window.__timelines["captions"] = tl;
94
160
  })();
95
161
  </script>
@@ -1,88 +1,107 @@
1
1
  <template id="intro-template">
2
- <div id="intro-comp" data-composition-id="intro" data-start="0" data-duration="16.04" data-width="1920" data-height="1080">
3
- <div class="intro-container">
4
- <h1 class="title">HYPERFRAMES</h1>
5
- </div>
2
+ <div
3
+ id="intro-comp"
4
+ data-composition-id="intro"
5
+ data-start="0"
6
+ data-duration="__VIDEO_DURATION__"
7
+ data-width="1920"
8
+ data-height="1080"
9
+ >
10
+ <div class="intro-container">
11
+ <h1 class="title">HYPERFRAMES</h1>
12
+ </div>
6
13
 
7
- <style>
8
- @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap');
14
+ <style>
15
+ @import url("https://fonts.googleapis.com/css2?family=Nunito:wght@900&display=swap");
9
16
 
10
- [data-composition-id="intro"] .intro-container {
11
- width: 100%;
12
- height: 100%;
13
- display: flex;
14
- justify-content: center;
15
- align-items: center;
16
- pointer-events: none;
17
- }
17
+ [data-composition-id="intro"] .intro-container {
18
+ width: 100%;
19
+ height: 100%;
20
+ display: flex;
21
+ justify-content: center;
22
+ align-items: center;
23
+ pointer-events: none;
24
+ }
18
25
 
19
- [data-composition-id="intro"] .title {
20
- font-family: 'Nunito', sans-serif;
21
- font-weight: 900;
22
- font-size: 180px;
23
- color: #FF2D8A; /* Hot Pink */
24
- text-transform: uppercase;
25
- transform: rotate(-5deg); /* Tilted 5 degrees */
26
- margin: 0;
27
- padding: 20px;
28
- /* Layered offset shadow for depth without suffocating letterforms */
29
- filter: drop-shadow(8px 8px 0 #FFFFFF) drop-shadow(15px 15px 0 rgba(0,0,0,0.1));
30
- opacity: 0;
31
- scale: 0;
32
- }
33
- </style>
26
+ [data-composition-id="intro"] .title {
27
+ font-family: "Nunito", sans-serif;
28
+ font-weight: 900;
29
+ font-size: 180px;
30
+ color: #ff2d8a; /* Hot Pink */
31
+ text-transform: uppercase;
32
+ transform: rotate(-5deg); /* Tilted 5 degrees */
33
+ margin: 0;
34
+ padding: 20px;
35
+ /* Layered offset shadow for depth without suffocating letterforms */
36
+ filter: drop-shadow(8px 8px 0 #ffffff) drop-shadow(15px 15px 0 rgba(0, 0, 0, 0.1));
37
+ opacity: 0;
38
+ scale: 0;
39
+ }
40
+ </style>
34
41
 
35
- <script>
36
- (function() {
37
- const tl = gsap.timeline({ paused: true });
38
-
39
- // --- INTRO SEQUENCE ---
40
- // Animation: Scale-up bounce (0% to 110% to 100%) with elastic overshoot
41
- // Starts at 0.5s, lasts until 3s
42
- tl.to('[data-composition-id="intro"] .title', {
43
- opacity: 1,
44
- scale: 1.1,
45
- duration: 0.6,
46
- ease: "back.out(1.7)",
47
- delay: 0.5
48
- })
42
+ <script>
43
+ (function () {
44
+ const tl = gsap.timeline({ paused: true });
45
+
46
+ // --- INTRO SEQUENCE ---
47
+ // Animation: Scale-up bounce (0% to 110% to 100%) with elastic overshoot
48
+ // Starts at 0.5s, lasts until 3s
49
+ tl.to('[data-composition-id="intro"] .title', {
50
+ opacity: 1,
51
+ scale: 1.1,
52
+ duration: 0.6,
53
+ ease: "back.out(1.7)",
54
+ delay: 0.5,
55
+ })
49
56
  .to('[data-composition-id="intro"] .title', {
50
57
  scale: 1,
51
58
  duration: 0.4,
52
- ease: "elastic.out(1, 0.3)"
59
+ ease: "elastic.out(1, 0.3)",
53
60
  })
54
61
  // Ambient motion
55
- .to('[data-composition-id="intro"] .title', {
56
- rotation: "-3deg",
57
- duration: 1,
58
- repeat: 1,
59
- yoyo: true,
60
- ease: "sine.inOut"
61
- }, "-=0.5")
62
+ .to(
63
+ '[data-composition-id="intro"] .title',
64
+ {
65
+ rotation: "-3deg",
66
+ duration: 1,
67
+ repeat: 1,
68
+ yoyo: true,
69
+ ease: "sine.inOut",
70
+ },
71
+ "-=0.5",
72
+ )
62
73
  // Exit intro
63
- .to('[data-composition-id="intro"] .title', {
64
- opacity: 0,
65
- scale: 0.5,
66
- duration: 0.3,
67
- ease: "power2.in"
68
- }, 1.4);
74
+ .to(
75
+ '[data-composition-id="intro"] .title',
76
+ {
77
+ opacity: 0,
78
+ scale: 0.5,
79
+ duration: 0.3,
80
+ ease: "power2.in",
81
+ },
82
+ 1.4,
83
+ );
69
84
 
70
- // --- END CARD SEQUENCE ---
71
- // Appears at 14.619s (after Moment 3 finishes exiting at 14.239 + 0.3)
72
- tl.to('[data-composition-id="intro"] .title', {
85
+ // --- END CARD SEQUENCE ---
86
+ // Appears at 14.619s (after Moment 3 finishes exiting at 14.239 + 0.3)
87
+ tl.to(
88
+ '[data-composition-id="intro"] .title',
89
+ {
73
90
  opacity: 1,
74
91
  scale: 1.1,
75
92
  duration: 0.6,
76
- ease: "back.out(1.7)"
77
- }, 14.619)
78
- .to('[data-composition-id="intro"] .title', {
79
- scale: 1,
80
- duration: 0.4,
81
- ease: "elastic.out(1, 0.3)"
82
- });
93
+ ease: "back.out(1.7)",
94
+ },
95
+ 14.619,
96
+ ).to('[data-composition-id="intro"] .title', {
97
+ scale: 1,
98
+ duration: 0.4,
99
+ ease: "elastic.out(1, 0.3)",
100
+ });
83
101
 
84
- window.__timelines["intro"] = tl;
85
- })();
86
- </script>
87
- </div>
102
+ window.__timelines = window.__timelines || {};
103
+ window.__timelines["intro"] = tl;
104
+ })();
105
+ </script>
106
+ </div>
88
107
  </template>