@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
package/SECURITY.md ADDED
@@ -0,0 +1,22 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes target the latest published version of `@vanillaskyai/video`.
6
+ Upgrade to the current release before reporting behavior that may already have
7
+ been corrected.
8
+
9
+ ## Report a vulnerability
10
+
11
+ Use [GitHub private vulnerability reporting](https://github.com/VanillaSkyAi/video/security/advisories/new)
12
+ to report a suspected vulnerability. Do not open a public issue, discussion,
13
+ or pull request containing exploit details, credentials, customer data, or an
14
+ unannounced vulnerability.
15
+
16
+ Include the affected version, impact, reproduction steps, and any suggested
17
+ mitigation. Maintainers will validate the report and coordinate remediation and
18
+ disclosure when appropriate, without a guaranteed response time.
19
+
20
+ For deployment guidance covering authentication, provider credentials, request
21
+ limits, media policy, and logging, read the
22
+ [integration security guide](docs/security.md).
package/SUPPORT.md ADDED
@@ -0,0 +1,28 @@
1
+ # Support
2
+
3
+ VanillaSky Video is a beta open-source project. There is no guaranteed response time.
4
+
5
+ ## Product and integration questions
6
+
7
+ Search the documentation and existing GitHub issues first. If the problem is
8
+ not covered, open a reproducible GitHub issue at
9
+ <https://github.com/VanillaSkyAi/video/issues> with:
10
+
11
+ - the exact package, Node, React, framework, and provider versions;
12
+ - a minimal reproduction or packed-consumer fixture;
13
+ - expected and observed behavior;
14
+ - redacted logs and the smallest relevant video input.
15
+
16
+ Please do not include API keys, customer data, private media URLs, or
17
+ unannounced security details.
18
+
19
+ ## Security reports
20
+
21
+ Do not use a public issue for a suspected vulnerability. Follow `SECURITY.md`
22
+ and use GitHub private vulnerability reporting.
23
+
24
+ ## Scope
25
+
26
+ Maintainers may close requests that cannot be reproduced, rely on unsupported
27
+ versions, or require application-specific implementation work. A public issue
28
+ does not create a response-time or resolution commitment.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import "../dist/cli.js";
@@ -0,0 +1,89 @@
1
+ import {
2
+ ConfettiLayer
3
+ } from "./chunk-CJ7F2CE6.js";
4
+ import "./chunk-QAAO7OAY.js";
5
+ import {
6
+ TemplateText
7
+ } from "./chunk-BCRUUJ6A.js";
8
+ import "./chunk-L5BTTCZV.js";
9
+ import {
10
+ BrandGradientOverlay
11
+ } from "./chunk-ABZACD4G.js";
12
+ import "./chunk-XTOXFMLM.js";
13
+ import {
14
+ resolveTokens
15
+ } from "./chunk-FNAEQ7QO.js";
16
+
17
+ // src/visual-system/scene-templates/bg-confetti.tsx
18
+ import { jsx, jsxs } from "react/jsx-runtime";
19
+ var BgConfettiTemplate = ({
20
+ variables,
21
+ style,
22
+ progress,
23
+ motionProgress = progress,
24
+ beatIntensity,
25
+ width,
26
+ height,
27
+ textArchetype,
28
+ safeZone,
29
+ sceneDuration
30
+ }) => {
31
+ const { background, foreground, font } = resolveTokens(style);
32
+ const textColor = foreground;
33
+ return /* @__PURE__ */ jsxs(
34
+ "div",
35
+ {
36
+ style: {
37
+ width,
38
+ height,
39
+ backgroundColor: "#000",
40
+ position: "relative",
41
+ overflow: "hidden",
42
+ fontFamily: font
43
+ },
44
+ children: [
45
+ /* @__PURE__ */ jsx(
46
+ BrandGradientOverlay,
47
+ {
48
+ style,
49
+ progress,
50
+ sceneDuration,
51
+ seed: String(variables.texts || "").split("").reduce((acc, c) => acc + c.charCodeAt(0), 0)
52
+ }
53
+ ),
54
+ /* @__PURE__ */ jsx(
55
+ ConfettiLayer,
56
+ {
57
+ progress: motionProgress,
58
+ width,
59
+ height,
60
+ beatIntensity,
61
+ bgColor: background.type === "solid" ? background.color : background.colors[1]
62
+ }
63
+ ),
64
+ /* @__PURE__ */ jsx(
65
+ TemplateText,
66
+ {
67
+ motionProgress,
68
+ typeTreatment: resolveTokens(style).preset.type,
69
+ archetype: textArchetype ?? "subtle",
70
+ text: String(variables.texts ?? ""),
71
+ progress,
72
+ sceneDuration: sceneDuration ?? 3,
73
+ width,
74
+ height,
75
+ position: "center",
76
+ sizeRole: "headline",
77
+ safeZone,
78
+ font,
79
+ color: textColor,
80
+ beatIntensity
81
+ }
82
+ )
83
+ ]
84
+ }
85
+ );
86
+ };
87
+ export {
88
+ BgConfettiTemplate
89
+ };
@@ -0,0 +1,150 @@
1
+ import {
2
+ getCelebrationParticleTiming
3
+ } from "./chunk-QAAO7OAY.js";
4
+ import {
5
+ TemplateText
6
+ } from "./chunk-BCRUUJ6A.js";
7
+ import {
8
+ Emoji
9
+ } from "./chunk-L5BTTCZV.js";
10
+ import {
11
+ BrandGradientOverlay
12
+ } from "./chunk-ABZACD4G.js";
13
+ import "./chunk-XTOXFMLM.js";
14
+ import {
15
+ resolveTokens
16
+ } from "./chunk-FNAEQ7QO.js";
17
+
18
+ // src/visual-system/scene-templates/bg-emoji.tsx
19
+ import { jsx, jsxs } from "react/jsx-runtime";
20
+ function seededRandom(seed) {
21
+ const x = Math.sin(seed * 12.9898 + seed * 78.233) * 43758.5453;
22
+ return x - Math.floor(x);
23
+ }
24
+ var EMOJI_LIST = [
25
+ "\u2764\uFE0F",
26
+ // red heart
27
+ "\u2B50",
28
+ // star
29
+ "\u{1F389}",
30
+ // party popper
31
+ "\u{1F984}",
32
+ // unicorn
33
+ "\u{1F525}",
34
+ // fire
35
+ "\u2728",
36
+ // sparkles
37
+ "\u{1F680}",
38
+ // rocket
39
+ "\u{1F49C}"
40
+ // purple heart
41
+ ];
42
+ var PARTICLE_COUNT = 100;
43
+ function easeOutQuad(p) {
44
+ return 1 - (1 - p) * (1 - p);
45
+ }
46
+ var BgEmojiTemplate = ({
47
+ variables,
48
+ style,
49
+ progress,
50
+ motionProgress = progress,
51
+ beatIntensity,
52
+ width,
53
+ height,
54
+ textArchetype,
55
+ safeZone,
56
+ sceneDuration
57
+ }) => {
58
+ const s = Math.min(width, height) / 1080;
59
+ const BURST_RADIUS = Math.max(width, height) * 0.95;
60
+ const { foreground, font } = resolveTokens(style);
61
+ const textColor = foreground;
62
+ return /* @__PURE__ */ jsxs(
63
+ "div",
64
+ {
65
+ style: {
66
+ width,
67
+ height,
68
+ backgroundColor: "#000",
69
+ position: "relative",
70
+ overflow: "hidden",
71
+ fontFamily: font
72
+ },
73
+ children: [
74
+ /* @__PURE__ */ jsx(BrandGradientOverlay, { style, progress, sceneDuration, seed: String(variables.texts || "").split("").reduce((acc, c) => acc + c.charCodeAt(0), 0) }),
75
+ Array.from({ length: PARTICLE_COUNT }, (_, i) => {
76
+ const seed = i + 1;
77
+ const angle = i / PARTICLE_COUNT * Math.PI * 2;
78
+ const forceFactor = 0.75 + seededRandom(seed * 1) * 0.5;
79
+ const durationFactor = 1.1 + seededRandom(seed * 3) * 0.6;
80
+ const emoji = EMOJI_LIST[i % EMOJI_LIST.length];
81
+ const startRot = seededRandom(seed * 5) * 60 - 30;
82
+ const rotSpeed = (seededRandom(seed * 6) - 0.5) * 540;
83
+ const sizeJitter = 0.7 + seededRandom(seed * 7) * 0.7;
84
+ const timing = getCelebrationParticleTiming(motionProgress, i, durationFactor);
85
+ if (!timing) return null;
86
+ const p = timing.progress;
87
+ const reach = BURST_RADIUS * forceFactor;
88
+ const radialP = easeOutQuad(p);
89
+ const gravity = height * 0.08 * p * p;
90
+ const x = width * 0.5 + Math.cos(angle) * reach * radialP;
91
+ const y = height * 0.5 + Math.sin(angle) * reach * radialP + gravity;
92
+ const baseSize = (28 + seededRandom(seed * 11) * 24) * s;
93
+ const size = baseSize * sizeJitter;
94
+ const popScale = Math.min(1, p * 30);
95
+ const particleOpacity = p < 0.85 ? 1 : Math.max(0, 1 - (p - 0.85) / 0.15);
96
+ const opacity = particleOpacity * timing.opacity;
97
+ const beatPulse = 1 + beatIntensity * 0.2;
98
+ const rot = startRot + rotSpeed * p;
99
+ if (opacity <= 0) return null;
100
+ if (y > height + 100 || y < -100 || x < -100 || x > width + 100) return null;
101
+ return /* @__PURE__ */ jsx(
102
+ "div",
103
+ {
104
+ style: {
105
+ position: "absolute",
106
+ left: x - size / 2,
107
+ top: y - size / 2,
108
+ width: size,
109
+ height: size,
110
+ fontSize: size * 0.8,
111
+ lineHeight: 1,
112
+ textAlign: "center",
113
+ opacity,
114
+ transform: `rotate(${rot}deg) scale(${popScale * beatPulse})`,
115
+ pointerEvents: "none",
116
+ display: "flex",
117
+ alignItems: "center",
118
+ justifyContent: "center"
119
+ },
120
+ children: /* @__PURE__ */ jsx(Emoji, { char: emoji, size: size * 0.8, verticalAlign: "baseline" })
121
+ },
122
+ i
123
+ );
124
+ }),
125
+ /* @__PURE__ */ jsx(
126
+ TemplateText,
127
+ {
128
+ motionProgress,
129
+ typeTreatment: resolveTokens(style).preset.type,
130
+ archetype: textArchetype ?? "subtle",
131
+ text: String(variables.texts ?? ""),
132
+ progress,
133
+ sceneDuration: sceneDuration ?? 3,
134
+ width,
135
+ height,
136
+ position: "center",
137
+ sizeRole: "headline",
138
+ safeZone,
139
+ font,
140
+ color: textColor,
141
+ beatIntensity
142
+ }
143
+ )
144
+ ]
145
+ }
146
+ );
147
+ };
148
+ export {
149
+ BgEmojiTemplate
150
+ };
@@ -0,0 +1,99 @@
1
+ import {
2
+ SceneBackground,
3
+ getMediaBackgroundProps
4
+ } from "./chunk-IFOW65Z6.js";
5
+ import {
6
+ ConfettiLayer
7
+ } from "./chunk-CJ7F2CE6.js";
8
+ import "./chunk-QAAO7OAY.js";
9
+ import {
10
+ TemplateText
11
+ } from "./chunk-BCRUUJ6A.js";
12
+ import "./chunk-L5BTTCZV.js";
13
+ import "./chunk-ABZACD4G.js";
14
+ import "./chunk-XTOXFMLM.js";
15
+ import {
16
+ resolveTokens
17
+ } from "./chunk-FNAEQ7QO.js";
18
+
19
+ // src/visual-system/scene-templates/bg-media.tsx
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ var BgMediaTemplate = ({
22
+ variables,
23
+ style,
24
+ progress,
25
+ motionProgress = progress,
26
+ beatIntensity,
27
+ width,
28
+ height,
29
+ textArchetype,
30
+ backgroundEffect,
31
+ safeZone,
32
+ sceneDuration,
33
+ isPlaying = true
34
+ }) => {
35
+ const { font, foreground, background } = resolveTokens(style);
36
+ const text = foreground;
37
+ return /* @__PURE__ */ jsxs(
38
+ "div",
39
+ {
40
+ style: {
41
+ width,
42
+ height,
43
+ backgroundColor: "#000",
44
+ position: "relative",
45
+ overflow: "hidden",
46
+ fontFamily: font
47
+ },
48
+ children: [
49
+ /* @__PURE__ */ jsx(
50
+ SceneBackground,
51
+ {
52
+ style,
53
+ progress,
54
+ sceneDuration,
55
+ width,
56
+ height,
57
+ ...getMediaBackgroundProps(variables),
58
+ backgroundEffect,
59
+ seed: String(variables.texts || ""),
60
+ isPlaying,
61
+ beatIntensity
62
+ }
63
+ ),
64
+ variables.confetti === true && /* @__PURE__ */ jsx(
65
+ ConfettiLayer,
66
+ {
67
+ progress: motionProgress,
68
+ width,
69
+ height,
70
+ beatIntensity,
71
+ bgColor: String(variables.mediaUrl || "").trim() === "" ? background.type === "solid" ? background.color : background.colors[1] : void 0
72
+ }
73
+ ),
74
+ /* @__PURE__ */ jsx(
75
+ TemplateText,
76
+ {
77
+ motionProgress,
78
+ typeTreatment: resolveTokens(style).preset.type,
79
+ archetype: textArchetype ?? "subtle",
80
+ text: String(variables.texts ?? ""),
81
+ progress,
82
+ sceneDuration: sceneDuration ?? 3,
83
+ width,
84
+ height,
85
+ position: "center",
86
+ sizeRole: "headline",
87
+ safeZone,
88
+ font,
89
+ color: text,
90
+ beatIntensity
91
+ }
92
+ )
93
+ ]
94
+ }
95
+ );
96
+ };
97
+ export {
98
+ BgMediaTemplate
99
+ };
@@ -0,0 +1,253 @@
1
+ import {
2
+ stripPipe
3
+ } from "./chunk-S7HFLYNN.js";
4
+ import {
5
+ SceneBackground,
6
+ getMediaBackgroundProps
7
+ } from "./chunk-IFOW65Z6.js";
8
+ import {
9
+ renderWithEmoji
10
+ } from "./chunk-L5BTTCZV.js";
11
+ import "./chunk-ABZACD4G.js";
12
+ import {
13
+ interpolate
14
+ } from "./chunk-XTOXFMLM.js";
15
+ import "./chunk-FNAEQ7QO.js";
16
+
17
+ // src/visual-system/primitives/typography/BrandMessageBubble.tsx
18
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
+ var CLAMP = { extrapolateLeft: "clamp", extrapolateRight: "clamp" };
20
+ var BUBBLE_BG = "rgba(245,242,238,0.92)";
21
+ var BUBBLE_TEXT = "#1c1c1e";
22
+ var DOT_COLOR = "#8C8C92";
23
+ function easeOutBack(t) {
24
+ const c1 = 1.70158;
25
+ const c3 = c1 + 1;
26
+ return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
27
+ }
28
+ var TAIL_WITH_EMOJI = /(\S+)(\s+)([\p{Extended_Pictographic}\p{Emoji_Modifier}\u{FE0E}\u{FE0F}\u{200D}]+)\s*$/u;
29
+ function renderMessageWithEmojiTail(text, fontSizePx) {
30
+ const match = TAIL_WITH_EMOJI.exec(text);
31
+ if (!match || match.index === void 0) {
32
+ return renderWithEmoji(text, fontSizePx);
33
+ }
34
+ const [, lastWord, space, emoji] = match;
35
+ const leading = text.slice(0, match.index);
36
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
37
+ renderWithEmoji(leading, fontSizePx),
38
+ /* @__PURE__ */ jsxs("span", { style: { whiteSpace: "nowrap" }, children: [
39
+ lastWord,
40
+ space,
41
+ renderWithEmoji(emoji, fontSizePx)
42
+ ] })
43
+ ] });
44
+ }
45
+ function popIn(t, start, dur = 0.4) {
46
+ if (t <= start) return 0;
47
+ if (t >= start + dur) return 1;
48
+ return easeOutBack((t - start) / dur);
49
+ }
50
+ var BrandMessageBubble = ({
51
+ progress,
52
+ sceneDuration,
53
+ brandName: rawBrandName,
54
+ message: rawMessage,
55
+ width,
56
+ height,
57
+ safeZone
58
+ }) => {
59
+ const isLandscape = width > height;
60
+ const s = isLandscape ? Math.min(width, height) / 534 * 1.3 : width / 534;
61
+ const brandName = stripPipe(rawBrandName);
62
+ const message = stripPipe(rawMessage);
63
+ const realTimeSeconds = progress * sceneDuration;
64
+ const typingStart = 0.1;
65
+ const bubbleStart = 0.38;
66
+ const typingPop = popIn(progress, typingStart, 0.1);
67
+ const typingFade = interpolate(progress, [bubbleStart - 0.06, bubbleStart], [1, 0], CLAMP);
68
+ const showTyping = progress >= typingStart && progress < bubbleStart;
69
+ const bubblePop = popIn(progress, bubbleStart, 0.18);
70
+ const showBubble = progress >= bubbleStart;
71
+ const topPad = Math.max(safeZone.top, height * 0.25);
72
+ const sidePad = Math.max(safeZone.left, width * 0.06);
73
+ return /* @__PURE__ */ jsxs(
74
+ "div",
75
+ {
76
+ style: {
77
+ position: "absolute",
78
+ top: topPad,
79
+ left: sidePad,
80
+ right: sidePad,
81
+ display: "flex",
82
+ justifyContent: "flex-end"
83
+ },
84
+ children: [
85
+ showTyping && /* @__PURE__ */ jsx(
86
+ "div",
87
+ {
88
+ style: {
89
+ opacity: typingPop * typingFade,
90
+ transform: `translateY(${(1 - typingPop) * 8 * s}px)`,
91
+ background: BUBBLE_BG,
92
+ borderRadius: 18 * s,
93
+ padding: `${12 * s}px ${16 * s}px`,
94
+ display: "flex",
95
+ gap: 5 * s,
96
+ alignItems: "center",
97
+ boxShadow: `0 ${1 * s}px ${4 * s}px rgba(0,0,0,0.10)`
98
+ },
99
+ children: [0, 1, 2].map((j) => {
100
+ const phase = (realTimeSeconds * 1.6 + j * 0.2) % 1;
101
+ const y = Math.sin(phase * Math.PI * 2) * 2.5 * s;
102
+ const op = 0.45 + 0.55 * Math.max(0, Math.sin(phase * Math.PI));
103
+ return /* @__PURE__ */ jsx(
104
+ "div",
105
+ {
106
+ style: {
107
+ width: 7 * s,
108
+ height: 7 * s,
109
+ borderRadius: 3.5 * s,
110
+ background: DOT_COLOR,
111
+ transform: `translateY(${-y}px)`,
112
+ opacity: op
113
+ }
114
+ },
115
+ j
116
+ );
117
+ })
118
+ }
119
+ ),
120
+ showBubble && /* @__PURE__ */ jsxs(
121
+ "div",
122
+ {
123
+ style: {
124
+ // `width: max-content` forces the bubble to size to its
125
+ // natural one-line content width up to `maxWidth`. Without
126
+ // this, modern-screenshot's foreignObject text shaping (the
127
+ // export path) was using an intrinsic width well below
128
+ // `maxWidth`, breaking text that would have fit on one line
129
+ // in the live DOM — even after the NBSP fix glued the
130
+ // trailing emoji to the last word. With `max-content` +
131
+ // `maxWidth`, the bubble grows up to the cap on a single
132
+ // line, then wraps naturally inside the cap for genuinely
133
+ // long messages.
134
+ width: "max-content",
135
+ maxWidth: width * 0.86,
136
+ // Render with native system fonts in BOTH paths. The export
137
+ // pipeline turns the iframe DOM into an SVG and loads it via
138
+ // <img src="data:image/svg+xml,…">, and SVG-as-image is a
139
+ // sandboxed graphics context that does NOT load @font-face
140
+ // resources (data: or otherwise — this is a browser security
141
+ // model, not a CSP issue). Inter therefore never resolves in
142
+ // the export; the SVG falls back to Helvetica/Helvetica Neue,
143
+ // which is wider at the same point size, and "We built this
144
+ // for you ❤️" wraps inside the pinned bubble box even though
145
+ // the iframe's Inter rendering fit on one line. Naming the
146
+ // system font explicitly here makes the iframe ALSO use that
147
+ // same OS-native font, so preview and export compute identical
148
+ // widths and both fit on one line. See PRs #598/#599/#604 for
149
+ // the months of font-embed work that this finally closes out.
150
+ fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
151
+ background: BUBBLE_BG,
152
+ color: BUBBLE_TEXT,
153
+ borderRadius: `${22 * s}px ${22 * s}px 0 ${22 * s}px`,
154
+ padding: `${14 * s}px ${18 * s}px ${12 * s}px`,
155
+ fontSize: 23 * s,
156
+ lineHeight: `${29 * s}px`,
157
+ fontWeight: 400,
158
+ opacity: bubblePop,
159
+ transform: `translateY(${(1 - bubblePop) * 8 * s}px) scale(${0.96 + 0.04 * bubblePop})`,
160
+ transformOrigin: "right top",
161
+ boxShadow: `0 ${2 * s}px ${10 * s}px rgba(0,0,0,0.14)`
162
+ },
163
+ children: [
164
+ /* @__PURE__ */ jsx(
165
+ "div",
166
+ {
167
+ style: {
168
+ fontSize: 14 * s,
169
+ fontStyle: "italic",
170
+ fontWeight: 400,
171
+ color: "rgba(0,0,0,0.45)",
172
+ lineHeight: 1.2,
173
+ marginBottom: 6 * s
174
+ },
175
+ children: brandName
176
+ }
177
+ ),
178
+ renderMessageWithEmojiTail(message, 23 * s)
179
+ ]
180
+ }
181
+ )
182
+ ]
183
+ }
184
+ );
185
+ };
186
+
187
+ // src/visual-system/scene-templates/brand-message.tsx
188
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
189
+ var BrandMessageTemplate = ({
190
+ variables,
191
+ style,
192
+ progress,
193
+ beatIntensity,
194
+ width,
195
+ height,
196
+ sceneDuration,
197
+ isPlaying = true,
198
+ safeZone,
199
+ backgroundEffect
200
+ }) => {
201
+ const brandName = stripPipe(style.brand.name ?? "Your brand");
202
+ const message = stripPipe(String(variables.message || ""));
203
+ const seed = (brandName + message).split("").reduce((acc, c) => acc + c.charCodeAt(0), 0);
204
+ return /* @__PURE__ */ jsxs2(
205
+ "div",
206
+ {
207
+ style: {
208
+ width,
209
+ height,
210
+ backgroundColor: "#000",
211
+ position: "relative",
212
+ overflow: "hidden",
213
+ // System fonts only — see BrandMessageBubble for the why
214
+ // (SVG-as-image can't load @font-face data: URLs, so the only
215
+ // way to get preview/export parity is to use a font the OS
216
+ // already has natively).
217
+ fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif'
218
+ },
219
+ children: [
220
+ /* @__PURE__ */ jsx2(
221
+ SceneBackground,
222
+ {
223
+ style,
224
+ progress,
225
+ sceneDuration,
226
+ width,
227
+ height,
228
+ ...getMediaBackgroundProps(variables),
229
+ backgroundEffect,
230
+ seed,
231
+ isPlaying,
232
+ beatIntensity
233
+ }
234
+ ),
235
+ /* @__PURE__ */ jsx2(
236
+ BrandMessageBubble,
237
+ {
238
+ progress,
239
+ sceneDuration: sceneDuration ?? 4,
240
+ brandName,
241
+ message,
242
+ width,
243
+ height,
244
+ safeZone
245
+ }
246
+ )
247
+ ]
248
+ }
249
+ );
250
+ };
251
+ export {
252
+ BrandMessageTemplate
253
+ };
@@ -0,0 +1,8 @@
1
+ import {
2
+ BUILTIN_SERVER_TEMPLATE_KIT
3
+ } from "./chunk-A2X45FET.js";
4
+ import "./chunk-CHLGW22F.js";
5
+ import "./chunk-2E6T633S.js";
6
+ export {
7
+ BUILTIN_SERVER_TEMPLATE_KIT
8
+ };