@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.
- package/CHANGELOG.md +29 -0
- package/README.md +3 -3
- package/dist/{bg-confetti-WNQXS7ZS.js → bg-confetti-KTHLUJPO.js} +3 -3
- package/dist/{bg-emoji-ETI47GLS.js → bg-emoji-AW7374DZ.js} +3 -3
- package/dist/{bg-media-SVUZAMGX.js → bg-media-KGYE6UVS.js} +9 -4
- package/dist/{brand-message-F3RD4P3P.js → brand-message-AY43ZQR2.js} +4 -3
- package/dist/{chart-bar-CNSC7BNK.js → chart-bar-Z42RDRQT.js} +8 -4
- package/dist/{chart-counter-MCRHKN77.js → chart-counter-X7NAOQ2C.js} +10 -5
- package/dist/{chart-progress-ring-RMI4A7ZK.js → chart-progress-ring-7NSNNHL4.js} +8 -4
- package/dist/check-runtime.js +2 -2
- package/dist/chunk-35LIYILY.js +25 -0
- package/dist/{chunk-IFOW65Z6.js → chunk-4AODC6MS.js} +76 -36
- package/dist/{chunk-FSG2PYWG.js → chunk-G5JPHBX7.js} +1 -1
- package/dist/{chunk-QTMHS7JD.js → chunk-HXSV6RHF.js} +1 -1
- package/dist/{chunk-ABZACD4G.js → chunk-IJM4B2ZN.js} +1 -1
- package/dist/{chunk-BCRUUJ6A.js → chunk-TCEHK2BW.js} +6 -2
- package/dist/{chunk-FNAEQ7QO.js → chunk-XWWLKRNU.js} +3 -1
- package/dist/control-visibility-NQOWTKOQ.js +258 -0
- package/dist/{cta-logo-SVA5GP2A.js → cta-logo-KNBLXUJU.js} +4 -3
- package/dist/{cta-media-E7VLLK42.js → cta-media-NY4ASBGG.js} +8 -4
- package/dist/{incoming-call-62MFZL3Z.js → incoming-call-KWOXLGJN.js} +4 -3
- package/dist/{infographic-before-after-AXCDAWND.js → infographic-before-after-OEM4DSTZ.js} +3 -3
- package/dist/{infographic-feature-list-GW5GUE6O.js → infographic-feature-list-ZZ25JRYQ.js} +8 -4
- package/dist/{infographic-problem-solution-7NURJANA.js → infographic-problem-solution-L3RLFDPE.js} +5 -4
- package/dist/{infographic-stat-row-J7IZR6ZN.js → infographic-stat-row-3OL3TNSH.js} +8 -4
- package/dist/{infographic-steps-VSZM6F5M.js → infographic-steps-LMBSW22P.js} +8 -4
- package/dist/preload-media-KIYBFYRH.js +30 -0
- package/dist/{prompt-input-LOUCRXCY.js → prompt-input-XCQ6TS2L.js} +4 -3
- package/dist/react.js +74 -52
- package/dist/{reaction-QG4CYZLQ.js → reaction-YL6YPGPB.js} +5 -4
- package/dist/{showcase-code-RUTFZR3H.js → showcase-code-EFVHRJUM.js} +8 -4
- package/dist/{showcase-phone-6CP6XEU5.js → showcase-phone-CTHXHEBT.js} +9 -5
- package/dist/{showcase-terminal-MGAEQWPR.js → showcase-terminal-XAMPADHN.js} +8 -4
- package/dist/{showcase-web-Y4W2HVRJ.js → showcase-web-LAKHYXSD.js} +9 -5
- package/dist/{social-milestone-XI2QE5BO.js → social-milestone-EOBEN7CX.js} +6 -4
- package/dist/{social-notification-2UOHQCUY.js → social-notification-MELRWIB6.js} +4 -3
- package/dist/{social-review-stack-FDYZGZTJ.js → social-review-stack-H3U437VT.js} +4 -3
- package/dist/{social-testimonial-OQ7N52GJ.js → social-testimonial-GNNMKMDD.js} +4 -3
- package/dist/{social-tweet-5OLCNPPC.js → social-tweet-PBUKKPT3.js} +4 -3
- package/docs/getting-started.md +2 -2
- package/docs/integrate-nextjs.md +2 -2
- package/examples/nextjs-quickstart/package.json +1 -1
- package/package.json +1 -1
- package/registry/items/barChart.json +9 -3
- package/registry/items/beforeAfter.json +1 -1
- package/registry/items/bigNumber.json +10 -4
- package/registry/items/brandMessage.json +7 -1
- package/registry/items/cardList.json +9 -3
- package/registry/items/codeEditor.json +9 -3
- package/registry/items/confetti.json +1 -1
- package/registry/items/ctaLogo.json +7 -1
- package/registry/items/ctaMedia.json +9 -3
- package/registry/items/emojiBurst.json +1 -1
- package/registry/items/incomingCall.json +7 -1
- package/registry/items/media.json +9 -3
- package/registry/items/milestone.json +8 -2
- package/registry/items/notification.json +7 -1
- package/registry/items/phoneMockup.json +9 -3
- package/registry/items/problemSolution.json +8 -2
- package/registry/items/progressRing.json +9 -3
- package/registry/items/promptInput.json +7 -1
- package/registry/items/reaction.json +8 -2
- package/registry/items/reviewStack.json +7 -1
- package/registry/items/steps.json +9 -3
- package/registry/items/terminal.json +9 -3
- package/registry/items/testimonial.json +7 -1
- package/registry/items/theme.json +1 -1
- package/registry/items/tripleStats.json +9 -3
- package/registry/items/tweet.json +7 -1
- package/registry/items/webMockup.json +9 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@ VanillaSky follows semantic versioning. This changelog begins with the 0.1 beta.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.3.2
|
|
8
|
+
|
|
9
|
+
- Rebuilds text legibility over photo and video backdrops. Scrims now ramp off
|
|
10
|
+
an eased curve instead of a two-stop linear fade, so they no longer leave a
|
|
11
|
+
visible band across the frame, and they are shaped to where each template's
|
|
12
|
+
copy actually sits rather than washing the whole picture. Type over media
|
|
13
|
+
carries its own halo, which lets the scrims stay lighter: the footage keeps
|
|
14
|
+
its contrast and highlights while the headline stays readable.
|
|
15
|
+
- Stops darkening the brand gradient for media that never arrives. A dead,
|
|
16
|
+
blocked, or unresolved `mediaUrl` used to leave the full scrim stack over
|
|
17
|
+
the gradient fallback, so the scene rendered as a muddy, vignetted version
|
|
18
|
+
of the gradient scenes beside it. The fallback is now the clean gradient it
|
|
19
|
+
was always documented to be.
|
|
20
|
+
- Holds a media scene's scrim back until the backdrop actually paints, so a
|
|
21
|
+
photo or video that is still loading shows the clean brand gradient instead
|
|
22
|
+
of a gradient wearing an overlay meant for footage. The scrim and the
|
|
23
|
+
picture now arrive on the same frame.
|
|
24
|
+
- Preloads scene backdrops as soon as their URL is known — including the
|
|
25
|
+
`asset.patch` that carries a resolved stock lookup — so the loading window
|
|
26
|
+
is usually gone before the scene plays. Video posters are warmed; video
|
|
27
|
+
streams deliberately are not.
|
|
28
|
+
- Hides playback controls while a video is playing until the viewer hovers,
|
|
29
|
+
focuses, or taps the player, and keeps paused and completed controls visible.
|
|
30
|
+
- Makes fullscreen usable on mobile browsers through prefixed fullscreen APIs
|
|
31
|
+
and a viewport-filling fallback when native fullscreen is unavailable.
|
|
32
|
+
- Restores configured soundtrack volume and end-of-video fades on iPhone Safari
|
|
33
|
+
by using a Web Audio gain stage for same-origin audio when element volume is
|
|
34
|
+
device-controlled, while preserving direct playback for cross-origin tracks.
|
|
35
|
+
|
|
7
36
|
## 0.3.1
|
|
8
37
|
|
|
9
38
|
- Redesigns player controls for each playback state with responsive circular
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Give your AI a video output
|
|
2
2
|
|
|
3
|
-

|
|
4
4
|
|
|
5
5
|
**VanillaSky is the open-source video response layer.** Turn text, structured
|
|
6
6
|
data, and live application context into personalized video responses that start
|
|
@@ -17,7 +17,7 @@ the planning prompt, trusted templates, validation, streaming, and player.
|
|
|
17
17
|
For humans:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
npm install @vanillaskyai/video@0.3.
|
|
20
|
+
npm install @vanillaskyai/video@0.3.2 ai @ai-sdk/openai
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
For coding agents:
|
|
@@ -106,7 +106,7 @@ shows each complete, validated scene as soon as it is ready and returns a
|
|
|
106
106
|
deterministic `Video` object when generation finishes.
|
|
107
107
|
|
|
108
108
|
A copy-and-run app is in
|
|
109
|
-
[`examples/nextjs-quickstart`](https://github.com/VanillaSkyAi/video/tree/v0.3.
|
|
109
|
+
[`examples/nextjs-quickstart`](https://github.com/VanillaSkyAi/video/tree/v0.3.2/examples/nextjs-quickstart).
|
|
110
110
|
|
|
111
111
|
## Shape the response
|
|
112
112
|
|
|
@@ -4,15 +4,15 @@ import {
|
|
|
4
4
|
import "./chunk-QAAO7OAY.js";
|
|
5
5
|
import {
|
|
6
6
|
TemplateText
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-TCEHK2BW.js";
|
|
8
8
|
import "./chunk-L5BTTCZV.js";
|
|
9
9
|
import {
|
|
10
10
|
BrandGradientOverlay
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-IJM4B2ZN.js";
|
|
12
12
|
import "./chunk-XTOXFMLM.js";
|
|
13
13
|
import {
|
|
14
14
|
resolveTokens
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-XWWLKRNU.js";
|
|
16
16
|
|
|
17
17
|
// src/visual-system/scene-templates/bg-confetti.tsx
|
|
18
18
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -3,17 +3,17 @@ import {
|
|
|
3
3
|
} from "./chunk-QAAO7OAY.js";
|
|
4
4
|
import {
|
|
5
5
|
TemplateText
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-TCEHK2BW.js";
|
|
7
7
|
import {
|
|
8
8
|
Emoji
|
|
9
9
|
} from "./chunk-L5BTTCZV.js";
|
|
10
10
|
import {
|
|
11
11
|
BrandGradientOverlay
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-IJM4B2ZN.js";
|
|
13
13
|
import "./chunk-XTOXFMLM.js";
|
|
14
14
|
import {
|
|
15
15
|
resolveTokens
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-XWWLKRNU.js";
|
|
17
17
|
|
|
18
18
|
// src/visual-system/scene-templates/bg-emoji.tsx
|
|
19
19
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SceneBackground,
|
|
3
3
|
getMediaBackgroundProps
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4AODC6MS.js";
|
|
5
|
+
import {
|
|
6
|
+
hasSceneMedia
|
|
7
|
+
} from "./chunk-35LIYILY.js";
|
|
5
8
|
import {
|
|
6
9
|
ConfettiLayer
|
|
7
10
|
} from "./chunk-CJ7F2CE6.js";
|
|
8
11
|
import "./chunk-QAAO7OAY.js";
|
|
9
12
|
import {
|
|
10
13
|
TemplateText
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-TCEHK2BW.js";
|
|
12
15
|
import "./chunk-L5BTTCZV.js";
|
|
13
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-IJM4B2ZN.js";
|
|
14
17
|
import "./chunk-XTOXFMLM.js";
|
|
15
18
|
import {
|
|
16
19
|
resolveTokens
|
|
17
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-XWWLKRNU.js";
|
|
18
21
|
|
|
19
22
|
// src/visual-system/scene-templates/bg-media.tsx
|
|
20
23
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -55,6 +58,7 @@ var BgMediaTemplate = ({
|
|
|
55
58
|
width,
|
|
56
59
|
height,
|
|
57
60
|
...getMediaBackgroundProps(variables),
|
|
61
|
+
textAnchor: "center",
|
|
58
62
|
backgroundEffect,
|
|
59
63
|
seed: String(variables.texts || ""),
|
|
60
64
|
isPlaying,
|
|
@@ -74,6 +78,7 @@ var BgMediaTemplate = ({
|
|
|
74
78
|
/* @__PURE__ */ jsx(
|
|
75
79
|
TemplateText,
|
|
76
80
|
{
|
|
81
|
+
overMedia: hasSceneMedia(variables),
|
|
77
82
|
motionProgress,
|
|
78
83
|
typeTreatment: resolveTokens(style).preset.type,
|
|
79
84
|
archetype: textArchetype ?? "subtle",
|
|
@@ -4,15 +4,16 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
SceneBackground,
|
|
6
6
|
getMediaBackgroundProps
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4AODC6MS.js";
|
|
8
|
+
import "./chunk-35LIYILY.js";
|
|
8
9
|
import {
|
|
9
10
|
renderWithEmoji
|
|
10
11
|
} from "./chunk-L5BTTCZV.js";
|
|
11
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-IJM4B2ZN.js";
|
|
12
13
|
import {
|
|
13
14
|
interpolate
|
|
14
15
|
} from "./chunk-XTOXFMLM.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-XWWLKRNU.js";
|
|
16
17
|
|
|
17
18
|
// src/visual-system/primitives/typography/BrandMessageBubble.tsx
|
|
18
19
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SceneBackground,
|
|
3
3
|
getMediaBackgroundProps
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4AODC6MS.js";
|
|
5
|
+
import {
|
|
6
|
+
hasSceneMedia
|
|
7
|
+
} from "./chunk-35LIYILY.js";
|
|
5
8
|
import {
|
|
6
9
|
TemplateText
|
|
7
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TCEHK2BW.js";
|
|
8
11
|
import "./chunk-L5BTTCZV.js";
|
|
9
12
|
import {
|
|
10
13
|
TOP_TEXT_AREA_RATIO,
|
|
11
14
|
withOpacity
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-IJM4B2ZN.js";
|
|
13
16
|
import {
|
|
14
17
|
SPRING_SNAPPY,
|
|
15
18
|
interpolate,
|
|
@@ -17,7 +20,7 @@ import {
|
|
|
17
20
|
} from "./chunk-XTOXFMLM.js";
|
|
18
21
|
import {
|
|
19
22
|
resolveTokens
|
|
20
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-XWWLKRNU.js";
|
|
21
24
|
|
|
22
25
|
// src/visual-system/primitives/charts/BarChart.tsx
|
|
23
26
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -279,6 +282,7 @@ var ChartBarTemplate = ({
|
|
|
279
282
|
/* @__PURE__ */ jsx2("div", { style: { position: "absolute", top: 0, left: 0, right: 0, height: height * TOP_TEXT_AREA_RATIO, overflow: "visible" }, children: /* @__PURE__ */ jsx2(
|
|
280
283
|
TemplateText,
|
|
281
284
|
{
|
|
285
|
+
overMedia: hasSceneMedia(variables),
|
|
282
286
|
motionProgress,
|
|
283
287
|
typeTreatment: resolveTokens(style).preset.type,
|
|
284
288
|
archetype: "subtle",
|
|
@@ -4,27 +4,31 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
SceneBackground,
|
|
6
6
|
getMediaBackgroundProps
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4AODC6MS.js";
|
|
8
|
+
import {
|
|
9
|
+
hasSceneMedia
|
|
10
|
+
} from "./chunk-35LIYILY.js";
|
|
8
11
|
import {
|
|
9
12
|
ConfettiLayer
|
|
10
13
|
} from "./chunk-CJ7F2CE6.js";
|
|
11
14
|
import "./chunk-QAAO7OAY.js";
|
|
12
15
|
import {
|
|
13
16
|
TemplateText
|
|
14
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-TCEHK2BW.js";
|
|
15
18
|
import "./chunk-L5BTTCZV.js";
|
|
16
19
|
import {
|
|
17
20
|
TOP_TEXT_AREA_RATIO,
|
|
18
21
|
withOpacity
|
|
19
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-IJM4B2ZN.js";
|
|
20
23
|
import {
|
|
21
24
|
interpolate,
|
|
22
25
|
spring
|
|
23
26
|
} from "./chunk-XTOXFMLM.js";
|
|
24
27
|
import {
|
|
28
|
+
MEDIA_TEXT_SHADOW,
|
|
25
29
|
TOKEN_DEFAULTS,
|
|
26
30
|
resolveTokens
|
|
27
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-XWWLKRNU.js";
|
|
28
32
|
|
|
29
33
|
// src/visual-system/primitives/typography/CountUpNumber.tsx
|
|
30
34
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -93,7 +97,7 @@ var CountUpNumber = ({
|
|
|
93
97
|
[0, 1],
|
|
94
98
|
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
|
|
95
99
|
);
|
|
96
|
-
const mediaTextShadow = hasMediaShadow ?
|
|
100
|
+
const mediaTextShadow = hasMediaShadow ? MEDIA_TEXT_SHADOW : void 0;
|
|
97
101
|
const finalLabelFontSize = labelFontSize ?? 36 * s * 1.3;
|
|
98
102
|
return /* @__PURE__ */ jsxs(
|
|
99
103
|
"div",
|
|
@@ -253,6 +257,7 @@ var ChartCounterTemplate = ({
|
|
|
253
257
|
/* @__PURE__ */ jsx2("div", { style: { position: "absolute", top: 0, left: 0, right: 0, height: height * TOP_TEXT_AREA_RATIO, overflow: "visible" }, children: /* @__PURE__ */ jsx2(
|
|
254
258
|
TemplateText,
|
|
255
259
|
{
|
|
260
|
+
overMedia: hasSceneMedia(variables),
|
|
256
261
|
motionProgress,
|
|
257
262
|
typeTreatment: resolveTokens(style).preset.type,
|
|
258
263
|
archetype: "subtle",
|
|
@@ -5,22 +5,25 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
SceneBackground,
|
|
7
7
|
getMediaBackgroundProps
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-4AODC6MS.js";
|
|
9
|
+
import {
|
|
10
|
+
hasSceneMedia
|
|
11
|
+
} from "./chunk-35LIYILY.js";
|
|
9
12
|
import {
|
|
10
13
|
TemplateText
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-TCEHK2BW.js";
|
|
12
15
|
import "./chunk-L5BTTCZV.js";
|
|
13
16
|
import {
|
|
14
17
|
TOP_TEXT_AREA_RATIO,
|
|
15
18
|
withOpacity
|
|
16
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-IJM4B2ZN.js";
|
|
17
20
|
import {
|
|
18
21
|
interpolate
|
|
19
22
|
} from "./chunk-XTOXFMLM.js";
|
|
20
23
|
import {
|
|
21
24
|
TOKEN_DEFAULTS,
|
|
22
25
|
resolveTokens
|
|
23
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-XWWLKRNU.js";
|
|
24
27
|
|
|
25
28
|
// src/visual-system/primitives/charts/ProgressRing.tsx
|
|
26
29
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -254,6 +257,7 @@ var ChartProgressRingTemplate = ({
|
|
|
254
257
|
/* @__PURE__ */ jsx2("div", { style: { position: "absolute", top: 0, left: 0, right: 0, height: height * TOP_TEXT_AREA_RATIO, overflow: "visible" }, children: /* @__PURE__ */ jsx2(
|
|
255
258
|
TemplateText,
|
|
256
259
|
{
|
|
260
|
+
overMedia: hasSceneMedia(variables),
|
|
257
261
|
motionProgress,
|
|
258
262
|
typeTreatment: resolveTokens(style).preset.type,
|
|
259
263
|
archetype: "subtle",
|
package/dist/check-runtime.js
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// src/visual-system/scene-templates/media-source.ts
|
|
2
|
+
var VIDEO_EXTENSIONS = [".mp4", ".webm", ".mov", ".m4v", ".avi"];
|
|
3
|
+
function isVideoUrl(url) {
|
|
4
|
+
try {
|
|
5
|
+
const pathname = new URL(url).pathname.toLowerCase();
|
|
6
|
+
return VIDEO_EXTENSIONS.some((ext) => pathname.endsWith(ext));
|
|
7
|
+
} catch {
|
|
8
|
+
const lower = url.toLowerCase();
|
|
9
|
+
return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function resolveMediaType(mediaType, mediaUrl) {
|
|
13
|
+
if (mediaType === "gradient") return "gradient";
|
|
14
|
+
if (mediaType === "video") return "video";
|
|
15
|
+
if (mediaType === "photo") return "photo";
|
|
16
|
+
return mediaUrl && isVideoUrl(mediaUrl) ? "video" : "photo";
|
|
17
|
+
}
|
|
18
|
+
function hasSceneMedia(variables) {
|
|
19
|
+
return String(variables.mediaUrl || "").trim() !== "" && String(variables.mediaType || "auto") !== "gradient";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
resolveMediaType,
|
|
24
|
+
hasSceneMedia
|
|
25
|
+
};
|
|
@@ -1,21 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveMediaType
|
|
3
|
+
} from "./chunk-35LIYILY.js";
|
|
1
4
|
import {
|
|
2
5
|
BrandGradientOverlay,
|
|
3
6
|
getBackgroundTransform
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IJM4B2ZN.js";
|
|
5
8
|
|
|
6
9
|
// src/visual-system/scene-templates/scene-background.tsx
|
|
7
|
-
import { useEffect, useRef } from "react";
|
|
10
|
+
import { useEffect, useRef, useState } from "react";
|
|
8
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
var VIDEO_EXTENSIONS = [".mp4", ".webm", ".mov", ".m4v", ".avi"];
|
|
10
|
-
function isVideoUrl(url) {
|
|
11
|
-
try {
|
|
12
|
-
const pathname = new URL(url).pathname.toLowerCase();
|
|
13
|
-
return VIDEO_EXTENSIONS.some((ext) => pathname.endsWith(ext));
|
|
14
|
-
} catch {
|
|
15
|
-
const lower = url.toLowerCase();
|
|
16
|
-
return VIDEO_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
12
|
var MEDIA_POSITIONS = {
|
|
20
13
|
center: "center center",
|
|
21
14
|
top: "center top",
|
|
@@ -29,38 +22,57 @@ function resolveMediaPosition(value) {
|
|
|
29
22
|
function resolveMediaTreatment(value) {
|
|
30
23
|
return value === "subtle" || value === "text-safe" ? value : "cinematic";
|
|
31
24
|
}
|
|
32
|
-
|
|
25
|
+
var SCRIM_STOP_COUNT = 7;
|
|
26
|
+
function smoothstep(t) {
|
|
27
|
+
return t * t * (3 - 2 * t);
|
|
28
|
+
}
|
|
29
|
+
function easedStops(peakAlpha, start, end, direction) {
|
|
30
|
+
const alphaAt = (t) => {
|
|
31
|
+
const eased = direction === "fade-out" ? 1 - smoothstep(t) : smoothstep(t);
|
|
32
|
+
return `rgba(0,0,0,${Number((peakAlpha * eased).toFixed(3))})`;
|
|
33
|
+
};
|
|
34
|
+
const stops = [];
|
|
35
|
+
if (start > 0) stops.push(`${alphaAt(0)} 0%`);
|
|
36
|
+
for (let i = 0; i < SCRIM_STOP_COUNT; i += 1) {
|
|
37
|
+
const t = i / (SCRIM_STOP_COUNT - 1);
|
|
38
|
+
const position = Number((start + (end - start) * t).toFixed(2));
|
|
39
|
+
stops.push(`${alphaAt(t)} ${position}%`);
|
|
40
|
+
}
|
|
41
|
+
if (end < 100) stops.push(`${alphaAt(1)} 100%`);
|
|
42
|
+
return stops.join(", ");
|
|
43
|
+
}
|
|
44
|
+
function getMediaTreatmentLayers(value, anchor = "full") {
|
|
33
45
|
const treatment = resolveMediaTreatment(value);
|
|
34
46
|
const vignette = {
|
|
35
47
|
id: "vignette",
|
|
36
|
-
background: treatment === "subtle" ?
|
|
48
|
+
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")})`
|
|
37
49
|
};
|
|
38
50
|
if (treatment === "subtle") return [vignette];
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
51
|
+
const textSafe = treatment === "text-safe";
|
|
52
|
+
const layers = [vignette];
|
|
53
|
+
if (anchor !== "bottom") {
|
|
54
|
+
layers.push({
|
|
42
55
|
id: "center-scrim",
|
|
43
|
-
background:
|
|
44
|
-
}
|
|
45
|
-
|
|
56
|
+
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")})`
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (anchor !== "center") {
|
|
60
|
+
layers.push({
|
|
46
61
|
id: "bottom-scrim",
|
|
47
|
-
background:
|
|
62
|
+
background: `linear-gradient(to top, ${easedStops(textSafe ? 0.64 : 0.5, 8, 100, "fade-out")})`,
|
|
48
63
|
style: { top: "55%" }
|
|
49
|
-
}
|
|
50
|
-
];
|
|
51
|
-
if (treatment === "text-safe") {
|
|
52
|
-
cinematic.splice(1, 0, {
|
|
53
|
-
id: "full-wash",
|
|
54
|
-
background: "rgba(0,0,0,0.30)"
|
|
55
64
|
});
|
|
56
65
|
}
|
|
57
|
-
return
|
|
66
|
+
return layers;
|
|
58
67
|
}
|
|
59
|
-
function
|
|
60
|
-
if (
|
|
61
|
-
if (
|
|
62
|
-
if (
|
|
63
|
-
|
|
68
|
+
function initialMediaPaint(wantsMedia, resolved, mediaUrl, mediaPoster) {
|
|
69
|
+
if (typeof window === "undefined") return "ready";
|
|
70
|
+
if (!wantsMedia) return "ready";
|
|
71
|
+
if (resolved === "video") return mediaPoster ? "ready" : "pending";
|
|
72
|
+
if (typeof Image === "undefined") return "ready";
|
|
73
|
+
const cached = new Image();
|
|
74
|
+
cached.src = mediaUrl;
|
|
75
|
+
return cached.complete && cached.naturalWidth > 0 ? "ready" : "pending";
|
|
64
76
|
}
|
|
65
77
|
function getMediaBackgroundProps(variables) {
|
|
66
78
|
return {
|
|
@@ -83,6 +95,7 @@ var SceneBackground = ({
|
|
|
83
95
|
mediaPoster,
|
|
84
96
|
mediaPosition = "center",
|
|
85
97
|
mediaTreatment = "cinematic",
|
|
98
|
+
textAnchor = "full",
|
|
86
99
|
backgroundEffect,
|
|
87
100
|
seed,
|
|
88
101
|
isPlaying = true,
|
|
@@ -91,10 +104,35 @@ var SceneBackground = ({
|
|
|
91
104
|
void _width;
|
|
92
105
|
void _height;
|
|
93
106
|
const resolved = resolveMediaType(mediaType, mediaUrl);
|
|
94
|
-
const
|
|
107
|
+
const wantsMedia = resolved !== "gradient" && !!mediaUrl;
|
|
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";
|
|
95
133
|
const resolvedPosition = resolveMediaPosition(mediaPosition);
|
|
96
134
|
const resolvedTreatment = resolveMediaTreatment(mediaTreatment);
|
|
97
|
-
const treatmentLayers = getMediaTreatmentLayers(resolvedTreatment);
|
|
135
|
+
const treatmentLayers = getMediaTreatmentLayers(resolvedTreatment, textAnchor);
|
|
98
136
|
const gradSeed = typeof seed === "number" ? seed : typeof seed === "string" ? seed.split("").reduce((acc, c) => acc + c.charCodeAt(0), 0) : 0;
|
|
99
137
|
const bgTransform = getBackgroundTransform(
|
|
100
138
|
backgroundEffect,
|
|
@@ -154,6 +192,8 @@ var SceneBackground = ({
|
|
|
154
192
|
loop: true,
|
|
155
193
|
playsInline: true,
|
|
156
194
|
preload: "auto",
|
|
195
|
+
onLoadedData: () => setMediaPaint("ready"),
|
|
196
|
+
onError: () => setMediaPaint("failed"),
|
|
157
197
|
"data-media-position": mediaPosition,
|
|
158
198
|
style: {
|
|
159
199
|
position: "absolute",
|
|
@@ -181,7 +221,7 @@ var SceneBackground = ({
|
|
|
181
221
|
}
|
|
182
222
|
}
|
|
183
223
|
)),
|
|
184
|
-
|
|
224
|
+
showTreatment && treatmentLayers.map((layer) => /* @__PURE__ */ jsx(
|
|
185
225
|
"div",
|
|
186
226
|
{
|
|
187
227
|
"data-media-treatment": resolvedTreatment,
|
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
interpolate,
|
|
10
10
|
spring
|
|
11
11
|
} from "./chunk-XTOXFMLM.js";
|
|
12
|
+
import {
|
|
13
|
+
MEDIA_TEXT_SHADOW
|
|
14
|
+
} from "./chunk-XWWLKRNU.js";
|
|
12
15
|
|
|
13
16
|
// src/visual-system/scene-templates/text-archetypes.ts
|
|
14
17
|
var TEXT_ARCHETYPES = [
|
|
@@ -526,7 +529,8 @@ var TemplateText = ({
|
|
|
526
529
|
safeZone = DEFAULT_SAFE_ZONE,
|
|
527
530
|
font = DEFAULT_FONT,
|
|
528
531
|
color = "#FFFFFF",
|
|
529
|
-
beatIntensity = 0
|
|
532
|
+
beatIntensity = 0,
|
|
533
|
+
overMedia = false
|
|
530
534
|
}) => {
|
|
531
535
|
const textSafe = typeof textRaw === "string" ? textRaw : "";
|
|
532
536
|
const isDevelopment = import.meta.env?.DEV;
|
|
@@ -568,7 +572,7 @@ var TemplateText = ({
|
|
|
568
572
|
} : baseTypo;
|
|
569
573
|
const presetWeight = tt ? Math.min(900, Math.max(100, fontWeight + tt.weightDelta)) : fontWeight;
|
|
570
574
|
const presetSize = tt ? fontSize * tt.sizeScale : fontSize;
|
|
571
|
-
const textShadow = dropShadowFor(color);
|
|
575
|
+
const textShadow = overMedia ? MEDIA_TEXT_SHADOW : dropShadowFor(color);
|
|
572
576
|
const containerStyle = {
|
|
573
577
|
position: "absolute",
|
|
574
578
|
left: 0,
|
|
@@ -144,6 +144,7 @@ function lighten(hex, factor) {
|
|
|
144
144
|
const lb = Math.min(255, Math.round(b + (255 - b) * factor));
|
|
145
145
|
return `#${lr.toString(16).padStart(2, "0")}${lg.toString(16).padStart(2, "0")}${lb.toString(16).padStart(2, "0")}`;
|
|
146
146
|
}
|
|
147
|
+
var MEDIA_TEXT_SHADOW = "0 2px 8px rgba(0,0,0,0.55), 0 6px 16px rgba(0,0,0,0.35)";
|
|
147
148
|
|
|
148
149
|
export {
|
|
149
150
|
TOKEN_DEFAULTS,
|
|
@@ -151,5 +152,6 @@ export {
|
|
|
151
152
|
resolveDensity,
|
|
152
153
|
resolveTokens,
|
|
153
154
|
darken,
|
|
154
|
-
lighten
|
|
155
|
+
lighten,
|
|
156
|
+
MEDIA_TEXT_SHADOW
|
|
155
157
|
};
|