@vanillaskyai/video 0.3.1 → 0.3.3

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 +42 -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-NKQ6JA3T.js +55 -0
  28. package/dist/{prompt-input-LOUCRXCY.js → prompt-input-XCQ6TS2L.js} +4 -3
  29. package/dist/react.js +81 -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-NKQ6JA3T.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,22 @@ 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
+ const unlocked = context.resume().catch(Boolean);
252
+ void import("./control-visibility-NQOWTKOQ.js").then(async (output) => {
253
+ await unlocked;
254
+ if (context.state !== "running") {
255
+ void context.close();
256
+ return;
257
+ }
258
+ output.default(audio, context);
259
+ }).catch(() => context.close());
260
+ };
244
261
  if (stream !== activeStream) {
245
262
  const autoStartReplacement = Boolean(playbackMode && stream && shouldAutoPlay && !reducedMotion);
246
263
  setActiveStream(stream);
@@ -269,12 +286,10 @@ function VideoPlayerRuntime({
269
286
  preference.addEventListener?.("change", handleChange);
270
287
  return () => preference.removeEventListener?.("change", handleChange);
271
288
  }, []);
272
- useEffect(() => setIsMuted(resolvedStartMuted), [resolvedStartMuted]);
273
289
  useEffect(() => {
274
- const updateFullscreen = () => setIsFullscreen(document.fullscreenElement === containerRef.current);
275
- document.addEventListener("fullscreenchange", updateFullscreen);
276
- return () => document.removeEventListener("fullscreenchange", updateFullscreen);
290
+ import("./control-visibility-NQOWTKOQ.js");
277
291
  }, []);
292
+ useEffect(() => setIsMuted(resolvedStartMuted), [resolvedStartMuted]);
278
293
  useEffect(() => {
279
294
  let cancelled = false;
280
295
  let started = false;
@@ -284,7 +299,10 @@ function VideoPlayerRuntime({
284
299
  setState(reset);
285
300
  setCurrentTime(0);
286
301
  if (video) {
287
- for (const scene of video.scenes) preloadBuiltinTemplate(scene.templateId);
302
+ for (const scene of video.scenes) {
303
+ preloadBuiltinTemplate(scene.templateId);
304
+ warmSceneMedia(scene.variables);
305
+ }
288
306
  return;
289
307
  }
290
308
  if (!stream) return;
@@ -331,7 +349,9 @@ function VideoPlayerRuntime({
331
349
  if (width != null) return;
332
350
  const container = containerRef.current;
333
351
  if (!container) return;
334
- const update = () => setObservedWidth(container.clientWidth);
352
+ const update = () => {
353
+ setObservedWidth(container.clientWidth);
354
+ };
335
355
  update();
336
356
  if (typeof ResizeObserver === "undefined") return;
337
357
  const observer = new ResizeObserver(update);
@@ -439,7 +459,8 @@ function VideoPlayerRuntime({
439
459
  return () => clearTimeout(timer);
440
460
  }, [startRequested, state.config?.audio?.volume, state.config?.scenes.length, state.status]);
441
461
  const streamOrientation = state.config?.orientation ?? "portrait";
442
- const responsiveWidth = width ?? observedWidth;
462
+ const isFullscreen = fullscreenMode !== "none";
463
+ const responsiveWidth = isFullscreen ? window.innerWidth : width ?? observedWidth;
443
464
  const orientation = orientationOverride === "auto" ? responsiveWidth > 0 ? responsiveWidth <= responsiveBreakpoint ? "portrait" : "landscape" : streamOrientation : orientationOverride ?? streamOrientation;
444
465
  const dimensions = getDimensions(orientation);
445
466
  const displayWidth = (width ?? observedWidth) || dimensions.width;
@@ -458,6 +479,7 @@ function VideoPlayerRuntime({
458
479
  const posterTime = firstSceneRange ? firstSceneRange.start + Math.max(0, firstSceneRange.end - firstSceneRange.start) * firstSceneHoldProgress : currentTime;
459
480
  const startPlayback = () => {
460
481
  setGenerationIntroComplete(true);
482
+ containerRef.current?.setAttribute("data-touch-controls", "false");
461
483
  const audio = audioRef.current;
462
484
  if (audio) {
463
485
  void audio.play().then(() => {
@@ -508,18 +530,16 @@ function VideoPlayerRuntime({
508
530
  if (isPlaying) setIsPlaying(false);
509
531
  else startPlayback();
510
532
  };
511
- const toggleFullscreen = async () => {
533
+ const toggleFullscreen = () => {
512
534
  const container = containerRef.current;
513
535
  if (!container) return;
514
- if (document.fullscreenElement === container) await document.exitFullscreen?.();
515
- else await container.requestFullscreen?.();
536
+ void import("./control-visibility-NQOWTKOQ.js").then((output) => output.togglePlayerFullscreen(container, setFullscreenMode));
516
537
  };
517
538
  const controlSize = Math.max(40, Math.min(52, Math.round(displayWidth * 0.15)));
518
539
  const controlInset = Math.max(10, Math.min(20, Math.round(displayWidth * 0.056)));
519
540
  const controlButtonStyle = {
520
541
  display: "inline-grid",
521
542
  placeItems: "center",
522
- flex: "0 0 auto",
523
543
  width: controlSize,
524
544
  height: controlSize,
525
545
  minWidth: controlSize,
@@ -568,6 +588,8 @@ function VideoPlayerRuntime({
568
588
  role: "region",
569
589
  "aria-label": ariaLabel,
570
590
  tabIndex: 0,
591
+ onClickCapture: primeSoundtrack,
592
+ onKeyDownCapture: primeSoundtrack,
571
593
  onKeyDown: (event) => {
572
594
  if (event.target === event.currentTarget && (event.key === " " || event.key === "Enter")) {
573
595
  event.preventDefault();
@@ -588,6 +610,7 @@ function VideoPlayerRuntime({
588
610
  "data-generation-intro-complete": generationIntroComplete,
589
611
  "data-audio-unlocked": audioUnlocked,
590
612
  "data-playback-mode": playbackMode ?? "custom",
613
+ "data-fullscreen": fullscreenMode,
591
614
  className,
592
615
  style: {
593
616
  width: width ?? "100%",
@@ -647,7 +670,8 @@ function VideoPlayerRuntime({
647
670
  playing: isPlaying,
648
671
  style: {
649
672
  position: "absolute",
650
- inset: 0,
673
+ left: 0,
674
+ top: 0,
651
675
  transform: `scale(${scale})`,
652
676
  transformOrigin: "top left"
653
677
  }
@@ -675,11 +699,13 @@ function VideoPlayerRuntime({
675
699
  {
676
700
  ref: audioRef,
677
701
  src: config.audio.audioUrl,
702
+ "data-v": config.audio.volume,
678
703
  autoPlay: isPlaying,
679
704
  muted: isMuted,
680
705
  preload: "auto",
681
706
  loop: state.status === "streaming" || introPlaying
682
- }
707
+ },
708
+ config.audio.audioUrl
683
709
  ) : null,
684
710
  ended ? /* @__PURE__ */ jsx(
685
711
  "div",
@@ -718,7 +744,6 @@ function VideoPlayerRuntime({
718
744
  "div",
719
745
  {
720
746
  "data-testid": "video-controls",
721
- "data-layout": "split",
722
747
  style: {
723
748
  position: "absolute",
724
749
  inset: 0,
@@ -1065,9 +1090,13 @@ function useVideo(options = {}) {
1065
1090
  credentials: currentOptions.credentials,
1066
1091
  fetcher: currentOptions.fetcher,
1067
1092
  onEvent: (_event, nextState) => {
1068
- if (_event.type === "scene.add" && !currentOptions.templates?.getTemplate(_event.data.scene.templateId)) {
1069
- preloadBuiltinTemplate(_event.data.scene.templateId);
1093
+ if (_event.type === "scene.add") {
1094
+ if (!currentOptions.templates?.getTemplate(_event.data.scene.templateId)) {
1095
+ preloadBuiltinTemplate(_event.data.scene.templateId);
1096
+ }
1070
1097
  }
1098
+ 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;
1099
+ if (backdrop) warmSceneMedia(backdrop);
1071
1100
  if (mounted.current && generation.current === currentGeneration) setState(nextState);
1072
1101
  }
1073
1102
  });
@@ -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.3 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.3/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.3 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.3/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.3",
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.3",
4
4
  "description": "Open-source video response SDK for personalized AI applications.",
5
5
  "keywords": [
6
6
  "generative-video",