@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,306 @@
1
+ import {
2
+ parseList
3
+ } from "./chunk-P22HHFDK.js";
4
+ import {
5
+ fitTextSize
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 "./chunk-L5BTTCZV.js";
15
+ import "./chunk-ABZACD4G.js";
16
+ import {
17
+ interpolate,
18
+ spring
19
+ } from "./chunk-XTOXFMLM.js";
20
+ import {
21
+ TOKEN_DEFAULTS,
22
+ resolveTokens
23
+ } from "./chunk-FNAEQ7QO.js";
24
+
25
+ // src/visual-system/primitives/devices/TerminalOutput.tsx
26
+ import { jsx, jsxs } from "react/jsx-runtime";
27
+ var SPRING_TERMINAL = { damping: 20, stiffness: 100 };
28
+ var CLAMP = { extrapolateLeft: "clamp", extrapolateRight: "clamp" };
29
+ var MONO_CHAR_RATIO = 0.63;
30
+ var MONO_MIN_SCALE = 0.68;
31
+ var MONO_FONT = "'Fira Code', 'SF Mono', 'Cascadia Code', Menlo, monospace";
32
+ var CHROME_FONT = "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
33
+ var TerminalOutput = ({
34
+ progress,
35
+ command,
36
+ outputLines,
37
+ promptPrefix = "$",
38
+ width,
39
+ height,
40
+ accent = TOKEN_DEFAULTS.primary,
41
+ beatIntensity = 0
42
+ }) => {
43
+ const s = Math.min(width, height) / 1080;
44
+ const termWidth = Math.min(width * 0.85, height * 0.55 * (16 / 9));
45
+ const chromeHeight = 44 * s;
46
+ const contentHeight = termWidth * (9 / 16);
47
+ const termHeight = chromeHeight + contentHeight;
48
+ const borderRadius = 12 * s;
49
+ const termBg = "#1e1e2e";
50
+ const termText = "#cdd6f4";
51
+ const promptColor = accent;
52
+ const contentAvailWidth = termWidth - 48 * s;
53
+ const baseFontSize = Math.max(18, 26 * s);
54
+ const promptChars = promptPrefix.length + 1;
55
+ const commandLineChars = promptChars + command.length + 1;
56
+ const longestLineChars = outputLines.reduce(
57
+ (m, l) => Math.max(m, l.length),
58
+ Math.max(commandLineChars, 1)
59
+ );
60
+ const fontSize = fitTextSize("M".repeat(longestLineChars), baseFontSize, contentAvailWidth, {
61
+ minScale: MONO_MIN_SCALE,
62
+ charWidthRatio: MONO_CHAR_RATIO
63
+ });
64
+ const atFloor = fontSize <= baseFontSize * MONO_MIN_SCALE + 0.01;
65
+ const maxLineChars = atFloor ? Math.max(4, Math.floor(contentAvailWidth / (fontSize * MONO_CHAR_RATIO))) : Infinity;
66
+ const ellipsize = (l) => l.length > maxLineChars ? `${l.slice(0, maxLineChars - 1).trimEnd()}\u2026` : l;
67
+ const displayCommand = commandLineChars > maxLineChars ? `${command.slice(0, Math.max(1, maxLineChars - promptChars - 2)).trimEnd()}\u2026` : command;
68
+ const displayOutputLines = outputLines.map(ellipsize);
69
+ const lineHeight = fontSize * 1.7;
70
+ const slideProgress = interpolate(progress, [0.02, 0.15], [0, 1], CLAMP);
71
+ const springVal = spring(slideProgress, SPRING_TERMINAL);
72
+ const termY = (1 - springVal) * 200 * s;
73
+ const termOpacity = interpolate(slideProgress, [0, 0.08], [0, 1], CLAMP);
74
+ const typeProgress = interpolate(progress, [0.1, 0.48], [0, 1], CLAMP);
75
+ const charsVisible = Math.floor(typeProgress * displayCommand.length);
76
+ const typedText = displayCommand.slice(0, charsVisible);
77
+ const isTyping = typeProgress > 0 && typeProgress < 1;
78
+ const cursorCycle = Math.floor(progress * 25);
79
+ const cursorVisible = isTyping || cursorCycle % 2 === 0;
80
+ const outputStartP = 0.55;
81
+ const outputEndP = 0.88;
82
+ const outputSlice = displayOutputLines.length > 0 ? (outputEndP - outputStartP) / displayOutputLines.length : 0;
83
+ const beatScale = 1 + beatIntensity * 0.01;
84
+ const dotSize = 12 * s;
85
+ const dotGap = 8 * s;
86
+ return /* @__PURE__ */ jsx(
87
+ "div",
88
+ {
89
+ style: {
90
+ position: "absolute",
91
+ top: height * 0.35,
92
+ left: (width - termWidth) / 2,
93
+ width: termWidth,
94
+ height: termHeight,
95
+ transform: `translateY(${termY}px) scale(${beatScale})`,
96
+ opacity: termOpacity
97
+ },
98
+ children: /* @__PURE__ */ jsxs(
99
+ "div",
100
+ {
101
+ style: {
102
+ width: termWidth,
103
+ height: termHeight,
104
+ borderRadius,
105
+ overflow: "hidden",
106
+ position: "relative",
107
+ boxShadow: `0 ${20 * s}px ${60 * s}px rgba(0,0,0,0.35)`
108
+ },
109
+ children: [
110
+ /* @__PURE__ */ jsxs(
111
+ "div",
112
+ {
113
+ style: {
114
+ width: "100%",
115
+ height: chromeHeight,
116
+ backgroundColor: "#313244",
117
+ display: "flex",
118
+ alignItems: "center",
119
+ paddingLeft: 16 * s,
120
+ paddingRight: 16 * s
121
+ },
122
+ children: [
123
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: dotGap, flexShrink: 0 }, children: [
124
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#ff5f57" } }),
125
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#febc2e" } }),
126
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#28c840" } })
127
+ ] }),
128
+ /* @__PURE__ */ jsx(
129
+ "div",
130
+ {
131
+ style: {
132
+ flex: 1,
133
+ textAlign: "center",
134
+ fontSize: 13 * s,
135
+ fontFamily: CHROME_FONT,
136
+ color: "#a6adc8",
137
+ whiteSpace: "nowrap"
138
+ },
139
+ children: "Terminal"
140
+ }
141
+ ),
142
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize * 3 + dotGap * 2, flexShrink: 0 } })
143
+ ]
144
+ }
145
+ ),
146
+ /* @__PURE__ */ jsxs(
147
+ "div",
148
+ {
149
+ style: {
150
+ width: "100%",
151
+ height: contentHeight,
152
+ backgroundColor: termBg,
153
+ padding: `${20 * s}px ${24 * s}px`,
154
+ overflow: "hidden"
155
+ },
156
+ children: [
157
+ /* @__PURE__ */ jsxs(
158
+ "div",
159
+ {
160
+ style: {
161
+ fontFamily: MONO_FONT,
162
+ fontSize,
163
+ lineHeight: `${lineHeight}px`,
164
+ whiteSpace: "nowrap"
165
+ },
166
+ children: [
167
+ /* @__PURE__ */ jsx("span", { style: { color: promptColor, fontWeight: 700 }, children: promptPrefix }),
168
+ /* @__PURE__ */ jsxs("span", { style: { color: termText }, children: [
169
+ " ",
170
+ typedText
171
+ ] }),
172
+ /* @__PURE__ */ jsx(
173
+ "span",
174
+ {
175
+ style: {
176
+ display: "inline-block",
177
+ width: fontSize * 0.55,
178
+ height: fontSize * 1.1,
179
+ backgroundColor: cursorVisible ? termText : "transparent",
180
+ verticalAlign: "text-bottom",
181
+ marginLeft: 1
182
+ }
183
+ }
184
+ )
185
+ ]
186
+ }
187
+ ),
188
+ displayOutputLines.map((line, i) => {
189
+ const lineStart = outputStartP + i * outputSlice;
190
+ const lineOpacity = interpolate(progress, [lineStart, lineStart + 0.03], [0, 1], CLAMP);
191
+ const lineSlideY = interpolate(progress, [lineStart, lineStart + 0.05], [8 * s, 0], CLAMP);
192
+ return /* @__PURE__ */ jsx(
193
+ "div",
194
+ {
195
+ style: {
196
+ fontFamily: MONO_FONT,
197
+ fontSize,
198
+ lineHeight: `${lineHeight}px`,
199
+ color: termText,
200
+ opacity: lineOpacity,
201
+ transform: `translateY(${lineSlideY}px)`,
202
+ marginTop: i === 0 ? lineHeight * 0.5 : 0,
203
+ whiteSpace: "nowrap"
204
+ },
205
+ children: line
206
+ },
207
+ i
208
+ );
209
+ })
210
+ ]
211
+ }
212
+ )
213
+ ]
214
+ }
215
+ )
216
+ }
217
+ );
218
+ };
219
+
220
+ // src/visual-system/scene-templates/showcase-terminal.tsx
221
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
222
+ var ShowcaseTerminalTemplate = ({
223
+ variables,
224
+ style,
225
+ progress,
226
+ motionProgress = progress,
227
+ beatIntensity,
228
+ width,
229
+ height,
230
+ safeZone,
231
+ sceneDuration,
232
+ backgroundEffect,
233
+ isPlaying = true
234
+ }) => {
235
+ const { primary, foreground, font } = resolveTokens(style);
236
+ const textColor = foreground;
237
+ const textsRaw = String(variables.texts || "");
238
+ const command = String(variables.command || "");
239
+ const promptPrefix = String(variables.promptPrefix || "$");
240
+ const outputLines = parseList(variables.output);
241
+ return /* @__PURE__ */ jsxs2(
242
+ "div",
243
+ {
244
+ style: {
245
+ width,
246
+ height,
247
+ backgroundColor: "#000",
248
+ position: "relative",
249
+ overflow: "hidden",
250
+ fontFamily: font
251
+ },
252
+ children: [
253
+ /* @__PURE__ */ jsx2(
254
+ SceneBackground,
255
+ {
256
+ style,
257
+ progress,
258
+ sceneDuration,
259
+ width,
260
+ height,
261
+ ...getMediaBackgroundProps(variables),
262
+ backgroundEffect,
263
+ seed: textsRaw,
264
+ isPlaying,
265
+ beatIntensity
266
+ }
267
+ ),
268
+ /* @__PURE__ */ jsx2(
269
+ TemplateText,
270
+ {
271
+ motionProgress,
272
+ typeTreatment: resolveTokens(style).preset.type,
273
+ archetype: "subtle",
274
+ text: String(variables.texts ?? ""),
275
+ progress,
276
+ sceneDuration: sceneDuration ?? 3,
277
+ width,
278
+ height,
279
+ position: "top",
280
+ sizeRole: "headline",
281
+ safeZone,
282
+ font,
283
+ color: textColor,
284
+ beatIntensity
285
+ }
286
+ ),
287
+ /* @__PURE__ */ jsx2(
288
+ TerminalOutput,
289
+ {
290
+ progress,
291
+ command,
292
+ outputLines,
293
+ promptPrefix,
294
+ width,
295
+ height,
296
+ accent: primary,
297
+ beatIntensity
298
+ }
299
+ )
300
+ ]
301
+ }
302
+ );
303
+ };
304
+ export {
305
+ ShowcaseTerminalTemplate
306
+ };
@@ -0,0 +1,390 @@
1
+ import {
2
+ ProductSurface,
3
+ WebScreenFill,
4
+ resolveProductSurfaceMotion
5
+ } from "./chunk-FSG2PYWG.js";
6
+ import {
7
+ stripPipe
8
+ } from "./chunk-S7HFLYNN.js";
9
+ import {
10
+ SceneBackground,
11
+ getMediaBackgroundProps
12
+ } from "./chunk-IFOW65Z6.js";
13
+ import {
14
+ TemplateText
15
+ } from "./chunk-BCRUUJ6A.js";
16
+ import "./chunk-L5BTTCZV.js";
17
+ import "./chunk-ABZACD4G.js";
18
+ import {
19
+ SPRING_SMOOTH,
20
+ interpolate,
21
+ spring
22
+ } from "./chunk-XTOXFMLM.js";
23
+ import {
24
+ TOKEN_DEFAULTS,
25
+ resolveTokens
26
+ } from "./chunk-FNAEQ7QO.js";
27
+
28
+ // src/visual-system/primitives/devices/WebMockup.tsx
29
+ import { jsx, jsxs } from "react/jsx-runtime";
30
+ var CLAMP = { extrapolateLeft: "clamp", extrapolateRight: "clamp" };
31
+ var WebMockup = ({
32
+ progress,
33
+ width,
34
+ height,
35
+ frame = "browser",
36
+ screenMediaUrl = "",
37
+ screens = [],
38
+ addressBarUrl = "yourapp.com",
39
+ font = TOKEN_DEFAULTS.font,
40
+ accent = TOKEN_DEFAULTS.primary,
41
+ secondary = "#00b5e5",
42
+ bg,
43
+ beatIntensity = 0,
44
+ screenFit = "cover",
45
+ screenFocusX = 50,
46
+ screenFocusY = 50,
47
+ screenMotion = "pushIn",
48
+ screenCalloutText = "",
49
+ screenCalloutX = 70,
50
+ screenCalloutY = 35
51
+ }) => {
52
+ const s = Math.min(width, height) / 1080;
53
+ const isBrowser = frame !== "tablet";
54
+ const addressBarUrlClean = stripPipe(String(addressBarUrl || "yourapp.com"));
55
+ const slidesMode = screens.length > 0;
56
+ const deviceWidth = Math.min(width * 0.85, height * 0.55 * (16 / 9));
57
+ const chromeHeight = isBrowser ? 44 * s : 0;
58
+ const contentHeight = deviceWidth * (9 / 16);
59
+ const deviceHeight = chromeHeight + contentHeight;
60
+ const borderRadius = isBrowser ? 12 * s : 24 * s;
61
+ const borderWidth = isBrowser ? 0 : 6 * s;
62
+ const enterRange = slidesMode ? [0.02, 0.35] : [0.02, 0.85];
63
+ const enterP = spring(
64
+ interpolate(progress, enterRange, [0, 1], CLAMP),
65
+ { damping: 28, stiffness: 80 }
66
+ );
67
+ const rotateX = (1 - enterP) * 70;
68
+ const deviceY = (1 - enterP) * 150 * s;
69
+ const deviceScale = interpolate(enterP, [0, 1], [0.85, 1]);
70
+ const deviceOpacity = interpolate(progress, [0.02, 0.1], [0, 1], CLAMP);
71
+ const slideCount = screens.length;
72
+ let slideOffset = 0;
73
+ if (slidesMode && slideCount >= 2) {
74
+ const transitionWidth = 0.1;
75
+ let totalSlides = 0;
76
+ for (let i = 1; i < slideCount; i++) {
77
+ const boundary = i / slideCount;
78
+ const start = boundary - transitionWidth / 2;
79
+ const end = boundary + transitionWidth / 2;
80
+ totalSlides += spring(
81
+ interpolate(progress, [start, end], [0, 1], CLAMP),
82
+ SPRING_SMOOTH
83
+ );
84
+ }
85
+ slideOffset = -totalSlides * deviceWidth;
86
+ }
87
+ const beatScale = slidesMode ? 1 + beatIntensity * 0.01 : 1 + beatIntensity * 0.015;
88
+ const dotSize = 12 * s;
89
+ const dotGap = 8 * s;
90
+ const placeholder = /* @__PURE__ */ jsx(
91
+ WebScreenFill,
92
+ {
93
+ accent,
94
+ secondary,
95
+ bg,
96
+ font,
97
+ s,
98
+ w: deviceWidth,
99
+ h: contentHeight,
100
+ progress
101
+ }
102
+ );
103
+ return /* @__PURE__ */ jsx(
104
+ "div",
105
+ {
106
+ style: {
107
+ position: "absolute",
108
+ top: height * 0.35,
109
+ left: (width - deviceWidth) / 2,
110
+ width: deviceWidth,
111
+ height: deviceHeight,
112
+ perspective: `${1200 * s}px`
113
+ },
114
+ children: /* @__PURE__ */ jsx(
115
+ "div",
116
+ {
117
+ style: {
118
+ width: deviceWidth,
119
+ height: deviceHeight,
120
+ transform: `rotateX(${rotateX}deg) translateY(${deviceY}px) scale(${deviceScale * beatScale})`,
121
+ transformOrigin: "center bottom",
122
+ opacity: deviceOpacity
123
+ },
124
+ children: /* @__PURE__ */ jsxs(
125
+ "div",
126
+ {
127
+ style: {
128
+ width: deviceWidth,
129
+ height: deviceHeight,
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
+ isBrowser && /* @__PURE__ */ jsxs(
137
+ "div",
138
+ {
139
+ style: {
140
+ width: "100%",
141
+ height: 44 * s,
142
+ backgroundColor: "#e8e8e8",
143
+ display: "flex",
144
+ alignItems: "center",
145
+ paddingLeft: 16 * s,
146
+ paddingRight: 16 * s,
147
+ gap: 0,
148
+ position: "relative",
149
+ zIndex: 2
150
+ },
151
+ children: [
152
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: dotGap, flexShrink: 0 }, children: [
153
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#ff5f57" } }),
154
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#febc2e" } }),
155
+ /* @__PURE__ */ jsx("div", { style: { width: dotSize, height: dotSize, borderRadius: "50%", backgroundColor: "#28c840" } })
156
+ ] }),
157
+ /* @__PURE__ */ jsxs(
158
+ "div",
159
+ {
160
+ style: {
161
+ flex: 1,
162
+ marginLeft: 16 * s,
163
+ height: 28 * s,
164
+ backgroundColor: "#ffffff",
165
+ borderRadius: 6 * s,
166
+ display: "flex",
167
+ alignItems: "center",
168
+ paddingLeft: 12 * s,
169
+ paddingRight: 12 * s,
170
+ overflow: "hidden"
171
+ },
172
+ children: [
173
+ /* @__PURE__ */ jsxs(
174
+ "svg",
175
+ {
176
+ width: 14 * s,
177
+ height: 14 * s,
178
+ viewBox: "0 0 14 14",
179
+ fill: "none",
180
+ style: { flexShrink: 0, marginRight: 6 * s },
181
+ children: [
182
+ /* @__PURE__ */ jsx("rect", { x: "2", y: "6", width: "10", height: "7", rx: "1.5", fill: "#999" }),
183
+ /* @__PURE__ */ jsx("path", { d: "M4.5 6V4.5a2.5 2.5 0 015 0V6", stroke: "#999", strokeWidth: "1.5", fill: "none", strokeLinecap: "round" })
184
+ ]
185
+ }
186
+ ),
187
+ /* @__PURE__ */ jsx(
188
+ "span",
189
+ {
190
+ style: {
191
+ fontSize: 13 * s,
192
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
193
+ color: "#666",
194
+ whiteSpace: "nowrap",
195
+ overflow: "hidden",
196
+ textOverflow: "ellipsis"
197
+ },
198
+ children: addressBarUrlClean
199
+ }
200
+ )
201
+ ]
202
+ }
203
+ )
204
+ ]
205
+ }
206
+ ),
207
+ !isBrowser && /* @__PURE__ */ jsx(
208
+ "div",
209
+ {
210
+ style: {
211
+ position: "absolute",
212
+ inset: 0,
213
+ borderRadius,
214
+ border: `${borderWidth * 1.5}px solid rgba(220,220,220,0.6)`,
215
+ pointerEvents: "none",
216
+ zIndex: 2
217
+ }
218
+ }
219
+ ),
220
+ slidesMode ? /* @__PURE__ */ jsx(
221
+ "div",
222
+ {
223
+ style: {
224
+ position: "absolute",
225
+ top: chromeHeight,
226
+ left: 0,
227
+ width: deviceWidth * screens.length,
228
+ height: contentHeight,
229
+ display: "flex",
230
+ transform: `translateX(${slideOffset}px)`
231
+ },
232
+ children: screens.map((url, i) => /* @__PURE__ */ jsx(
233
+ "div",
234
+ {
235
+ style: {
236
+ width: deviceWidth,
237
+ height: contentHeight,
238
+ flexShrink: 0
239
+ },
240
+ children: /* @__PURE__ */ jsx(
241
+ ProductSurface,
242
+ {
243
+ mediaUrl: url,
244
+ progress,
245
+ width: deviceWidth,
246
+ height: contentHeight,
247
+ fit: screenFit,
248
+ focusX: screenFocusX,
249
+ focusY: screenFocusY,
250
+ motion: "still",
251
+ accent,
252
+ font,
253
+ placeholder
254
+ }
255
+ )
256
+ },
257
+ i
258
+ ))
259
+ }
260
+ ) : /* @__PURE__ */ jsx("div", { style: { position: "absolute", top: chromeHeight, left: 0, width: deviceWidth, height: contentHeight }, children: /* @__PURE__ */ jsx(
261
+ ProductSurface,
262
+ {
263
+ mediaUrl: screenMediaUrl,
264
+ progress,
265
+ width: deviceWidth,
266
+ height: contentHeight,
267
+ fit: screenFit,
268
+ focusX: screenFocusX,
269
+ focusY: screenFocusY,
270
+ motion: screenMotion,
271
+ calloutText: screenCalloutText,
272
+ calloutX: screenCalloutX,
273
+ calloutY: screenCalloutY,
274
+ accent,
275
+ font,
276
+ placeholder
277
+ }
278
+ ) })
279
+ ]
280
+ }
281
+ )
282
+ }
283
+ )
284
+ }
285
+ );
286
+ };
287
+
288
+ // src/visual-system/scene-templates/showcase-web.tsx
289
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
290
+ var ShowcaseWebTemplate = ({
291
+ variables,
292
+ style,
293
+ progress,
294
+ motionProgress = progress,
295
+ beatIntensity,
296
+ width,
297
+ height,
298
+ textArchetype,
299
+ safeZone,
300
+ sceneDuration,
301
+ backgroundEffect,
302
+ isPlaying
303
+ }) => {
304
+ const tokens = resolveTokens(style);
305
+ const { primary, secondary, foreground, font, background } = tokens;
306
+ const textColor = foreground;
307
+ const screenMediaUrl = String(variables.screenMediaUrl || "");
308
+ const extraScreens = [
309
+ String(variables.screen1Url || ""),
310
+ String(variables.screen2Url || "")
311
+ ].filter(Boolean);
312
+ const screens = extraScreens.length > 0 && screenMediaUrl ? [screenMediaUrl, ...extraScreens] : extraScreens;
313
+ const frame = String(variables.frame || "browser").toLowerCase() === "tablet" ? "tablet" : "browser";
314
+ return /* @__PURE__ */ jsxs2(
315
+ "div",
316
+ {
317
+ style: {
318
+ width,
319
+ height,
320
+ backgroundColor: "#000",
321
+ position: "relative",
322
+ overflow: "hidden",
323
+ fontFamily: font
324
+ },
325
+ children: [
326
+ /* @__PURE__ */ jsx2(
327
+ SceneBackground,
328
+ {
329
+ style,
330
+ progress,
331
+ sceneDuration,
332
+ width,
333
+ height,
334
+ ...getMediaBackgroundProps(variables),
335
+ backgroundEffect,
336
+ seed: String(variables.texts || ""),
337
+ isPlaying,
338
+ beatIntensity
339
+ }
340
+ ),
341
+ /* @__PURE__ */ jsx2(
342
+ TemplateText,
343
+ {
344
+ motionProgress,
345
+ typeTreatment: tokens.preset.type,
346
+ archetype: textArchetype ?? "subtle",
347
+ text: String(variables.texts ?? ""),
348
+ progress,
349
+ sceneDuration: sceneDuration ?? 3,
350
+ width,
351
+ height,
352
+ position: "top",
353
+ sizeRole: "headline",
354
+ safeZone,
355
+ font,
356
+ color: textColor,
357
+ beatIntensity
358
+ }
359
+ ),
360
+ /* @__PURE__ */ jsx2(
361
+ WebMockup,
362
+ {
363
+ progress,
364
+ width,
365
+ height,
366
+ frame,
367
+ screenMediaUrl,
368
+ screens,
369
+ addressBarUrl: String(variables.addressBarUrl || ""),
370
+ font,
371
+ accent: primary,
372
+ secondary,
373
+ bg: background.type === "solid" ? background.color : void 0,
374
+ beatIntensity,
375
+ screenFit: variables.screenFit === "contain" ? "contain" : "cover",
376
+ screenFocusX: Number(variables.screenFocusX ?? 50),
377
+ screenFocusY: Number(variables.screenFocusY ?? 50),
378
+ screenMotion: resolveProductSurfaceMotion(variables.screenMotion),
379
+ screenCalloutText: String(variables.screenCalloutText || ""),
380
+ screenCalloutX: Number(variables.screenCalloutX ?? 70),
381
+ screenCalloutY: Number(variables.screenCalloutY ?? 35)
382
+ }
383
+ )
384
+ ]
385
+ }
386
+ );
387
+ };
388
+ export {
389
+ ShowcaseWebTemplate
390
+ };