@vanillaskyai/video 0.10.7 → 0.10.9
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.
- package/CHANGELOG.md +18 -0
- package/dist/check-runtime.js +2 -2
- package/dist/{chunk-OBRKB7PL.js → chunk-J7EGPURK.js} +291 -127
- package/dist/{chunk-24TCMDAA.js → chunk-KUCEOG2L.js} +31 -94
- package/dist/{chunk-PMJNBR4F.js → chunk-Q3LPOPHL.js} +1 -1
- package/dist/{chunk-MKMCX3AF.js → chunk-R5ZX2LJV.js} +1 -1
- package/dist/{cinema-media-BVQFZL3A.js → cinema-media-WUS7CKPC.js} +3 -4
- package/dist/{comparison-T27C7FSV.js → comparison-T4OYCOH3.js} +3 -4
- package/dist/{editorial-timeline-JADHHNEV.js → editorial-timeline-JHQZIPNE.js} +3 -4
- package/dist/{key-figure-TZQWPFMI.js → key-figure-YWN2OBQU.js} +3 -4
- package/dist/{mobile-message-GADX632R.js → mobile-message-CDKOERRZ.js} +3 -4
- package/dist/{quote-FRCEC34C.js → quote-JKABOMIG.js} +3 -4
- package/dist/react.js +8 -8
- package/dist/server.js +22 -3
- package/package.json +1 -1
- package/registry/items/backgrounds.json +2 -2
- package/starters/video-chat/README.md +27 -8
- package/starters/video-chat/package.json +1 -1
- package/starters/video-chat/server.ts +1 -6
- package/starters/video-chat/stock.ts +27 -4
- package/dist/chunk-X4RGAEL5.js +0 -207
- package/dist/scene-video-backdrop-NK2XK3XE.js +0 -7
- package/dist/{chunk-OOBT4X46.js → chunk-5JBMYQP6.js} +34 -34
|
@@ -25,11 +25,6 @@ export const handleVideoChat = createVideoChatHandler({
|
|
|
25
25
|
output_config: { effort: "medium" },
|
|
26
26
|
},
|
|
27
27
|
},
|
|
28
|
-
onFinish: ({ finishReason, text }) => {
|
|
29
|
-
if (finishReason !== "stop") console.warn(`[planner] ${finishReason}: ${text.slice(0, 300)}`);
|
|
30
|
-
const keyed = (text.match(/"mediaKeyword"/g) ?? []).length;
|
|
31
|
-
console.log(`[planner] ${(text.match(/"scene\.add"/g) ?? []).length} scenes, ${keyed} asked for footage`);
|
|
32
|
-
},
|
|
33
28
|
}),
|
|
34
29
|
generateText: async ({ systemPrompt, userPrompt, maxOutputTokens, signal }) => {
|
|
35
30
|
const { text } = await generateText({
|
|
@@ -42,7 +37,7 @@ export const handleVideoChat = createVideoChatHandler({
|
|
|
42
37
|
return text;
|
|
43
38
|
},
|
|
44
39
|
searchMedia: process.env.PEXELS_API_KEY
|
|
45
|
-
? (query, { orientation, signal }) => findStockFootage(query, orientation, signal)
|
|
40
|
+
? (query, { orientation, signal, scene }) => findStockFootage(query, orientation, signal, scene?.variables.stockSelection)
|
|
46
41
|
: undefined,
|
|
47
42
|
...providers,
|
|
48
43
|
welcome: {
|
|
@@ -9,11 +9,27 @@ interface PexelsVideo {
|
|
|
9
9
|
url?: string;
|
|
10
10
|
image?: string;
|
|
11
11
|
title?: unknown;
|
|
12
|
+
description?: unknown;
|
|
12
13
|
tags?: unknown;
|
|
13
14
|
video_files?: { link?: string; width?: number; height?: number; file_type?: string }[];
|
|
14
15
|
}
|
|
15
16
|
const cache = new Map<string, { expires: number; media: StockVideo | null }>();
|
|
16
17
|
const words = (value: string): string[] => value.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
|
|
18
|
+
const ignored = new Set(['a','an','the','in','on','at','of','with','and','to']);
|
|
19
|
+
const terms = (value: string) => words(value).filter(word => !ignored.has(word));
|
|
20
|
+
function selectionHint(value: unknown) {
|
|
21
|
+
const phrase = (input: unknown) => {
|
|
22
|
+
if (typeof input !== 'string') return undefined;
|
|
23
|
+
const normalized = input.trim().toLowerCase().replace(/\s+/gu,' ').replaceAll('’', "'");
|
|
24
|
+
return normalized.length <= 48 && /^[\p{L}\p{N} '-]+$/u.test(normalized) && words(normalized).length <= 4 && terms(normalized).length ? normalized : undefined;
|
|
25
|
+
};
|
|
26
|
+
const raw = value && typeof value === 'object' ? value as Record<string, unknown> : {};
|
|
27
|
+
const subject = phrase(raw.subject);
|
|
28
|
+
if (!subject) return undefined;
|
|
29
|
+
const activity = phrase(raw.activity), equipment = phrase(raw.equipment);
|
|
30
|
+
const exclude = Array.isArray(raw.exclude) && raw.exclude.length <= 3 ? raw.exclude.map(phrase).filter((item): item is string => Boolean(item)) : [];
|
|
31
|
+
return {subject, ...(activity ? {activity} : {}), ...(equipment ? {equipment} : {}), ...(exclude.length ? {exclude} : {})};
|
|
32
|
+
}
|
|
17
33
|
function pexelsUrl(value: unknown): value is string {
|
|
18
34
|
if (typeof value !== "string") return false;
|
|
19
35
|
try {
|
|
@@ -27,11 +43,12 @@ function pexelsUrl(value: unknown): value is string {
|
|
|
27
43
|
* Applications using this adapter must display a prominent link to Pexels.
|
|
28
44
|
* https://www.pexels.com/api/documentation/#guidelines
|
|
29
45
|
*/
|
|
30
|
-
export async function findStockFootage(query: string, orientation: VideoOrientation, signal: AbortSignal) {
|
|
46
|
+
export async function findStockFootage(query: string, orientation: VideoOrientation, signal: AbortSignal, rawSelection?: unknown) {
|
|
31
47
|
signal.throwIfAborted();
|
|
32
48
|
const normalized = query.trim().toLowerCase().replace(/\s+/g, " ");
|
|
33
49
|
const tokens = words(normalized);
|
|
34
|
-
const
|
|
50
|
+
const selection = selectionHint(rawSelection);
|
|
51
|
+
const key = JSON.stringify({version: 2, orientation, query: normalized, selection});
|
|
35
52
|
const apiKey = process.env.PEXELS_API_KEY;
|
|
36
53
|
if (!apiKey || !tokens.length || normalized.length > 80 || tokens.length > 8) return null;
|
|
37
54
|
const existing = cache.get(key);
|
|
@@ -49,8 +66,14 @@ export async function findStockFootage(query: string, orientation: VideoOrientat
|
|
|
49
66
|
const slug = new URL(video.url).pathname.replace(/^\/video\//, "");
|
|
50
67
|
const title = typeof video.title === "string" ? video.title : "";
|
|
51
68
|
const tags = Array.isArray(video.tags) ? video.tags.filter((tag): tag is string => typeof tag === "string").join(" ") : "";
|
|
52
|
-
const subject = words(`${slug} ${title} ${tags}`).filter(token => !/^\d+$/.test(token));
|
|
53
|
-
|
|
69
|
+
const subject = words(`${slug} ${title} ${typeof video.description === "string" ? video.description : ""} ${tags}`).filter(token => !/^\d+$/.test(token));
|
|
70
|
+
let matches = tokens.filter(token => subject.includes(token)).length;
|
|
71
|
+
if (selection && subject.length) {
|
|
72
|
+
const covers = (phrase: string) => terms(phrase).every(word => subject.includes(word));
|
|
73
|
+
if (!covers(selection.subject) || selection.exclude?.some(covers)) continue;
|
|
74
|
+
matches = 2 + Number(Boolean(selection.activity && covers(selection.activity)))
|
|
75
|
+
+ Number(Boolean(selection.equipment && covers(selection.equipment)));
|
|
76
|
+
}
|
|
54
77
|
// The documented Video resource can have only a numeric page URL and no
|
|
55
78
|
// editorial metadata. Preserve provider search order for unknown relevance;
|
|
56
79
|
// positive overlap ranks above it, while explicitly unrelated copy is skipped.
|
package/dist/chunk-X4RGAEL5.js
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BrandGradientOverlay,
|
|
3
|
-
SceneVideoBackdrop,
|
|
4
|
-
getBackgroundTransform,
|
|
5
|
-
resolveMediaPosition
|
|
6
|
-
} from "./chunk-OBRKB7PL.js";
|
|
7
|
-
import {
|
|
8
|
-
resolveMediaType
|
|
9
|
-
} from "./chunk-224QNWRA.js";
|
|
10
|
-
import {
|
|
11
|
-
useExternalVideoBackdrop
|
|
12
|
-
} from "./chunk-OOBT4X46.js";
|
|
13
|
-
|
|
14
|
-
// src/visual-system/scene-templates/scene-background.tsx
|
|
15
|
-
import { useEffect, useState } from "react";
|
|
16
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
17
|
-
function resolveMediaTreatment(value) {
|
|
18
|
-
return value === "none" || value === "subtle" || value === "text-safe" ? value : "cinematic";
|
|
19
|
-
}
|
|
20
|
-
var SCRIM_STOP_COUNT = 7;
|
|
21
|
-
function smoothstep(t) {
|
|
22
|
-
return t * t * (3 - 2 * t);
|
|
23
|
-
}
|
|
24
|
-
function easedStops(peakAlpha, start, end, direction) {
|
|
25
|
-
const alphaAt = (t) => {
|
|
26
|
-
const eased = direction === "fade-out" ? 1 - smoothstep(t) : smoothstep(t);
|
|
27
|
-
return `rgba(0,0,0,${Number((peakAlpha * eased).toFixed(3))})`;
|
|
28
|
-
};
|
|
29
|
-
const stops = [];
|
|
30
|
-
if (start > 0) stops.push(`${alphaAt(0)} 0%`);
|
|
31
|
-
for (let i = 0; i < SCRIM_STOP_COUNT; i += 1) {
|
|
32
|
-
const t = i / (SCRIM_STOP_COUNT - 1);
|
|
33
|
-
const position = Number((start + (end - start) * t).toFixed(2));
|
|
34
|
-
stops.push(`${alphaAt(t)} ${position}%`);
|
|
35
|
-
}
|
|
36
|
-
if (end < 100) stops.push(`${alphaAt(1)} 100%`);
|
|
37
|
-
return stops.join(", ");
|
|
38
|
-
}
|
|
39
|
-
function getMediaTreatmentLayers(value, anchor = "full") {
|
|
40
|
-
const treatment = resolveMediaTreatment(value);
|
|
41
|
-
if (treatment === "none") return [];
|
|
42
|
-
const vignette = {
|
|
43
|
-
id: "vignette",
|
|
44
|
-
background: treatment === "subtle" ? `radial-gradient(ellipse at center, ${easedStops(0.28, 45, 100, "fade-in")})` : `radial-gradient(ellipse at center, ${easedStops(0.72, 32, 100, "fade-in")})`
|
|
45
|
-
};
|
|
46
|
-
if (treatment === "subtle") return [vignette];
|
|
47
|
-
const textSafe = treatment === "text-safe";
|
|
48
|
-
const layers = [vignette];
|
|
49
|
-
if (anchor !== "bottom") {
|
|
50
|
-
layers.push({
|
|
51
|
-
id: "center-scrim",
|
|
52
|
-
background: textSafe ? `radial-gradient(ellipse 92% 58% at 50% 50%, ${easedStops(0.46, 34, 90, "fade-out")})` : `radial-gradient(ellipse 88% 52% at 50% 50%, ${easedStops(0.26, 30, 88, "fade-out")})`
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
if (anchor !== "center") {
|
|
56
|
-
layers.push({
|
|
57
|
-
id: "bottom-scrim",
|
|
58
|
-
background: `linear-gradient(to top, ${easedStops(textSafe ? 0.64 : 0.5, 8, 100, "fade-out")})`,
|
|
59
|
-
style: { top: "55%" }
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
return layers;
|
|
63
|
-
}
|
|
64
|
-
function initialMediaPaint(wantsMedia, resolved, mediaUrl, mediaPoster) {
|
|
65
|
-
if (typeof window === "undefined") return "ready";
|
|
66
|
-
if (!wantsMedia) return "ready";
|
|
67
|
-
if (resolved === "video") return mediaPoster ? "ready" : "pending";
|
|
68
|
-
if (typeof Image === "undefined") return "ready";
|
|
69
|
-
const cached = new Image();
|
|
70
|
-
cached.src = mediaUrl;
|
|
71
|
-
return cached.complete && cached.naturalWidth > 0 ? "ready" : "pending";
|
|
72
|
-
}
|
|
73
|
-
function getMediaBackgroundProps(variables) {
|
|
74
|
-
return {
|
|
75
|
-
mediaUrl: String(variables.mediaUrl || ""),
|
|
76
|
-
mediaType: String(variables.mediaType || "auto"),
|
|
77
|
-
mediaPoster: String(variables.mediaPoster || ""),
|
|
78
|
-
mediaPosition: String(variables.mediaPosition || "center"),
|
|
79
|
-
mediaTreatment: String(variables.mediaTreatment || "cinematic")
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
var SceneBackground = ({
|
|
83
|
-
style,
|
|
84
|
-
progress,
|
|
85
|
-
sceneDuration,
|
|
86
|
-
width: _width,
|
|
87
|
-
// accepted for symmetry; not currently used in render
|
|
88
|
-
height: _height,
|
|
89
|
-
mediaUrl = "",
|
|
90
|
-
mediaType = "auto",
|
|
91
|
-
mediaPoster,
|
|
92
|
-
mediaPosition = "center",
|
|
93
|
-
mediaTreatment = "cinematic",
|
|
94
|
-
textAnchor = "full",
|
|
95
|
-
backgroundEffect,
|
|
96
|
-
seed,
|
|
97
|
-
isPlaying = true,
|
|
98
|
-
beatIntensity = 0
|
|
99
|
-
}) => {
|
|
100
|
-
void _width;
|
|
101
|
-
void _height;
|
|
102
|
-
const resolved = resolveMediaType(mediaType, mediaUrl);
|
|
103
|
-
const wantsMedia = resolved !== "gradient" && !!mediaUrl;
|
|
104
|
-
const externalVideoBackdrop = useExternalVideoBackdrop();
|
|
105
|
-
const hasExternalVideoBackdrop = externalVideoBackdrop !== false && resolved === "video";
|
|
106
|
-
const externalVideoFailed = externalVideoBackdrop === "fallback" && resolved === "video";
|
|
107
|
-
const externalVideoReady = externalVideoBackdrop === "ready" && resolved === "video";
|
|
108
|
-
const [mediaPaint, setMediaPaint] = useState(
|
|
109
|
-
() => initialMediaPaint(wantsMedia, resolved, mediaUrl, mediaPoster)
|
|
110
|
-
);
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
setMediaPaint(initialMediaPaint(wantsMedia, resolved, mediaUrl, mediaPoster));
|
|
113
|
-
if (!wantsMedia || resolved !== "photo") return;
|
|
114
|
-
if (typeof Image === "undefined") return;
|
|
115
|
-
let cancelled = false;
|
|
116
|
-
const probe = new Image();
|
|
117
|
-
probe.onload = () => {
|
|
118
|
-
if (!cancelled) setMediaPaint("ready");
|
|
119
|
-
};
|
|
120
|
-
probe.onerror = () => {
|
|
121
|
-
if (!cancelled) setMediaPaint("failed");
|
|
122
|
-
};
|
|
123
|
-
probe.src = mediaUrl;
|
|
124
|
-
if (probe.complete) setMediaPaint(probe.naturalWidth > 0 ? "ready" : "failed");
|
|
125
|
-
return () => {
|
|
126
|
-
cancelled = true;
|
|
127
|
-
probe.onload = null;
|
|
128
|
-
probe.onerror = null;
|
|
129
|
-
};
|
|
130
|
-
}, [mediaUrl, mediaPoster, resolved, wantsMedia]);
|
|
131
|
-
const showMedia = wantsMedia && mediaPaint !== "failed";
|
|
132
|
-
const showTreatment = wantsMedia && mediaPaint === "ready";
|
|
133
|
-
const resolvedPosition = resolveMediaPosition(mediaPosition);
|
|
134
|
-
const resolvedTreatment = resolveMediaTreatment(mediaTreatment);
|
|
135
|
-
const treatmentLayers = getMediaTreatmentLayers(resolvedTreatment, textAnchor);
|
|
136
|
-
const gradSeed = typeof seed === "number" ? seed : typeof seed === "string" ? seed.split("").reduce((acc, c) => acc + c.charCodeAt(0), 0) : 0;
|
|
137
|
-
const bgTransform = getBackgroundTransform(
|
|
138
|
-
backgroundEffect,
|
|
139
|
-
progress,
|
|
140
|
-
beatIntensity
|
|
141
|
-
);
|
|
142
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
143
|
-
(!hasExternalVideoBackdrop || externalVideoFailed) && /* @__PURE__ */ jsx(
|
|
144
|
-
BrandGradientOverlay,
|
|
145
|
-
{
|
|
146
|
-
style,
|
|
147
|
-
progress,
|
|
148
|
-
sceneDuration,
|
|
149
|
-
seed: gradSeed
|
|
150
|
-
}
|
|
151
|
-
),
|
|
152
|
-
showMedia && !hasExternalVideoBackdrop && (resolved === "video" ? /* @__PURE__ */ jsx(
|
|
153
|
-
SceneVideoBackdrop,
|
|
154
|
-
{
|
|
155
|
-
mediaUrl,
|
|
156
|
-
mediaPoster,
|
|
157
|
-
mediaPosition,
|
|
158
|
-
backgroundEffect,
|
|
159
|
-
progress,
|
|
160
|
-
sceneDuration,
|
|
161
|
-
beatIntensity,
|
|
162
|
-
isPlaying,
|
|
163
|
-
onReady: () => setMediaPaint("ready"),
|
|
164
|
-
onError: () => setMediaPaint("failed")
|
|
165
|
-
}
|
|
166
|
-
) : /* @__PURE__ */ jsx(
|
|
167
|
-
"img",
|
|
168
|
-
{
|
|
169
|
-
src: mediaUrl,
|
|
170
|
-
alt: "",
|
|
171
|
-
"aria-hidden": "true",
|
|
172
|
-
draggable: false,
|
|
173
|
-
"data-media-position": mediaPosition,
|
|
174
|
-
style: {
|
|
175
|
-
position: "absolute",
|
|
176
|
-
inset: 0,
|
|
177
|
-
transform: bgTransform.transform,
|
|
178
|
-
transformOrigin: bgTransform.transformOrigin,
|
|
179
|
-
width: "100%",
|
|
180
|
-
height: "100%",
|
|
181
|
-
objectFit: "cover",
|
|
182
|
-
objectPosition: resolvedPosition
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
)),
|
|
186
|
-
(hasExternalVideoBackdrop ? externalVideoReady : showTreatment) && !externalVideoFailed && treatmentLayers.map((layer) => /* @__PURE__ */ jsx(
|
|
187
|
-
"div",
|
|
188
|
-
{
|
|
189
|
-
"data-media-treatment": resolvedTreatment,
|
|
190
|
-
"data-media-overlay": layer.id,
|
|
191
|
-
style: {
|
|
192
|
-
position: "absolute",
|
|
193
|
-
inset: 0,
|
|
194
|
-
background: layer.background,
|
|
195
|
-
pointerEvents: "none",
|
|
196
|
-
...layer.style
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
layer.id
|
|
200
|
-
))
|
|
201
|
-
] });
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
export {
|
|
205
|
-
getMediaBackgroundProps,
|
|
206
|
-
SceneBackground
|
|
207
|
-
};
|
|
@@ -1,37 +1,3 @@
|
|
|
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
|
-
preparingNarration = false,
|
|
12
|
-
onMediaError,
|
|
13
|
-
children
|
|
14
|
-
}) {
|
|
15
|
-
const value = React.useMemo(
|
|
16
|
-
() => ({ mode, audioMuted, audioVolume, preparingNarration, onMediaError }),
|
|
17
|
-
[mode, audioMuted, audioVolume, preparingNarration, onMediaError]
|
|
18
|
-
);
|
|
19
|
-
return /* @__PURE__ */ jsx(BackdropContext.Provider, { value, children });
|
|
20
|
-
}
|
|
21
|
-
function useExternalVideoBackdrop() {
|
|
22
|
-
return React.useContext(BackdropContext).mode;
|
|
23
|
-
}
|
|
24
|
-
function useMediaAudio() {
|
|
25
|
-
const { audioMuted, audioVolume } = React.useContext(BackdropContext);
|
|
26
|
-
return { muted: audioMuted, volume: audioVolume };
|
|
27
|
-
}
|
|
28
|
-
function useNarrationPreroll() {
|
|
29
|
-
return React.useContext(BackdropContext).preparingNarration === true;
|
|
30
|
-
}
|
|
31
|
-
function useMediaFailure() {
|
|
32
|
-
return React.useContext(BackdropContext).onMediaError;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
1
|
// src/visual-system/scene-templates/tokens.ts
|
|
36
2
|
var STYLE_PRESETS = {
|
|
37
3
|
bold: {
|
|
@@ -144,6 +110,40 @@ function darken(hex, factor) {
|
|
|
144
110
|
return `#${ch(1)}${ch(3)}${ch(5)}`;
|
|
145
111
|
}
|
|
146
112
|
|
|
113
|
+
// src/visual-system/scene-templates/external-video-backdrop.tsx
|
|
114
|
+
import React from "react";
|
|
115
|
+
import { jsx } from "react/jsx-runtime";
|
|
116
|
+
var DEFAULT = { mode: false, audioMuted: true, audioVolume: 1 };
|
|
117
|
+
var sharedContext = globalThis;
|
|
118
|
+
var BackdropContext = sharedContext.__vanillaskyVideoBackdropContext ??= React.createContext(DEFAULT);
|
|
119
|
+
function ExternalVideoBackdropProvider({
|
|
120
|
+
mode,
|
|
121
|
+
audioMuted = true,
|
|
122
|
+
audioVolume = 1,
|
|
123
|
+
preparingNarration = false,
|
|
124
|
+
onMediaError,
|
|
125
|
+
children
|
|
126
|
+
}) {
|
|
127
|
+
const value = React.useMemo(
|
|
128
|
+
() => ({ mode, audioMuted, audioVolume, preparingNarration, onMediaError }),
|
|
129
|
+
[mode, audioMuted, audioVolume, preparingNarration, onMediaError]
|
|
130
|
+
);
|
|
131
|
+
return /* @__PURE__ */ jsx(BackdropContext.Provider, { value, children });
|
|
132
|
+
}
|
|
133
|
+
function useExternalVideoBackdrop() {
|
|
134
|
+
return React.useContext(BackdropContext).mode;
|
|
135
|
+
}
|
|
136
|
+
function useMediaAudio() {
|
|
137
|
+
const { audioMuted, audioVolume } = React.useContext(BackdropContext);
|
|
138
|
+
return { muted: audioMuted, volume: audioVolume };
|
|
139
|
+
}
|
|
140
|
+
function useNarrationPreroll() {
|
|
141
|
+
return React.useContext(BackdropContext).preparingNarration === true;
|
|
142
|
+
}
|
|
143
|
+
function useMediaFailure() {
|
|
144
|
+
return React.useContext(BackdropContext).onMediaError;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
147
|
export {
|
|
148
148
|
resolveDensity,
|
|
149
149
|
resolveTokens,
|