@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,266 @@
1
+ import {
2
+ parseList
3
+ } from "./chunk-P22HHFDK.js";
4
+ import {
5
+ stripPipe
6
+ } from "./chunk-S7HFLYNN.js";
7
+ import {
8
+ SceneBackground,
9
+ getMediaBackgroundProps
10
+ } from "./chunk-IFOW65Z6.js";
11
+ import {
12
+ TemplateText
13
+ } from "./chunk-BCRUUJ6A.js";
14
+ import {
15
+ Emoji
16
+ } from "./chunk-L5BTTCZV.js";
17
+ import "./chunk-ABZACD4G.js";
18
+ import {
19
+ interpolate,
20
+ spring
21
+ } from "./chunk-XTOXFMLM.js";
22
+ import {
23
+ TOKEN_DEFAULTS,
24
+ resolveTokens
25
+ } from "./chunk-FNAEQ7QO.js";
26
+
27
+ // src/visual-system/primitives/infographic/FeatureList.tsx
28
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
29
+ var SPRING_ROW = { damping: 14, stiffness: 170 };
30
+ var SPRING_EMOJI = { damping: 8, stiffness: 200 };
31
+ var FeatureList = ({
32
+ progress,
33
+ width,
34
+ height,
35
+ features,
36
+ textColor = "#ffffff",
37
+ font = TOKEN_DEFAULTS.font,
38
+ beatIntensity = 0
39
+ }) => {
40
+ void beatIntensity;
41
+ const s = Math.min(width, height) / 1080;
42
+ const itemLabels = features.slice(0, 3).map((f) => stripPipe(String(f.title || f.description || "")));
43
+ const itemEmojis = features.slice(0, 3).map((f) => String(f.icon || ""));
44
+ const itemCount = itemLabels.length;
45
+ if (itemCount === 0) return null;
46
+ const isLandscape = width > height;
47
+ const contentAreaTop = height * (isLandscape ? 0.28 : 0.25);
48
+ const contentAreaHeight = height * (isLandscape ? 0.65 : 0.7);
49
+ const sidePadding = 40 * s;
50
+ const gap = 20 * s;
51
+ const borderRadius = 20 * s;
52
+ let cardWidth;
53
+ let cardHeight;
54
+ let emojiFontSize;
55
+ let labelFontSize;
56
+ let listLeft;
57
+ if (isLandscape) {
58
+ const totalWidth = width * 0.9;
59
+ cardWidth = (totalWidth - gap * (itemCount - 1)) / itemCount;
60
+ cardHeight = Math.min(cardWidth, contentAreaHeight * 0.85);
61
+ emojiFontSize = Math.min(cardHeight * 0.35, 110 * s);
62
+ labelFontSize = Math.min(cardHeight * 0.16, 48 * s);
63
+ listLeft = (width - (cardWidth * itemCount + gap * (itemCount - 1))) / 2;
64
+ } else {
65
+ cardWidth = width - sidePadding * 2;
66
+ const maxRowHeight = 260 * s;
67
+ cardHeight = Math.min((contentAreaHeight - gap * (itemCount - 1)) / itemCount, maxRowHeight);
68
+ emojiFontSize = Math.min(cardHeight * 0.35, 64 * s);
69
+ labelFontSize = Math.min(cardHeight * 0.25, 44 * s);
70
+ listLeft = sidePadding;
71
+ }
72
+ const totalHeight = isLandscape ? cardHeight : cardHeight * itemCount + gap * (itemCount - 1);
73
+ const verticalAnchor = isLandscape ? 0.5 : 0.25;
74
+ const listTop = contentAreaTop + (contentAreaHeight - totalHeight) * verticalAnchor;
75
+ const cardBg = "rgba(255,255,255,0.15)";
76
+ const cardBorder = "rgba(255,255,255,0.2)";
77
+ const firstRow = 0.08;
78
+ return /* @__PURE__ */ jsx(Fragment, { children: itemLabels.map((label, i) => {
79
+ const x = isLandscape ? listLeft + i * (cardWidth + gap) : listLeft;
80
+ const y = isLandscape ? listTop : listTop + i * (cardHeight + gap);
81
+ const itemStart = firstRow;
82
+ const rowP = spring(
83
+ interpolate(progress, [itemStart, itemStart + 0.12], [0, 1], {
84
+ extrapolateLeft: "clamp",
85
+ extrapolateRight: "clamp"
86
+ }),
87
+ SPRING_ROW
88
+ );
89
+ const cardScale = isLandscape ? interpolate(rowP, [0, 1], [0.6, 1]) : 1;
90
+ const rowX = isLandscape ? 0 : (1 - rowP) * -120 * s;
91
+ const rowOpacity = interpolate(progress, [itemStart, itemStart + 0.05], [0, 1], {
92
+ extrapolateLeft: "clamp",
93
+ extrapolateRight: "clamp"
94
+ });
95
+ const emojiDelay = itemStart + 0.04;
96
+ const emojiP = spring(
97
+ interpolate(progress, [emojiDelay, emojiDelay + 0.08], [0, 1], {
98
+ extrapolateLeft: "clamp",
99
+ extrapolateRight: "clamp"
100
+ }),
101
+ SPRING_EMOJI
102
+ );
103
+ const emojiScale = interpolate(emojiP, [0, 1], [0, 1]);
104
+ const textDelay = itemStart + 0.06;
105
+ const textOpacity = interpolate(progress, [textDelay, textDelay + 0.05], [0, 1], {
106
+ extrapolateLeft: "clamp",
107
+ extrapolateRight: "clamp"
108
+ });
109
+ const EXIT_START = 0.78;
110
+ const EXIT_DURATION = 0.1;
111
+ const EXIT_STAGGER = 0.04;
112
+ const exitStart = EXIT_START + i * EXIT_STAGGER;
113
+ const exitEnd = exitStart + EXIT_DURATION;
114
+ const exitRaw = interpolate(progress, [exitStart, exitEnd], [0, 1], {
115
+ extrapolateLeft: "clamp",
116
+ extrapolateRight: "clamp"
117
+ });
118
+ const exitEased = exitRaw * exitRaw;
119
+ const exitTranslateX = -90 * s * exitEased;
120
+ const exitFade = 1 - exitEased;
121
+ const emoji = itemEmojis[i] || "\u2726";
122
+ const transform = isLandscape ? `translate(${exitTranslateX}px, 0) scale(${cardScale})` : `translateX(${rowX + exitTranslateX}px)`;
123
+ return /* @__PURE__ */ jsxs(
124
+ "div",
125
+ {
126
+ "data-template-item": "cardList",
127
+ style: {
128
+ position: "absolute",
129
+ left: x,
130
+ top: y,
131
+ width: cardWidth,
132
+ height: cardHeight,
133
+ borderRadius,
134
+ backgroundColor: cardBg,
135
+ border: `1.5px solid ${cardBorder}`,
136
+ display: "flex",
137
+ flexDirection: isLandscape ? "column" : "row",
138
+ alignItems: "center",
139
+ justifyContent: isLandscape ? "center" : void 0,
140
+ gap: isLandscape ? 32 * s : 0,
141
+ opacity: rowOpacity * exitFade,
142
+ transform,
143
+ transformOrigin: "center center"
144
+ },
145
+ children: [
146
+ /* @__PURE__ */ jsx(
147
+ "div",
148
+ {
149
+ style: {
150
+ width: isLandscape ? void 0 : Math.min(cardHeight * 0.7, 130 * s),
151
+ height: isLandscape ? void 0 : cardHeight,
152
+ display: "flex",
153
+ alignItems: "center",
154
+ justifyContent: "center",
155
+ flexShrink: 0
156
+ },
157
+ children: /* @__PURE__ */ jsx(
158
+ Emoji,
159
+ {
160
+ char: emoji,
161
+ size: emojiFontSize,
162
+ verticalAlign: "middle",
163
+ style: { transform: `scale(${emojiScale})`, display: "block" }
164
+ }
165
+ )
166
+ }
167
+ ),
168
+ /* @__PURE__ */ jsx(
169
+ "div",
170
+ {
171
+ style: {
172
+ flex: isLandscape ? void 0 : 1,
173
+ fontSize: labelFontSize,
174
+ fontWeight: 600,
175
+ color: textColor,
176
+ fontFamily: font,
177
+ lineHeight: 1.25,
178
+ letterSpacing: -0.3,
179
+ opacity: textOpacity,
180
+ textAlign: isLandscape ? "center" : void 0,
181
+ padding: isLandscape ? `0 ${16 * s}px` : `0 ${20 * s}px 0 0`,
182
+ textShadow: "0 1px 6px rgba(0,0,0,0.1)"
183
+ },
184
+ children: label
185
+ }
186
+ )
187
+ ]
188
+ },
189
+ i
190
+ );
191
+ }) });
192
+ };
193
+
194
+ // src/visual-system/scene-templates/infographic-feature-list.tsx
195
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
196
+ var InfographicFeatureListTemplate = ({
197
+ variables,
198
+ style,
199
+ progress,
200
+ motionProgress = progress,
201
+ beatIntensity,
202
+ width,
203
+ height,
204
+ safeZone,
205
+ sceneDuration,
206
+ backgroundEffect,
207
+ isPlaying = true
208
+ }) => {
209
+ const { foreground, font } = resolveTokens(style);
210
+ const textColor = foreground;
211
+ const text = String(variables.texts || "");
212
+ const labels = parseList(variables.items, 3);
213
+ const emojis = parseList(variables.itemEmojis);
214
+ const features = labels.map((title, index) => ({ title, icon: emojis[index] || "\u2726" }));
215
+ return /* @__PURE__ */ jsxs2("div", { style: { width, height, backgroundColor: "#000", position: "relative", overflow: "hidden", fontFamily: font }, children: [
216
+ /* @__PURE__ */ jsx2(
217
+ SceneBackground,
218
+ {
219
+ style,
220
+ progress,
221
+ sceneDuration,
222
+ width,
223
+ height,
224
+ ...getMediaBackgroundProps(variables),
225
+ backgroundEffect,
226
+ seed: text,
227
+ isPlaying,
228
+ beatIntensity
229
+ }
230
+ ),
231
+ /* @__PURE__ */ jsx2(
232
+ TemplateText,
233
+ {
234
+ motionProgress,
235
+ typeTreatment: resolveTokens(style).preset.type,
236
+ archetype: "subtle",
237
+ text,
238
+ progress,
239
+ sceneDuration: sceneDuration ?? 3,
240
+ width,
241
+ height,
242
+ position: "top",
243
+ sizeRole: "headline",
244
+ safeZone,
245
+ font,
246
+ color: textColor,
247
+ beatIntensity
248
+ }
249
+ ),
250
+ /* @__PURE__ */ jsx2(
251
+ FeatureList,
252
+ {
253
+ progress: motionProgress,
254
+ width,
255
+ height,
256
+ features,
257
+ textColor,
258
+ font,
259
+ beatIntensity
260
+ }
261
+ )
262
+ ] });
263
+ };
264
+ export {
265
+ InfographicFeatureListTemplate
266
+ };
@@ -0,0 +1,340 @@
1
+ import {
2
+ stripPipe
3
+ } from "./chunk-S7HFLYNN.js";
4
+ import {
5
+ SceneBackground,
6
+ getMediaBackgroundProps
7
+ } from "./chunk-IFOW65Z6.js";
8
+ import {
9
+ smoothSize
10
+ } from "./chunk-BCRUUJ6A.js";
11
+ import "./chunk-L5BTTCZV.js";
12
+ import "./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/infographic/ProblemSolution.tsx
23
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
24
+ var SPRING_TEXT = { damping: 10, stiffness: 150 };
25
+ var ProblemSolution = ({
26
+ progress,
27
+ width,
28
+ height,
29
+ problemText: rawProblemText,
30
+ solutionText: rawSolutionText,
31
+ problemLabel = "THE PROBLEM",
32
+ solutionLabel = "THE SOLUTION",
33
+ textColor = "#ffffff",
34
+ font = TOKEN_DEFAULTS.font,
35
+ beatIntensity = 0
36
+ }) => {
37
+ void beatIntensity;
38
+ const s = Math.min(width, height) / 1080;
39
+ const problemText = stripPipe(String(rawProblemText || ""));
40
+ const solutionText = stripPipe(String(rawSolutionText || ""));
41
+ const problemColor = "#ef4444";
42
+ const solutionColor = "#22c55e";
43
+ const isLandscape = width > height;
44
+ const pillTop = height * (isLandscape ? 0.3 : 0.38);
45
+ const textTop = height * (isLandscape ? 0.45 : 0.46);
46
+ const labelFontSize = 32 * s;
47
+ const longerChars = Math.max(problemText.length, solutionText.length, 1);
48
+ const mainSize = smoothSize(longerChars, 70, 88, 60) * s;
49
+ const CLAMP = { extrapolateLeft: "clamp", extrapolateRight: "clamp" };
50
+ const problemLabelOpacity = interpolate(progress, [0.03, 0.1], [0, 1], CLAMP);
51
+ const problemPillP = spring(interpolate(progress, [0.03, 0.15], [0, 1], CLAMP), { damping: 9, stiffness: 220 });
52
+ const problemPillScale = interpolate(problemPillP, [0, 1], [0.55, 1]);
53
+ const problemTextP = spring(interpolate(progress, [0.1, 0.25], [0, 1], CLAMP), SPRING_TEXT);
54
+ const problemTextScale = interpolate(problemTextP, [0, 1], [1.4, 1]);
55
+ const problemTextOpacity = interpolate(progress, [0.1, 0.2], [0, 1], CLAMP);
56
+ const tremorActive = progress > 0.2 && progress < 0.4;
57
+ const tremorX = tremorActive ? Math.sin(progress * 90) * 3 * s : 0;
58
+ const problemFadeOut = interpolate(progress, [0.4, 0.48], [1, 0], CLAMP);
59
+ const problemFallY = interpolate(progress, [0.4, 0.5], [0, height * 0.35], CLAMP);
60
+ const solutionOverall = interpolate(progress, [0.5, 0.55], [0, 1], CLAMP);
61
+ const SOLUTION_LAND = [0.55, 0.7];
62
+ const solutionLandP = spring(
63
+ interpolate(progress, [SOLUTION_LAND[0], SOLUTION_LAND[1]], [0, 1], CLAMP),
64
+ { damping: 9, stiffness: 220 }
65
+ );
66
+ const solutionLandScale = interpolate(solutionLandP, [0, 1], [0.7, 1]);
67
+ const solutionLandRiseY = interpolate(solutionLandP, [0, 1], [40 * s, 0]);
68
+ const solutionLandOpacity = interpolate(
69
+ progress,
70
+ [SOLUTION_LAND[0], SOLUTION_LAND[0] + 0.05],
71
+ [0, 1],
72
+ CLAMP
73
+ );
74
+ const solutionLabelOpacity = solutionLandOpacity;
75
+ const solutionPillScale = solutionLandScale;
76
+ const solutionTextOpacity = solutionLandOpacity;
77
+ const solutionTextScale = solutionLandScale;
78
+ const solutionTextRiseY = solutionLandRiseY;
79
+ const CONFETTI_COUNT = 14;
80
+ const CONFETTI_ANGLE_JITTER = [-12, 8, -5, 14, -7, 11, -16, 6, -9, 13, -4, 10, -11, 7];
81
+ const CONFETTI_DISTANCE = [60, 230, 100, 180, 130, 260, 80, 210, 50, 240, 150, 90, 220, 170];
82
+ const CONFETTI_ROTATION = [-180, 220, -140, 260, -200, 180, -240, 200, -160, 240, -200, 280, -180, 220];
83
+ const CONFETTI_COLORS = [
84
+ "#22c55e",
85
+ "#4ade80",
86
+ "#86efac",
87
+ "#bbf7d0",
88
+ "#dcfce7",
89
+ "#f0fdf4"
90
+ ];
91
+ const CONFETTI_TINT_INDEX = [0, 1, 2, 0, 3, 1, 4, 0, 2, 1, 5, 0, 3, 2];
92
+ const confettiRaw = interpolate(progress, [0.55, 0.7], [0, 1], CLAMP);
93
+ const confettiActive = confettiRaw > 0 && confettiRaw < 1;
94
+ const confettiDist = 1 - Math.pow(1 - confettiRaw, 2.5);
95
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
96
+ /* @__PURE__ */ jsxs(
97
+ "div",
98
+ {
99
+ style: {
100
+ position: "absolute",
101
+ inset: 0,
102
+ opacity: problemFadeOut,
103
+ transform: `translateY(${problemFallY}px)`
104
+ },
105
+ children: [
106
+ /* @__PURE__ */ jsx(
107
+ "div",
108
+ {
109
+ style: {
110
+ position: "absolute",
111
+ top: pillTop,
112
+ left: 0,
113
+ right: 0,
114
+ display: "flex",
115
+ justifyContent: "center"
116
+ },
117
+ children: /* @__PURE__ */ jsx(
118
+ "div",
119
+ {
120
+ style: {
121
+ fontSize: labelFontSize,
122
+ fontWeight: 700,
123
+ color: problemColor,
124
+ letterSpacing: 3 * s,
125
+ textTransform: "uppercase",
126
+ whiteSpace: "nowrap",
127
+ opacity: problemLabelOpacity,
128
+ transform: `scale(${problemPillScale})`,
129
+ transformOrigin: "center center",
130
+ fontFamily: font,
131
+ backgroundColor: "rgba(0,0,0,0.3)",
132
+ border: "1px solid rgba(255,255,255,0.15)",
133
+ borderRadius: 100 * s,
134
+ padding: `${14 * s}px ${36 * s}px`,
135
+ textShadow: "0 1px 6px rgba(0,0,0,0.1)"
136
+ },
137
+ children: problemLabel
138
+ }
139
+ )
140
+ }
141
+ ),
142
+ /* @__PURE__ */ jsx(
143
+ "div",
144
+ {
145
+ style: {
146
+ position: "absolute",
147
+ top: textTop,
148
+ left: 0,
149
+ right: 0,
150
+ fontSize: mainSize,
151
+ fontWeight: 800,
152
+ color: textColor,
153
+ textAlign: "center",
154
+ padding: `0 ${60 * s}px`,
155
+ lineHeight: 1.2,
156
+ letterSpacing: -1,
157
+ opacity: problemTextOpacity,
158
+ transform: `translateX(${tremorX}px) scale(${problemTextScale})`,
159
+ fontFamily: font,
160
+ textShadow: "0 2px 12px rgba(0,0,0,0.15)"
161
+ },
162
+ children: problemText
163
+ }
164
+ )
165
+ ]
166
+ }
167
+ ),
168
+ /* @__PURE__ */ jsxs(
169
+ "div",
170
+ {
171
+ style: {
172
+ position: "absolute",
173
+ inset: 0,
174
+ opacity: solutionOverall
175
+ },
176
+ children: [
177
+ confettiActive && Array.from({ length: CONFETTI_COUNT }, (_, i) => {
178
+ const baseAngle = 200 + i / (CONFETTI_COUNT - 1) * 140 + CONFETTI_ANGLE_JITTER[i];
179
+ const angleRad = baseAngle * Math.PI / 180;
180
+ const distance = confettiDist * CONFETTI_DISTANCE[i] * s;
181
+ const gravity = confettiRaw * confettiRaw * 35 * s;
182
+ const dx = Math.cos(angleRad) * distance;
183
+ const dy = Math.sin(angleRad) * distance + gravity;
184
+ const rot = confettiRaw * CONFETTI_ROTATION[i];
185
+ const op = interpolate(confettiRaw, [0, 0.08, 0.7, 1], [0, 1, 1, 0]);
186
+ const particleSize = 9 * s;
187
+ const originX = width / 2;
188
+ const originY = pillTop - 6 * s;
189
+ const tint = CONFETTI_COLORS[CONFETTI_TINT_INDEX[i]];
190
+ return /* @__PURE__ */ jsx(
191
+ "div",
192
+ {
193
+ style: {
194
+ position: "absolute",
195
+ left: originX - particleSize / 2,
196
+ top: originY - particleSize / 2 * 1.6,
197
+ width: particleSize,
198
+ height: particleSize * 1.6,
199
+ backgroundColor: tint,
200
+ borderRadius: 1 * s,
201
+ transform: `translate(${dx}px, ${dy}px) rotate(${rot}deg)`,
202
+ opacity: op,
203
+ pointerEvents: "none",
204
+ boxShadow: `0 0 ${4 * s}px ${tint}66`
205
+ }
206
+ },
207
+ `confetti-${i}`
208
+ );
209
+ }),
210
+ /* @__PURE__ */ jsx(
211
+ "div",
212
+ {
213
+ style: {
214
+ position: "absolute",
215
+ top: pillTop,
216
+ left: 0,
217
+ right: 0,
218
+ display: "flex",
219
+ justifyContent: "center"
220
+ },
221
+ children: /* @__PURE__ */ jsx(
222
+ "div",
223
+ {
224
+ style: {
225
+ fontSize: labelFontSize,
226
+ fontWeight: 700,
227
+ color: solutionColor,
228
+ letterSpacing: 3 * s,
229
+ textTransform: "uppercase",
230
+ whiteSpace: "nowrap",
231
+ opacity: solutionLabelOpacity,
232
+ transform: `scale(${solutionPillScale})`,
233
+ transformOrigin: "center center",
234
+ fontFamily: font,
235
+ backgroundColor: "rgba(0,0,0,0.3)",
236
+ border: "1px solid rgba(255,255,255,0.15)",
237
+ borderRadius: 100 * s,
238
+ padding: `${14 * s}px ${36 * s}px`,
239
+ textShadow: "0 1px 6px rgba(0,0,0,0.1)"
240
+ },
241
+ children: solutionLabel
242
+ }
243
+ )
244
+ }
245
+ ),
246
+ /* @__PURE__ */ jsx(
247
+ "div",
248
+ {
249
+ style: {
250
+ position: "absolute",
251
+ top: textTop,
252
+ left: 0,
253
+ right: 0,
254
+ fontSize: mainSize,
255
+ fontWeight: 800,
256
+ color: textColor,
257
+ textAlign: "center",
258
+ padding: `0 ${60 * s}px`,
259
+ lineHeight: 1.2,
260
+ letterSpacing: -1,
261
+ opacity: solutionTextOpacity,
262
+ transform: `translateY(${solutionTextRiseY}px) scale(${solutionTextScale})`,
263
+ fontFamily: font,
264
+ textShadow: "0 2px 12px rgba(0,0,0,0.15)"
265
+ },
266
+ children: solutionText
267
+ }
268
+ )
269
+ ]
270
+ }
271
+ )
272
+ ] });
273
+ };
274
+
275
+ // src/visual-system/scene-templates/infographic-problem-solution.tsx
276
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
277
+ var InfographicProblemSolutionTemplate = ({
278
+ variables,
279
+ style,
280
+ progress,
281
+ beatIntensity,
282
+ width,
283
+ height,
284
+ sceneDuration,
285
+ backgroundEffect,
286
+ isPlaying = true
287
+ }) => {
288
+ const { foreground, font } = resolveTokens(style);
289
+ const textColor = foreground;
290
+ const problemText = String(variables.problemText || "");
291
+ const solutionText = String(variables.solutionText || "");
292
+ return /* @__PURE__ */ jsxs2(
293
+ "div",
294
+ {
295
+ style: {
296
+ width,
297
+ height,
298
+ backgroundColor: "#000",
299
+ position: "relative",
300
+ overflow: "hidden",
301
+ fontFamily: font
302
+ },
303
+ children: [
304
+ /* @__PURE__ */ jsx2(
305
+ SceneBackground,
306
+ {
307
+ style,
308
+ progress,
309
+ sceneDuration,
310
+ width,
311
+ height,
312
+ ...getMediaBackgroundProps(variables),
313
+ backgroundEffect,
314
+ seed: `${problemText}${solutionText}`,
315
+ isPlaying,
316
+ beatIntensity
317
+ }
318
+ ),
319
+ /* @__PURE__ */ jsx2(
320
+ ProblemSolution,
321
+ {
322
+ progress,
323
+ width,
324
+ height,
325
+ problemLabel: String(variables.problemLabel || "THE PROBLEM"),
326
+ problemText,
327
+ solutionLabel: String(variables.solutionLabel || "THE SOLUTION"),
328
+ solutionText,
329
+ textColor,
330
+ font,
331
+ beatIntensity
332
+ }
333
+ )
334
+ ]
335
+ }
336
+ );
337
+ };
338
+ export {
339
+ InfographicProblemSolutionTemplate
340
+ };