@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,351 @@
1
+ import {
2
+ fitTextSize,
3
+ stripPipe
4
+ } from "./chunk-S7HFLYNN.js";
5
+ import {
6
+ SceneBackground,
7
+ getMediaBackgroundProps
8
+ } from "./chunk-IFOW65Z6.js";
9
+ import {
10
+ TemplateText
11
+ } from "./chunk-BCRUUJ6A.js";
12
+ import "./chunk-L5BTTCZV.js";
13
+ import "./chunk-ABZACD4G.js";
14
+ import {
15
+ interpolate,
16
+ spring
17
+ } from "./chunk-XTOXFMLM.js";
18
+ import {
19
+ resolveTokens
20
+ } from "./chunk-FNAEQ7QO.js";
21
+
22
+ // src/visual-system/primitives/devices/CodeEditor.tsx
23
+ import { jsx, jsxs } from "react/jsx-runtime";
24
+ var SPRING_EDITOR = { damping: 20, stiffness: 100 };
25
+ var CLAMP = { extrapolateLeft: "clamp", extrapolateRight: "clamp" };
26
+ var MONO_CHAR_RATIO = 0.63;
27
+ var MONO_MIN_SCALE = 0.68;
28
+ var MONO_FONT = "'Fira Code', 'SF Mono', 'Cascadia Code', Menlo, monospace";
29
+ var CHROME_FONT = "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
30
+ var KEYWORDS = /* @__PURE__ */ new Set([
31
+ "const",
32
+ "let",
33
+ "var",
34
+ "function",
35
+ "return",
36
+ "import",
37
+ "export",
38
+ "from",
39
+ "async",
40
+ "await",
41
+ "if",
42
+ "else",
43
+ "for",
44
+ "while",
45
+ "class",
46
+ "new",
47
+ "this",
48
+ "true",
49
+ "false",
50
+ "null",
51
+ "undefined",
52
+ "def",
53
+ "self",
54
+ "print",
55
+ "in",
56
+ "not",
57
+ "and",
58
+ "or",
59
+ "try",
60
+ "catch",
61
+ "throw"
62
+ ]);
63
+ function tokenizeLine(line, keywordColor, stringColor, commentColor, numberColor, defaultColor) {
64
+ const tokens = [];
65
+ const commentMatch = line.match(/^(.*?)(\/\/.*|#.*)$/);
66
+ if (commentMatch) {
67
+ tokens.push(...tokenizeCode(commentMatch[1], keywordColor, stringColor, numberColor, defaultColor));
68
+ tokens.push({ text: commentMatch[2], color: commentColor });
69
+ return tokens;
70
+ }
71
+ return tokenizeCode(line, keywordColor, stringColor, numberColor, defaultColor);
72
+ }
73
+ function tokenizeCode(code, keywordColor, stringColor, numberColor, defaultColor) {
74
+ const tokens = [];
75
+ const regex = /("[^"]*"|'[^']*'|`[^`]*`|\b\d+\.?\d*\b|\b\w+\b|[^\s]|\s+)/g;
76
+ let match;
77
+ while ((match = regex.exec(code)) !== null) {
78
+ const t = match[0];
79
+ if (t.startsWith('"') || t.startsWith("'") || t.startsWith("`")) {
80
+ tokens.push({ text: t, color: stringColor });
81
+ } else if (/^\d+\.?\d*$/.test(t)) {
82
+ tokens.push({ text: t, color: numberColor });
83
+ } else if (KEYWORDS.has(t)) {
84
+ tokens.push({ text: t, color: keywordColor });
85
+ } else {
86
+ tokens.push({ text: t, color: defaultColor });
87
+ }
88
+ }
89
+ return tokens;
90
+ }
91
+ var CodeEditor = ({
92
+ progress,
93
+ code,
94
+ filename = "app.ts",
95
+ width,
96
+ height,
97
+ beatIntensity = 0
98
+ }) => {
99
+ const s = Math.min(width, height) / 1080;
100
+ const codeRaw = String(code || "").replace(/\\n/g, "\n");
101
+ const filenameClean = stripPipe(String(filename || "app.ts"));
102
+ const codeLines = codeRaw.split("\n");
103
+ const editorWidth = Math.min(width * 0.88, height * 0.55 * (16 / 9));
104
+ const chromeHeight = 44 * s;
105
+ const contentHeight = editorWidth * (9 / 16);
106
+ const editorHeight = chromeHeight + contentHeight;
107
+ const borderRadius = 12 * s;
108
+ const editorBg = "#1e1e2e";
109
+ const chromeBg = "#313244";
110
+ const codeDefault = "#cdd6f4";
111
+ const keywordColor = "#cba6f7";
112
+ const stringColor = "#a6e3a1";
113
+ const commentColor = "#6c7086";
114
+ const numberColor = "#fab387";
115
+ const lineNumColor = "#45475a";
116
+ const lineNumWidth = 40 * s;
117
+ const codeAvailWidth = editorWidth - lineNumWidth - 16 * s;
118
+ const baseFontSize = Math.max(16, 22 * s);
119
+ const longestLineChars = codeLines.reduce((m, l) => Math.max(m, l.length), 1);
120
+ const fontSize = fitTextSize("M".repeat(longestLineChars), baseFontSize, codeAvailWidth, {
121
+ minScale: MONO_MIN_SCALE,
122
+ charWidthRatio: MONO_CHAR_RATIO
123
+ });
124
+ const atFloor = fontSize <= baseFontSize * MONO_MIN_SCALE + 0.01;
125
+ const maxLineChars = atFloor ? Math.max(4, Math.floor(codeAvailWidth / (fontSize * MONO_CHAR_RATIO))) : Infinity;
126
+ const displayLines = codeLines.map(
127
+ (l) => l.length > maxLineChars ? `${l.slice(0, maxLineChars - 1).trimEnd()}\u2026` : l
128
+ );
129
+ const lineHeight = fontSize * 1.7;
130
+ const slideProgress = interpolate(progress, [0.02, 0.15], [0, 1], CLAMP);
131
+ const springVal = spring(slideProgress, SPRING_EDITOR);
132
+ const editorY = (1 - springVal) * 200 * s;
133
+ const editorOpacity = interpolate(slideProgress, [0, 0.08], [0, 1], CLAMP);
134
+ const lineStaggerStart = 0.15;
135
+ const lineStaggerEnd = 0.8;
136
+ const lineSlice = codeLines.length > 0 ? (lineStaggerEnd - lineStaggerStart) / codeLines.length : 0;
137
+ const beatScale = 1 + beatIntensity * 0.01;
138
+ const dotSize = 12 * s;
139
+ const dotGap = 8 * s;
140
+ return /* @__PURE__ */ jsx(
141
+ "div",
142
+ {
143
+ style: {
144
+ position: "absolute",
145
+ top: height * 0.35,
146
+ left: (width - editorWidth) / 2,
147
+ width: editorWidth,
148
+ height: editorHeight,
149
+ transform: `translateY(${editorY}px) scale(${beatScale})`,
150
+ opacity: editorOpacity
151
+ },
152
+ children: /* @__PURE__ */ jsxs(
153
+ "div",
154
+ {
155
+ style: {
156
+ width: editorWidth,
157
+ height: editorHeight,
158
+ borderRadius,
159
+ overflow: "hidden",
160
+ position: "relative",
161
+ boxShadow: `0 ${20 * s}px ${60 * s}px rgba(0,0,0,0.35)`
162
+ },
163
+ children: [
164
+ /* @__PURE__ */ jsxs(
165
+ "div",
166
+ {
167
+ style: {
168
+ width: "100%",
169
+ height: chromeHeight,
170
+ backgroundColor: chromeBg,
171
+ display: "flex",
172
+ alignItems: "center",
173
+ paddingLeft: 16 * s,
174
+ paddingRight: 16 * s
175
+ },
176
+ children: [
177
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: dotGap, flexShrink: 0 }, children: [
178
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#ff5f57" } }),
179
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#febc2e" } }),
180
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#28c840" } })
181
+ ] }),
182
+ /* @__PURE__ */ jsx(
183
+ "div",
184
+ {
185
+ style: {
186
+ flex: 1,
187
+ textAlign: "center",
188
+ fontSize: 13 * s,
189
+ fontFamily: CHROME_FONT,
190
+ color: "#a6adc8",
191
+ whiteSpace: "nowrap"
192
+ },
193
+ children: filenameClean
194
+ }
195
+ ),
196
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize * 3 + dotGap * 2, flexShrink: 0 } })
197
+ ]
198
+ }
199
+ ),
200
+ /* @__PURE__ */ jsx(
201
+ "div",
202
+ {
203
+ style: {
204
+ width: "100%",
205
+ height: contentHeight,
206
+ backgroundColor: editorBg,
207
+ padding: `${16 * s}px 0`,
208
+ overflow: "hidden"
209
+ },
210
+ children: displayLines.map((line, i) => {
211
+ const lineStart = lineStaggerStart + i * lineSlice;
212
+ const lineOpacity = interpolate(progress, [lineStart, lineStart + 0.04], [0, 1], CLAMP);
213
+ const lineSlideX = interpolate(progress, [lineStart, lineStart + 0.06], [12 * s, 0], CLAMP);
214
+ const tokens = line.trim() === "" ? [{ text: " ", color: codeDefault }] : tokenizeLine(line, keywordColor, stringColor, commentColor, numberColor, codeDefault);
215
+ return /* @__PURE__ */ jsxs(
216
+ "div",
217
+ {
218
+ style: {
219
+ display: "flex",
220
+ alignItems: "baseline",
221
+ height: lineHeight,
222
+ opacity: lineOpacity,
223
+ transform: `translateX(${lineSlideX}px)`
224
+ },
225
+ children: [
226
+ /* @__PURE__ */ jsx(
227
+ "div",
228
+ {
229
+ style: {
230
+ width: lineNumWidth,
231
+ textAlign: "right",
232
+ paddingRight: 12 * s,
233
+ fontSize,
234
+ fontFamily: MONO_FONT,
235
+ color: lineNumColor,
236
+ lineHeight: `${lineHeight}px`,
237
+ flexShrink: 0,
238
+ userSelect: "none"
239
+ },
240
+ children: i + 1
241
+ }
242
+ ),
243
+ /* @__PURE__ */ jsx(
244
+ "div",
245
+ {
246
+ style: {
247
+ fontSize,
248
+ fontFamily: MONO_FONT,
249
+ lineHeight: `${lineHeight}px`,
250
+ whiteSpace: "pre"
251
+ },
252
+ children: tokens.map((token, j) => /* @__PURE__ */ jsx("span", { style: { color: token.color }, children: token.text }, j))
253
+ }
254
+ )
255
+ ]
256
+ },
257
+ i
258
+ );
259
+ })
260
+ }
261
+ )
262
+ ]
263
+ }
264
+ )
265
+ }
266
+ );
267
+ };
268
+
269
+ // src/visual-system/scene-templates/showcase-code.tsx
270
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
271
+ var ShowcaseCodeTemplate = ({
272
+ variables,
273
+ style,
274
+ progress,
275
+ motionProgress = progress,
276
+ beatIntensity,
277
+ width,
278
+ height,
279
+ safeZone,
280
+ sceneDuration,
281
+ backgroundEffect,
282
+ isPlaying = true
283
+ }) => {
284
+ const { primary, foreground, font } = resolveTokens(style);
285
+ const textColor = foreground;
286
+ const textsRaw = String(variables.texts || "");
287
+ return /* @__PURE__ */ jsxs2(
288
+ "div",
289
+ {
290
+ style: {
291
+ width,
292
+ height,
293
+ backgroundColor: "#000",
294
+ position: "relative",
295
+ overflow: "hidden",
296
+ fontFamily: font
297
+ },
298
+ children: [
299
+ /* @__PURE__ */ jsx2(
300
+ SceneBackground,
301
+ {
302
+ style,
303
+ progress,
304
+ sceneDuration,
305
+ width,
306
+ height,
307
+ ...getMediaBackgroundProps(variables),
308
+ backgroundEffect,
309
+ seed: textsRaw,
310
+ isPlaying,
311
+ beatIntensity
312
+ }
313
+ ),
314
+ /* @__PURE__ */ jsx2(
315
+ TemplateText,
316
+ {
317
+ motionProgress,
318
+ typeTreatment: resolveTokens(style).preset.type,
319
+ archetype: "subtle",
320
+ text: String(variables.texts ?? ""),
321
+ progress,
322
+ sceneDuration: sceneDuration ?? 3,
323
+ width,
324
+ height,
325
+ position: "top",
326
+ sizeRole: "headline",
327
+ safeZone,
328
+ font,
329
+ color: textColor,
330
+ beatIntensity
331
+ }
332
+ ),
333
+ /* @__PURE__ */ jsx2(
334
+ CodeEditor,
335
+ {
336
+ progress,
337
+ code: String(variables.code || ""),
338
+ filename: String(variables.filename || "app.ts"),
339
+ width,
340
+ height,
341
+ accent: primary,
342
+ beatIntensity
343
+ }
344
+ )
345
+ ]
346
+ }
347
+ );
348
+ };
349
+ export {
350
+ ShowcaseCodeTemplate
351
+ };
@@ -0,0 +1,272 @@
1
+ import {
2
+ PhoneScreenFill,
3
+ ProductSurface,
4
+ resolveProductSurfaceMotion
5
+ } from "./chunk-FSG2PYWG.js";
6
+ import "./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 "./chunk-L5BTTCZV.js";
15
+ import "./chunk-ABZACD4G.js";
16
+ import {
17
+ SPRING_SMOOTH,
18
+ interpolate,
19
+ spring
20
+ } from "./chunk-XTOXFMLM.js";
21
+ import {
22
+ TOKEN_DEFAULTS,
23
+ resolveTokens
24
+ } from "./chunk-FNAEQ7QO.js";
25
+
26
+ // src/visual-system/primitives/devices/PhoneFrame.tsx
27
+ import { jsx, jsxs } from "react/jsx-runtime";
28
+ var PhoneFrame = ({
29
+ progress,
30
+ motionProgress = progress,
31
+ screenMediaUrl = "",
32
+ screens = [],
33
+ width,
34
+ height,
35
+ font = TOKEN_DEFAULTS.font,
36
+ beatIntensity = 0,
37
+ accent = TOKEN_DEFAULTS.primary,
38
+ secondary = "#00b5e5",
39
+ bg,
40
+ screenFit = "cover",
41
+ screenFocusX = 50,
42
+ screenFocusY = 50,
43
+ screenMotion = "pushIn",
44
+ screenCalloutText = "",
45
+ screenCalloutX = 70,
46
+ screenCalloutY = 35
47
+ }) => {
48
+ const s = Math.min(width, height) / 1080;
49
+ const slidesMode = screens.length > 0;
50
+ const maxPhoneH = height * 0.6;
51
+ const phoneWidth = width > height ? Math.min(width * 0.55, maxPhoneH / 2) : Math.min(width * 0.55, height * 0.35);
52
+ const phoneHeight = phoneWidth * 2;
53
+ const borderRadius = 40 * s;
54
+ const borderWidth = 6 * s;
55
+ const enterRange = slidesMode ? [0.02, 0.35] : [0.02, 0.85];
56
+ const enterP = spring(
57
+ interpolate(motionProgress, enterRange, [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }),
58
+ { damping: 26, stiffness: 80 }
59
+ );
60
+ const phoneRotateX = (1 - enterP) * 60;
61
+ const phoneY = (1 - enterP) * 180 * s;
62
+ const phoneScale = interpolate(enterP, [0, 1], [0.85, 1]);
63
+ const phoneOpacity = interpolate(motionProgress, [0.02, 0.12], [0, 1], {
64
+ extrapolateLeft: "clamp",
65
+ extrapolateRight: "clamp"
66
+ });
67
+ const slide1to2 = slidesMode && screens.length >= 2 ? spring(interpolate(progress, [0.28, 0.48], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }), SPRING_SMOOTH) : 0;
68
+ const slide2to3 = slidesMode && screens.length >= 3 ? spring(interpolate(progress, [0.58, 0.78], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }), SPRING_SMOOTH) : 0;
69
+ const slideOffset = -(slide1to2 + slide2to3) * phoneWidth;
70
+ const beatScale = 1 + beatIntensity * (slidesMode ? 0.01 : 0.015);
71
+ const renderScreen = (url, key, withCallout = false) => /* @__PURE__ */ jsx("div", { style: { position: "relative", width: phoneWidth, height: phoneHeight, flexShrink: 0 }, children: /* @__PURE__ */ jsx(
72
+ ProductSurface,
73
+ {
74
+ mediaUrl: url,
75
+ progress,
76
+ width: phoneWidth,
77
+ height: phoneHeight,
78
+ fit: screenFit,
79
+ focusX: screenFocusX,
80
+ focusY: screenFocusY,
81
+ motion: withCallout ? screenMotion : "still",
82
+ calloutText: withCallout ? screenCalloutText : "",
83
+ calloutX: screenCalloutX,
84
+ calloutY: screenCalloutY,
85
+ accent,
86
+ font,
87
+ placeholder: /* @__PURE__ */ jsx(
88
+ PhoneScreenFill,
89
+ {
90
+ accent,
91
+ secondary,
92
+ bg,
93
+ font,
94
+ s,
95
+ w: phoneWidth,
96
+ h: phoneHeight,
97
+ progress
98
+ }
99
+ )
100
+ }
101
+ ) }, key);
102
+ return /* @__PURE__ */ jsx(
103
+ "div",
104
+ {
105
+ style: {
106
+ position: "absolute",
107
+ top: height * 0.32,
108
+ left: (width - phoneWidth) / 2,
109
+ width: phoneWidth,
110
+ height: phoneHeight,
111
+ perspective: `${1600 * s}px`,
112
+ transformStyle: "preserve-3d"
113
+ },
114
+ children: /* @__PURE__ */ jsx(
115
+ "div",
116
+ {
117
+ style: {
118
+ width: phoneWidth,
119
+ height: phoneHeight,
120
+ transform: `translateY(${phoneY}px) rotateX(${phoneRotateX}deg) scale(${phoneScale * beatScale})`,
121
+ transformOrigin: "center bottom",
122
+ opacity: phoneOpacity
123
+ },
124
+ children: /* @__PURE__ */ jsxs(
125
+ "div",
126
+ {
127
+ style: {
128
+ width: phoneWidth,
129
+ height: phoneHeight,
130
+ borderRadius,
131
+ overflow: "hidden",
132
+ position: "relative",
133
+ boxShadow: `0 ${20 * s}px ${60 * s}px rgba(0,0,0,0.35)`
134
+ },
135
+ children: [
136
+ slidesMode ? /* @__PURE__ */ jsx(
137
+ "div",
138
+ {
139
+ "data-phone-screen-progress": Number((slide1to2 + slide2to3).toFixed(6)),
140
+ style: {
141
+ display: "flex",
142
+ width: phoneWidth * screens.length,
143
+ height: phoneHeight,
144
+ transform: `translateX(${slideOffset}px)`
145
+ },
146
+ children: screens.map((url, i) => renderScreen(url, i))
147
+ }
148
+ ) : renderScreen(screenMediaUrl, void 0, true),
149
+ /* @__PURE__ */ jsx(
150
+ "div",
151
+ {
152
+ style: {
153
+ position: "absolute",
154
+ inset: 0,
155
+ borderRadius,
156
+ border: `${borderWidth * 1.5}px solid rgba(220,220,220,0.6)`,
157
+ boxShadow: `inset 0 0 0 ${1 * s}px rgba(255,255,255,0.1)`,
158
+ pointerEvents: "none",
159
+ zIndex: 2
160
+ }
161
+ }
162
+ )
163
+ ]
164
+ }
165
+ )
166
+ }
167
+ )
168
+ }
169
+ );
170
+ };
171
+
172
+ // src/visual-system/scene-templates/showcase-phone.tsx
173
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
174
+ var ShowcasePhoneTemplate = ({
175
+ variables,
176
+ style,
177
+ progress,
178
+ motionProgress = progress,
179
+ beatIntensity,
180
+ width,
181
+ height,
182
+ textArchetype,
183
+ safeZone,
184
+ sceneDuration,
185
+ backgroundEffect,
186
+ isPlaying
187
+ }) => {
188
+ const tokens = resolveTokens(style);
189
+ const { primary, secondary, foreground, font, background } = tokens;
190
+ const textColor = foreground;
191
+ const screenMediaUrl = String(variables.screenMediaUrl || "");
192
+ const extraScreens = [
193
+ String(variables.screen1Url || ""),
194
+ String(variables.screen2Url || "")
195
+ ].filter(Boolean);
196
+ const screens = extraScreens.length > 0 && screenMediaUrl ? [screenMediaUrl, ...extraScreens] : extraScreens;
197
+ return /* @__PURE__ */ jsxs2(
198
+ "div",
199
+ {
200
+ style: {
201
+ width,
202
+ height,
203
+ backgroundColor: "#000",
204
+ position: "relative",
205
+ overflow: "hidden",
206
+ fontFamily: font
207
+ },
208
+ children: [
209
+ /* @__PURE__ */ jsx2(
210
+ SceneBackground,
211
+ {
212
+ style,
213
+ progress,
214
+ sceneDuration,
215
+ width,
216
+ height,
217
+ ...getMediaBackgroundProps(variables),
218
+ backgroundEffect,
219
+ seed: String(variables.texts || ""),
220
+ isPlaying,
221
+ beatIntensity
222
+ }
223
+ ),
224
+ /* @__PURE__ */ jsx2(
225
+ TemplateText,
226
+ {
227
+ motionProgress,
228
+ typeTreatment: tokens.preset.type,
229
+ archetype: textArchetype ?? "subtle",
230
+ text: String(variables.texts ?? ""),
231
+ progress,
232
+ sceneDuration: sceneDuration ?? 3,
233
+ width,
234
+ height,
235
+ position: "top",
236
+ sizeRole: "headline",
237
+ safeZone,
238
+ font,
239
+ color: textColor,
240
+ beatIntensity
241
+ }
242
+ ),
243
+ /* @__PURE__ */ jsx2(
244
+ PhoneFrame,
245
+ {
246
+ progress,
247
+ motionProgress,
248
+ screenMediaUrl,
249
+ screens,
250
+ width,
251
+ height,
252
+ font,
253
+ beatIntensity,
254
+ accent: primary,
255
+ secondary,
256
+ bg: background.type === "solid" ? background.color : void 0,
257
+ screenFit: variables.screenFit === "contain" ? "contain" : "cover",
258
+ screenFocusX: Number(variables.screenFocusX ?? 50),
259
+ screenFocusY: Number(variables.screenFocusY ?? 50),
260
+ screenMotion: resolveProductSurfaceMotion(variables.screenMotion),
261
+ screenCalloutText: String(variables.screenCalloutText || ""),
262
+ screenCalloutX: Number(variables.screenCalloutX ?? 70),
263
+ screenCalloutY: Number(variables.screenCalloutY ?? 35)
264
+ }
265
+ )
266
+ ]
267
+ }
268
+ );
269
+ };
270
+ export {
271
+ ShowcasePhoneTemplate
272
+ };