@democraft/remotion 0.1.0-beta.0
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/LICENSE +21 -0
- package/README.md +12 -0
- package/dist/chunk-6AAAFZRJ.js +265 -0
- package/dist/chunk-RINGSQ6X.js +28 -0
- package/dist/chunk-SER75PIJ.js +47 -0
- package/dist/chunk-TWKRXLNL.js +684 -0
- package/dist/client.d.ts +116 -0
- package/dist/client.js +40 -0
- package/dist/entry.d.ts +2 -0
- package/dist/entry.js +34 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +58 -0
- package/dist/media-CILzIgah.d.ts +146 -0
- package/dist/server.d.ts +77 -0
- package/dist/server.js +21 -0
- package/package.json +65 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createProductDemoVideoProps
|
|
3
|
+
} from "./chunk-RINGSQ6X.js";
|
|
4
|
+
|
|
5
|
+
// src/stage.ts
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { Img, OffthreadVideo, interpolate, staticFile } from "remotion";
|
|
8
|
+
|
|
9
|
+
// src/utils.ts
|
|
10
|
+
function active(track, frame) {
|
|
11
|
+
return frame >= track.fromFrame && frame < track.fromFrame + track.durationInFrames;
|
|
12
|
+
}
|
|
13
|
+
function lerp(from, to, progress) {
|
|
14
|
+
return from + (to - from) * progress;
|
|
15
|
+
}
|
|
16
|
+
function smoothstep(value) {
|
|
17
|
+
return value * value * (3 - 2 * value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/camera.ts
|
|
21
|
+
function makeCamera(scale, focusX, focusY) {
|
|
22
|
+
return {
|
|
23
|
+
scale,
|
|
24
|
+
focusX,
|
|
25
|
+
focusY,
|
|
26
|
+
translateX: 720 / scale - focusX,
|
|
27
|
+
translateY: 450 / scale - focusY
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function identityCamera() {
|
|
31
|
+
return makeCamera(1, 720, 450);
|
|
32
|
+
}
|
|
33
|
+
function cameraStateAt(timeline, frame) {
|
|
34
|
+
const tracks = [...timeline.camera].sort((a, b) => a.fromFrame - b.fromFrame);
|
|
35
|
+
let index = -1;
|
|
36
|
+
for (let cursor = 0; cursor < tracks.length; cursor += 1) {
|
|
37
|
+
if (frame >= tracks[cursor].fromFrame) index = cursor;
|
|
38
|
+
}
|
|
39
|
+
if (index === -1) return identityCamera();
|
|
40
|
+
const track = tracks[index];
|
|
41
|
+
const previous = index > 0 ? cameraTarget(tracks[index - 1]) : identityCamera();
|
|
42
|
+
const next = cameraTarget(track);
|
|
43
|
+
const progress = smoothstep(
|
|
44
|
+
Math.min(
|
|
45
|
+
1,
|
|
46
|
+
Math.max(0, (frame - track.fromFrame) / track.durationInFrames)
|
|
47
|
+
)
|
|
48
|
+
);
|
|
49
|
+
return makeCamera(
|
|
50
|
+
lerp(previous.scale, next.scale, progress),
|
|
51
|
+
lerp(previous.focusX, next.focusX, progress),
|
|
52
|
+
lerp(previous.focusY, next.focusY, progress)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
function cameraTarget(track) {
|
|
56
|
+
if (!track?.boundingBox || track.kind === "establish")
|
|
57
|
+
return identityCamera();
|
|
58
|
+
const padding = 88;
|
|
59
|
+
const scale = Math.min(
|
|
60
|
+
1.32,
|
|
61
|
+
Math.max(
|
|
62
|
+
1,
|
|
63
|
+
Math.min(
|
|
64
|
+
1440 / (track.boundingBox.width + padding * 2),
|
|
65
|
+
900 / (track.boundingBox.height + padding * 2)
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
const focusX = track.boundingBox.x + track.boundingBox.width / 2;
|
|
70
|
+
const focusY = track.boundingBox.y + track.boundingBox.height / 2;
|
|
71
|
+
return makeCamera(scale, focusX, focusY);
|
|
72
|
+
}
|
|
73
|
+
function cameraTransform(camera, stage) {
|
|
74
|
+
const scale = stage.scale * camera.scale;
|
|
75
|
+
return `matrix(${scale}, 0, 0, ${scale}, ${stage.x + camera.translateX * scale}, ${stage.y + camera.translateY * scale})`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/stage.ts
|
|
79
|
+
var DEFAULT_CAPTURE = { width: 1920, height: 1080 };
|
|
80
|
+
function stageLayout(width, height, capture = DEFAULT_CAPTURE) {
|
|
81
|
+
const scale = Math.min(width / capture.width, height / capture.height);
|
|
82
|
+
return {
|
|
83
|
+
scale,
|
|
84
|
+
x: (width - capture.width * scale) / 2,
|
|
85
|
+
y: (height - capture.height * scale) / 2
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function transformedBox(box, camera, stage) {
|
|
89
|
+
const scale = stage.scale * camera.scale;
|
|
90
|
+
return {
|
|
91
|
+
x: stage.x + (box.x + camera.translateX) * scale,
|
|
92
|
+
y: stage.y + (box.y + camera.translateY) * scale,
|
|
93
|
+
width: box.width * scale,
|
|
94
|
+
height: box.height * scale
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function imageStyle(opacity, capture = DEFAULT_CAPTURE) {
|
|
98
|
+
const dsf = capture.deviceScaleFactor ?? 1;
|
|
99
|
+
return {
|
|
100
|
+
position: "absolute",
|
|
101
|
+
top: 0,
|
|
102
|
+
left: 0,
|
|
103
|
+
width: capture.width * dsf,
|
|
104
|
+
height: capture.height * dsf,
|
|
105
|
+
// Host styles such as Tailwind's `img { max-width: 100% }` must not clamp
|
|
106
|
+
// the native DPR-sized bitmap before the compensating transform runs.
|
|
107
|
+
maxWidth: "none",
|
|
108
|
+
maxHeight: "none",
|
|
109
|
+
transform: `scale(${1 / dsf})`,
|
|
110
|
+
transformOrigin: "0 0",
|
|
111
|
+
objectFit: "contain",
|
|
112
|
+
opacity
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function currentStep(steps, frame) {
|
|
116
|
+
return [...steps].reverse().find((step) => frame >= step.fromFrame);
|
|
117
|
+
}
|
|
118
|
+
function firstScreenshot(sources) {
|
|
119
|
+
return Object.values(sources)[0];
|
|
120
|
+
}
|
|
121
|
+
function previousRenderStep(steps, step) {
|
|
122
|
+
const index = step ? steps.findIndex((item) => item.stepId === step.stepId) : -1;
|
|
123
|
+
return index > 0 ? steps[index - 1] : void 0;
|
|
124
|
+
}
|
|
125
|
+
function nextRenderStep(steps, step) {
|
|
126
|
+
const index = step ? steps.findIndex((item) => item.stepId === step.stepId) : -1;
|
|
127
|
+
return index >= 0 && index < steps.length - 1 ? steps[index + 1] : void 0;
|
|
128
|
+
}
|
|
129
|
+
function screenshotForStep(sources, step) {
|
|
130
|
+
return step ? sources[step.stepId] : firstScreenshot(sources);
|
|
131
|
+
}
|
|
132
|
+
function stageMediaState(steps, sources, frame) {
|
|
133
|
+
const step = currentStep(steps, frame);
|
|
134
|
+
if (!step) {
|
|
135
|
+
return {
|
|
136
|
+
currentSrc: firstScreenshot(sources),
|
|
137
|
+
currentOpacity: 1,
|
|
138
|
+
previousOpacity: 0
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
if (step.kind !== "timeline.transition" || step.durationInFrames <= 1) {
|
|
142
|
+
return {
|
|
143
|
+
currentSrc: screenshotForStep(sources, step),
|
|
144
|
+
currentOpacity: 1,
|
|
145
|
+
previousOpacity: 0
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const progress = interpolate(
|
|
149
|
+
frame,
|
|
150
|
+
[step.fromFrame, step.fromFrame + step.durationInFrames],
|
|
151
|
+
[0, 1],
|
|
152
|
+
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
|
|
153
|
+
);
|
|
154
|
+
return {
|
|
155
|
+
currentSrc: screenshotForStep(sources, nextRenderStep(steps, step) ?? step),
|
|
156
|
+
currentOpacity: progress,
|
|
157
|
+
previousSrc: screenshotForStep(sources, previousRenderStep(steps, step)),
|
|
158
|
+
previousOpacity: 1 - progress
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function Backdrop() {
|
|
162
|
+
return React.createElement("div", {
|
|
163
|
+
style: {
|
|
164
|
+
position: "absolute",
|
|
165
|
+
inset: 0,
|
|
166
|
+
background: "linear-gradient(135deg, #10131a 0%, #18202b 52%, #0d1118 100%)"
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
function StageMedia({
|
|
171
|
+
camera,
|
|
172
|
+
capture = DEFAULT_CAPTURE,
|
|
173
|
+
frame,
|
|
174
|
+
recordingSrc,
|
|
175
|
+
screenshotSrcByStepId,
|
|
176
|
+
stage,
|
|
177
|
+
steps
|
|
178
|
+
}) {
|
|
179
|
+
const media = stageMediaState(steps, screenshotSrcByStepId, frame);
|
|
180
|
+
return React.createElement(
|
|
181
|
+
"div",
|
|
182
|
+
{
|
|
183
|
+
style: {
|
|
184
|
+
position: "absolute",
|
|
185
|
+
left: stage.x,
|
|
186
|
+
top: stage.y,
|
|
187
|
+
width: capture.width * stage.scale,
|
|
188
|
+
height: capture.height * stage.scale,
|
|
189
|
+
borderRadius: 18,
|
|
190
|
+
boxShadow: "0 28px 90px rgba(0,0,0,.35)",
|
|
191
|
+
overflow: "hidden"
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
React.createElement(
|
|
195
|
+
"div",
|
|
196
|
+
{
|
|
197
|
+
style: {
|
|
198
|
+
position: "absolute",
|
|
199
|
+
width: capture.width,
|
|
200
|
+
height: capture.height,
|
|
201
|
+
transform: cameraTransform(camera, { ...stage, x: 0, y: 0 }),
|
|
202
|
+
transformOrigin: "0 0"
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
recordingSrc ? React.createElement(OffthreadVideo, {
|
|
206
|
+
muted: true,
|
|
207
|
+
src: staticFile(recordingSrc),
|
|
208
|
+
style: imageStyle(1, capture)
|
|
209
|
+
}) : null,
|
|
210
|
+
recordingSrc ? null : media.previousSrc && media.previousOpacity > 0 ? React.createElement(Img, {
|
|
211
|
+
src: media.previousSrc,
|
|
212
|
+
style: imageStyle(media.previousOpacity, capture)
|
|
213
|
+
}) : null,
|
|
214
|
+
!recordingSrc && media.currentSrc ? React.createElement(Img, {
|
|
215
|
+
src: media.currentSrc,
|
|
216
|
+
style: imageStyle(media.currentOpacity, capture)
|
|
217
|
+
}) : null
|
|
218
|
+
)
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/overlays.ts
|
|
223
|
+
import React2 from "react";
|
|
224
|
+
import { interpolate as interpolate3, Sequence } from "remotion";
|
|
225
|
+
|
|
226
|
+
// src/components/remocn/soft-blur-in.tsx
|
|
227
|
+
import { Easing, interpolate as interpolate2, useCurrentFrame } from "remotion";
|
|
228
|
+
import { jsx } from "react/jsx-runtime";
|
|
229
|
+
function SoftBlurIn({
|
|
230
|
+
text,
|
|
231
|
+
blur = 12,
|
|
232
|
+
fontSize = 72,
|
|
233
|
+
color = "#171717",
|
|
234
|
+
fontWeight = 600,
|
|
235
|
+
speed = 1,
|
|
236
|
+
className
|
|
237
|
+
}) {
|
|
238
|
+
const frame = useCurrentFrame() * speed;
|
|
239
|
+
const chars = Array.from(text);
|
|
240
|
+
const charDurationFrames = 27;
|
|
241
|
+
const staggerFrames = 1;
|
|
242
|
+
return /* @__PURE__ */ jsx(
|
|
243
|
+
"div",
|
|
244
|
+
{
|
|
245
|
+
style: {
|
|
246
|
+
position: "absolute",
|
|
247
|
+
inset: 0,
|
|
248
|
+
display: "flex",
|
|
249
|
+
alignItems: "center",
|
|
250
|
+
justifyContent: "center",
|
|
251
|
+
background: "transparent"
|
|
252
|
+
},
|
|
253
|
+
children: /* @__PURE__ */ jsx(
|
|
254
|
+
"span",
|
|
255
|
+
{
|
|
256
|
+
className,
|
|
257
|
+
style: {
|
|
258
|
+
fontSize,
|
|
259
|
+
fontWeight,
|
|
260
|
+
color,
|
|
261
|
+
letterSpacing: "-0.05em",
|
|
262
|
+
fontFamily: "var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif"
|
|
263
|
+
},
|
|
264
|
+
children: chars.map((char, i) => {
|
|
265
|
+
const local = frame - i * staggerFrames;
|
|
266
|
+
const easing = Easing.bezier(0.22, 1, 0.36, 1);
|
|
267
|
+
const opacity = interpolate2(local, [0, charDurationFrames], [0, 1], {
|
|
268
|
+
extrapolateLeft: "clamp",
|
|
269
|
+
extrapolateRight: "clamp",
|
|
270
|
+
easing
|
|
271
|
+
});
|
|
272
|
+
const y = interpolate2(local, [0, charDurationFrames], [16, 0], {
|
|
273
|
+
extrapolateLeft: "clamp",
|
|
274
|
+
extrapolateRight: "clamp",
|
|
275
|
+
easing
|
|
276
|
+
});
|
|
277
|
+
const blurAmount = interpolate2(
|
|
278
|
+
local,
|
|
279
|
+
[0, charDurationFrames],
|
|
280
|
+
[blur, 0],
|
|
281
|
+
{ extrapolateLeft: "clamp", extrapolateRight: "clamp", easing }
|
|
282
|
+
);
|
|
283
|
+
return /* @__PURE__ */ jsx(
|
|
284
|
+
"span",
|
|
285
|
+
{
|
|
286
|
+
style: {
|
|
287
|
+
display: "inline-block",
|
|
288
|
+
whiteSpace: "pre",
|
|
289
|
+
backfaceVisibility: "hidden",
|
|
290
|
+
transformOrigin: "50% 55%",
|
|
291
|
+
opacity,
|
|
292
|
+
transform: `translateY(${y}px)`,
|
|
293
|
+
filter: `blur(${blurAmount}px)`
|
|
294
|
+
},
|
|
295
|
+
children: char
|
|
296
|
+
},
|
|
297
|
+
i
|
|
298
|
+
);
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
)
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/overlays.ts
|
|
307
|
+
function overlayOpacity(overlay, frame) {
|
|
308
|
+
return interpolate3(
|
|
309
|
+
frame,
|
|
310
|
+
[
|
|
311
|
+
overlay.fromFrame,
|
|
312
|
+
overlay.fromFrame + 12,
|
|
313
|
+
overlay.fromFrame + overlay.durationInFrames - 12,
|
|
314
|
+
overlay.fromFrame + overlay.durationInFrames
|
|
315
|
+
],
|
|
316
|
+
[0, 1, 1, 0],
|
|
317
|
+
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
function calloutStyle(box, opacity, backgroundColor) {
|
|
321
|
+
return {
|
|
322
|
+
position: "absolute",
|
|
323
|
+
left: Math.min(box.x + box.width + 24, 1920 - 460),
|
|
324
|
+
top: Math.max(42, box.y),
|
|
325
|
+
width: 380,
|
|
326
|
+
padding: 22,
|
|
327
|
+
borderRadius: 14,
|
|
328
|
+
backgroundColor,
|
|
329
|
+
color: "white",
|
|
330
|
+
boxShadow: "0 24px 70px rgba(0,0,0,.32)",
|
|
331
|
+
opacity
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
function OverlayLayer({
|
|
335
|
+
camera,
|
|
336
|
+
frame,
|
|
337
|
+
registry,
|
|
338
|
+
stage,
|
|
339
|
+
timeline
|
|
340
|
+
}) {
|
|
341
|
+
return React2.createElement(
|
|
342
|
+
React2.Fragment,
|
|
343
|
+
null,
|
|
344
|
+
...timeline.overlays.filter((overlay) => active(overlay, frame)).map((overlay) => {
|
|
345
|
+
if (overlay.kind === "caption") {
|
|
346
|
+
const opacity2 = overlayOpacity(overlay, frame);
|
|
347
|
+
const Component2 = resolveCaptionComponent(
|
|
348
|
+
registry,
|
|
349
|
+
overlay.renderer
|
|
350
|
+
);
|
|
351
|
+
return React2.createElement(Component2, {
|
|
352
|
+
key: overlay.id,
|
|
353
|
+
opacity: opacity2,
|
|
354
|
+
overlay
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
if (overlay.kind === "visual") {
|
|
358
|
+
const Component2 = resolveVisualComponent(registry, overlay.visual);
|
|
359
|
+
return React2.createElement(
|
|
360
|
+
Sequence,
|
|
361
|
+
{
|
|
362
|
+
key: overlay.id,
|
|
363
|
+
from: overlay.fromFrame,
|
|
364
|
+
durationInFrames: overlay.durationInFrames,
|
|
365
|
+
name: overlay.visual
|
|
366
|
+
},
|
|
367
|
+
React2.createElement(Component2, overlay.props)
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
const opacity = overlayOpacity(overlay, frame);
|
|
371
|
+
const rawBox = overlay.boundingBox ?? {
|
|
372
|
+
x: 40,
|
|
373
|
+
y: 40,
|
|
374
|
+
width: 0,
|
|
375
|
+
height: 0
|
|
376
|
+
};
|
|
377
|
+
const box = transformedBox(rawBox, camera, stage);
|
|
378
|
+
const Component = resolveCalloutComponent(registry, overlay.renderer);
|
|
379
|
+
return React2.createElement(Component, {
|
|
380
|
+
box,
|
|
381
|
+
key: overlay.id,
|
|
382
|
+
opacity,
|
|
383
|
+
overlay
|
|
384
|
+
});
|
|
385
|
+
})
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
function resolveCaptionComponent(registry, renderer) {
|
|
389
|
+
if (!renderer) return registry.captions["motion.caption"] ?? Caption;
|
|
390
|
+
const component = registry.captions[renderer];
|
|
391
|
+
if (component) return component;
|
|
392
|
+
throw unknownRenderer("caption", renderer, Object.keys(registry.captions));
|
|
393
|
+
}
|
|
394
|
+
function resolveCalloutComponent(registry, renderer) {
|
|
395
|
+
if (!renderer) return registry.callouts["motion.callout"] ?? Callout;
|
|
396
|
+
const component = registry.callouts[renderer];
|
|
397
|
+
if (component) return component;
|
|
398
|
+
throw unknownRenderer("callout", renderer, Object.keys(registry.callouts));
|
|
399
|
+
}
|
|
400
|
+
function resolveVisualComponent(registry, visual) {
|
|
401
|
+
const component = registry.visuals[visual];
|
|
402
|
+
if (component) return component;
|
|
403
|
+
throw unknownRenderer("visual", visual, Object.keys(registry.visuals));
|
|
404
|
+
}
|
|
405
|
+
function unknownRenderer(kind, renderer, registered) {
|
|
406
|
+
return new Error(
|
|
407
|
+
`Unknown ${kind} renderer "${renderer}". Registered renderers: ${registered.sort().join(", ") || "none"}.`
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
function Caption({ opacity, overlay }) {
|
|
411
|
+
return React2.createElement(
|
|
412
|
+
"div",
|
|
413
|
+
{
|
|
414
|
+
style: {
|
|
415
|
+
position: "absolute",
|
|
416
|
+
left: "50%",
|
|
417
|
+
bottom: 74,
|
|
418
|
+
transform: "translateX(-50%)",
|
|
419
|
+
maxWidth: 980,
|
|
420
|
+
padding: "18px 26px",
|
|
421
|
+
borderRadius: 14,
|
|
422
|
+
backgroundColor: "rgba(10,14,20,.84)",
|
|
423
|
+
color: "white",
|
|
424
|
+
font: "500 34px Inter, system-ui, sans-serif",
|
|
425
|
+
opacity
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
overlay.text
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
function KineticCaption({ opacity, overlay }) {
|
|
432
|
+
return React2.createElement(
|
|
433
|
+
"div",
|
|
434
|
+
{
|
|
435
|
+
style: {
|
|
436
|
+
position: "absolute",
|
|
437
|
+
left: "50%",
|
|
438
|
+
bottom: 96,
|
|
439
|
+
transform: `translateX(-50%) scale(${0.96 + opacity * 0.04})`,
|
|
440
|
+
width: 980,
|
|
441
|
+
maxWidth: 980,
|
|
442
|
+
height: 76,
|
|
443
|
+
padding: "16px 24px",
|
|
444
|
+
borderRadius: 16,
|
|
445
|
+
backgroundColor: "rgba(10,14,20,.72)",
|
|
446
|
+
color: "white",
|
|
447
|
+
font: "800 38px Inter, system-ui, sans-serif",
|
|
448
|
+
letterSpacing: 0,
|
|
449
|
+
opacity,
|
|
450
|
+
textShadow: "0 18px 50px rgba(0,0,0,.42)"
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
React2.createElement(SoftBlurIn, {
|
|
454
|
+
blur: 10,
|
|
455
|
+
color: "white",
|
|
456
|
+
fontSize: 38,
|
|
457
|
+
fontWeight: 800,
|
|
458
|
+
speed: 1.2,
|
|
459
|
+
text: overlay.text
|
|
460
|
+
})
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
function Callout({ box, opacity, overlay }) {
|
|
464
|
+
return React2.createElement(
|
|
465
|
+
"div",
|
|
466
|
+
{
|
|
467
|
+
style: calloutStyle(box, opacity, "rgba(10,14,20,.88)")
|
|
468
|
+
},
|
|
469
|
+
React2.createElement(
|
|
470
|
+
"strong",
|
|
471
|
+
{ style: { display: "block", color: "#79e3c7", fontSize: 26 } },
|
|
472
|
+
overlay.title
|
|
473
|
+
),
|
|
474
|
+
overlay.description ? React2.createElement(
|
|
475
|
+
"p",
|
|
476
|
+
{ style: { margin: "10px 0 0", fontSize: 21, lineHeight: 1.45 } },
|
|
477
|
+
overlay.description
|
|
478
|
+
) : null
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
function GlassCallout({
|
|
482
|
+
box,
|
|
483
|
+
opacity,
|
|
484
|
+
overlay
|
|
485
|
+
}) {
|
|
486
|
+
return React2.createElement(
|
|
487
|
+
"div",
|
|
488
|
+
{
|
|
489
|
+
style: {
|
|
490
|
+
...calloutStyle(box, opacity, "rgba(255,255,255,.86)"),
|
|
491
|
+
color: "#121722",
|
|
492
|
+
fontFamily: "Inter, system-ui, sans-serif"
|
|
493
|
+
}
|
|
494
|
+
},
|
|
495
|
+
React2.createElement(
|
|
496
|
+
"strong",
|
|
497
|
+
{ style: { display: "block", color: "#185eaa", fontSize: 26 } },
|
|
498
|
+
overlay.title
|
|
499
|
+
),
|
|
500
|
+
overlay.description ? React2.createElement(
|
|
501
|
+
"p",
|
|
502
|
+
{ style: { margin: "10px 0 0", fontSize: 21, lineHeight: 1.45 } },
|
|
503
|
+
overlay.description
|
|
504
|
+
) : null
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
var defaultVisualRegistry = {
|
|
508
|
+
captions: {
|
|
509
|
+
"motion.caption": Caption,
|
|
510
|
+
"remocn.kinetic-title": KineticCaption
|
|
511
|
+
},
|
|
512
|
+
callouts: {
|
|
513
|
+
"motion.callout": Callout,
|
|
514
|
+
"remocn.glass-callout": GlassCallout
|
|
515
|
+
},
|
|
516
|
+
visuals: {}
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// src/composition.ts
|
|
520
|
+
import React4 from "react";
|
|
521
|
+
import { AbsoluteFill, useCurrentFrame as useCurrentFrame2, useVideoConfig } from "remotion";
|
|
522
|
+
|
|
523
|
+
// src/cursor.ts
|
|
524
|
+
import React3 from "react";
|
|
525
|
+
import { interpolate as interpolate4 } from "remotion";
|
|
526
|
+
var CLICK_PULSE_FRAMES = 28;
|
|
527
|
+
function TargetAndCursorLayer({
|
|
528
|
+
camera,
|
|
529
|
+
frame,
|
|
530
|
+
stage,
|
|
531
|
+
timeline
|
|
532
|
+
}) {
|
|
533
|
+
return React3.createElement(
|
|
534
|
+
"div",
|
|
535
|
+
{
|
|
536
|
+
style: {
|
|
537
|
+
position: "absolute",
|
|
538
|
+
width: 1440,
|
|
539
|
+
height: 900,
|
|
540
|
+
transform: cameraTransform(camera, stage),
|
|
541
|
+
transformOrigin: "0 0"
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
...timeline.cursor.filter((track) => track.point && frame >= track.fromFrame).map(
|
|
545
|
+
(track) => React3.createElement(ClickRipple, {
|
|
546
|
+
key: track.id,
|
|
547
|
+
track,
|
|
548
|
+
frame
|
|
549
|
+
})
|
|
550
|
+
)
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
function ClickRipple({
|
|
554
|
+
track,
|
|
555
|
+
frame
|
|
556
|
+
}) {
|
|
557
|
+
if (!track.point) return null;
|
|
558
|
+
const local = frame - track.fromFrame;
|
|
559
|
+
if (local >= CLICK_PULSE_FRAMES) return null;
|
|
560
|
+
const progress = local / CLICK_PULSE_FRAMES;
|
|
561
|
+
const dotOpacity = interpolate4(progress, [0, 0.2, 0.7, 1], [0, 1, 1, 0], {
|
|
562
|
+
extrapolateLeft: "clamp",
|
|
563
|
+
extrapolateRight: "clamp"
|
|
564
|
+
});
|
|
565
|
+
const ringScale = interpolate4(progress, [0, 1], [0.4, 2.2], {
|
|
566
|
+
extrapolateRight: "clamp"
|
|
567
|
+
});
|
|
568
|
+
const ringOpacity = interpolate4(progress, [0, 0.3, 1], [0, 0.55, 0], {
|
|
569
|
+
extrapolateLeft: "clamp",
|
|
570
|
+
extrapolateRight: "clamp"
|
|
571
|
+
});
|
|
572
|
+
const size = 26;
|
|
573
|
+
return React3.createElement(
|
|
574
|
+
"div",
|
|
575
|
+
{
|
|
576
|
+
style: {
|
|
577
|
+
position: "absolute",
|
|
578
|
+
left: track.point.x,
|
|
579
|
+
top: track.point.y,
|
|
580
|
+
width: 0,
|
|
581
|
+
height: 0
|
|
582
|
+
}
|
|
583
|
+
},
|
|
584
|
+
React3.createElement("div", {
|
|
585
|
+
style: {
|
|
586
|
+
position: "absolute",
|
|
587
|
+
left: -size / 2,
|
|
588
|
+
top: -size / 2,
|
|
589
|
+
width: size,
|
|
590
|
+
height: size,
|
|
591
|
+
borderRadius: 999,
|
|
592
|
+
backgroundColor: "#79e3c7",
|
|
593
|
+
opacity: dotOpacity,
|
|
594
|
+
boxShadow: "0 0 0 6px rgba(121,227,199,.25)"
|
|
595
|
+
}
|
|
596
|
+
}),
|
|
597
|
+
React3.createElement("div", {
|
|
598
|
+
style: {
|
|
599
|
+
position: "absolute",
|
|
600
|
+
left: -size / 2,
|
|
601
|
+
top: -size / 2,
|
|
602
|
+
width: size,
|
|
603
|
+
height: size,
|
|
604
|
+
borderRadius: 999,
|
|
605
|
+
border: "3px solid #79e3c7",
|
|
606
|
+
transform: `scale(${ringScale})`,
|
|
607
|
+
opacity: ringOpacity
|
|
608
|
+
}
|
|
609
|
+
})
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// src/composition.ts
|
|
614
|
+
var defaultProductDemoProps = createProductDemoVideoProps({
|
|
615
|
+
manifest: {
|
|
616
|
+
schemaVersion: "1",
|
|
617
|
+
demoId: "demo",
|
|
618
|
+
steps: [],
|
|
619
|
+
diagnostics: []
|
|
620
|
+
},
|
|
621
|
+
timeline: {
|
|
622
|
+
schemaVersion: "1",
|
|
623
|
+
demoId: "demo",
|
|
624
|
+
fps: 60,
|
|
625
|
+
durationInFrames: 1,
|
|
626
|
+
scenes: [],
|
|
627
|
+
camera: [],
|
|
628
|
+
cursor: [],
|
|
629
|
+
overlays: []
|
|
630
|
+
},
|
|
631
|
+
screenshotSrcByStepId: {}
|
|
632
|
+
});
|
|
633
|
+
function ProductDemoVideo(props) {
|
|
634
|
+
const frame = useCurrentFrame2();
|
|
635
|
+
const { width, height } = useVideoConfig();
|
|
636
|
+
const capture = props.manifest.capture ? {
|
|
637
|
+
width: props.manifest.capture.width,
|
|
638
|
+
height: props.manifest.capture.height,
|
|
639
|
+
deviceScaleFactor: props.manifest.capture.deviceScaleFactor
|
|
640
|
+
} : void 0;
|
|
641
|
+
const stage = stageLayout(width, height, capture);
|
|
642
|
+
const camera = cameraStateAt(props.timeline, frame);
|
|
643
|
+
const steps = props.timeline.scenes.flatMap((scene) => scene.steps);
|
|
644
|
+
const registry = props.registry ?? defaultVisualRegistry;
|
|
645
|
+
return React4.createElement(
|
|
646
|
+
AbsoluteFill,
|
|
647
|
+
{ style: { backgroundColor: "#10131a" } },
|
|
648
|
+
React4.createElement(Backdrop),
|
|
649
|
+
React4.createElement(StageMedia, {
|
|
650
|
+
camera,
|
|
651
|
+
capture,
|
|
652
|
+
frame,
|
|
653
|
+
recordingSrc: props.recordingSrc,
|
|
654
|
+
screenshotSrcByStepId: props.screenshotSrcByStepId,
|
|
655
|
+
stage,
|
|
656
|
+
steps
|
|
657
|
+
}),
|
|
658
|
+
React4.createElement(TargetAndCursorLayer, {
|
|
659
|
+
camera,
|
|
660
|
+
frame,
|
|
661
|
+
stage,
|
|
662
|
+
timeline: props.timeline
|
|
663
|
+
}),
|
|
664
|
+
React4.createElement(OverlayLayer, {
|
|
665
|
+
camera,
|
|
666
|
+
frame,
|
|
667
|
+
registry,
|
|
668
|
+
stage,
|
|
669
|
+
timeline: props.timeline
|
|
670
|
+
})
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export {
|
|
675
|
+
stageLayout,
|
|
676
|
+
OverlayLayer,
|
|
677
|
+
Caption,
|
|
678
|
+
KineticCaption,
|
|
679
|
+
Callout,
|
|
680
|
+
GlassCallout,
|
|
681
|
+
defaultVisualRegistry,
|
|
682
|
+
defaultProductDemoProps,
|
|
683
|
+
ProductDemoVideo
|
|
684
|
+
};
|