@vanillaskyai/video 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 (162) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/LICENSE +201 -0
  3. package/PUBLIC-API.md +276 -0
  4. package/README.md +152 -0
  5. package/SECURITY.md +22 -0
  6. package/SUPPORT.md +28 -0
  7. package/bin/vanillasky.js +3 -0
  8. package/dist/bg-confetti-WNQXS7ZS.js +89 -0
  9. package/dist/bg-emoji-ETI47GLS.js +150 -0
  10. package/dist/bg-media-SVUZAMGX.js +99 -0
  11. package/dist/brand-message-F3RD4P3P.js +253 -0
  12. package/dist/builtin-server-F7YXRVCH.js +8 -0
  13. package/dist/catalog-types-BIhSpOWK.d.ts +74 -0
  14. package/dist/chart-bar-CNSC7BNK.js +304 -0
  15. package/dist/chart-counter-MCRHKN77.js +299 -0
  16. package/dist/chart-progress-ring-RMI4A7ZK.js +296 -0
  17. package/dist/check-runtime.d.ts +15 -0
  18. package/dist/check-runtime.js +102 -0
  19. package/dist/chunk-2E6T633S.js +27 -0
  20. package/dist/chunk-352ZZCET.js +83 -0
  21. package/dist/chunk-73NTSFFI.js +81 -0
  22. package/dist/chunk-A2X45FET.js +46 -0
  23. package/dist/chunk-ABPKM4GK.js +187 -0
  24. package/dist/chunk-ABZACD4G.js +216 -0
  25. package/dist/chunk-BCRUUJ6A.js +756 -0
  26. package/dist/chunk-CHLGW22F.js +3551 -0
  27. package/dist/chunk-CJ7F2CE6.js +104 -0
  28. package/dist/chunk-CR7FE7BW.js +109 -0
  29. package/dist/chunk-E7CL7UPB.js +109 -0
  30. package/dist/chunk-EE6PK6XC.js +18 -0
  31. package/dist/chunk-ERY4S6QV.js +385 -0
  32. package/dist/chunk-EVG2ZYIY.js +125 -0
  33. package/dist/chunk-FNAEQ7QO.js +155 -0
  34. package/dist/chunk-FQ47WXAJ.js +38 -0
  35. package/dist/chunk-FSG2PYWG.js +336 -0
  36. package/dist/chunk-GHJEAP4O.js +504 -0
  37. package/dist/chunk-GRMUV7QY.js +262 -0
  38. package/dist/chunk-IFOW65Z6.js +205 -0
  39. package/dist/chunk-IXCUY3B3.js +786 -0
  40. package/dist/chunk-L5BTTCZV.js +97 -0
  41. package/dist/chunk-LMG3GHLL.js +107 -0
  42. package/dist/chunk-OOPIETLW.js +101 -0
  43. package/dist/chunk-P22HHFDK.js +43 -0
  44. package/dist/chunk-QAAO7OAY.js +19 -0
  45. package/dist/chunk-S7HFLYNN.js +35 -0
  46. package/dist/chunk-SPVTJH3F.js +24 -0
  47. package/dist/chunk-W2XJKG6C.js +3177 -0
  48. package/dist/chunk-XB7LH4J2.js +301 -0
  49. package/dist/chunk-XGRA2MUV.js +242 -0
  50. package/dist/chunk-XTOXFMLM.js +105 -0
  51. package/dist/chunk-YC5MFXA5.js +132 -0
  52. package/dist/cli.d.ts +1 -0
  53. package/dist/cli.js +1681 -0
  54. package/dist/compose-video-CN3VSWST.js +13 -0
  55. package/dist/cta-logo-SVA5GP2A.js +209 -0
  56. package/dist/cta-media-E7VLLK42.js +215 -0
  57. package/dist/events-_wfjbmEp.d.ts +81 -0
  58. package/dist/incoming-call-62MFZL3Z.js +320 -0
  59. package/dist/index.d.ts +15 -0
  60. package/dist/index.js +14 -0
  61. package/dist/infographic-before-after-AXCDAWND.js +460 -0
  62. package/dist/infographic-feature-list-GW5GUE6O.js +266 -0
  63. package/dist/infographic-problem-solution-7NURJANA.js +340 -0
  64. package/dist/infographic-stat-row-J7IZR6ZN.js +241 -0
  65. package/dist/infographic-steps-VSZM6F5M.js +400 -0
  66. package/dist/kit-BMNcHqa9.d.ts +79 -0
  67. package/dist/prompt-input-LOUCRXCY.js +236 -0
  68. package/dist/react.d.ts +81 -0
  69. package/dist/react.js +835 -0
  70. package/dist/reaction-QG4CYZLQ.js +119 -0
  71. package/dist/server.d.ts +141 -0
  72. package/dist/server.js +498 -0
  73. package/dist/showcase-code-RUTFZR3H.js +351 -0
  74. package/dist/showcase-phone-6CP6XEU5.js +272 -0
  75. package/dist/showcase-terminal-MGAEQWPR.js +306 -0
  76. package/dist/showcase-web-Y4W2HVRJ.js +390 -0
  77. package/dist/social-conversation-75SD2637.js +695 -0
  78. package/dist/social-milestone-XI2QE5BO.js +292 -0
  79. package/dist/social-notification-2UOHQCUY.js +244 -0
  80. package/dist/social-review-stack-FDYZGZTJ.js +239 -0
  81. package/dist/social-testimonial-OQ7N52GJ.js +284 -0
  82. package/dist/social-tweet-5OLCNPPC.js +295 -0
  83. package/dist/state-DZcKuS32.d.ts +3 -0
  84. package/dist/system-prompt-A6UXNTPK.js +8 -0
  85. package/dist/template-catalog.d.ts +24 -0
  86. package/dist/template-catalog.js +6 -0
  87. package/dist/templates.d.ts +25 -0
  88. package/dist/templates.js +19 -0
  89. package/dist/test.d.ts +149 -0
  90. package/dist/test.js +272 -0
  91. package/dist/text-stream-6XHC7J47.js +10 -0
  92. package/dist/types-B-PZR6G_.d.ts +208 -0
  93. package/dist/validate-T7GBU2YF.js +8 -0
  94. package/docs/agent-integration.md +39 -0
  95. package/docs/architecture.md +84 -0
  96. package/docs/branding-and-personalization.md +87 -0
  97. package/docs/concepts.md +106 -0
  98. package/docs/custom-templates.md +329 -0
  99. package/docs/customization.md +141 -0
  100. package/docs/errors.md +70 -0
  101. package/docs/getting-started.md +111 -0
  102. package/docs/input-and-first-scene.md +41 -0
  103. package/docs/integrate-nextjs.md +79 -0
  104. package/docs/media-and-audio.md +69 -0
  105. package/docs/motion-and-effects.md +107 -0
  106. package/docs/persistence.md +95 -0
  107. package/docs/production.md +122 -0
  108. package/docs/prompt-and-input.md +185 -0
  109. package/docs/provider-integration.md +115 -0
  110. package/docs/reference/protocol.md +96 -0
  111. package/docs/reference/provider-adapters.md +158 -0
  112. package/docs/responsive-orientation.md +37 -0
  113. package/docs/security.md +38 -0
  114. package/docs/streaming-protocol.md +15 -0
  115. package/docs/testing.md +137 -0
  116. package/docs/use-cases.md +59 -0
  117. package/examples/custom-template/README.md +19 -0
  118. package/examples/custom-template/minimal-text.tsx +82 -0
  119. package/examples/custom-template/structured-data.tsx +104 -0
  120. package/examples/custom-template/supplied-media.tsx +92 -0
  121. package/examples/nextjs-quickstart/.env.example +2 -0
  122. package/examples/nextjs-quickstart/README.md +22 -0
  123. package/examples/nextjs-quickstart/next-env.d.ts +4 -0
  124. package/examples/nextjs-quickstart/package.json +24 -0
  125. package/examples/nextjs-quickstart/src/app/api/video/route.ts +22 -0
  126. package/examples/nextjs-quickstart/src/app/layout.tsx +5 -0
  127. package/examples/nextjs-quickstart/src/app/page.tsx +31 -0
  128. package/examples/nextjs-quickstart/tsconfig.json +26 -0
  129. package/package.json +167 -0
  130. package/registry/items/backgrounds.json +52 -0
  131. package/registry/items/barChart.json +237 -0
  132. package/registry/items/beforeAfter.json +180 -0
  133. package/registry/items/bigNumber.json +225 -0
  134. package/registry/items/brandMessage.json +158 -0
  135. package/registry/items/cardList.json +206 -0
  136. package/registry/items/chatMessenger.json +151 -0
  137. package/registry/items/chatWhatsapp.json +151 -0
  138. package/registry/items/codeEditor.json +184 -0
  139. package/registry/items/confetti.json +107 -0
  140. package/registry/items/ctaLogo.json +160 -0
  141. package/registry/items/ctaMedia.json +193 -0
  142. package/registry/items/emojiBurst.json +101 -0
  143. package/registry/items/incomingCall.json +170 -0
  144. package/registry/items/media.json +179 -0
  145. package/registry/items/milestone.json +205 -0
  146. package/registry/items/motion.json +45 -0
  147. package/registry/items/notification.json +182 -0
  148. package/registry/items/phoneMockup.json +254 -0
  149. package/registry/items/problemSolution.json +186 -0
  150. package/registry/items/progressRing.json +199 -0
  151. package/registry/items/promptInput.json +148 -0
  152. package/registry/items/reaction.json +170 -0
  153. package/registry/items/reviewStack.json +224 -0
  154. package/registry/items/steps.json +207 -0
  155. package/registry/items/template-context.json +31 -0
  156. package/registry/items/terminal.json +212 -0
  157. package/registry/items/testimonial.json +164 -0
  158. package/registry/items/theme.json +47 -0
  159. package/registry/items/tripleStats.json +228 -0
  160. package/registry/items/tweet.json +203 -0
  161. package/registry/items/typography.json +47 -0
  162. package/registry/items/webMockup.json +273 -0
@@ -0,0 +1,241 @@
1
+ import {
2
+ SceneBackground,
3
+ getMediaBackgroundProps
4
+ } from "./chunk-IFOW65Z6.js";
5
+ import {
6
+ TemplateText
7
+ } from "./chunk-BCRUUJ6A.js";
8
+ import "./chunk-L5BTTCZV.js";
9
+ import {
10
+ TOP_TEXT_AREA_RATIO,
11
+ withOpacity
12
+ } from "./chunk-ABZACD4G.js";
13
+ import {
14
+ interpolate,
15
+ spring
16
+ } from "./chunk-XTOXFMLM.js";
17
+ import {
18
+ TOKEN_DEFAULTS,
19
+ resolveTokens
20
+ } from "./chunk-FNAEQ7QO.js";
21
+
22
+ // src/visual-system/primitives/typography/StatBadgeRow.tsx
23
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
24
+ var SPRING_STAT = { damping: 12, stiffness: 170 };
25
+ var StatBadgeRow = ({
26
+ progress,
27
+ stats: rawStats,
28
+ width,
29
+ height,
30
+ font = TOKEN_DEFAULTS.font,
31
+ textColor = "#ffffff"
32
+ }) => {
33
+ const s = Math.min(width, height) / 1080;
34
+ const stats = rawStats.filter((st) => st.value);
35
+ const isLandscape = width > height;
36
+ const textAreaHeight = height * TOP_TEXT_AREA_RATIO;
37
+ const statsAreaTop = textAreaHeight;
38
+ const statsAreaHeight = height - statsAreaTop;
39
+ const valueFontSize = isLandscape ? 72 * s : 100 * s;
40
+ const labelFontSize = isLandscape ? 28 * s : 38 * s;
41
+ const statCount = stats.length;
42
+ const getStatPosition = (i) => {
43
+ if (isLandscape) {
44
+ const spacing = width / (statCount + 1);
45
+ return {
46
+ x: spacing * (i + 1),
47
+ y: statsAreaTop + statsAreaHeight * 0.4
48
+ };
49
+ }
50
+ const sectionH = statsAreaHeight / (statCount + 0.5);
51
+ return {
52
+ x: width / 2,
53
+ y: statsAreaTop + sectionH * (i + 0.5)
54
+ };
55
+ };
56
+ return /* @__PURE__ */ jsx(Fragment, { children: stats.map((stat, i) => {
57
+ const pos = getStatPosition(i);
58
+ const itemStart = 0.1 + i * 0.12;
59
+ const statP = spring(
60
+ interpolate(progress, [itemStart, itemStart + 0.12], [0, 1], {
61
+ extrapolateLeft: "clamp",
62
+ extrapolateRight: "clamp"
63
+ }),
64
+ SPRING_STAT
65
+ );
66
+ const scaleVal = interpolate(statP, [0, 1], [0.5, 1]);
67
+ const opacity = interpolate(progress, [itemStart, itemStart + 0.06], [0, 1], {
68
+ extrapolateLeft: "clamp",
69
+ extrapolateRight: "clamp"
70
+ });
71
+ const labelDelay = itemStart + 0.06;
72
+ const labelOpacity = interpolate(progress, [labelDelay, labelDelay + 0.05], [0, 1], {
73
+ extrapolateLeft: "clamp",
74
+ extrapolateRight: "clamp"
75
+ });
76
+ const labelSlideY = interpolate(progress, [labelDelay, labelDelay + 0.06], [10 * s, 0], {
77
+ extrapolateLeft: "clamp",
78
+ extrapolateRight: "clamp"
79
+ });
80
+ const EXIT_START = 0.78;
81
+ const EXIT_DURATION = 0.1;
82
+ const EXIT_STAGGER = 0.04;
83
+ const exitStart = EXIT_START + i * EXIT_STAGGER;
84
+ const exitEnd = exitStart + EXIT_DURATION;
85
+ const exitRaw = interpolate(progress, [exitStart, exitEnd], [0, 1], {
86
+ extrapolateLeft: "clamp",
87
+ extrapolateRight: "clamp"
88
+ });
89
+ const exitEased = exitRaw * exitRaw;
90
+ const exitTranslateX = -90 * s * exitEased;
91
+ const exitFade = 1 - exitEased;
92
+ return /* @__PURE__ */ jsxs(
93
+ "div",
94
+ {
95
+ style: {
96
+ position: "absolute",
97
+ left: pos.x,
98
+ top: pos.y,
99
+ transform: `translate(-50%, -50%) translate(${exitTranslateX}px, 0) scale(${scaleVal})`,
100
+ opacity: opacity * exitFade,
101
+ display: "flex",
102
+ flexDirection: "column",
103
+ alignItems: "center",
104
+ justifyContent: "center",
105
+ gap: isLandscape ? 12 * s : 24 * s,
106
+ backgroundColor: "rgba(255,255,255,0.15)",
107
+ border: "1.5px solid rgba(255,255,255,0.2)",
108
+ borderRadius: isLandscape ? 20 * s : 28 * s,
109
+ padding: isLandscape ? `${28 * s}px ${24 * s}px` : `${48 * s}px ${56 * s}px`,
110
+ width: isLandscape ? width / (statCount + 1) * 0.85 : void 0,
111
+ maxWidth: isLandscape ? width * 0.28 : void 0,
112
+ minWidth: isLandscape ? void 0 : width * 0.6
113
+ },
114
+ children: [
115
+ /* @__PURE__ */ jsx(
116
+ "div",
117
+ {
118
+ style: {
119
+ fontSize: valueFontSize,
120
+ fontWeight: 800,
121
+ color: textColor,
122
+ fontFamily: font,
123
+ lineHeight: 1,
124
+ whiteSpace: "nowrap"
125
+ },
126
+ children: stat.value
127
+ }
128
+ ),
129
+ /* @__PURE__ */ jsx(
130
+ "div",
131
+ {
132
+ style: {
133
+ fontSize: labelFontSize,
134
+ fontWeight: 500,
135
+ color: withOpacity(textColor, 0.8),
136
+ fontFamily: font,
137
+ lineHeight: 1.2,
138
+ whiteSpace: isLandscape ? "normal" : "nowrap",
139
+ textAlign: "center",
140
+ textTransform: "uppercase",
141
+ letterSpacing: isLandscape ? 1 * s : 2 * s,
142
+ opacity: labelOpacity,
143
+ transform: `translateY(${labelSlideY}px)`
144
+ },
145
+ children: stat.label
146
+ }
147
+ )
148
+ ]
149
+ },
150
+ i
151
+ );
152
+ }) });
153
+ };
154
+
155
+ // src/visual-system/scene-templates/infographic-stat-row.tsx
156
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
157
+ var InfographicStatRowTemplate = ({
158
+ variables,
159
+ style,
160
+ progress,
161
+ motionProgress = progress,
162
+ beatIntensity,
163
+ width,
164
+ height,
165
+ safeZone,
166
+ sceneDuration,
167
+ backgroundEffect,
168
+ isPlaying = true
169
+ }) => {
170
+ const { foreground, font } = resolveTokens(style);
171
+ const textColor = foreground;
172
+ const textsRaw = String(variables.texts || "");
173
+ const stats = [
174
+ { value: String(variables.stat1Value || ""), label: String(variables.stat1Label || "") },
175
+ { value: String(variables.stat2Value || ""), label: String(variables.stat2Label || "") },
176
+ { value: String(variables.stat3Value || ""), label: String(variables.stat3Label || "") }
177
+ ];
178
+ return /* @__PURE__ */ jsxs2(
179
+ "div",
180
+ {
181
+ style: {
182
+ width,
183
+ height,
184
+ backgroundColor: "#000",
185
+ position: "relative",
186
+ overflow: "hidden",
187
+ fontFamily: font
188
+ },
189
+ children: [
190
+ /* @__PURE__ */ jsx2(
191
+ SceneBackground,
192
+ {
193
+ style,
194
+ progress,
195
+ sceneDuration,
196
+ width,
197
+ height,
198
+ ...getMediaBackgroundProps(variables),
199
+ backgroundEffect,
200
+ seed: textsRaw,
201
+ isPlaying,
202
+ beatIntensity
203
+ }
204
+ ),
205
+ /* @__PURE__ */ jsx2(
206
+ TemplateText,
207
+ {
208
+ motionProgress,
209
+ typeTreatment: resolveTokens(style).preset.type,
210
+ archetype: "subtle",
211
+ text: String(variables.texts ?? ""),
212
+ progress,
213
+ sceneDuration: sceneDuration ?? 3,
214
+ width,
215
+ height,
216
+ position: "top",
217
+ sizeRole: "headline",
218
+ safeZone,
219
+ font,
220
+ color: textColor,
221
+ beatIntensity
222
+ }
223
+ ),
224
+ /* @__PURE__ */ jsx2(
225
+ StatBadgeRow,
226
+ {
227
+ progress: motionProgress,
228
+ stats,
229
+ width,
230
+ height,
231
+ font,
232
+ textColor
233
+ }
234
+ )
235
+ ]
236
+ }
237
+ );
238
+ };
239
+ export {
240
+ InfographicStatRowTemplate
241
+ };
@@ -0,0 +1,400 @@
1
+ import {
2
+ parseList
3
+ } from "./chunk-P22HHFDK.js";
4
+ import {
5
+ fitTextSize,
6
+ stripPipe
7
+ } from "./chunk-S7HFLYNN.js";
8
+ import {
9
+ SceneBackground,
10
+ getMediaBackgroundProps
11
+ } from "./chunk-IFOW65Z6.js";
12
+ import {
13
+ TemplateText
14
+ } from "./chunk-BCRUUJ6A.js";
15
+ import {
16
+ Emoji
17
+ } from "./chunk-L5BTTCZV.js";
18
+ import {
19
+ TOP_TEXT_AREA_RATIO,
20
+ autoTextColor,
21
+ withOpacity
22
+ } from "./chunk-ABZACD4G.js";
23
+ import {
24
+ interpolate,
25
+ spring
26
+ } from "./chunk-XTOXFMLM.js";
27
+ import {
28
+ TOKEN_DEFAULTS,
29
+ resolveTokens
30
+ } from "./chunk-FNAEQ7QO.js";
31
+
32
+ // src/visual-system/primitives/infographic/StepsList.tsx
33
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
34
+ var SPRING_POP = { damping: 8, stiffness: 200 };
35
+ var SPRING_TITLE = { damping: 18, stiffness: 200 };
36
+ function computeStepsLayout({
37
+ width,
38
+ height,
39
+ labels,
40
+ safeZone = { top: 0, right: 0, bottom: 0, left: 0 }
41
+ }) {
42
+ const stepCount = Math.max(1, Math.min(labels.length, 4));
43
+ const s = Math.min(width, height) / 1080;
44
+ const textAreaBottom = Math.max(height * TOP_TEXT_AREA_RATIO, safeZone.top);
45
+ if (width > height) {
46
+ const availableWidth = Math.max(1, width - safeZone.left - safeZone.right);
47
+ const sectionWidth = availableWidth / stepCount;
48
+ const circleRadius2 = Math.min(104 * s, sectionWidth * 0.25);
49
+ const y = Math.min(
50
+ height * 0.55,
51
+ height - safeZone.bottom - circleRadius2 - 86 * s
52
+ );
53
+ return {
54
+ mode: "landscape-row",
55
+ items: labels.slice(0, 4).map((label, index) => {
56
+ const x2 = safeZone.left + sectionWidth * (index + 0.5);
57
+ const labelWidth2 = sectionWidth * 0.76;
58
+ return {
59
+ x: x2,
60
+ y,
61
+ circleRadius: circleRadius2,
62
+ labelLeft: x2 - labelWidth2 / 2,
63
+ labelTop: y + circleRadius2 + 20 * s,
64
+ labelWidth: labelWidth2,
65
+ labelFontSize: fitTextSize(label, 42 * s, labelWidth2, { minScale: 0.72 })
66
+ };
67
+ })
68
+ };
69
+ }
70
+ const contentTop = textAreaBottom;
71
+ const contentBottom = Math.max(contentTop + 1, height - safeZone.bottom);
72
+ const rowHeight = (contentBottom - contentTop) / stepCount;
73
+ const circleRadius = Math.min(82 * s, rowHeight * 0.27);
74
+ const x = safeZone.left + circleRadius + 48 * s;
75
+ const labelLeft = x + circleRadius + 42 * s;
76
+ const labelWidth = Math.max(1, width - safeZone.right - labelLeft);
77
+ return {
78
+ mode: "portrait-timeline",
79
+ items: labels.slice(0, 4).map((label, index) => {
80
+ const y = contentTop + rowHeight * (index + 0.5);
81
+ return {
82
+ x,
83
+ y,
84
+ circleRadius,
85
+ labelLeft,
86
+ labelTop: y - circleRadius,
87
+ labelWidth,
88
+ labelFontSize: fitTextSize(label, 50 * s, labelWidth, { minScale: 0.68 })
89
+ };
90
+ })
91
+ };
92
+ }
93
+ var StepsList = ({
94
+ progress,
95
+ width,
96
+ height,
97
+ steps,
98
+ stepEmojis = [],
99
+ accent = TOKEN_DEFAULTS.primary,
100
+ textColor = "#ffffff",
101
+ font = TOKEN_DEFAULTS.font,
102
+ beatIntensity = 0,
103
+ safeZone
104
+ }) => {
105
+ void beatIntensity;
106
+ const s = Math.min(width, height) / 1080;
107
+ const stepLabels = steps.slice(0, 4).map((st) => stripPipe(String(st.title || "")));
108
+ const hasEmojis = stepEmojis.some((e) => (e || "").length > 0);
109
+ const isLandscape = width > height;
110
+ const layout = computeStepsLayout({ width, height, labels: stepLabels, safeZone });
111
+ const connectorPairs = layout.items.slice(0, -1).map((item, index) => ({
112
+ item,
113
+ next: layout.items[index + 1]
114
+ }));
115
+ const lineProgress = interpolate(progress, [0.07, 0.62], [0, 1], {
116
+ extrapolateLeft: "clamp",
117
+ extrapolateRight: "clamp"
118
+ });
119
+ const firstStep = 0.08;
120
+ const EXIT_START = 0.78;
121
+ const EXIT_DURATION = 0.1;
122
+ const EXIT_STAGGER = 0.04;
123
+ const exitForIndex = (i) => {
124
+ const start = EXIT_START + i * EXIT_STAGGER;
125
+ const raw = interpolate(progress, [start, start + EXIT_DURATION], [0, 1], {
126
+ extrapolateLeft: "clamp",
127
+ extrapolateRight: "clamp"
128
+ });
129
+ const eased = raw * raw;
130
+ return { translateX: -90 * s * eased, fade: 1 - eased };
131
+ };
132
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
133
+ connectorPairs.map(({ item, next }, index) => {
134
+ const exit = exitForIndex(index);
135
+ const segmentProgress = interpolate(
136
+ lineProgress,
137
+ [index / connectorPairs.length, (index + 1) / connectorPairs.length],
138
+ [0, 1],
139
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
140
+ );
141
+ return /* @__PURE__ */ jsx(
142
+ "div",
143
+ {
144
+ style: layout.mode === "portrait-timeline" ? {
145
+ position: "absolute",
146
+ left: item.x - 2 * s,
147
+ top: item.y + item.circleRadius,
148
+ width: 4 * s,
149
+ height: Math.max(
150
+ 0,
151
+ next.y - next.circleRadius - (item.y + item.circleRadius)
152
+ ),
153
+ borderRadius: 999,
154
+ background: `linear-gradient(to bottom, ${withOpacity(accent, 0.9)}, ${withOpacity(textColor, 0.22)})`,
155
+ transform: `translateX(${exit.translateX}px) scaleY(${segmentProgress})`,
156
+ transformOrigin: "top",
157
+ opacity: 0.75 * exit.fade
158
+ } : {
159
+ position: "absolute",
160
+ left: item.x + item.circleRadius,
161
+ top: item.y - 2 * s,
162
+ width: Math.max(
163
+ 0,
164
+ next.x - next.circleRadius - (item.x + item.circleRadius)
165
+ ),
166
+ height: 4 * s,
167
+ borderRadius: 999,
168
+ background: `linear-gradient(to right, ${withOpacity(accent, 0.9)}, ${withOpacity(textColor, 0.22)})`,
169
+ transform: `translateX(${exit.translateX}px) scaleX(${segmentProgress})`,
170
+ transformOrigin: "left",
171
+ opacity: 0.75 * exit.fade
172
+ }
173
+ },
174
+ `step-connector-${index}`
175
+ );
176
+ }),
177
+ layout.items.map((pos, i) => {
178
+ const circleRadius = pos.circleRadius;
179
+ const circleSize = circleRadius * 2;
180
+ const emojiFontSize = circleRadius * (isLandscape ? 0.9 : 0.8);
181
+ const numberFontSize = circleRadius * 0.7;
182
+ const itemStart = firstStep;
183
+ const circleP = spring(
184
+ interpolate(progress, [itemStart, itemStart + 0.12], [0, 1], {
185
+ extrapolateLeft: "clamp",
186
+ extrapolateRight: "clamp"
187
+ }),
188
+ SPRING_POP
189
+ );
190
+ const circleScale = interpolate(circleP, [0, 1], [0, 1]);
191
+ const contentDelay = itemStart + 0.03;
192
+ const contentOpacity = interpolate(progress, [contentDelay, contentDelay + 0.05], [0, 1], {
193
+ extrapolateLeft: "clamp",
194
+ extrapolateRight: "clamp"
195
+ });
196
+ const titleDelay = itemStart + 0.05;
197
+ const titleP = spring(
198
+ interpolate(progress, [titleDelay, titleDelay + 0.1], [0, 1], {
199
+ extrapolateLeft: "clamp",
200
+ extrapolateRight: "clamp"
201
+ }),
202
+ SPRING_TITLE
203
+ );
204
+ const titleSlide = isLandscape ? (1 - titleP) * 40 * s : (1 - titleP) * 120 * s;
205
+ const titleOpacity = interpolate(progress, [titleDelay, titleDelay + 0.05], [0, 1], {
206
+ extrapolateLeft: "clamp",
207
+ extrapolateRight: "clamp"
208
+ });
209
+ const emoji = hasEmojis ? stepEmojis[i] || "" : "";
210
+ const glowOpacity = circleScale * 0.2;
211
+ const exit = exitForIndex(i);
212
+ return /* @__PURE__ */ jsxs(
213
+ "div",
214
+ {
215
+ "data-template-item": "steps",
216
+ style: {
217
+ position: "absolute",
218
+ top: pos.y - circleRadius,
219
+ left: 0,
220
+ width,
221
+ height: circleSize,
222
+ transform: `translateX(${exit.translateX}px)`,
223
+ opacity: exit.fade
224
+ },
225
+ children: [
226
+ /* @__PURE__ */ jsx(
227
+ "div",
228
+ {
229
+ style: {
230
+ position: "absolute",
231
+ top: -circleRadius * 0.6,
232
+ left: pos.x - circleRadius * 1.75,
233
+ width: circleRadius * 3.5,
234
+ height: circleRadius * 3.5,
235
+ borderRadius: "50%",
236
+ background: `radial-gradient(circle, ${withOpacity(accent, 0.4)} 0%, transparent 70%)`,
237
+ opacity: glowOpacity,
238
+ pointerEvents: "none"
239
+ }
240
+ }
241
+ ),
242
+ /* @__PURE__ */ jsx(
243
+ "div",
244
+ {
245
+ style: {
246
+ position: "absolute",
247
+ left: pos.x - circleRadius,
248
+ top: 0,
249
+ width: circleSize,
250
+ height: circleSize,
251
+ borderRadius: "50%",
252
+ backgroundColor: emoji ? "rgba(255,255,255,0.15)" : accent,
253
+ border: "2px solid rgba(255,255,255,0.2)",
254
+ display: "flex",
255
+ justifyContent: "center",
256
+ alignItems: "center",
257
+ transform: `scale(${circleScale})`,
258
+ boxShadow: `0 0 ${20 * s}px ${withOpacity(accent, glowOpacity)}`
259
+ },
260
+ children: emoji ? /* @__PURE__ */ jsx(Emoji, { char: emoji, size: emojiFontSize, verticalAlign: "middle", style: { opacity: contentOpacity } }) : /* @__PURE__ */ jsx(
261
+ "span",
262
+ {
263
+ style: {
264
+ fontSize: numberFontSize,
265
+ fontWeight: 800,
266
+ color: autoTextColor(accent),
267
+ fontFamily: font,
268
+ lineHeight: 1,
269
+ opacity: contentOpacity
270
+ },
271
+ children: i + 1
272
+ }
273
+ )
274
+ }
275
+ ),
276
+ /* @__PURE__ */ jsx(
277
+ "div",
278
+ {
279
+ style: {
280
+ position: "absolute",
281
+ left: pos.labelLeft,
282
+ top: pos.labelTop - (pos.y - circleRadius),
283
+ width: pos.labelWidth,
284
+ height: isLandscape ? 80 * s : circleSize,
285
+ display: "flex",
286
+ alignItems: isLandscape ? "flex-start" : "center",
287
+ justifyContent: isLandscape ? "center" : "flex-start",
288
+ fontSize: pos.labelFontSize,
289
+ fontWeight: 600,
290
+ color: textColor,
291
+ fontFamily: font,
292
+ letterSpacing: -0.3,
293
+ textAlign: isLandscape ? "center" : "left",
294
+ opacity: titleOpacity,
295
+ transform: isLandscape ? `translateY(${titleSlide}px)` : `translateX(${titleSlide}px)`,
296
+ textShadow: "0 1px 6px rgba(0,0,0,0.1)",
297
+ lineHeight: 1.12,
298
+ whiteSpace: "normal"
299
+ },
300
+ children: stepLabels[i]
301
+ }
302
+ )
303
+ ]
304
+ },
305
+ `step-${i}`
306
+ );
307
+ })
308
+ ] });
309
+ };
310
+
311
+ // src/visual-system/scene-templates/infographic-steps.tsx
312
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
313
+ var InfographicStepsTemplate = ({
314
+ variables,
315
+ style,
316
+ progress,
317
+ motionProgress = progress,
318
+ beatIntensity,
319
+ width,
320
+ height,
321
+ textArchetype,
322
+ safeZone,
323
+ sceneDuration,
324
+ backgroundEffect,
325
+ isPlaying
326
+ }) => {
327
+ const { primary, foreground, font } = resolveTokens(style);
328
+ const textColor = foreground;
329
+ const textsRaw = String(variables.texts || "");
330
+ const stepLabels = parseList(variables.steps, 3);
331
+ const stepEmojis = parseList(variables.stepEmojis, 3);
332
+ void textArchetype;
333
+ return /* @__PURE__ */ jsxs2(
334
+ "div",
335
+ {
336
+ style: {
337
+ width,
338
+ height,
339
+ backgroundColor: "#000",
340
+ position: "relative",
341
+ overflow: "hidden",
342
+ fontFamily: font
343
+ },
344
+ children: [
345
+ /* @__PURE__ */ jsx2(
346
+ SceneBackground,
347
+ {
348
+ style,
349
+ progress,
350
+ sceneDuration,
351
+ width,
352
+ height,
353
+ ...getMediaBackgroundProps(variables),
354
+ backgroundEffect,
355
+ seed: textsRaw,
356
+ isPlaying,
357
+ beatIntensity
358
+ }
359
+ ),
360
+ /* @__PURE__ */ jsx2(
361
+ TemplateText,
362
+ {
363
+ motionProgress,
364
+ typeTreatment: resolveTokens(style).preset.type,
365
+ archetype: "subtle",
366
+ text: String(variables.texts ?? ""),
367
+ progress,
368
+ sceneDuration: sceneDuration ?? 3,
369
+ width,
370
+ height,
371
+ position: "top",
372
+ sizeRole: "headline",
373
+ safeZone,
374
+ font,
375
+ color: textColor,
376
+ beatIntensity
377
+ }
378
+ ),
379
+ /* @__PURE__ */ jsx2(
380
+ StepsList,
381
+ {
382
+ progress: motionProgress,
383
+ width,
384
+ height,
385
+ steps: stepLabels.map((title) => ({ title })),
386
+ stepEmojis,
387
+ accent: primary,
388
+ textColor,
389
+ font,
390
+ beatIntensity,
391
+ safeZone
392
+ }
393
+ )
394
+ ]
395
+ }
396
+ );
397
+ };
398
+ export {
399
+ InfographicStepsTemplate
400
+ };