@vanillaskyai/video 0.3.1 → 0.3.2

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 (70) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +3 -3
  3. package/dist/{bg-confetti-WNQXS7ZS.js → bg-confetti-KTHLUJPO.js} +3 -3
  4. package/dist/{bg-emoji-ETI47GLS.js → bg-emoji-AW7374DZ.js} +3 -3
  5. package/dist/{bg-media-SVUZAMGX.js → bg-media-KGYE6UVS.js} +9 -4
  6. package/dist/{brand-message-F3RD4P3P.js → brand-message-AY43ZQR2.js} +4 -3
  7. package/dist/{chart-bar-CNSC7BNK.js → chart-bar-Z42RDRQT.js} +8 -4
  8. package/dist/{chart-counter-MCRHKN77.js → chart-counter-X7NAOQ2C.js} +10 -5
  9. package/dist/{chart-progress-ring-RMI4A7ZK.js → chart-progress-ring-7NSNNHL4.js} +8 -4
  10. package/dist/check-runtime.js +2 -2
  11. package/dist/chunk-35LIYILY.js +25 -0
  12. package/dist/{chunk-IFOW65Z6.js → chunk-4AODC6MS.js} +76 -36
  13. package/dist/{chunk-FSG2PYWG.js → chunk-G5JPHBX7.js} +1 -1
  14. package/dist/{chunk-QTMHS7JD.js → chunk-HXSV6RHF.js} +1 -1
  15. package/dist/{chunk-ABZACD4G.js → chunk-IJM4B2ZN.js} +1 -1
  16. package/dist/{chunk-BCRUUJ6A.js → chunk-TCEHK2BW.js} +6 -2
  17. package/dist/{chunk-FNAEQ7QO.js → chunk-XWWLKRNU.js} +3 -1
  18. package/dist/control-visibility-NQOWTKOQ.js +258 -0
  19. package/dist/{cta-logo-SVA5GP2A.js → cta-logo-KNBLXUJU.js} +4 -3
  20. package/dist/{cta-media-E7VLLK42.js → cta-media-NY4ASBGG.js} +8 -4
  21. package/dist/{incoming-call-62MFZL3Z.js → incoming-call-KWOXLGJN.js} +4 -3
  22. package/dist/{infographic-before-after-AXCDAWND.js → infographic-before-after-OEM4DSTZ.js} +3 -3
  23. package/dist/{infographic-feature-list-GW5GUE6O.js → infographic-feature-list-ZZ25JRYQ.js} +8 -4
  24. package/dist/{infographic-problem-solution-7NURJANA.js → infographic-problem-solution-L3RLFDPE.js} +5 -4
  25. package/dist/{infographic-stat-row-J7IZR6ZN.js → infographic-stat-row-3OL3TNSH.js} +8 -4
  26. package/dist/{infographic-steps-VSZM6F5M.js → infographic-steps-LMBSW22P.js} +8 -4
  27. package/dist/preload-media-KIYBFYRH.js +30 -0
  28. package/dist/{prompt-input-LOUCRXCY.js → prompt-input-XCQ6TS2L.js} +4 -3
  29. package/dist/react.js +74 -52
  30. package/dist/{reaction-QG4CYZLQ.js → reaction-YL6YPGPB.js} +5 -4
  31. package/dist/{showcase-code-RUTFZR3H.js → showcase-code-EFVHRJUM.js} +8 -4
  32. package/dist/{showcase-phone-6CP6XEU5.js → showcase-phone-CTHXHEBT.js} +9 -5
  33. package/dist/{showcase-terminal-MGAEQWPR.js → showcase-terminal-XAMPADHN.js} +8 -4
  34. package/dist/{showcase-web-Y4W2HVRJ.js → showcase-web-LAKHYXSD.js} +9 -5
  35. package/dist/{social-milestone-XI2QE5BO.js → social-milestone-EOBEN7CX.js} +6 -4
  36. package/dist/{social-notification-2UOHQCUY.js → social-notification-MELRWIB6.js} +4 -3
  37. package/dist/{social-review-stack-FDYZGZTJ.js → social-review-stack-H3U437VT.js} +4 -3
  38. package/dist/{social-testimonial-OQ7N52GJ.js → social-testimonial-GNNMKMDD.js} +4 -3
  39. package/dist/{social-tweet-5OLCNPPC.js → social-tweet-PBUKKPT3.js} +4 -3
  40. package/docs/getting-started.md +2 -2
  41. package/docs/integrate-nextjs.md +2 -2
  42. package/examples/nextjs-quickstart/package.json +1 -1
  43. package/package.json +1 -1
  44. package/registry/items/barChart.json +9 -3
  45. package/registry/items/beforeAfter.json +1 -1
  46. package/registry/items/bigNumber.json +10 -4
  47. package/registry/items/brandMessage.json +7 -1
  48. package/registry/items/cardList.json +9 -3
  49. package/registry/items/codeEditor.json +9 -3
  50. package/registry/items/confetti.json +1 -1
  51. package/registry/items/ctaLogo.json +7 -1
  52. package/registry/items/ctaMedia.json +9 -3
  53. package/registry/items/emojiBurst.json +1 -1
  54. package/registry/items/incomingCall.json +7 -1
  55. package/registry/items/media.json +9 -3
  56. package/registry/items/milestone.json +8 -2
  57. package/registry/items/notification.json +7 -1
  58. package/registry/items/phoneMockup.json +9 -3
  59. package/registry/items/problemSolution.json +8 -2
  60. package/registry/items/progressRing.json +9 -3
  61. package/registry/items/promptInput.json +7 -1
  62. package/registry/items/reaction.json +8 -2
  63. package/registry/items/reviewStack.json +7 -1
  64. package/registry/items/steps.json +9 -3
  65. package/registry/items/terminal.json +9 -3
  66. package/registry/items/testimonial.json +7 -1
  67. package/registry/items/theme.json +1 -1
  68. package/registry/items/tripleStats.json +9 -3
  69. package/registry/items/tweet.json +7 -1
  70. package/registry/items/webMockup.json +9 -3
package/dist/react.js CHANGED
@@ -29,10 +29,10 @@ import "./chunk-2E6T633S.js";
29
29
  import {
30
30
  VideoFrame,
31
31
  getDimensions
32
- } from "./chunk-QTMHS7JD.js";
32
+ } from "./chunk-HXSV6RHF.js";
33
33
  import {
34
34
  fontStack
35
- } from "./chunk-FNAEQ7QO.js";
35
+ } from "./chunk-XWWLKRNU.js";
36
36
  import {
37
37
  getVideoDuration,
38
38
  resolveVideoTimeline
@@ -53,34 +53,34 @@ import { createElement } from "react";
53
53
 
54
54
  // src/visual-system/catalog/builtin-loaders.generated.ts
55
55
  var GENERATED_BUILTIN_TEMPLATE_LOADERS = {
56
- "media": () => import("./bg-media-SVUZAMGX.js").then((module) => ({ default: module.BgMediaTemplate })),
57
- "reaction": () => import("./reaction-QG4CYZLQ.js").then((module) => ({ default: module.ReactionTemplate })),
58
- "confetti": () => import("./bg-confetti-WNQXS7ZS.js").then((module) => ({ default: module.BgConfettiTemplate })),
59
- "emojiBurst": () => import("./bg-emoji-ETI47GLS.js").then((module) => ({ default: module.BgEmojiTemplate })),
60
- "bigNumber": () => import("./chart-counter-MCRHKN77.js").then((module) => ({ default: module.ChartCounterTemplate })),
61
- "barChart": () => import("./chart-bar-CNSC7BNK.js").then((module) => ({ default: module.ChartBarTemplate })),
62
- "progressRing": () => import("./chart-progress-ring-RMI4A7ZK.js").then((module) => ({ default: module.ChartProgressRingTemplate })),
63
- "phoneMockup": () => import("./showcase-phone-6CP6XEU5.js").then((module) => ({ default: module.ShowcasePhoneTemplate })),
64
- "webMockup": () => import("./showcase-web-Y4W2HVRJ.js").then((module) => ({ default: module.ShowcaseWebTemplate })),
65
- "codeEditor": () => import("./showcase-code-RUTFZR3H.js").then((module) => ({ default: module.ShowcaseCodeTemplate })),
66
- "terminal": () => import("./showcase-terminal-MGAEQWPR.js").then((module) => ({ default: module.ShowcaseTerminalTemplate })),
67
- "tweet": () => import("./social-tweet-5OLCNPPC.js").then((module) => ({ default: module.SocialTweetTemplate })),
68
- "notification": () => import("./social-notification-2UOHQCUY.js").then((module) => ({ default: module.SocialNotificationTemplate })),
56
+ "media": () => import("./bg-media-KGYE6UVS.js").then((module) => ({ default: module.BgMediaTemplate })),
57
+ "reaction": () => import("./reaction-YL6YPGPB.js").then((module) => ({ default: module.ReactionTemplate })),
58
+ "confetti": () => import("./bg-confetti-KTHLUJPO.js").then((module) => ({ default: module.BgConfettiTemplate })),
59
+ "emojiBurst": () => import("./bg-emoji-AW7374DZ.js").then((module) => ({ default: module.BgEmojiTemplate })),
60
+ "bigNumber": () => import("./chart-counter-X7NAOQ2C.js").then((module) => ({ default: module.ChartCounterTemplate })),
61
+ "barChart": () => import("./chart-bar-Z42RDRQT.js").then((module) => ({ default: module.ChartBarTemplate })),
62
+ "progressRing": () => import("./chart-progress-ring-7NSNNHL4.js").then((module) => ({ default: module.ChartProgressRingTemplate })),
63
+ "phoneMockup": () => import("./showcase-phone-CTHXHEBT.js").then((module) => ({ default: module.ShowcasePhoneTemplate })),
64
+ "webMockup": () => import("./showcase-web-LAKHYXSD.js").then((module) => ({ default: module.ShowcaseWebTemplate })),
65
+ "codeEditor": () => import("./showcase-code-EFVHRJUM.js").then((module) => ({ default: module.ShowcaseCodeTemplate })),
66
+ "terminal": () => import("./showcase-terminal-XAMPADHN.js").then((module) => ({ default: module.ShowcaseTerminalTemplate })),
67
+ "tweet": () => import("./social-tweet-PBUKKPT3.js").then((module) => ({ default: module.SocialTweetTemplate })),
68
+ "notification": () => import("./social-notification-MELRWIB6.js").then((module) => ({ default: module.SocialNotificationTemplate })),
69
69
  "chatMessenger": () => import("./social-conversation-75SD2637.js").then((module) => ({ default: module.SocialConversationTemplate })),
70
70
  "chatWhatsapp": () => import("./social-conversation-75SD2637.js").then((module) => ({ default: module.SocialConversationTemplate })),
71
- "milestone": () => import("./social-milestone-XI2QE5BO.js").then((module) => ({ default: module.SocialMilestoneTemplate })),
72
- "reviewStack": () => import("./social-review-stack-FDYZGZTJ.js").then((module) => ({ default: module.SocialReviewStackTemplate })),
73
- "testimonial": () => import("./social-testimonial-OQ7N52GJ.js").then((module) => ({ default: module.SocialTestimonialTemplate })),
74
- "incomingCall": () => import("./incoming-call-62MFZL3Z.js").then((module) => ({ default: module.IncomingCallTemplate })),
75
- "brandMessage": () => import("./brand-message-F3RD4P3P.js").then((module) => ({ default: module.BrandMessageTemplate })),
76
- "promptInput": () => import("./prompt-input-LOUCRXCY.js").then((module) => ({ default: module.PromptInputTemplate })),
77
- "beforeAfter": () => import("./infographic-before-after-AXCDAWND.js").then((module) => ({ default: module.InfographicBeforeAfterTemplate })),
78
- "tripleStats": () => import("./infographic-stat-row-J7IZR6ZN.js").then((module) => ({ default: module.InfographicStatRowTemplate })),
79
- "problemSolution": () => import("./infographic-problem-solution-7NURJANA.js").then((module) => ({ default: module.InfographicProblemSolutionTemplate })),
80
- "cardList": () => import("./infographic-feature-list-GW5GUE6O.js").then((module) => ({ default: module.InfographicFeatureListTemplate })),
81
- "steps": () => import("./infographic-steps-VSZM6F5M.js").then((module) => ({ default: module.InfographicStepsTemplate })),
82
- "ctaLogo": () => import("./cta-logo-SVA5GP2A.js").then((module) => ({ default: module.CtaLogoTemplate })),
83
- "ctaMedia": () => import("./cta-media-E7VLLK42.js").then((module) => ({ default: module.CtaMediaTemplate }))
71
+ "milestone": () => import("./social-milestone-EOBEN7CX.js").then((module) => ({ default: module.SocialMilestoneTemplate })),
72
+ "reviewStack": () => import("./social-review-stack-H3U437VT.js").then((module) => ({ default: module.SocialReviewStackTemplate })),
73
+ "testimonial": () => import("./social-testimonial-GNNMKMDD.js").then((module) => ({ default: module.SocialTestimonialTemplate })),
74
+ "incomingCall": () => import("./incoming-call-KWOXLGJN.js").then((module) => ({ default: module.IncomingCallTemplate })),
75
+ "brandMessage": () => import("./brand-message-AY43ZQR2.js").then((module) => ({ default: module.BrandMessageTemplate })),
76
+ "promptInput": () => import("./prompt-input-XCQ6TS2L.js").then((module) => ({ default: module.PromptInputTemplate })),
77
+ "beforeAfter": () => import("./infographic-before-after-OEM4DSTZ.js").then((module) => ({ default: module.InfographicBeforeAfterTemplate })),
78
+ "tripleStats": () => import("./infographic-stat-row-3OL3TNSH.js").then((module) => ({ default: module.InfographicStatRowTemplate })),
79
+ "problemSolution": () => import("./infographic-problem-solution-L3RLFDPE.js").then((module) => ({ default: module.InfographicProblemSolutionTemplate })),
80
+ "cardList": () => import("./infographic-feature-list-ZZ25JRYQ.js").then((module) => ({ default: module.InfographicFeatureListTemplate })),
81
+ "steps": () => import("./infographic-steps-LMBSW22P.js").then((module) => ({ default: module.InfographicStepsTemplate })),
82
+ "ctaLogo": () => import("./cta-logo-KNBLXUJU.js").then((module) => ({ default: module.CtaLogoTemplate })),
83
+ "ctaMedia": () => import("./cta-media-NY4ASBGG.js").then((module) => ({ default: module.CtaMediaTemplate }))
84
84
  };
85
85
 
86
86
  // src/visual-system/catalog/builtin.ts
@@ -142,6 +142,12 @@ function preloadBuiltinTemplate(id) {
142
142
  return preloadableById.get(id)?.preload();
143
143
  }
144
144
 
145
+ // src/player/warm-scene-media.ts
146
+ function warmSceneMedia(variables) {
147
+ void import("./preload-media-KIYBFYRH.js").then((module) => module.preloadSceneMedia(variables)).catch(() => {
148
+ });
149
+ }
150
+
145
151
  // src/player/video-player.tsx
146
152
  import { jsx, jsxs } from "react/jsx-runtime";
147
153
  var MINIMUM_GENERATION_INTRO_MS = 3e3;
@@ -161,18 +167,13 @@ function PlayerIcon({ name, size = 22 }) {
161
167
  stroke: "currentColor",
162
168
  strokeWidth: 2,
163
169
  strokeLinecap: "round",
164
- strokeLinejoin: "round",
165
- "aria-hidden": true,
166
- focusable: false
170
+ strokeLinejoin: "round"
167
171
  };
168
172
  if (name === "play") {
169
173
  return /* @__PURE__ */ jsx("svg", { ...shared, children: /* @__PURE__ */ jsx("path", { d: "M8 5v14l11-7z", fill: "currentColor", stroke: "none" }) });
170
174
  }
171
175
  if (name === "pause") {
172
- return /* @__PURE__ */ jsxs("svg", { ...shared, children: [
173
- /* @__PURE__ */ jsx("rect", { x: "7", y: "5", width: "3.5", height: "14", rx: "1", fill: "currentColor", stroke: "none" }),
174
- /* @__PURE__ */ jsx("rect", { x: "13.5", y: "5", width: "3.5", height: "14", rx: "1", fill: "currentColor", stroke: "none" })
175
- ] });
176
+ return /* @__PURE__ */ jsx("svg", { ...shared, children: /* @__PURE__ */ jsx("path", { d: "M7 5h4v14H7zm6 0h4v14h-4z", fill: "currentColor", stroke: "none" }) });
176
177
  }
177
178
  if (name === "replay") {
178
179
  return /* @__PURE__ */ jsxs("svg", { ...shared, children: [
@@ -223,7 +224,7 @@ function VideoPlayerRuntime({
223
224
  const autoStartGeneration = Boolean(playbackMode && stream && shouldAutoPlay && !reducedMotion);
224
225
  const [isPlaying, setIsPlaying] = useState(() => shouldAutoPlay && !reducedMotion && !autoStartGeneration);
225
226
  const [isMuted, setIsMuted] = useState(resolvedStartMuted);
226
- const [isFullscreen, setIsFullscreen] = useState(false);
227
+ const [fullscreenMode, setFullscreenMode] = useState("none");
227
228
  const [state, setState] = useState(() => video ? savedVideoState(video) : createVideoState());
228
229
  const [currentTime, setCurrentTime] = useState(0);
229
230
  const [activeStream, setActiveStream] = useState(stream);
@@ -241,6 +242,15 @@ function VideoPlayerRuntime({
241
242
  stateRef.current = state;
242
243
  timeRef.current = currentTime;
243
244
  callbacksRef.current = { onComplete, onError, onStateChange };
245
+ const primeSoundtrack = () => {
246
+ const audio = audioRef.current;
247
+ if (!audio || audio.dataset.audioOutput) return;
248
+ const Context = window.AudioContext ?? window.webkitAudioContext;
249
+ if (!Context) return;
250
+ const context = new Context();
251
+ context.resume().catch(Boolean);
252
+ import("./control-visibility-NQOWTKOQ.js").then((output) => output.default(audio, context)).catch(() => context.close());
253
+ };
244
254
  if (stream !== activeStream) {
245
255
  const autoStartReplacement = Boolean(playbackMode && stream && shouldAutoPlay && !reducedMotion);
246
256
  setActiveStream(stream);
@@ -269,12 +279,10 @@ function VideoPlayerRuntime({
269
279
  preference.addEventListener?.("change", handleChange);
270
280
  return () => preference.removeEventListener?.("change", handleChange);
271
281
  }, []);
272
- useEffect(() => setIsMuted(resolvedStartMuted), [resolvedStartMuted]);
273
282
  useEffect(() => {
274
- const updateFullscreen = () => setIsFullscreen(document.fullscreenElement === containerRef.current);
275
- document.addEventListener("fullscreenchange", updateFullscreen);
276
- return () => document.removeEventListener("fullscreenchange", updateFullscreen);
283
+ import("./control-visibility-NQOWTKOQ.js");
277
284
  }, []);
285
+ useEffect(() => setIsMuted(resolvedStartMuted), [resolvedStartMuted]);
278
286
  useEffect(() => {
279
287
  let cancelled = false;
280
288
  let started = false;
@@ -284,7 +292,10 @@ function VideoPlayerRuntime({
284
292
  setState(reset);
285
293
  setCurrentTime(0);
286
294
  if (video) {
287
- for (const scene of video.scenes) preloadBuiltinTemplate(scene.templateId);
295
+ for (const scene of video.scenes) {
296
+ preloadBuiltinTemplate(scene.templateId);
297
+ warmSceneMedia(scene.variables);
298
+ }
288
299
  return;
289
300
  }
290
301
  if (!stream) return;
@@ -331,7 +342,9 @@ function VideoPlayerRuntime({
331
342
  if (width != null) return;
332
343
  const container = containerRef.current;
333
344
  if (!container) return;
334
- const update = () => setObservedWidth(container.clientWidth);
345
+ const update = () => {
346
+ setObservedWidth(container.clientWidth);
347
+ };
335
348
  update();
336
349
  if (typeof ResizeObserver === "undefined") return;
337
350
  const observer = new ResizeObserver(update);
@@ -439,7 +452,8 @@ function VideoPlayerRuntime({
439
452
  return () => clearTimeout(timer);
440
453
  }, [startRequested, state.config?.audio?.volume, state.config?.scenes.length, state.status]);
441
454
  const streamOrientation = state.config?.orientation ?? "portrait";
442
- const responsiveWidth = width ?? observedWidth;
455
+ const isFullscreen = fullscreenMode !== "none";
456
+ const responsiveWidth = isFullscreen ? window.innerWidth : width ?? observedWidth;
443
457
  const orientation = orientationOverride === "auto" ? responsiveWidth > 0 ? responsiveWidth <= responsiveBreakpoint ? "portrait" : "landscape" : streamOrientation : orientationOverride ?? streamOrientation;
444
458
  const dimensions = getDimensions(orientation);
445
459
  const displayWidth = (width ?? observedWidth) || dimensions.width;
@@ -458,6 +472,7 @@ function VideoPlayerRuntime({
458
472
  const posterTime = firstSceneRange ? firstSceneRange.start + Math.max(0, firstSceneRange.end - firstSceneRange.start) * firstSceneHoldProgress : currentTime;
459
473
  const startPlayback = () => {
460
474
  setGenerationIntroComplete(true);
475
+ containerRef.current?.setAttribute("data-touch-controls", "false");
461
476
  const audio = audioRef.current;
462
477
  if (audio) {
463
478
  void audio.play().then(() => {
@@ -508,18 +523,16 @@ function VideoPlayerRuntime({
508
523
  if (isPlaying) setIsPlaying(false);
509
524
  else startPlayback();
510
525
  };
511
- const toggleFullscreen = async () => {
526
+ const toggleFullscreen = () => {
512
527
  const container = containerRef.current;
513
528
  if (!container) return;
514
- if (document.fullscreenElement === container) await document.exitFullscreen?.();
515
- else await container.requestFullscreen?.();
529
+ void import("./control-visibility-NQOWTKOQ.js").then((output) => output.togglePlayerFullscreen(container, setFullscreenMode));
516
530
  };
517
531
  const controlSize = Math.max(40, Math.min(52, Math.round(displayWidth * 0.15)));
518
532
  const controlInset = Math.max(10, Math.min(20, Math.round(displayWidth * 0.056)));
519
533
  const controlButtonStyle = {
520
534
  display: "inline-grid",
521
535
  placeItems: "center",
522
- flex: "0 0 auto",
523
536
  width: controlSize,
524
537
  height: controlSize,
525
538
  minWidth: controlSize,
@@ -568,6 +581,8 @@ function VideoPlayerRuntime({
568
581
  role: "region",
569
582
  "aria-label": ariaLabel,
570
583
  tabIndex: 0,
584
+ onClickCapture: primeSoundtrack,
585
+ onKeyDownCapture: primeSoundtrack,
571
586
  onKeyDown: (event) => {
572
587
  if (event.target === event.currentTarget && (event.key === " " || event.key === "Enter")) {
573
588
  event.preventDefault();
@@ -588,6 +603,7 @@ function VideoPlayerRuntime({
588
603
  "data-generation-intro-complete": generationIntroComplete,
589
604
  "data-audio-unlocked": audioUnlocked,
590
605
  "data-playback-mode": playbackMode ?? "custom",
606
+ "data-fullscreen": fullscreenMode,
591
607
  className,
592
608
  style: {
593
609
  width: width ?? "100%",
@@ -647,7 +663,8 @@ function VideoPlayerRuntime({
647
663
  playing: isPlaying,
648
664
  style: {
649
665
  position: "absolute",
650
- inset: 0,
666
+ left: 0,
667
+ top: 0,
651
668
  transform: `scale(${scale})`,
652
669
  transformOrigin: "top left"
653
670
  }
@@ -675,11 +692,13 @@ function VideoPlayerRuntime({
675
692
  {
676
693
  ref: audioRef,
677
694
  src: config.audio.audioUrl,
695
+ "data-v": config.audio.volume,
678
696
  autoPlay: isPlaying,
679
697
  muted: isMuted,
680
698
  preload: "auto",
681
699
  loop: state.status === "streaming" || introPlaying
682
- }
700
+ },
701
+ config.audio.audioUrl
683
702
  ) : null,
684
703
  ended ? /* @__PURE__ */ jsx(
685
704
  "div",
@@ -718,7 +737,6 @@ function VideoPlayerRuntime({
718
737
  "div",
719
738
  {
720
739
  "data-testid": "video-controls",
721
- "data-layout": "split",
722
740
  style: {
723
741
  position: "absolute",
724
742
  inset: 0,
@@ -1065,9 +1083,13 @@ function useVideo(options = {}) {
1065
1083
  credentials: currentOptions.credentials,
1066
1084
  fetcher: currentOptions.fetcher,
1067
1085
  onEvent: (_event, nextState) => {
1068
- if (_event.type === "scene.add" && !currentOptions.templates?.getTemplate(_event.data.scene.templateId)) {
1069
- preloadBuiltinTemplate(_event.data.scene.templateId);
1086
+ if (_event.type === "scene.add") {
1087
+ if (!currentOptions.templates?.getTemplate(_event.data.scene.templateId)) {
1088
+ preloadBuiltinTemplate(_event.data.scene.templateId);
1089
+ }
1070
1090
  }
1091
+ const backdrop = _event.type === "scene.add" ? _event.data.scene.variables : _event.type === "asset.patch" ? _event.data.variables : _event.type === "scene.patch" ? _event.data.patch.variables : void 0;
1092
+ if (backdrop) warmSceneMedia(backdrop);
1071
1093
  if (mounted.current && generation.current === currentGeneration) setState(nextState);
1072
1094
  }
1073
1095
  });
@@ -1,15 +1,16 @@
1
1
  import {
2
2
  SceneBackground
3
- } from "./chunk-IFOW65Z6.js";
3
+ } from "./chunk-4AODC6MS.js";
4
+ import "./chunk-35LIYILY.js";
4
5
  import {
5
6
  TemplateText
6
- } from "./chunk-BCRUUJ6A.js";
7
+ } from "./chunk-TCEHK2BW.js";
7
8
  import "./chunk-L5BTTCZV.js";
8
- import "./chunk-ABZACD4G.js";
9
+ import "./chunk-IJM4B2ZN.js";
9
10
  import "./chunk-XTOXFMLM.js";
10
11
  import {
11
12
  resolveTokens
12
- } from "./chunk-FNAEQ7QO.js";
13
+ } from "./chunk-XWWLKRNU.js";
13
14
 
14
15
  // src/visual-system/scene-templates/reaction.tsx
15
16
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -5,19 +5,22 @@ import {
5
5
  import {
6
6
  SceneBackground,
7
7
  getMediaBackgroundProps
8
- } from "./chunk-IFOW65Z6.js";
8
+ } from "./chunk-4AODC6MS.js";
9
+ import {
10
+ hasSceneMedia
11
+ } from "./chunk-35LIYILY.js";
9
12
  import {
10
13
  TemplateText
11
- } from "./chunk-BCRUUJ6A.js";
14
+ } from "./chunk-TCEHK2BW.js";
12
15
  import "./chunk-L5BTTCZV.js";
13
- import "./chunk-ABZACD4G.js";
16
+ import "./chunk-IJM4B2ZN.js";
14
17
  import {
15
18
  interpolate,
16
19
  spring
17
20
  } from "./chunk-XTOXFMLM.js";
18
21
  import {
19
22
  resolveTokens
20
- } from "./chunk-FNAEQ7QO.js";
23
+ } from "./chunk-XWWLKRNU.js";
21
24
 
22
25
  // src/visual-system/primitives/devices/CodeEditor.tsx
23
26
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -314,6 +317,7 @@ var ShowcaseCodeTemplate = ({
314
317
  /* @__PURE__ */ jsx2(
315
318
  TemplateText,
316
319
  {
320
+ overMedia: hasSceneMedia(variables),
317
321
  motionProgress,
318
322
  typeTreatment: resolveTokens(style).preset.type,
319
323
  archetype: "subtle",
@@ -2,17 +2,20 @@ import {
2
2
  PhoneScreenFill,
3
3
  ProductSurface,
4
4
  resolveProductSurfaceMotion
5
- } from "./chunk-FSG2PYWG.js";
5
+ } from "./chunk-G5JPHBX7.js";
6
6
  import "./chunk-S7HFLYNN.js";
7
7
  import {
8
8
  SceneBackground,
9
9
  getMediaBackgroundProps
10
- } from "./chunk-IFOW65Z6.js";
10
+ } from "./chunk-4AODC6MS.js";
11
+ import {
12
+ hasSceneMedia
13
+ } from "./chunk-35LIYILY.js";
11
14
  import {
12
15
  TemplateText
13
- } from "./chunk-BCRUUJ6A.js";
16
+ } from "./chunk-TCEHK2BW.js";
14
17
  import "./chunk-L5BTTCZV.js";
15
- import "./chunk-ABZACD4G.js";
18
+ import "./chunk-IJM4B2ZN.js";
16
19
  import {
17
20
  SPRING_SMOOTH,
18
21
  interpolate,
@@ -21,7 +24,7 @@ import {
21
24
  import {
22
25
  TOKEN_DEFAULTS,
23
26
  resolveTokens
24
- } from "./chunk-FNAEQ7QO.js";
27
+ } from "./chunk-XWWLKRNU.js";
25
28
 
26
29
  // src/visual-system/primitives/devices/PhoneFrame.tsx
27
30
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -224,6 +227,7 @@ var ShowcasePhoneTemplate = ({
224
227
  /* @__PURE__ */ jsx2(
225
228
  TemplateText,
226
229
  {
230
+ overMedia: hasSceneMedia(variables),
227
231
  motionProgress,
228
232
  typeTreatment: tokens.preset.type,
229
233
  archetype: textArchetype ?? "subtle",
@@ -7,12 +7,15 @@ import {
7
7
  import {
8
8
  SceneBackground,
9
9
  getMediaBackgroundProps
10
- } from "./chunk-IFOW65Z6.js";
10
+ } from "./chunk-4AODC6MS.js";
11
+ import {
12
+ hasSceneMedia
13
+ } from "./chunk-35LIYILY.js";
11
14
  import {
12
15
  TemplateText
13
- } from "./chunk-BCRUUJ6A.js";
16
+ } from "./chunk-TCEHK2BW.js";
14
17
  import "./chunk-L5BTTCZV.js";
15
- import "./chunk-ABZACD4G.js";
18
+ import "./chunk-IJM4B2ZN.js";
16
19
  import {
17
20
  interpolate,
18
21
  spring
@@ -20,7 +23,7 @@ import {
20
23
  import {
21
24
  TOKEN_DEFAULTS,
22
25
  resolveTokens
23
- } from "./chunk-FNAEQ7QO.js";
26
+ } from "./chunk-XWWLKRNU.js";
24
27
 
25
28
  // src/visual-system/primitives/devices/TerminalOutput.tsx
26
29
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -268,6 +271,7 @@ var ShowcaseTerminalTemplate = ({
268
271
  /* @__PURE__ */ jsx2(
269
272
  TemplateText,
270
273
  {
274
+ overMedia: hasSceneMedia(variables),
271
275
  motionProgress,
272
276
  typeTreatment: resolveTokens(style).preset.type,
273
277
  archetype: "subtle",
@@ -2,19 +2,22 @@ import {
2
2
  ProductSurface,
3
3
  WebScreenFill,
4
4
  resolveProductSurfaceMotion
5
- } from "./chunk-FSG2PYWG.js";
5
+ } from "./chunk-G5JPHBX7.js";
6
6
  import {
7
7
  stripPipe
8
8
  } from "./chunk-S7HFLYNN.js";
9
9
  import {
10
10
  SceneBackground,
11
11
  getMediaBackgroundProps
12
- } from "./chunk-IFOW65Z6.js";
12
+ } from "./chunk-4AODC6MS.js";
13
+ import {
14
+ hasSceneMedia
15
+ } from "./chunk-35LIYILY.js";
13
16
  import {
14
17
  TemplateText
15
- } from "./chunk-BCRUUJ6A.js";
18
+ } from "./chunk-TCEHK2BW.js";
16
19
  import "./chunk-L5BTTCZV.js";
17
- import "./chunk-ABZACD4G.js";
20
+ import "./chunk-IJM4B2ZN.js";
18
21
  import {
19
22
  SPRING_SMOOTH,
20
23
  interpolate,
@@ -23,7 +26,7 @@ import {
23
26
  import {
24
27
  TOKEN_DEFAULTS,
25
28
  resolveTokens
26
- } from "./chunk-FNAEQ7QO.js";
29
+ } from "./chunk-XWWLKRNU.js";
27
30
 
28
31
  // src/visual-system/primitives/devices/WebMockup.tsx
29
32
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -341,6 +344,7 @@ var ShowcaseWebTemplate = ({
341
344
  /* @__PURE__ */ jsx2(
342
345
  TemplateText,
343
346
  {
347
+ overMedia: hasSceneMedia(variables),
344
348
  motionProgress,
345
349
  typeTreatment: tokens.preset.type,
346
350
  archetype: textArchetype ?? "subtle",
@@ -4,7 +4,8 @@ import {
4
4
  import {
5
5
  SceneBackground,
6
6
  getMediaBackgroundProps
7
- } from "./chunk-IFOW65Z6.js";
7
+ } from "./chunk-4AODC6MS.js";
8
+ import "./chunk-35LIYILY.js";
8
9
  import {
9
10
  ConfettiLayer
10
11
  } from "./chunk-CJ7F2CE6.js";
@@ -16,7 +17,7 @@ import {
16
17
  import {
17
18
  accessibleTextColor,
18
19
  withOpacity
19
- } from "./chunk-ABZACD4G.js";
20
+ } from "./chunk-IJM4B2ZN.js";
20
21
  import {
21
22
  SPRING_BOUNCY,
22
23
  SPRING_SMOOTH,
@@ -24,9 +25,10 @@ import {
24
25
  spring
25
26
  } from "./chunk-XTOXFMLM.js";
26
27
  import {
28
+ MEDIA_TEXT_SHADOW,
27
29
  TOKEN_DEFAULTS,
28
30
  resolveTokens
29
- } from "./chunk-FNAEQ7QO.js";
31
+ } from "./chunk-XWWLKRNU.js";
30
32
 
31
33
  // src/visual-system/primitives/social/MilestoneBadge.tsx
32
34
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -60,7 +62,7 @@ var MilestoneBadge = ({
60
62
  const safeStart = startNumber != null && Number.isFinite(startNumber) ? startNumber : Math.max(0, Math.round(safeTarget * 0.98));
61
63
  const mainTextColor = hasMedia ? "#FFFFFF" : foreground;
62
64
  const pillTextColor = accessibleTextColor(surfaceElevated, foreground);
63
- const mediaTextShadow = hasMedia ? "0 2px 8px rgba(0,0,0,0.55), 0 6px 16px rgba(0,0,0,0.35)" : void 0;
65
+ const mediaTextShadow = hasMedia ? MEDIA_TEXT_SHADOW : void 0;
64
66
  const followerCount = Math.round(
65
67
  interpolate(progress, [0.056, 0.556], [safeStart, safeTarget], CLAMP)
66
68
  );
@@ -4,12 +4,13 @@ import {
4
4
  import {
5
5
  SceneBackground,
6
6
  getMediaBackgroundProps
7
- } from "./chunk-IFOW65Z6.js";
7
+ } from "./chunk-4AODC6MS.js";
8
+ import "./chunk-35LIYILY.js";
8
9
  import {
9
10
  Emoji,
10
11
  renderWithEmoji
11
12
  } from "./chunk-L5BTTCZV.js";
12
- import "./chunk-ABZACD4G.js";
13
+ import "./chunk-IJM4B2ZN.js";
13
14
  import {
14
15
  SPRING_SMOOTH,
15
16
  interpolate,
@@ -17,7 +18,7 @@ import {
17
18
  } from "./chunk-XTOXFMLM.js";
18
19
  import {
19
20
  resolveTokens
20
- } from "./chunk-FNAEQ7QO.js";
21
+ } from "./chunk-XWWLKRNU.js";
21
22
 
22
23
  // src/visual-system/primitives/social/NotificationCard.tsx
23
24
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -4,11 +4,12 @@ import {
4
4
  import {
5
5
  SceneBackground,
6
6
  getMediaBackgroundProps
7
- } from "./chunk-IFOW65Z6.js";
7
+ } from "./chunk-4AODC6MS.js";
8
+ import "./chunk-35LIYILY.js";
8
9
  import {
9
10
  accessibleTextColor,
10
11
  withOpacity
11
- } from "./chunk-ABZACD4G.js";
12
+ } from "./chunk-IJM4B2ZN.js";
12
13
  import {
13
14
  SPRING_SNAPPY,
14
15
  interpolate,
@@ -17,7 +18,7 @@ import {
17
18
  import {
18
19
  lighten,
19
20
  resolveTokens
20
- } from "./chunk-FNAEQ7QO.js";
21
+ } from "./chunk-XWWLKRNU.js";
21
22
 
22
23
  // src/visual-system/primitives/social/ReviewStack.tsx
23
24
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -4,12 +4,13 @@ import {
4
4
  import {
5
5
  SceneBackground,
6
6
  getMediaBackgroundProps
7
- } from "./chunk-IFOW65Z6.js";
7
+ } from "./chunk-4AODC6MS.js";
8
+ import "./chunk-35LIYILY.js";
8
9
  import {
9
10
  accessibleTextColor,
10
11
  autoTextColor,
11
12
  withOpacity
12
- } from "./chunk-ABZACD4G.js";
13
+ } from "./chunk-IJM4B2ZN.js";
13
14
  import {
14
15
  SPRING_SMOOTH,
15
16
  SPRING_SNAPPY,
@@ -20,7 +21,7 @@ import {
20
21
  TOKEN_DEFAULTS,
21
22
  lighten,
22
23
  resolveTokens
23
- } from "./chunk-FNAEQ7QO.js";
24
+ } from "./chunk-XWWLKRNU.js";
24
25
 
25
26
  // src/visual-system/primitives/social/TestimonialCard.tsx
26
27
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -4,13 +4,14 @@ import {
4
4
  import {
5
5
  SceneBackground,
6
6
  getMediaBackgroundProps
7
- } from "./chunk-IFOW65Z6.js";
7
+ } from "./chunk-4AODC6MS.js";
8
+ import "./chunk-35LIYILY.js";
8
9
  import {
9
10
  renderWithEmoji
10
11
  } from "./chunk-L5BTTCZV.js";
11
12
  import {
12
13
  autoTextColor
13
- } from "./chunk-ABZACD4G.js";
14
+ } from "./chunk-IJM4B2ZN.js";
14
15
  import {
15
16
  SPRING_SMOOTH,
16
17
  interpolate,
@@ -18,7 +19,7 @@ import {
18
19
  } from "./chunk-XTOXFMLM.js";
19
20
  import {
20
21
  resolveTokens
21
- } from "./chunk-FNAEQ7QO.js";
22
+ } from "./chunk-XWWLKRNU.js";
22
23
 
23
24
  // src/visual-system/primitives/social/TweetCard.tsx
24
25
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -5,7 +5,7 @@
5
5
  Install VanillaSky:
6
6
 
7
7
  ```bash
8
- npm install @vanillaskyai/video@0.3.1 ai @ai-sdk/openai
8
+ npm install @vanillaskyai/video@0.3.2 ai @ai-sdk/openai
9
9
  ```
10
10
 
11
11
  Set your provider key in `.env.local` (never commit it):
@@ -50,7 +50,7 @@ sets its marker only for `next dev`, and it accepts only localhost. Every
50
50
  production request is denied. Replace it with your real session validation
51
51
  before deploying. For literal files and commands,
52
52
  use the tested
53
- [`examples/nextjs-quickstart` directory](https://github.com/VanillaSkyAi/video/tree/v0.3.1/examples/nextjs-quickstart).
53
+ [`examples/nextjs-quickstart` directory](https://github.com/VanillaSkyAi/video/tree/v0.3.2/examples/nextjs-quickstart).
54
54
 
55
55
  `model` can come from any AI SDK provider, registry, gateway, compatible API,
56
56
  or custom implementation. The application can choose a cheaper or faster model
@@ -5,7 +5,7 @@
5
5
  Install VanillaSky and one AI SDK provider:
6
6
 
7
7
  ```bash
8
- npm install @vanillaskyai/video@0.3.1 ai @ai-sdk/openai
8
+ npm install @vanillaskyai/video@0.3.2 ai @ai-sdk/openai
9
9
  ```
10
10
 
11
11
  Create an ignored `.env.local`:
@@ -74,7 +74,7 @@ requests; replace it with your application's session validation before
74
74
  deploying.
75
75
 
76
76
  The copy-and-run app is in the
77
- [`examples/nextjs-quickstart` directory](https://github.com/VanillaSkyAi/video/tree/v0.3.1/examples/nextjs-quickstart).
77
+ [`examples/nextjs-quickstart` directory](https://github.com/VanillaSkyAi/video/tree/v0.3.2/examples/nextjs-quickstart).
78
78
 
79
79
  For another LLM, replace `openai(...)` with the matching AI SDK model. The route
80
80
  shape and React code stay the same. See [Provider integration](provider-integration.md)
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@ai-sdk/openai": "^4.0.42",
12
- "@vanillaskyai/video": "0.3.1",
12
+ "@vanillaskyai/video": "0.3.2",
13
13
  "ai": "^7.0.66",
14
14
  "next": "16.3.1",
15
15
  "react": "19.2.8",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanillaskyai/video",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Open-source video response SDK for personalized AI applications.",
5
5
  "keywords": [
6
6
  "generative-video",