@vanillaskyai/video 0.5.6 → 0.5.7

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 (67) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{bg-confetti-572VDSYM.js → bg-confetti-SHQI7ATB.js} +2 -2
  3. package/dist/{bg-emoji-T4IEJ6U2.js → bg-emoji-XYFRA63Q.js} +2 -2
  4. package/dist/{bg-media-2D5SQSJX.js → bg-media-FEBATBT2.js} +8 -6
  5. package/dist/{brand-message-2JCTRIGS.js → brand-message-P56WEJPG.js} +5 -3
  6. package/dist/{chart-bar-GAJMUB2E.js → chart-bar-ZB45ZRKH.js} +5 -3
  7. package/dist/{chart-counter-HYGBGXNX.js → chart-counter-HFYNE4HT.js} +8 -6
  8. package/dist/{chart-progress-ring-DUUVMJAJ.js → chart-progress-ring-ZKMLRGSB.js} +5 -3
  9. package/dist/check-runtime.js +3 -1
  10. package/dist/{chunk-CTEYFVUY.js → chunk-6M6DATLW.js} +26 -82
  11. package/dist/chunk-C6WVCZRW.js +19 -0
  12. package/dist/chunk-HT6BGERF.js +167 -0
  13. package/dist/{chunk-3QEKIC6C.js → chunk-NGY3TNND.js} +121 -11
  14. package/dist/{chunk-MFYFZQHM.js → chunk-W3VDIBGR.js} +1 -0
  15. package/dist/chunk-WJ6FLKNC.js +15 -0
  16. package/dist/cli.js +9 -0
  17. package/dist/{cta-logo-JIG22SWA.js → cta-logo-S4OMTNXD.js} +5 -3
  18. package/dist/{cta-media-GIHQTPPK.js → cta-media-EROTHDRR.js} +5 -3
  19. package/dist/{incoming-call-2O5NPJ7B.js → incoming-call-5IWJ2TAS.js} +5 -3
  20. package/dist/{infographic-before-after-FQXCQ2CY.js → infographic-before-after-2I7YZVDD.js} +2 -2
  21. package/dist/{infographic-feature-list-MVJ3GQVK.js → infographic-feature-list-7SK65U3K.js} +5 -3
  22. package/dist/{infographic-problem-solution-ZUF54SNF.js → infographic-problem-solution-IW35S6BR.js} +5 -3
  23. package/dist/{infographic-stat-row-4DLC5NSC.js → infographic-stat-row-XHUZZPDM.js} +5 -3
  24. package/dist/{infographic-steps-IT23RFV6.js → infographic-steps-JDDEDI7X.js} +5 -3
  25. package/dist/{preload-media-IYFMPMLB.js → preload-media-LJXWKTWG.js} +2 -0
  26. package/dist/{prompt-input-IL7HP5WX.js → prompt-input-6ZWXEL3V.js} +5 -3
  27. package/dist/react.js +30 -28
  28. package/dist/{reaction-IDFJZ7HI.js → reaction-Z3JIM3MQ.js} +5 -3
  29. package/dist/scene-video-backdrop-IL4F2SVD.js +9 -0
  30. package/dist/{showcase-code-EIGXDZE3.js → showcase-code-NWQAAJIA.js} +5 -3
  31. package/dist/{showcase-phone-STUZJRXV.js → showcase-phone-5UW45ATT.js} +5 -3
  32. package/dist/{showcase-terminal-SYP6TKP2.js → showcase-terminal-UVOD25UF.js} +5 -3
  33. package/dist/{showcase-web-57R4RMTG.js → showcase-web-3AW6VHIG.js} +5 -3
  34. package/dist/{social-milestone-J6QVX4YJ.js → social-milestone-KPKHFOB5.js} +8 -6
  35. package/dist/{social-notification-2RYS7NM4.js → social-notification-EDOU6TZB.js} +5 -3
  36. package/dist/{social-review-stack-25C6JJ4W.js → social-review-stack-EZOO33SV.js} +5 -3
  37. package/dist/{social-testimonial-SH54T4CW.js → social-testimonial-DLOINMMY.js} +5 -3
  38. package/dist/{social-tweet-T7RTFQ6T.js → social-tweet-6JUM323G.js} +5 -3
  39. package/examples/nextjs-quickstart/package.json +1 -1
  40. package/package.json +1 -1
  41. package/registry/items/backgrounds.json +19 -1
  42. package/registry/items/barChart.json +2 -2
  43. package/registry/items/beforeAfter.json +1 -1
  44. package/registry/items/bigNumber.json +2 -2
  45. package/registry/items/brandMessage.json +2 -2
  46. package/registry/items/cardList.json +2 -2
  47. package/registry/items/codeEditor.json +2 -2
  48. package/registry/items/confetti.json +1 -1
  49. package/registry/items/ctaLogo.json +2 -2
  50. package/registry/items/ctaMedia.json +2 -2
  51. package/registry/items/emojiBurst.json +1 -1
  52. package/registry/items/incomingCall.json +2 -2
  53. package/registry/items/media.json +2 -2
  54. package/registry/items/milestone.json +2 -2
  55. package/registry/items/notification.json +2 -2
  56. package/registry/items/phoneMockup.json +2 -2
  57. package/registry/items/problemSolution.json +2 -2
  58. package/registry/items/progressRing.json +2 -2
  59. package/registry/items/promptInput.json +2 -2
  60. package/registry/items/reaction.json +2 -2
  61. package/registry/items/reviewStack.json +2 -2
  62. package/registry/items/steps.json +2 -2
  63. package/registry/items/terminal.json +2 -2
  64. package/registry/items/testimonial.json +2 -2
  65. package/registry/items/tripleStats.json +2 -2
  66. package/registry/items/tweet.json +2 -2
  67. package/registry/items/webMockup.json +2 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ VanillaSky follows semantic versioning. This changelog begins with the 0.1 beta.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.5.7
8
+
9
+ - Keeps one persistent video backdrop element across consecutive iPhone and
10
+ iPad scenes, cross-fades through the decoded incoming poster during Safari's
11
+ source reset, avoids detached iOS preload decoders, and removes the CSS
12
+ poster workaround introduced in 0.5.6. Desktop retains its decoded
13
+ video-to-video cross-fade.
14
+
7
15
  ## 0.5.6
8
16
 
9
17
  - Keeps a video's warmed poster painted behind its frame so Mobile Safari
@@ -8,7 +8,7 @@ import {
8
8
  import "./chunk-L5BTTCZV.js";
9
9
  import {
10
10
  BrandGradientOverlay
11
- } from "./chunk-MFYFZQHM.js";
11
+ } from "./chunk-W3VDIBGR.js";
12
12
  import "./chunk-XTOXFMLM.js";
13
13
  import {
14
14
  resolveTokens
@@ -36,7 +36,7 @@ var BgConfettiTemplate = ({
36
36
  style: {
37
37
  width,
38
38
  height,
39
- backgroundColor: "#000",
39
+ backgroundColor: "var(--vanillasky-template-surface, #000)",
40
40
  position: "relative",
41
41
  overflow: "hidden",
42
42
  fontFamily: font
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-L5BTTCZV.js";
10
10
  import {
11
11
  BrandGradientOverlay
12
- } from "./chunk-MFYFZQHM.js";
12
+ } from "./chunk-W3VDIBGR.js";
13
13
  import "./chunk-XTOXFMLM.js";
14
14
  import {
15
15
  resolveTokens
@@ -65,7 +65,7 @@ var BgEmojiTemplate = ({
65
65
  style: {
66
66
  width,
67
67
  height,
68
- backgroundColor: "#000",
68
+ backgroundColor: "var(--vanillasky-template-surface, #000)",
69
69
  position: "relative",
70
70
  overflow: "hidden",
71
71
  fontFamily: font
@@ -1,17 +1,19 @@
1
- import {
2
- SceneBackground,
3
- getMediaBackgroundProps
4
- } from "./chunk-CTEYFVUY.js";
5
1
  import {
6
2
  ConfettiLayer
7
3
  } from "./chunk-CJ7F2CE6.js";
8
4
  import "./chunk-QAAO7OAY.js";
5
+ import {
6
+ SceneBackground,
7
+ getMediaBackgroundProps
8
+ } from "./chunk-6M6DATLW.js";
9
9
  import {
10
10
  TemplateText
11
11
  } from "./chunk-TCEHK2BW.js";
12
12
  import "./chunk-L5BTTCZV.js";
13
- import "./chunk-MFYFZQHM.js";
13
+ import "./chunk-HT6BGERF.js";
14
+ import "./chunk-W3VDIBGR.js";
14
15
  import "./chunk-XTOXFMLM.js";
16
+ import "./chunk-C6WVCZRW.js";
15
17
  import {
16
18
  hasSceneMedia
17
19
  } from "./chunk-224QNWRA.js";
@@ -43,7 +45,7 @@ var BgMediaTemplate = ({
43
45
  style: {
44
46
  width,
45
47
  height,
46
- backgroundColor: "#000",
48
+ backgroundColor: "var(--vanillasky-template-surface, #000)",
47
49
  position: "relative",
48
50
  overflow: "hidden",
49
51
  fontFamily: font
@@ -4,14 +4,16 @@ import {
4
4
  import {
5
5
  SceneBackground,
6
6
  getMediaBackgroundProps
7
- } from "./chunk-CTEYFVUY.js";
7
+ } from "./chunk-6M6DATLW.js";
8
8
  import {
9
9
  renderWithEmoji
10
10
  } from "./chunk-L5BTTCZV.js";
11
- import "./chunk-MFYFZQHM.js";
11
+ import "./chunk-HT6BGERF.js";
12
+ import "./chunk-W3VDIBGR.js";
12
13
  import {
13
14
  interpolate
14
15
  } from "./chunk-XTOXFMLM.js";
16
+ import "./chunk-C6WVCZRW.js";
15
17
  import "./chunk-224QNWRA.js";
16
18
  import "./chunk-XWWLKRNU.js";
17
19
 
@@ -208,7 +210,7 @@ var BrandMessageTemplate = ({
208
210
  style: {
209
211
  width,
210
212
  height,
211
- backgroundColor: "#000",
213
+ backgroundColor: "var(--vanillasky-template-surface, #000)",
212
214
  position: "relative",
213
215
  overflow: "hidden",
214
216
  // System fonts only — see BrandMessageBubble for the why
@@ -1,20 +1,22 @@
1
1
  import {
2
2
  SceneBackground,
3
3
  getMediaBackgroundProps
4
- } from "./chunk-CTEYFVUY.js";
4
+ } from "./chunk-6M6DATLW.js";
5
5
  import {
6
6
  TemplateText
7
7
  } from "./chunk-TCEHK2BW.js";
8
8
  import "./chunk-L5BTTCZV.js";
9
+ import "./chunk-HT6BGERF.js";
9
10
  import {
10
11
  TOP_TEXT_AREA_RATIO,
11
12
  withOpacity
12
- } from "./chunk-MFYFZQHM.js";
13
+ } from "./chunk-W3VDIBGR.js";
13
14
  import {
14
15
  SPRING_SNAPPY,
15
16
  interpolate,
16
17
  spring
17
18
  } from "./chunk-XTOXFMLM.js";
19
+ import "./chunk-C6WVCZRW.js";
18
20
  import {
19
21
  hasSceneMedia
20
22
  } from "./chunk-224QNWRA.js";
@@ -246,7 +248,7 @@ var ChartBarTemplate = ({
246
248
  style: {
247
249
  width,
248
250
  height,
249
- backgroundColor: "#000",
251
+ backgroundColor: "var(--vanillasky-template-surface, #000)",
250
252
  position: "relative",
251
253
  overflow: "hidden",
252
254
  fontFamily: font
@@ -1,26 +1,28 @@
1
1
  import {
2
2
  getResponsiveFontSize
3
3
  } from "./chunk-S7HFLYNN.js";
4
- import {
5
- SceneBackground,
6
- getMediaBackgroundProps
7
- } from "./chunk-CTEYFVUY.js";
8
4
  import {
9
5
  ConfettiLayer
10
6
  } from "./chunk-CJ7F2CE6.js";
11
7
  import "./chunk-QAAO7OAY.js";
8
+ import {
9
+ SceneBackground,
10
+ getMediaBackgroundProps
11
+ } from "./chunk-6M6DATLW.js";
12
12
  import {
13
13
  TemplateText
14
14
  } from "./chunk-TCEHK2BW.js";
15
15
  import "./chunk-L5BTTCZV.js";
16
+ import "./chunk-HT6BGERF.js";
16
17
  import {
17
18
  TOP_TEXT_AREA_RATIO,
18
19
  withOpacity
19
- } from "./chunk-MFYFZQHM.js";
20
+ } from "./chunk-W3VDIBGR.js";
20
21
  import {
21
22
  interpolate,
22
23
  spring
23
24
  } from "./chunk-XTOXFMLM.js";
25
+ import "./chunk-C6WVCZRW.js";
24
26
  import {
25
27
  hasSceneMedia
26
28
  } from "./chunk-224QNWRA.js";
@@ -207,7 +209,7 @@ var ChartCounterTemplate = ({
207
209
  style: {
208
210
  width,
209
211
  height,
210
- backgroundColor: "#000",
212
+ backgroundColor: "var(--vanillasky-template-surface, #000)",
211
213
  position: "relative",
212
214
  overflow: "hidden",
213
215
  fontFamily: font
@@ -5,18 +5,20 @@ import {
5
5
  import {
6
6
  SceneBackground,
7
7
  getMediaBackgroundProps
8
- } from "./chunk-CTEYFVUY.js";
8
+ } from "./chunk-6M6DATLW.js";
9
9
  import {
10
10
  TemplateText
11
11
  } from "./chunk-TCEHK2BW.js";
12
12
  import "./chunk-L5BTTCZV.js";
13
+ import "./chunk-HT6BGERF.js";
13
14
  import {
14
15
  TOP_TEXT_AREA_RATIO,
15
16
  withOpacity
16
- } from "./chunk-MFYFZQHM.js";
17
+ } from "./chunk-W3VDIBGR.js";
17
18
  import {
18
19
  interpolate
19
20
  } from "./chunk-XTOXFMLM.js";
21
+ import "./chunk-C6WVCZRW.js";
20
22
  import {
21
23
  hasSceneMedia
22
24
  } from "./chunk-224QNWRA.js";
@@ -233,7 +235,7 @@ var ChartProgressRingTemplate = ({
233
235
  style: {
234
236
  width,
235
237
  height,
236
- backgroundColor: "#000",
238
+ backgroundColor: "var(--vanillasky-template-surface, #000)",
237
239
  position: "relative",
238
240
  overflow: "hidden",
239
241
  fontFamily: font
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  VideoFrame
3
- } from "./chunk-3QEKIC6C.js";
3
+ } from "./chunk-NGY3TNND.js";
4
+ import "./chunk-C6WVCZRW.js";
4
5
  import "./chunk-224QNWRA.js";
5
6
  import "./chunk-XWWLKRNU.js";
6
7
  import "./chunk-SPVTJH3F.js";
7
8
  import {
8
9
  resolveVideoBrand
9
10
  } from "./chunk-XGRA2MUV.js";
11
+ import "./chunk-WJ6FLKNC.js";
10
12
  import "./chunk-73NTSFFI.js";
11
13
 
12
14
  // src/cli/check-runtime.ts
@@ -1,25 +1,21 @@
1
+ import {
2
+ SceneVideoBackdrop,
3
+ resolveMediaPosition
4
+ } from "./chunk-HT6BGERF.js";
1
5
  import {
2
6
  BrandGradientOverlay,
3
7
  getBackgroundTransform
4
- } from "./chunk-MFYFZQHM.js";
8
+ } from "./chunk-W3VDIBGR.js";
9
+ import {
10
+ useExternalVideoBackdrop
11
+ } from "./chunk-C6WVCZRW.js";
5
12
  import {
6
- limitsConcurrentVideoDecoders,
7
13
  resolveMediaType
8
14
  } from "./chunk-224QNWRA.js";
9
15
 
10
16
  // src/visual-system/scene-templates/scene-background.tsx
11
- import { useEffect, useRef, useState } from "react";
17
+ import { useEffect, useState } from "react";
12
18
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
- var MEDIA_POSITIONS = {
14
- center: "center center",
15
- top: "center top",
16
- bottom: "center bottom",
17
- left: "left center",
18
- right: "right center"
19
- };
20
- function resolveMediaPosition(value) {
21
- return MEDIA_POSITIONS[value] ?? MEDIA_POSITIONS.center;
22
- }
23
19
  function resolveMediaTreatment(value) {
24
20
  return value === "subtle" || value === "text-safe" ? value : "cinematic";
25
21
  }
@@ -106,10 +102,13 @@ var SceneBackground = ({
106
102
  void _height;
107
103
  const resolved = resolveMediaType(mediaType, mediaUrl);
108
104
  const wantsMedia = resolved !== "gradient" && !!mediaUrl;
105
+ const externalVideoBackdrop = useExternalVideoBackdrop();
106
+ const hasExternalVideoBackdrop = externalVideoBackdrop !== false && resolved === "video";
107
+ const externalVideoFailed = externalVideoBackdrop === "fallback" && resolved === "video";
108
+ const externalVideoReady = externalVideoBackdrop === "ready" && resolved === "video";
109
109
  const [mediaPaint, setMediaPaint] = useState(
110
110
  () => initialMediaPaint(wantsMedia, resolved, mediaUrl, mediaPoster)
111
111
  );
112
- const [decodedVideoUrl, setDecodedVideoUrl] = useState();
113
112
  useEffect(() => {
114
113
  setMediaPaint(initialMediaPaint(wantsMedia, resolved, mediaUrl, mediaPoster));
115
114
  if (!wantsMedia || resolved !== "photo") return;
@@ -141,35 +140,8 @@ var SceneBackground = ({
141
140
  progress,
142
141
  beatIntensity
143
142
  );
144
- const videoRef = useRef(null);
145
- const videoStarted = useRef(false);
146
- useEffect(() => {
147
- const vid = videoRef.current;
148
- if (!vid) return;
149
- if (!isPlaying) {
150
- vid.pause();
151
- videoStarted.current = false;
152
- return;
153
- }
154
- if (!videoStarted.current) {
155
- vid.playbackRate = 1;
156
- if (vid.currentTime > 0) vid.currentTime = 0;
157
- vid.play().catch(() => {
158
- });
159
- videoStarted.current = true;
160
- }
161
- }, [progress, isPlaying]);
162
- useEffect(() => {
163
- const vid = videoRef.current;
164
- return () => {
165
- if (!vid) return;
166
- vid.pause();
167
- vid.removeAttribute("src");
168
- vid.load();
169
- };
170
- }, []);
171
143
  return /* @__PURE__ */ jsxs(Fragment, { children: [
172
- /* @__PURE__ */ jsx(
144
+ (!hasExternalVideoBackdrop || externalVideoFailed) && /* @__PURE__ */ jsx(
173
145
  BrandGradientOverlay,
174
146
  {
175
147
  style,
@@ -178,46 +150,18 @@ var SceneBackground = ({
178
150
  seed: gradSeed
179
151
  }
180
152
  ),
181
- showMedia && (resolved === "video" ? /* @__PURE__ */ jsx(
182
- "video",
153
+ showMedia && !hasExternalVideoBackdrop && (resolved === "video" ? /* @__PURE__ */ jsx(
154
+ SceneVideoBackdrop,
183
155
  {
184
- ref: videoRef,
185
- src: mediaUrl,
186
- poster: decodedVideoUrl === mediaUrl ? void 0 : mediaPoster || void 0,
187
- muted: true,
188
- loop: true,
189
- playsInline: true,
190
- preload: "auto",
191
- onLoadedData: (event) => {
192
- setMediaPaint("ready");
193
- const video = event.currentTarget;
194
- if (!limitsConcurrentVideoDecoders()) {
195
- setDecodedVideoUrl(mediaUrl);
196
- return;
197
- }
198
- video.requestVideoFrameCallback?.(() => {
199
- if (video.isConnected) setDecodedVideoUrl(mediaUrl);
200
- });
201
- },
202
- onError: () => setMediaPaint("failed"),
203
- "data-media-position": mediaPosition,
204
- style: {
205
- position: "absolute",
206
- inset: 0,
207
- width: "100%",
208
- height: "100%",
209
- objectFit: "cover",
210
- objectPosition: resolvedPosition,
211
- // Mobile WebKit can briefly make a newly mounted video layer
212
- // transparent while handing the decoder over from the previous
213
- // scene. Keep the already-warmed poster painted behind the
214
- // replaced content so that gap never exposes the gradient.
215
- backgroundImage: mediaPoster ? `url(${mediaPoster})` : void 0,
216
- backgroundSize: "cover",
217
- backgroundPosition: resolvedPosition,
218
- transform: bgTransform.transform,
219
- transformOrigin: bgTransform.transformOrigin
220
- }
156
+ mediaUrl,
157
+ mediaPoster,
158
+ mediaPosition,
159
+ backgroundEffect,
160
+ progress,
161
+ beatIntensity,
162
+ isPlaying,
163
+ onReady: () => setMediaPaint("ready"),
164
+ onError: () => setMediaPaint("failed")
221
165
  }
222
166
  ) : /* @__PURE__ */ jsx(
223
167
  "div",
@@ -234,7 +178,7 @@ var SceneBackground = ({
234
178
  }
235
179
  }
236
180
  )),
237
- showTreatment && treatmentLayers.map((layer) => /* @__PURE__ */ jsx(
181
+ (hasExternalVideoBackdrop ? externalVideoReady : showTreatment) && !externalVideoFailed && treatmentLayers.map((layer) => /* @__PURE__ */ jsx(
238
182
  "div",
239
183
  {
240
184
  "data-media-treatment": resolvedTreatment,
@@ -0,0 +1,19 @@
1
+ // src/visual-system/scene-templates/external-video-backdrop.tsx
2
+ import React from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+ var sharedContext = globalThis;
5
+ var ExternalVideoBackdropContext = sharedContext.__vanillaskyExternalVideoBackdropContext ??= React.createContext(false);
6
+ function ExternalVideoBackdropProvider({
7
+ mode,
8
+ children
9
+ }) {
10
+ return /* @__PURE__ */ jsx(ExternalVideoBackdropContext.Provider, { value: mode, children });
11
+ }
12
+ function useExternalVideoBackdrop() {
13
+ return React.useContext(ExternalVideoBackdropContext);
14
+ }
15
+
16
+ export {
17
+ ExternalVideoBackdropProvider,
18
+ useExternalVideoBackdrop
19
+ };
@@ -0,0 +1,167 @@
1
+ import {
2
+ getBackgroundTransform
3
+ } from "./chunk-W3VDIBGR.js";
4
+
5
+ // src/visual-system/scene-templates/scene-video-backdrop.tsx
6
+ import { useEffect, useRef, useState } from "react";
7
+
8
+ // src/visual-system/scene-templates/media-position.ts
9
+ var MEDIA_POSITIONS = {
10
+ center: "center center",
11
+ top: "center top",
12
+ bottom: "center bottom",
13
+ left: "left center",
14
+ right: "right center"
15
+ };
16
+ function resolveMediaPosition(value) {
17
+ return MEDIA_POSITIONS[value] ?? MEDIA_POSITIONS.center;
18
+ }
19
+
20
+ // src/visual-system/scene-templates/scene-video-backdrop.tsx
21
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
22
+ var SceneVideoBackdrop = ({
23
+ mediaUrl,
24
+ mediaPoster,
25
+ mediaPosition = "center",
26
+ backgroundEffect,
27
+ progress,
28
+ beatIntensity = 0,
29
+ isPlaying,
30
+ playbackId = mediaUrl,
31
+ retainPoster = false,
32
+ persistent = false,
33
+ preparedPoster,
34
+ onReady,
35
+ onError
36
+ }) => {
37
+ const resolvedPosition = resolveMediaPosition(mediaPosition);
38
+ const bgTransform = getBackgroundTransform(backgroundEffect, progress, beatIntensity);
39
+ const [decodedVideoUrl, setDecodedVideoUrl] = useState();
40
+ const videoRef = useRef(null);
41
+ const startedVideoUrl = useRef(void 0);
42
+ const startedPlaybackId = useRef(void 0);
43
+ const videoPresentationKey = `${playbackId}\0${mediaUrl}`;
44
+ useEffect(() => {
45
+ const video = videoRef.current;
46
+ if (!video) return;
47
+ if (!isPlaying) {
48
+ video.pause();
49
+ startedVideoUrl.current = void 0;
50
+ startedPlaybackId.current = void 0;
51
+ return;
52
+ }
53
+ if (startedPlaybackId.current === playbackId) return;
54
+ const changingSource = startedVideoUrl.current !== void 0 && startedVideoUrl.current !== mediaUrl;
55
+ video.playbackRate = 1;
56
+ if (!changingSource && video.currentTime > 0) video.currentTime = 0;
57
+ video.play().catch(() => {
58
+ });
59
+ startedVideoUrl.current = mediaUrl;
60
+ startedPlaybackId.current = playbackId;
61
+ }, [isPlaying, mediaUrl, playbackId]);
62
+ useEffect(() => {
63
+ const video = videoRef.current;
64
+ return () => {
65
+ if (!video) return;
66
+ video.pause();
67
+ video.removeAttribute("src");
68
+ video.load();
69
+ };
70
+ }, []);
71
+ const mediaStyle = {
72
+ position: "absolute",
73
+ inset: 0,
74
+ width: "100%",
75
+ height: "100%",
76
+ objectFit: "cover",
77
+ objectPosition: resolvedPosition,
78
+ transform: bgTransform.transform,
79
+ transformOrigin: bgTransform.transformOrigin,
80
+ zIndex: persistent ? 1 : void 0
81
+ };
82
+ const preparedPosition = preparedPoster ? resolveMediaPosition(preparedPoster.mediaPosition) : resolvedPosition;
83
+ const preparedTransform = getBackgroundTransform(preparedPoster?.backgroundEffect, 0, 0);
84
+ const posterPlanes = [
85
+ ...persistent && mediaPoster ? [{
86
+ presentationKey: videoPresentationKey,
87
+ mediaPoster,
88
+ mediaPosition: resolvedPosition,
89
+ transform: bgTransform.transform,
90
+ transformOrigin: bgTransform.transformOrigin,
91
+ opacity: 1,
92
+ zIndex: 0,
93
+ role: "current"
94
+ }] : [],
95
+ ...preparedPoster && preparedPoster.presentationKey !== videoPresentationKey ? [{
96
+ presentationKey: preparedPoster.presentationKey,
97
+ mediaPoster: preparedPoster.mediaPoster,
98
+ mediaPosition: preparedPosition,
99
+ transform: preparedTransform.transform,
100
+ transformOrigin: preparedTransform.transformOrigin,
101
+ opacity: preparedPoster.opacity ?? 0,
102
+ zIndex: 2,
103
+ role: "prepared"
104
+ }] : []
105
+ ];
106
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
107
+ posterPlanes.map((posterPlane) => /* @__PURE__ */ jsx(
108
+ "img",
109
+ {
110
+ src: posterPlane.mediaPoster,
111
+ alt: "",
112
+ "aria-hidden": "true",
113
+ draggable: false,
114
+ "data-video-poster-plane": posterPlane.role,
115
+ "data-video-poster-visible": posterPlane.opacity > 0 ? "true" : "false",
116
+ style: {
117
+ position: "absolute",
118
+ inset: 0,
119
+ width: "100%",
120
+ height: "100%",
121
+ objectFit: "cover",
122
+ objectPosition: posterPlane.mediaPosition,
123
+ transform: posterPlane.transform,
124
+ transformOrigin: posterPlane.transformOrigin,
125
+ zIndex: posterPlane.zIndex,
126
+ opacity: posterPlane.opacity,
127
+ pointerEvents: "none"
128
+ }
129
+ },
130
+ posterPlane.presentationKey
131
+ )),
132
+ /* @__PURE__ */ jsx(
133
+ "video",
134
+ {
135
+ ref: videoRef,
136
+ src: mediaUrl,
137
+ poster: retainPoster || decodedVideoUrl !== mediaUrl ? mediaPoster || void 0 : void 0,
138
+ muted: true,
139
+ loop: true,
140
+ playsInline: true,
141
+ preload: "auto",
142
+ onLoadedData: (event) => {
143
+ const video = event.currentTarget;
144
+ const markPresented = () => {
145
+ if (!video.isConnected) return;
146
+ onReady?.();
147
+ if (!retainPoster) setDecodedVideoUrl(mediaUrl);
148
+ };
149
+ if (video.requestVideoFrameCallback) {
150
+ video.requestVideoFrameCallback(markPresented);
151
+ return;
152
+ }
153
+ markPresented();
154
+ },
155
+ onError,
156
+ "data-media-position": mediaPosition,
157
+ "data-video-backdrop": persistent ? "persistent" : "scene",
158
+ style: mediaStyle
159
+ }
160
+ )
161
+ ] });
162
+ };
163
+
164
+ export {
165
+ resolveMediaPosition,
166
+ SceneVideoBackdrop
167
+ };