@vanillaskyai/video 0.8.8 → 0.10.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 (173) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/PUBLIC-API.md +5 -8
  3. package/dist/{builtin-server-CUYPIDE7.js → builtin-server-W4PLJUZ5.js} +2 -2
  4. package/dist/{catalog-types-BIhSpOWK.d.ts → catalog-types-WTbLP6Jh.d.ts} +5 -1
  5. package/dist/chapter-title-YRLIQY3V.js +7 -0
  6. package/dist/check-runtime.js +5 -14
  7. package/dist/{chunk-AITKH6QT.js → chunk-2HFO22K2.js} +15 -40
  8. package/dist/chunk-4YM2M62S.js +13 -0
  9. package/dist/chunk-4ZJLPHBV.js +684 -0
  10. package/dist/chunk-77VY4O7A.js +390 -0
  11. package/dist/{chunk-MMUXVA47.js → chunk-7M56IUUX.js} +9 -8
  12. package/dist/chunk-7NZOMTAL.js +63 -0
  13. package/dist/{chunk-2DOLF4QN.js → chunk-AUPC6MDK.js} +12 -14
  14. package/dist/{chunk-352ZZCET.js → chunk-EGVQODKU.js} +2 -2
  15. package/dist/{chunk-2USVB3CY.js → chunk-ELVOT2FQ.js} +284 -177
  16. package/dist/chunk-EWWCQFTI.js +18 -0
  17. package/dist/{chunk-KT3M7KDL.js → chunk-HKUI5BTB.js} +3 -3
  18. package/dist/chunk-IIN5M5HW.js +697 -0
  19. package/dist/{chunk-LMG3GHLL.js → chunk-IQMYK5DX.js} +29 -3
  20. package/dist/{chunk-OWBT45EN.js → chunk-IR44XKBI.js} +1 -1
  21. package/dist/{chunk-MXZSDGZQ.js → chunk-NMFDC2W2.js} +4 -6
  22. package/dist/{chunk-5SLENAJW.js → chunk-PAJ44TFW.js} +1 -2
  23. package/dist/{chunk-L7QGGKJ2.js → chunk-PDQFQIQW.js} +1 -1
  24. package/dist/{chunk-WJ6FLKNC.js → chunk-R3XAOMKP.js} +14 -0
  25. package/dist/{chunk-2OKB27TG.js → chunk-RXTN2CW6.js} +2 -2
  26. package/dist/{chunk-XWWLKRNU.js → chunk-TVIU23OM.js} +38 -49
  27. package/dist/chunk-XX4GXKTX.js +35 -0
  28. package/dist/chunk-Z67Q5KUW.js +16 -0
  29. package/dist/{chunk-3VRMKFM7.js → chunk-ZDJNFA52.js} +11 -24
  30. package/dist/cinema-media-C7OUPNSH.js +12 -0
  31. package/dist/cli.js +18 -9
  32. package/dist/comparison-GNZOR7MF.js +37 -0
  33. package/dist/compose-video-TBFTONUC.js +12 -0
  34. package/dist/editorial-timeline-EMV5335S.js +43 -0
  35. package/dist/{events-BQ6z264n.d.ts → events-B4YCc4vc.d.ts} +1 -1
  36. package/dist/index.d.ts +4 -6
  37. package/dist/index.js +3 -7
  38. package/dist/key-figure-P37VK425.js +30 -0
  39. package/dist/{kit-tQnCPMOM.d.ts → kit-DrRpdn0p.d.ts} +2 -2
  40. package/dist/mobile-message-OF7T62B7.js +50 -0
  41. package/dist/quote-T6WYLN7A.js +33 -0
  42. package/dist/react.d.ts +21 -11
  43. package/dist/react.js +585 -826
  44. package/dist/scene-video-backdrop-PCTARAAJ.js +7 -0
  45. package/dist/server.d.ts +7 -8
  46. package/dist/server.js +179 -84
  47. package/dist/{system-prompt-RRXIWDDD.js → system-prompt-SYRT5DWM.js} +1 -1
  48. package/dist/template-catalog.d.ts +392 -16
  49. package/dist/template-catalog.js +1 -1
  50. package/dist/templates.d.ts +5 -5
  51. package/dist/test.d.ts +3 -3
  52. package/dist/test.js +18 -18
  53. package/dist/text-stream-LD364KBI.js +9 -0
  54. package/dist/{types-DWFO6qca.d.ts → types-CdBmNTGD.d.ts} +1 -1
  55. package/dist/{types-CEh9eUFu.d.ts → types-DdZw4GRQ.d.ts} +17 -48
  56. package/dist/validate-4OUD2CLX.js +10 -0
  57. package/docs/architecture.md +1 -1
  58. package/docs/concepts.md +1 -1
  59. package/docs/custom-templates.md +13 -28
  60. package/docs/customization.md +11 -59
  61. package/docs/getting-started.md +2 -2
  62. package/docs/immersive-interface.md +3 -4
  63. package/docs/maintainers/cinematic-migration.md +38 -0
  64. package/docs/media-and-audio.md +14 -14
  65. package/docs/motion-and-effects.md +6 -14
  66. package/docs/persistence.md +3 -3
  67. package/docs/production.md +11 -9
  68. package/docs/provider-integration.md +9 -16
  69. package/docs/reference/design-system.html +1 -1
  70. package/docs/reference/protocol.md +14 -4
  71. package/docs/testing.md +1 -1
  72. package/package.json +6 -3
  73. package/registry/items/backgrounds.json +1 -1
  74. package/registry/items/chapterTitle.json +80 -0
  75. package/registry/items/cinemaMedia.json +136 -0
  76. package/registry/items/comparison.json +168 -0
  77. package/registry/items/editorialTimeline.json +172 -0
  78. package/registry/items/keyFigure.json +162 -0
  79. package/registry/items/mobileMessage.json +153 -0
  80. package/registry/items/quote.json +161 -0
  81. package/registry/items/template-context.json +1 -1
  82. package/registry/items/theme.json +1 -1
  83. package/starters/video-chat/README.md +24 -26
  84. package/starters/video-chat/package.json +1 -1
  85. package/starters/video-chat/providers/video.ts +6 -5
  86. package/starters/video-chat/stock.ts +35 -151
  87. package/styles/fonts/OFL.txt +93 -0
  88. package/styles/fonts/manifest.json +66 -0
  89. package/styles/fonts/roboto-v51-cyrillic-ext.woff2 +0 -0
  90. package/styles/fonts/roboto-v51-cyrillic.woff2 +0 -0
  91. package/styles/fonts/roboto-v51-greek-ext.woff2 +0 -0
  92. package/styles/fonts/roboto-v51-greek.woff2 +0 -0
  93. package/styles/fonts/roboto-v51-latin-ext.woff2 +0 -0
  94. package/styles/fonts/roboto-v51-latin.woff2 +0 -0
  95. package/styles/fonts/roboto-v51-math.woff2 +0 -0
  96. package/styles/fonts/roboto-v51-symbols.woff2 +0 -0
  97. package/styles/fonts/roboto-v51-vietnamese.woff2 +0 -0
  98. package/styles/fonts/roboto.css +91 -0
  99. package/styles/video-chat.css +30 -22
  100. package/dist/bg-confetti-HITCGLGD.js +0 -89
  101. package/dist/bg-emoji-VU4UZYZN.js +0 -150
  102. package/dist/bg-media-L34PDQXJ.js +0 -106
  103. package/dist/brand-message-FUJ4STFO.js +0 -256
  104. package/dist/chart-bar-EGPHJATL.js +0 -310
  105. package/dist/chart-counter-5FFWQNZO.js +0 -306
  106. package/dist/chart-progress-ring-JMXQLMLC.js +0 -302
  107. package/dist/chunk-4UNKZEAT.js +0 -3575
  108. package/dist/chunk-5CDAM24P.js +0 -31
  109. package/dist/chunk-AOWSXU2K.js +0 -18
  110. package/dist/chunk-CJ7F2CE6.js +0 -104
  111. package/dist/chunk-FRN6WKHA.js +0 -185
  112. package/dist/chunk-G5JPHBX7.js +0 -336
  113. package/dist/chunk-L5BTTCZV.js +0 -97
  114. package/dist/chunk-P22HHFDK.js +0 -43
  115. package/dist/chunk-PP3MCPN4.js +0 -1998
  116. package/dist/chunk-QAAO7OAY.js +0 -19
  117. package/dist/chunk-S7HFLYNN.js +0 -35
  118. package/dist/chunk-W3VDIBGR.js +0 -217
  119. package/dist/chunk-XGRA2MUV.js +0 -242
  120. package/dist/chunk-XTOXFMLM.js +0 -105
  121. package/dist/chunk-YJJC4N4D.js +0 -761
  122. package/dist/compose-video-2NFH4DZY.js +0 -13
  123. package/dist/cta-logo-YR7LYUR5.js +0 -212
  124. package/dist/cta-media-DQJBKUO2.js +0 -221
  125. package/dist/incoming-call-54KQ7O5A.js +0 -323
  126. package/dist/infographic-before-after-ROS52GOW.js +0 -460
  127. package/dist/infographic-feature-list-E7MGUDAN.js +0 -272
  128. package/dist/infographic-problem-solution-3S6NGO5N.js +0 -343
  129. package/dist/infographic-stat-row-SYB7AB7H.js +0 -247
  130. package/dist/infographic-steps-KCE6JWE2.js +0 -406
  131. package/dist/prompt-input-MHX4O42G.js +0 -239
  132. package/dist/reaction-SLEGR3BE.js +0 -122
  133. package/dist/scene-video-backdrop-XFPX4O3I.js +0 -10
  134. package/dist/showcase-code-2HLAVKBM.js +0 -357
  135. package/dist/showcase-phone-Q4HEO4LH.js +0 -278
  136. package/dist/showcase-terminal-DL45LUFG.js +0 -312
  137. package/dist/showcase-web-2QZO73FZ.js +0 -396
  138. package/dist/social-conversation-75SD2637.js +0 -695
  139. package/dist/social-milestone-GEFUQSBF.js +0 -296
  140. package/dist/social-notification-FJ5VHVLK.js +0 -247
  141. package/dist/social-review-stack-KXQCKFRP.js +0 -242
  142. package/dist/social-testimonial-JZ7CHC7S.js +0 -287
  143. package/dist/social-tweet-UCDXM25F.js +0 -298
  144. package/dist/text-stream-54LXABJW.js +0 -10
  145. package/dist/validate-T7GBU2YF.js +0 -8
  146. package/registry/items/barChart.json +0 -245
  147. package/registry/items/beforeAfter.json +0 -180
  148. package/registry/items/bigNumber.json +0 -232
  149. package/registry/items/brandMessage.json +0 -164
  150. package/registry/items/cardList.json +0 -214
  151. package/registry/items/chatMessenger.json +0 -151
  152. package/registry/items/chatWhatsapp.json +0 -151
  153. package/registry/items/codeEditor.json +0 -191
  154. package/registry/items/confetti.json +0 -107
  155. package/registry/items/ctaLogo.json +0 -167
  156. package/registry/items/ctaMedia.json +0 -200
  157. package/registry/items/emojiBurst.json +0 -101
  158. package/registry/items/incomingCall.json +0 -177
  159. package/registry/items/media.json +0 -187
  160. package/registry/items/milestone.json +0 -212
  161. package/registry/items/notification.json +0 -189
  162. package/registry/items/phoneMockup.json +0 -261
  163. package/registry/items/problemSolution.json +0 -193
  164. package/registry/items/progressRing.json +0 -206
  165. package/registry/items/promptInput.json +0 -155
  166. package/registry/items/reaction.json +0 -176
  167. package/registry/items/reviewStack.json +0 -231
  168. package/registry/items/steps.json +0 -215
  169. package/registry/items/terminal.json +0 -219
  170. package/registry/items/testimonial.json +0 -171
  171. package/registry/items/tripleStats.json +0 -235
  172. package/registry/items/tweet.json +0 -210
  173. package/registry/items/webMockup.json +0 -280
@@ -1,31 +0,0 @@
1
- // src/visual-system/scene-templates/external-video-backdrop.tsx
2
- import React from "react";
3
- import { jsx } from "react/jsx-runtime";
4
- var DEFAULT = { mode: false, audioMuted: true, audioVolume: 1 };
5
- var sharedContext = globalThis;
6
- var BackdropContext = sharedContext.__vanillaskyVideoBackdropContext ??= React.createContext(DEFAULT);
7
- function ExternalVideoBackdropProvider({
8
- mode,
9
- audioMuted = true,
10
- audioVolume = 1,
11
- children
12
- }) {
13
- const value = React.useMemo(
14
- () => ({ mode, audioMuted, audioVolume }),
15
- [mode, audioMuted, audioVolume]
16
- );
17
- return /* @__PURE__ */ jsx(BackdropContext.Provider, { value, children });
18
- }
19
- function useExternalVideoBackdrop() {
20
- return React.useContext(BackdropContext).mode;
21
- }
22
- function useMediaAudio() {
23
- const { audioMuted, audioVolume } = React.useContext(BackdropContext);
24
- return { muted: audioMuted, volume: audioVolume };
25
- }
26
-
27
- export {
28
- ExternalVideoBackdropProvider,
29
- useExternalVideoBackdrop,
30
- useMediaAudio
31
- };
@@ -1,18 +0,0 @@
1
- // src/protocol/types.ts
2
- var VIDEO_PROTOCOL_VERSION = "0.5";
3
- var VIDEO_SCHEMA_VERSION = "0.1";
4
- function createVideoRequest(input, options) {
5
- return {
6
- protocolVersion: VIDEO_PROTOCOL_VERSION,
7
- requestId: options.requestId,
8
- input,
9
- ...options.capabilities ? { capabilities: options.capabilities } : {},
10
- ...options.resume ? { resume: options.resume } : {}
11
- };
12
- }
13
-
14
- export {
15
- VIDEO_PROTOCOL_VERSION,
16
- VIDEO_SCHEMA_VERSION,
17
- createVideoRequest
18
- };
@@ -1,104 +0,0 @@
1
- import {
2
- getCelebrationParticleTiming
3
- } from "./chunk-QAAO7OAY.js";
4
-
5
- // src/visual-system/scene-templates/confetti-layer.tsx
6
- import { Fragment, jsx } from "react/jsx-runtime";
7
- var PARTICLE_COUNT = 200;
8
- var COLORS = ["#ef4444", "#ff6b6b", "#f97316", "#fb923c", "#ffd93d", "#34d399", "#6bcbff", "#818cf8", "#a78bfa", "#f472b6", "#ffffff"];
9
- function seededRandom(seed) {
10
- const x = Math.sin(seed * 12.9898 + seed * 78.233) * 43758.5453;
11
- return x - Math.floor(x);
12
- }
13
- function easeOutQuad(p) {
14
- return 1 - (1 - p) * (1 - p);
15
- }
16
- function hexHue(hex) {
17
- const r = parseInt(hex.slice(1, 3), 16) / 255;
18
- const g = parseInt(hex.slice(3, 5), 16) / 255;
19
- const b = parseInt(hex.slice(5, 7), 16) / 255;
20
- const max = Math.max(r, g, b);
21
- const min = Math.min(r, g, b);
22
- const d = max - min;
23
- if (d === 0) return 0;
24
- let h = 0;
25
- if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
26
- else if (max === g) h = ((b - r) / d + 2) / 6;
27
- else h = ((r - g) / d + 4) / 6;
28
- return h * 360;
29
- }
30
- function hueDistance(a, b) {
31
- const d = Math.abs(a - b) % 360;
32
- return d > 180 ? 360 - d : d;
33
- }
34
- var ConfettiLayer = ({
35
- progress,
36
- width,
37
- height,
38
- beatIntensity = 0,
39
- bgColor
40
- }) => {
41
- const s = Math.min(width, height) / 1080;
42
- const BURST_RADIUS = Math.max(width, height) * 0.95;
43
- let allColors = COLORS;
44
- if (bgColor) {
45
- const bgHue = hexHue(bgColor);
46
- const filtered = COLORS.filter((c) => c === "#ffffff" || hueDistance(hexHue(c), bgHue) > 35);
47
- if (filtered.length >= 4) allColors = filtered;
48
- }
49
- return /* @__PURE__ */ jsx(Fragment, { children: Array.from({ length: PARTICLE_COUNT }, (_, i) => {
50
- const seed = i + 1;
51
- const angle = i / PARTICLE_COUNT * Math.PI * 2;
52
- const forceFactor = 0.75 + seededRandom(seed * 1) * 0.5;
53
- const durationFactor = 1.1 + seededRandom(seed * 3) * 0.6;
54
- const color = allColors[i % allColors.length];
55
- const isCircle = seededRandom(seed * 4) > 0.85;
56
- const startRot = seededRandom(seed * 5) * 360;
57
- const rotSpeed = (seededRandom(seed * 6) - 0.5) * 1440;
58
- const flipSpeed = 3 + seededRandom(seed * 7) * 4;
59
- const flipPhase = seededRandom(seed * 8) * Math.PI * 2;
60
- const widthFactor = 0.45 + seededRandom(seed * 9) * 0.6;
61
- const heightFactor = 0.7 + seededRandom(seed * 10) * 0.6;
62
- const timing = getCelebrationParticleTiming(progress, i, durationFactor);
63
- if (!timing) return null;
64
- const p = timing.progress;
65
- const reach = BURST_RADIUS * forceFactor;
66
- const radialP = easeOutQuad(p);
67
- const gravity = height * 0.08 * p * p;
68
- const x = width * 0.5 + Math.cos(angle) * reach * radialP;
69
- const y = height * 0.5 + Math.sin(angle) * reach * radialP + gravity;
70
- const flip = Math.cos(p * Math.PI * flipSpeed + flipPhase);
71
- const rot = startRot + rotSpeed * p;
72
- const baseSize = (8 + seededRandom(seed * 11) * 10) * s;
73
- const w = baseSize * widthFactor;
74
- const h = isCircle ? w : baseSize * heightFactor;
75
- const popScale = Math.min(1, p * 30);
76
- const particleOpacity = p < 0.85 ? 1 : Math.max(0, 1 - (p - 0.85) / 0.15);
77
- const opacity = particleOpacity * timing.opacity;
78
- const beatPulse = 1 + beatIntensity * 0.15;
79
- if (opacity <= 0) return null;
80
- if (y > height + 120 || y < -120 || x < -120 || x > width + 120) return null;
81
- return /* @__PURE__ */ jsx(
82
- "div",
83
- {
84
- style: {
85
- position: "absolute",
86
- left: x - w / 2,
87
- top: y - h / 2,
88
- width: w,
89
- height: h,
90
- borderRadius: isCircle ? "50%" : 1,
91
- backgroundColor: color,
92
- opacity,
93
- transform: `rotate(${rot}deg) scaleX(${flip}) scale(${popScale * beatPulse})`,
94
- pointerEvents: "none"
95
- }
96
- },
97
- i
98
- );
99
- }) });
100
- };
101
-
102
- export {
103
- ConfettiLayer
104
- };
@@ -1,185 +0,0 @@
1
- import {
2
- getBackgroundTransform
3
- } from "./chunk-W3VDIBGR.js";
4
- import {
5
- useMediaAudio
6
- } from "./chunk-5CDAM24P.js";
7
-
8
- // src/visual-system/scene-templates/scene-video-backdrop.tsx
9
- import { useEffect, useRef, useState } from "react";
10
-
11
- // src/visual-system/scene-templates/media-position.ts
12
- var MEDIA_POSITIONS = {
13
- center: "center center",
14
- top: "center top",
15
- bottom: "center bottom",
16
- left: "left center",
17
- right: "right center"
18
- };
19
- function resolveMediaPosition(value) {
20
- return MEDIA_POSITIONS[value] ?? MEDIA_POSITIONS.center;
21
- }
22
-
23
- // src/visual-system/scene-templates/scene-video-backdrop.tsx
24
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
25
- var SceneVideoBackdrop = ({
26
- mediaUrl,
27
- mediaPoster,
28
- mediaPosition = "center",
29
- backgroundEffect,
30
- progress,
31
- beatIntensity = 0,
32
- isPlaying,
33
- muted,
34
- volume,
35
- playbackId = mediaUrl,
36
- retainPoster = false,
37
- persistent = false,
38
- preparedPoster,
39
- onReady,
40
- onError
41
- }) => {
42
- const inheritedAudio = useMediaAudio();
43
- const resolvedMuted = muted ?? inheritedAudio.muted;
44
- const resolvedVolume = volume ?? inheritedAudio.volume;
45
- const resolvedPosition = resolveMediaPosition(mediaPosition);
46
- const bgTransform = getBackgroundTransform(backgroundEffect, progress, beatIntensity);
47
- const [decodedVideoUrl, setDecodedVideoUrl] = useState();
48
- const videoRef = useRef(null);
49
- const startedVideoUrl = useRef(void 0);
50
- const startedPlaybackId = useRef(void 0);
51
- const videoPresentationKey = `${playbackId}\0${mediaUrl}`;
52
- useEffect(() => {
53
- const video = videoRef.current;
54
- if (!video) return;
55
- if (video.getAttribute("src") !== mediaUrl) {
56
- video.setAttribute("src", mediaUrl);
57
- video.load();
58
- }
59
- return () => {
60
- video.pause();
61
- video.removeAttribute("src");
62
- video.load();
63
- startedVideoUrl.current = void 0;
64
- startedPlaybackId.current = void 0;
65
- };
66
- }, [mediaUrl]);
67
- useEffect(() => {
68
- const video = videoRef.current;
69
- if (video) video.volume = resolvedVolume;
70
- }, [resolvedVolume]);
71
- useEffect(() => {
72
- const video = videoRef.current;
73
- if (!video) return;
74
- if (!isPlaying) {
75
- video.pause();
76
- startedVideoUrl.current = void 0;
77
- startedPlaybackId.current = void 0;
78
- return;
79
- }
80
- if (startedPlaybackId.current === playbackId) return;
81
- const changingSource = startedVideoUrl.current !== void 0 && startedVideoUrl.current !== mediaUrl;
82
- video.playbackRate = 1;
83
- if (!changingSource && video.currentTime > 0) video.currentTime = 0;
84
- video.play().catch(() => {
85
- });
86
- startedVideoUrl.current = mediaUrl;
87
- startedPlaybackId.current = playbackId;
88
- }, [isPlaying, mediaUrl, playbackId]);
89
- const mediaStyle = {
90
- position: "absolute",
91
- inset: 0,
92
- width: "100%",
93
- height: "100%",
94
- objectFit: "cover",
95
- objectPosition: resolvedPosition,
96
- transform: bgTransform.transform,
97
- transformOrigin: bgTransform.transformOrigin,
98
- zIndex: persistent ? 1 : void 0
99
- };
100
- const preparedPosition = preparedPoster ? resolveMediaPosition(preparedPoster.mediaPosition) : resolvedPosition;
101
- const preparedTransform = getBackgroundTransform(preparedPoster?.backgroundEffect, 0, 0);
102
- const posterPlanes = [
103
- ...persistent && mediaPoster ? [{
104
- presentationKey: videoPresentationKey,
105
- mediaPoster,
106
- mediaPosition: resolvedPosition,
107
- transform: bgTransform.transform,
108
- transformOrigin: bgTransform.transformOrigin,
109
- opacity: 1,
110
- zIndex: 0,
111
- role: "current"
112
- }] : [],
113
- ...preparedPoster && preparedPoster.presentationKey !== videoPresentationKey ? [{
114
- presentationKey: preparedPoster.presentationKey,
115
- mediaPoster: preparedPoster.mediaPoster,
116
- mediaPosition: preparedPosition,
117
- transform: preparedTransform.transform,
118
- transformOrigin: preparedTransform.transformOrigin,
119
- opacity: preparedPoster.opacity ?? 0,
120
- zIndex: 2,
121
- role: "prepared"
122
- }] : []
123
- ];
124
- return /* @__PURE__ */ jsxs(Fragment, { children: [
125
- posterPlanes.map((posterPlane) => /* @__PURE__ */ jsx(
126
- "img",
127
- {
128
- src: posterPlane.mediaPoster,
129
- alt: "",
130
- "aria-hidden": "true",
131
- draggable: false,
132
- "data-video-poster-plane": posterPlane.role,
133
- "data-video-poster-visible": posterPlane.opacity > 0 ? "true" : "false",
134
- style: {
135
- position: "absolute",
136
- inset: 0,
137
- width: "100%",
138
- height: "100%",
139
- objectFit: "cover",
140
- objectPosition: posterPlane.mediaPosition,
141
- transform: posterPlane.transform,
142
- transformOrigin: posterPlane.transformOrigin,
143
- zIndex: posterPlane.zIndex,
144
- opacity: posterPlane.opacity,
145
- pointerEvents: "none"
146
- }
147
- },
148
- posterPlane.presentationKey
149
- )),
150
- /* @__PURE__ */ jsx(
151
- "video",
152
- {
153
- ref: videoRef,
154
- src: mediaUrl,
155
- poster: retainPoster || decodedVideoUrl !== mediaUrl ? mediaPoster || void 0 : void 0,
156
- muted: resolvedMuted,
157
- loop: true,
158
- playsInline: true,
159
- preload: "auto",
160
- onLoadedData: (event) => {
161
- const video = event.currentTarget;
162
- const markPresented = () => {
163
- if (!video.isConnected) return;
164
- onReady?.();
165
- if (!retainPoster) setDecodedVideoUrl(mediaUrl);
166
- };
167
- if (video.requestVideoFrameCallback) {
168
- video.requestVideoFrameCallback(markPresented);
169
- return;
170
- }
171
- markPresented();
172
- },
173
- onError,
174
- "data-media-position": mediaPosition,
175
- "data-video-backdrop": persistent ? "persistent" : "scene",
176
- style: mediaStyle
177
- }
178
- )
179
- ] });
180
- };
181
-
182
- export {
183
- resolveMediaPosition,
184
- SceneVideoBackdrop
185
- };
@@ -1,336 +0,0 @@
1
- import {
2
- stripPipe
3
- } from "./chunk-S7HFLYNN.js";
4
- import {
5
- renderWithEmoji
6
- } from "./chunk-L5BTTCZV.js";
7
- import {
8
- SPRING_SMOOTH,
9
- interpolate,
10
- spring
11
- } from "./chunk-XTOXFMLM.js";
12
- import {
13
- TOKEN_DEFAULTS
14
- } from "./chunk-XWWLKRNU.js";
15
-
16
- // src/visual-system/primitives/devices/product-surface-config.ts
17
- function resolveProductSurfaceMotion(value) {
18
- return value === "still" || value === "pan" ? value : "pushIn";
19
- }
20
-
21
- // src/visual-system/primitives/devices/DesignedScreenFill.tsx
22
- import { jsx, jsxs } from "react/jsx-runtime";
23
- function parseHex(hex) {
24
- const m = String(hex).match(/^#([0-9a-f]{3,8})$/i);
25
- if (!m) return null;
26
- const h = m[1];
27
- if (h.length === 3) {
28
- return [parseInt(h[0] + h[0], 16), parseInt(h[1] + h[1], 16), parseInt(h[2] + h[2], 16)];
29
- }
30
- if (h.length >= 6) {
31
- return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
32
- }
33
- return null;
34
- }
35
- function rgba(hex, a) {
36
- const p = parseHex(hex);
37
- if (!p) return hex;
38
- return `rgba(${p[0]},${p[1]},${p[2]},${a})`;
39
- }
40
- function isDark(hex) {
41
- const p = parseHex(hex);
42
- if (!p) return false;
43
- const [r, g, b] = p;
44
- return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255 < 0.5;
45
- }
46
- function surface(bg) {
47
- const dark = bg ? isDark(bg) : false;
48
- return dark ? {
49
- dark,
50
- page: "#15171c",
51
- panel: "#1e2128",
52
- line: "rgba(255,255,255,0.07)",
53
- block: "rgba(255,255,255,0.10)",
54
- blockSoft: "rgba(255,255,255,0.055)"
55
- } : {
56
- dark,
57
- page: "#f5f6f8",
58
- panel: "#ffffff",
59
- line: "rgba(15,20,30,0.07)",
60
- block: "rgba(15,20,30,0.10)",
61
- blockSoft: "rgba(15,20,30,0.05)"
62
- };
63
- }
64
- var stroke = (s, c) => `${Math.max(1, Math.round(1 * s))}px solid ${c}`;
65
- var WebScreenFill = ({ accent, secondary, bg, font, s, w, h, progress }) => {
66
- const c = surface(bg);
67
- const pad = Math.round(h * 0.055);
68
- const headerH = Math.round(h * 0.13);
69
- const sidebarW = Math.round(w * 0.18);
70
- const grow = interpolate(progress, [0.1, 0.7], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
71
- const bars = [0.55, 0.78, 0.4, 0.92, 0.66, 0.84, 0.5];
72
- const chartH = h - headerH - pad * 2 - Math.round(h * 0.22) - Math.round(h * 0.04);
73
- const card = (i) => {
74
- const tint = [accent, secondary, accent][i % 3];
75
- return /* @__PURE__ */ jsxs(
76
- "div",
77
- {
78
- style: {
79
- flex: 1,
80
- height: Math.round(h * 0.22),
81
- backgroundColor: c.panel,
82
- borderRadius: Math.round(12 * s),
83
- border: stroke(s, c.line),
84
- padding: Math.round(h * 0.03),
85
- display: "flex",
86
- flexDirection: "column",
87
- justifyContent: "space-between",
88
- boxSizing: "border-box"
89
- },
90
- children: [
91
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: Math.round(8 * s) }, children: [
92
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(h * 0.05), height: Math.round(h * 0.05), borderRadius: Math.round(7 * s), backgroundColor: rgba(tint, c.dark ? 0.28 : 0.16) } }),
93
- /* @__PURE__ */ jsx("div", { style: { width: "42%", height: Math.round(h * 0.018), borderRadius: 99, backgroundColor: c.blockSoft } })
94
- ] }),
95
- /* @__PURE__ */ jsx("div", { style: { width: "62%", height: Math.round(h * 0.05), borderRadius: Math.round(5 * s), backgroundColor: c.block } }),
96
- /* @__PURE__ */ jsx("div", { style: { width: "34%", height: Math.round(h * 0.016), borderRadius: 99, backgroundColor: rgba(tint, c.dark ? 0.7 : 0.55) } })
97
- ]
98
- },
99
- i
100
- );
101
- };
102
- return /* @__PURE__ */ jsxs("div", { style: { width: "100%", height: "100%", backgroundColor: c.page, fontFamily: font, display: "flex", flexDirection: "column", boxSizing: "border-box", overflow: "hidden" }, children: [
103
- /* @__PURE__ */ jsxs(
104
- "div",
105
- {
106
- style: {
107
- height: headerH,
108
- backgroundColor: accent,
109
- display: "flex",
110
- alignItems: "center",
111
- paddingLeft: pad,
112
- paddingRight: pad,
113
- gap: Math.round(10 * s),
114
- flexShrink: 0
115
- },
116
- children: [
117
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(h * 0.05), height: Math.round(h * 0.05), borderRadius: Math.round(8 * s), backgroundColor: "rgba(255,255,255,0.92)" } }),
118
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(w * 0.18), height: Math.round(h * 0.022), borderRadius: 99, backgroundColor: "rgba(255,255,255,0.85)" } }),
119
- /* @__PURE__ */ jsx("div", { style: { flex: 1 } }),
120
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(w * 0.1), height: Math.round(h * 0.04), borderRadius: 99, backgroundColor: "rgba(255,255,255,0.22)" } }),
121
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(h * 0.06), height: Math.round(h * 0.06), borderRadius: "50%", backgroundColor: "rgba(255,255,255,0.85)" } })
122
- ]
123
- }
124
- ),
125
- /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", minHeight: 0 }, children: [
126
- /* @__PURE__ */ jsx("div", { style: { width: sidebarW, backgroundColor: c.panel, borderRight: stroke(s, c.line), padding: pad, display: "flex", flexDirection: "column", gap: Math.round(h * 0.028), boxSizing: "border-box", flexShrink: 0 }, children: [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: Math.round(8 * s) }, children: [
127
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(h * 0.032), height: Math.round(h * 0.032), borderRadius: Math.round(5 * s), backgroundColor: i === 0 ? accent : c.block } }),
128
- /* @__PURE__ */ jsx("div", { style: { flex: 1, height: Math.round(h * 0.016), borderRadius: 99, backgroundColor: i === 0 ? rgba(accent, 0.55) : c.blockSoft } })
129
- ] }, i)) }),
130
- /* @__PURE__ */ jsxs("div", { style: { flex: 1, padding: pad, display: "flex", flexDirection: "column", gap: pad, minWidth: 0, boxSizing: "border-box" }, children: [
131
- /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: pad }, children: [0, 1, 2].map(card) }),
132
- /* @__PURE__ */ jsxs("div", { style: { flex: 1, backgroundColor: c.panel, borderRadius: Math.round(12 * s), border: stroke(s, c.line), padding: Math.round(h * 0.03), display: "flex", flexDirection: "column", boxSizing: "border-box", minHeight: 0 }, children: [
133
- /* @__PURE__ */ jsx("div", { style: { width: "30%", height: Math.round(h * 0.02), borderRadius: 99, backgroundColor: c.block, marginBottom: Math.round(h * 0.03) } }),
134
- /* @__PURE__ */ jsx("div", { style: { flex: 1, display: "flex", alignItems: "flex-end", gap: Math.round(w * 0.018), minHeight: 0 }, children: bars.map((bh, i) => /* @__PURE__ */ jsx("div", { style: { flex: 1, height: Math.max(2, Math.round(chartH * bh * grow)), borderRadius: Math.round(4 * s), backgroundColor: i % 2 === 0 ? accent : rgba(secondary, c.dark ? 0.85 : 0.7) } }, i)) })
135
- ] })
136
- ] })
137
- ] })
138
- ] });
139
- };
140
- var PhoneScreenFill = ({ accent, secondary, bg, font, s, w, h, progress }) => {
141
- const c = surface(bg);
142
- const pad = Math.round(w * 0.07);
143
- const statusH = Math.round(h * 0.04);
144
- const headerH = Math.round(h * 0.14);
145
- const grow = interpolate(progress, [0.12, 0.7], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
146
- const onAccent = "rgba(255,255,255,";
147
- const listItem = (i) => {
148
- const tint = [accent, secondary][i % 2];
149
- return /* @__PURE__ */ jsxs(
150
- "div",
151
- {
152
- style: {
153
- backgroundColor: c.panel,
154
- borderRadius: Math.round(16 * s),
155
- border: stroke(s, c.line),
156
- padding: Math.round(w * 0.05),
157
- display: "flex",
158
- alignItems: "center",
159
- gap: Math.round(w * 0.045),
160
- boxSizing: "border-box"
161
- },
162
- children: [
163
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(w * 0.13), height: Math.round(w * 0.13), borderRadius: Math.round(12 * s), backgroundColor: rgba(tint, c.dark ? 0.3 : 0.18), flexShrink: 0 } }),
164
- /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", gap: Math.round(h * 0.012) }, children: [
165
- /* @__PURE__ */ jsx("div", { style: { width: `${70 - i * 8}%`, height: Math.round(h * 0.018), borderRadius: 99, backgroundColor: c.block } }),
166
- /* @__PURE__ */ jsx("div", { style: { width: `${48 - i * 4}%`, height: Math.round(h * 0.014), borderRadius: 99, backgroundColor: c.blockSoft } })
167
- ] }),
168
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(w * 0.12), height: Math.round(h * 0.026), borderRadius: 99, backgroundColor: rgba(tint, c.dark ? 0.6 : 0.5) } })
169
- ]
170
- },
171
- i
172
- );
173
- };
174
- return /* @__PURE__ */ jsxs("div", { style: { width: "100%", height: "100%", backgroundColor: c.page, fontFamily: font, display: "flex", flexDirection: "column", boxSizing: "border-box", overflow: "hidden" }, children: [
175
- /* @__PURE__ */ jsxs("div", { style: { height: statusH, display: "flex", alignItems: "center", justifyContent: "space-between", paddingLeft: pad, paddingRight: pad, flexShrink: 0 }, children: [
176
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(w * 0.1), height: Math.round(h * 0.012), borderRadius: 99, backgroundColor: c.block } }),
177
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: Math.round(4 * s) }, children: [
178
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(w * 0.04), height: Math.round(h * 0.012), borderRadius: 2, backgroundColor: c.block } }),
179
- /* @__PURE__ */ jsx("div", { style: { width: Math.round(w * 0.03), height: Math.round(h * 0.012), borderRadius: 2, backgroundColor: c.block } })
180
- ] })
181
- ] }),
182
- /* @__PURE__ */ jsxs("div", { style: { height: headerH, backgroundColor: accent, padding: pad, display: "flex", flexDirection: "column", justifyContent: "center", gap: Math.round(h * 0.018), flexShrink: 0 }, children: [
183
- /* @__PURE__ */ jsx("div", { style: { width: "44%", height: Math.round(h * 0.02), borderRadius: 99, backgroundColor: `${onAccent}0.5)` } }),
184
- /* @__PURE__ */ jsx("div", { style: { width: "70%", height: Math.round(h * 0.032), borderRadius: Math.round(5 * s), backgroundColor: `${onAccent}0.92)` } })
185
- ] }),
186
- /* @__PURE__ */ jsx("div", { style: { padding: pad, paddingBottom: 0 }, children: /* @__PURE__ */ jsxs("div", { style: { backgroundColor: c.panel, borderRadius: Math.round(16 * s), border: stroke(s, c.line), padding: Math.round(w * 0.05), display: "flex", flexDirection: "column", gap: Math.round(h * 0.018), boxSizing: "border-box" }, children: [
187
- /* @__PURE__ */ jsx("div", { style: { width: "50%", height: Math.round(h * 0.016), borderRadius: 99, backgroundColor: c.blockSoft } }),
188
- /* @__PURE__ */ jsx("div", { style: { width: "100%", height: Math.round(h * 0.012), borderRadius: 99, backgroundColor: c.blockSoft, position: "relative", overflow: "hidden" }, children: /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, width: `${Math.round(grow * 72)}%`, borderRadius: 99, backgroundColor: accent } }) })
189
- ] }) }),
190
- /* @__PURE__ */ jsx("div", { style: { flex: 1, padding: pad, display: "flex", flexDirection: "column", gap: Math.round(h * 0.018), minHeight: 0 }, children: [0, 1, 2, 3].map(listItem) }),
191
- /* @__PURE__ */ jsx("div", { style: { height: Math.round(h * 0.075), backgroundColor: c.panel, borderTop: stroke(s, c.line), display: "flex", alignItems: "center", justifyContent: "space-around", flexShrink: 0 }, children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsx("div", { style: { width: Math.round(w * 0.06), height: Math.round(w * 0.06), borderRadius: Math.round(7 * s), backgroundColor: i === 0 ? accent : c.block } }, i)) })
192
- ] });
193
- };
194
-
195
- // src/visual-system/primitives/devices/ProductSurface.tsx
196
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
197
- function clampPercent(value, fallback) {
198
- if (!Number.isFinite(value)) return fallback;
199
- return Math.min(100, Math.max(0, value));
200
- }
201
- var ProductSurface = ({
202
- mediaUrl = "",
203
- progress,
204
- width,
205
- height,
206
- fit = "cover",
207
- focusX = 50,
208
- focusY = 50,
209
- motion = "pushIn",
210
- calloutText = "",
211
- calloutX = 70,
212
- calloutY = 35,
213
- accent = TOKEN_DEFAULTS.primary,
214
- font = TOKEN_DEFAULTS.font,
215
- placeholder
216
- }) => {
217
- const resolvedFit = fit === "contain" ? "contain" : "cover";
218
- const resolvedMotion = resolveProductSurfaceMotion(motion);
219
- const resolvedFocusX = clampPercent(Number(focusX), 50);
220
- const resolvedFocusY = clampPercent(Number(focusY), 50);
221
- const resolvedCalloutX = clampPercent(Number(calloutX), 70);
222
- const resolvedCalloutY = clampPercent(Number(calloutY), 35);
223
- const cleanCallout = stripPipe(String(calloutText || "")).trim();
224
- const s = Math.min(width, height) / 1080;
225
- const cameraProgress = interpolate(progress, [0.12, 0.94], [0, 1], {
226
- extrapolateLeft: "clamp",
227
- extrapolateRight: "clamp"
228
- });
229
- const cameraTransform = resolvedMotion === "pushIn" ? `scale(${1 + cameraProgress * 0.06})` : resolvedMotion === "pan" ? `translateX(${2.5 - cameraProgress * 5}%) scale(1.08)` : "none";
230
- const calloutProgress = spring(
231
- interpolate(progress, [0.42, 0.62], [0, 1], {
232
- extrapolateLeft: "clamp",
233
- extrapolateRight: "clamp"
234
- }),
235
- SPRING_SMOOTH
236
- );
237
- const calloutPointsLeft = resolvedCalloutX > 58;
238
- const calloutFontSize = Math.max(18, 36 * s);
239
- const dotSize = Math.max(11, 22 * s);
240
- const labelOffset = Math.max(18, 34 * s);
241
- return /* @__PURE__ */ jsxs2(
242
- "div",
243
- {
244
- "data-product-surface": "true",
245
- "data-camera-motion": resolvedMotion,
246
- style: {
247
- position: "absolute",
248
- inset: 0,
249
- overflow: "hidden",
250
- backgroundColor: "#0b1020"
251
- },
252
- children: [
253
- mediaUrl ? /* @__PURE__ */ jsx2(
254
- "img",
255
- {
256
- src: mediaUrl,
257
- alt: "",
258
- style: {
259
- position: "absolute",
260
- inset: 0,
261
- width: "100%",
262
- height: "100%",
263
- display: "block",
264
- objectFit: resolvedFit,
265
- objectPosition: `${resolvedFocusX}% ${resolvedFocusY}%`,
266
- transform: cameraTransform,
267
- transformOrigin: `${resolvedFocusX}% ${resolvedFocusY}%`
268
- }
269
- }
270
- ) : placeholder ?? null,
271
- mediaUrl && cleanCallout ? /* @__PURE__ */ jsxs2(
272
- "div",
273
- {
274
- style: {
275
- position: "absolute",
276
- left: `${resolvedCalloutX}%`,
277
- top: `${resolvedCalloutY}%`,
278
- opacity: calloutProgress,
279
- transform: `translate(-50%, -50%) scale(${0.82 + calloutProgress * 0.18})`,
280
- transformOrigin: "center",
281
- pointerEvents: "none",
282
- zIndex: 2
283
- },
284
- children: [
285
- /* @__PURE__ */ jsx2(
286
- "div",
287
- {
288
- style: {
289
- width: dotSize,
290
- height: dotSize,
291
- borderRadius: "50%",
292
- backgroundColor: accent,
293
- border: `${Math.max(2, 4 * s)}px solid #ffffff`,
294
- boxShadow: `0 0 0 ${Math.max(3, 8 * s)}px ${accent}55, 0 ${Math.max(4, 10 * s)}px ${Math.max(10, 26 * s)}px rgba(0,0,0,0.32)`
295
- }
296
- }
297
- ),
298
- /* @__PURE__ */ jsx2(
299
- "div",
300
- {
301
- style: {
302
- position: "absolute",
303
- top: "50%",
304
- ...calloutPointsLeft ? { right: labelOffset } : { left: labelOffset },
305
- transform: "translateY(-50%)",
306
- maxWidth: width * 0.48,
307
- padding: `${Math.max(5, 10 * s)}px ${Math.max(8, 16 * s)}px`,
308
- borderRadius: Math.max(7, 14 * s),
309
- backgroundColor: "rgba(7,10,18,0.82)",
310
- border: "1px solid rgba(255,255,255,0.22)",
311
- boxShadow: `0 ${Math.max(5, 12 * s)}px ${Math.max(14, 34 * s)}px rgba(0,0,0,0.28)`,
312
- color: "#ffffff",
313
- fontFamily: font,
314
- fontSize: calloutFontSize,
315
- fontWeight: 650,
316
- lineHeight: 1.05,
317
- letterSpacing: "-0.01em",
318
- whiteSpace: "nowrap"
319
- },
320
- children: renderWithEmoji(cleanCallout, calloutFontSize)
321
- }
322
- )
323
- ]
324
- }
325
- ) : null
326
- ]
327
- }
328
- );
329
- };
330
-
331
- export {
332
- WebScreenFill,
333
- PhoneScreenFill,
334
- resolveProductSurfaceMotion,
335
- ProductSurface
336
- };