@json-render/remotion 0.4.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 +201 -0
- package/README.md +310 -0
- package/dist/chunk-5C3GTKV7.mjs +356 -0
- package/dist/chunk-5C3GTKV7.mjs.map +1 -0
- package/dist/index.d.mts +166 -0
- package/dist/index.d.ts +166 -0
- package/dist/index.js +913 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +532 -0
- package/dist/index.mjs.map +1 -0
- package/dist/server.d.mts +426 -0
- package/dist/server.d.ts +426 -0
- package/dist/server.js +385 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +13 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +69 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,913 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ClipWrapper: () => ClipWrapper,
|
|
24
|
+
ImageSlide: () => ImageSlide,
|
|
25
|
+
LogoBug: () => LogoBug,
|
|
26
|
+
LowerThird: () => LowerThird,
|
|
27
|
+
QuoteCard: () => QuoteCard,
|
|
28
|
+
Renderer: () => Renderer,
|
|
29
|
+
SplitScreen: () => SplitScreen,
|
|
30
|
+
StatCard: () => StatCard,
|
|
31
|
+
TextOverlay: () => TextOverlay,
|
|
32
|
+
TitleCard: () => TitleCard,
|
|
33
|
+
TypingText: () => TypingText,
|
|
34
|
+
VideoClip: () => VideoClip,
|
|
35
|
+
schema: () => schema,
|
|
36
|
+
standardComponentDefinitions: () => standardComponentDefinitions,
|
|
37
|
+
standardComponents: () => standardComponents,
|
|
38
|
+
standardEffectDefinitions: () => standardEffectDefinitions,
|
|
39
|
+
standardTransitionDefinitions: () => standardTransitionDefinitions,
|
|
40
|
+
useTransition: () => useTransition
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(index_exports);
|
|
43
|
+
|
|
44
|
+
// src/schema.ts
|
|
45
|
+
var import_core = require("@json-render/core");
|
|
46
|
+
function remotionPromptTemplate(context) {
|
|
47
|
+
const { catalog, options } = context;
|
|
48
|
+
const { system = "You are a video timeline generator.", customRules = [] } = options;
|
|
49
|
+
const lines = [];
|
|
50
|
+
lines.push(system);
|
|
51
|
+
lines.push("");
|
|
52
|
+
lines.push("OUTPUT FORMAT:");
|
|
53
|
+
lines.push(
|
|
54
|
+
"Output JSONL (one JSON object per line) with patches to build a timeline spec."
|
|
55
|
+
);
|
|
56
|
+
lines.push(
|
|
57
|
+
"Each line is a JSON patch operation. Build the timeline incrementally."
|
|
58
|
+
);
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push("Example output (each line is a separate JSON object):");
|
|
61
|
+
lines.push("");
|
|
62
|
+
lines.push(`{"op":"set","path":"/composition","value":{"id":"intro","fps":30,"width":1920,"height":1080,"durationInFrames":300}}
|
|
63
|
+
{"op":"set","path":"/tracks","value":[{"id":"main","name":"Main","type":"video","enabled":true},{"id":"overlay","name":"Overlay","type":"overlay","enabled":true}]}
|
|
64
|
+
{"op":"set","path":"/clips/0","value":{"id":"clip-1","trackId":"main","component":"TitleCard","props":{"title":"Welcome","subtitle":"Getting Started"},"from":0,"durationInFrames":90,"transitionIn":{"type":"fade","durationInFrames":15},"transitionOut":{"type":"fade","durationInFrames":15}}}
|
|
65
|
+
{"op":"set","path":"/clips/1","value":{"id":"clip-2","trackId":"main","component":"TitleCard","props":{"title":"Features"},"from":90,"durationInFrames":90}}
|
|
66
|
+
{"op":"set","path":"/audio","value":{"tracks":[]}}`);
|
|
67
|
+
lines.push("");
|
|
68
|
+
const catalogData = catalog;
|
|
69
|
+
if (catalogData.components) {
|
|
70
|
+
lines.push(
|
|
71
|
+
`AVAILABLE COMPONENTS (${Object.keys(catalogData.components).length}):`
|
|
72
|
+
);
|
|
73
|
+
lines.push("");
|
|
74
|
+
for (const [name, def] of Object.entries(catalogData.components)) {
|
|
75
|
+
const duration = def.defaultDuration ? ` [default: ${def.defaultDuration} frames]` : "";
|
|
76
|
+
lines.push(
|
|
77
|
+
`- ${name}: ${def.description || "No description"}${duration}`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
lines.push("");
|
|
81
|
+
}
|
|
82
|
+
if (catalogData.transitions && Object.keys(catalogData.transitions).length > 0) {
|
|
83
|
+
lines.push("AVAILABLE TRANSITIONS:");
|
|
84
|
+
lines.push("");
|
|
85
|
+
for (const [name, def] of Object.entries(catalogData.transitions)) {
|
|
86
|
+
lines.push(`- ${name}: ${def.description || "No description"}`);
|
|
87
|
+
}
|
|
88
|
+
lines.push("");
|
|
89
|
+
}
|
|
90
|
+
lines.push("RULES:");
|
|
91
|
+
const baseRules = [
|
|
92
|
+
"Output ONLY JSONL patches - one JSON object per line, no markdown, no code fences",
|
|
93
|
+
"First set /composition with {id, fps:30, width:1920, height:1080, durationInFrames}",
|
|
94
|
+
"Then set /tracks array with video/overlay tracks",
|
|
95
|
+
"Then set each clip: /clips/0, /clips/1, etc.",
|
|
96
|
+
"Finally set /audio with {tracks:[]}",
|
|
97
|
+
"ONLY use components listed above",
|
|
98
|
+
"fps is always 30 (1 second = 30 frames, 10 seconds = 300 frames)",
|
|
99
|
+
`Clips on "main" track flow sequentially (from = previous clip's from + durationInFrames)`,
|
|
100
|
+
'Overlay clips (LowerThird, TextOverlay) go on "overlay" track'
|
|
101
|
+
];
|
|
102
|
+
const allRules = [...baseRules, ...customRules];
|
|
103
|
+
allRules.forEach((rule, i) => {
|
|
104
|
+
lines.push(`${i + 1}. ${rule}`);
|
|
105
|
+
});
|
|
106
|
+
return lines.join("\n");
|
|
107
|
+
}
|
|
108
|
+
var schema = (0, import_core.defineSchema)(
|
|
109
|
+
(s) => ({
|
|
110
|
+
// What the AI-generated SPEC looks like (timeline-based)
|
|
111
|
+
spec: s.object({
|
|
112
|
+
/** Composition settings */
|
|
113
|
+
composition: s.object({
|
|
114
|
+
/** Unique composition ID */
|
|
115
|
+
id: s.string(),
|
|
116
|
+
/** Frames per second */
|
|
117
|
+
fps: s.number(),
|
|
118
|
+
/** Width in pixels */
|
|
119
|
+
width: s.number(),
|
|
120
|
+
/** Height in pixels */
|
|
121
|
+
height: s.number(),
|
|
122
|
+
/** Total duration in frames */
|
|
123
|
+
durationInFrames: s.number()
|
|
124
|
+
}),
|
|
125
|
+
/** Timeline tracks (like layers in video editing) */
|
|
126
|
+
tracks: s.array(
|
|
127
|
+
s.object({
|
|
128
|
+
/** Unique track ID */
|
|
129
|
+
id: s.string(),
|
|
130
|
+
/** Track name for organization */
|
|
131
|
+
name: s.string(),
|
|
132
|
+
/** Track type: "video" | "audio" | "overlay" | "text" */
|
|
133
|
+
type: s.string(),
|
|
134
|
+
/** Whether track is muted/hidden */
|
|
135
|
+
enabled: s.boolean()
|
|
136
|
+
})
|
|
137
|
+
),
|
|
138
|
+
/** Clips placed on the timeline */
|
|
139
|
+
clips: s.array(
|
|
140
|
+
s.object({
|
|
141
|
+
/** Unique clip ID */
|
|
142
|
+
id: s.string(),
|
|
143
|
+
/** Which track this clip belongs to */
|
|
144
|
+
trackId: s.string(),
|
|
145
|
+
/** Component type from catalog */
|
|
146
|
+
component: s.ref("catalog.components"),
|
|
147
|
+
/** Component props */
|
|
148
|
+
props: s.propsOf("catalog.components"),
|
|
149
|
+
/** Start frame (when clip begins) */
|
|
150
|
+
from: s.number(),
|
|
151
|
+
/** Duration in frames */
|
|
152
|
+
durationInFrames: s.number(),
|
|
153
|
+
/** Transition in effect */
|
|
154
|
+
transitionIn: s.object({
|
|
155
|
+
type: s.ref("catalog.transitions"),
|
|
156
|
+
durationInFrames: s.number()
|
|
157
|
+
}),
|
|
158
|
+
/** Transition out effect */
|
|
159
|
+
transitionOut: s.object({
|
|
160
|
+
type: s.ref("catalog.transitions"),
|
|
161
|
+
durationInFrames: s.number()
|
|
162
|
+
})
|
|
163
|
+
})
|
|
164
|
+
),
|
|
165
|
+
/** Audio configuration */
|
|
166
|
+
audio: s.object({
|
|
167
|
+
/** Background music/audio clips */
|
|
168
|
+
tracks: s.array(
|
|
169
|
+
s.object({
|
|
170
|
+
id: s.string(),
|
|
171
|
+
src: s.string(),
|
|
172
|
+
from: s.number(),
|
|
173
|
+
durationInFrames: s.number(),
|
|
174
|
+
volume: s.number()
|
|
175
|
+
})
|
|
176
|
+
)
|
|
177
|
+
})
|
|
178
|
+
}),
|
|
179
|
+
// What the CATALOG must provide
|
|
180
|
+
catalog: s.object({
|
|
181
|
+
/** Video component definitions (scenes, overlays, etc.) */
|
|
182
|
+
components: s.map({
|
|
183
|
+
/** Zod schema for component props */
|
|
184
|
+
props: s.zod(),
|
|
185
|
+
/** Component type: "scene" | "overlay" | "text" | "image" | "video" */
|
|
186
|
+
type: s.string(),
|
|
187
|
+
/** Default duration in frames (can be overridden per clip) */
|
|
188
|
+
defaultDuration: s.number(),
|
|
189
|
+
/** Description for AI generation hints */
|
|
190
|
+
description: s.string()
|
|
191
|
+
}),
|
|
192
|
+
/** Transition effect definitions */
|
|
193
|
+
transitions: s.map({
|
|
194
|
+
/** Default duration in frames */
|
|
195
|
+
defaultDuration: s.number(),
|
|
196
|
+
/** Description for AI generation hints */
|
|
197
|
+
description: s.string()
|
|
198
|
+
}),
|
|
199
|
+
/** Effect definitions (filters, animations, etc.) */
|
|
200
|
+
effects: s.map({
|
|
201
|
+
/** Zod schema for effect params */
|
|
202
|
+
params: s.zod(),
|
|
203
|
+
/** Description for AI generation hints */
|
|
204
|
+
description: s.string()
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
}),
|
|
208
|
+
{
|
|
209
|
+
promptTemplate: remotionPromptTemplate
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
// src/components/hooks.ts
|
|
214
|
+
var import_remotion = require("remotion");
|
|
215
|
+
function useTransition(clip, frame) {
|
|
216
|
+
const { fps } = (0, import_remotion.useVideoConfig)();
|
|
217
|
+
const relativeFrame = frame - clip.from;
|
|
218
|
+
const clipEnd = clip.durationInFrames;
|
|
219
|
+
let opacity = 1;
|
|
220
|
+
let translateX = 0;
|
|
221
|
+
let translateY = 0;
|
|
222
|
+
let scale = 1;
|
|
223
|
+
if (clip.transitionIn && relativeFrame < clip.transitionIn.durationInFrames) {
|
|
224
|
+
const progress = relativeFrame / clip.transitionIn.durationInFrames;
|
|
225
|
+
const easedProgress = (0, import_remotion.spring)({
|
|
226
|
+
frame: relativeFrame,
|
|
227
|
+
fps,
|
|
228
|
+
config: { damping: 200 },
|
|
229
|
+
durationInFrames: clip.transitionIn.durationInFrames
|
|
230
|
+
});
|
|
231
|
+
switch (clip.transitionIn.type) {
|
|
232
|
+
case "fade":
|
|
233
|
+
opacity = easedProgress;
|
|
234
|
+
break;
|
|
235
|
+
case "slideLeft":
|
|
236
|
+
translateX = (0, import_remotion.interpolate)(easedProgress, [0, 1], [100, 0]);
|
|
237
|
+
opacity = easedProgress;
|
|
238
|
+
break;
|
|
239
|
+
case "slideRight":
|
|
240
|
+
translateX = (0, import_remotion.interpolate)(easedProgress, [0, 1], [-100, 0]);
|
|
241
|
+
opacity = easedProgress;
|
|
242
|
+
break;
|
|
243
|
+
case "slideUp":
|
|
244
|
+
translateY = (0, import_remotion.interpolate)(easedProgress, [0, 1], [100, 0]);
|
|
245
|
+
opacity = easedProgress;
|
|
246
|
+
break;
|
|
247
|
+
case "slideDown":
|
|
248
|
+
translateY = (0, import_remotion.interpolate)(easedProgress, [0, 1], [-100, 0]);
|
|
249
|
+
opacity = easedProgress;
|
|
250
|
+
break;
|
|
251
|
+
case "zoom":
|
|
252
|
+
scale = (0, import_remotion.interpolate)(easedProgress, [0, 1], [0.8, 1]);
|
|
253
|
+
opacity = easedProgress;
|
|
254
|
+
break;
|
|
255
|
+
case "wipe":
|
|
256
|
+
opacity = progress;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (clip.transitionOut && relativeFrame > clipEnd - clip.transitionOut.durationInFrames) {
|
|
261
|
+
const outStart = clipEnd - clip.transitionOut.durationInFrames;
|
|
262
|
+
const outProgress = (relativeFrame - outStart) / clip.transitionOut.durationInFrames;
|
|
263
|
+
const easedOutProgress = 1 - outProgress;
|
|
264
|
+
switch (clip.transitionOut.type) {
|
|
265
|
+
case "fade":
|
|
266
|
+
opacity = Math.min(opacity, easedOutProgress);
|
|
267
|
+
break;
|
|
268
|
+
case "slideLeft":
|
|
269
|
+
translateX = (0, import_remotion.interpolate)(outProgress, [0, 1], [0, -100]);
|
|
270
|
+
opacity = Math.min(opacity, easedOutProgress);
|
|
271
|
+
break;
|
|
272
|
+
case "slideRight":
|
|
273
|
+
translateX = (0, import_remotion.interpolate)(outProgress, [0, 1], [0, 100]);
|
|
274
|
+
opacity = Math.min(opacity, easedOutProgress);
|
|
275
|
+
break;
|
|
276
|
+
case "slideUp":
|
|
277
|
+
translateY = (0, import_remotion.interpolate)(outProgress, [0, 1], [0, -100]);
|
|
278
|
+
opacity = Math.min(opacity, easedOutProgress);
|
|
279
|
+
break;
|
|
280
|
+
case "slideDown":
|
|
281
|
+
translateY = (0, import_remotion.interpolate)(outProgress, [0, 1], [0, 100]);
|
|
282
|
+
opacity = Math.min(opacity, easedOutProgress);
|
|
283
|
+
break;
|
|
284
|
+
case "zoom":
|
|
285
|
+
scale = (0, import_remotion.interpolate)(outProgress, [0, 1], [1, 1.2]);
|
|
286
|
+
opacity = Math.min(opacity, easedOutProgress);
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return { opacity, translateX, translateY, scale };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/components/ClipWrapper.tsx
|
|
294
|
+
var import_remotion2 = require("remotion");
|
|
295
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
296
|
+
function ClipWrapper({ clip, children }) {
|
|
297
|
+
const frame = (0, import_remotion2.useCurrentFrame)();
|
|
298
|
+
const { opacity, translateX, translateY, scale } = useTransition(
|
|
299
|
+
clip,
|
|
300
|
+
frame + clip.from
|
|
301
|
+
);
|
|
302
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
303
|
+
import_remotion2.AbsoluteFill,
|
|
304
|
+
{
|
|
305
|
+
style: {
|
|
306
|
+
opacity,
|
|
307
|
+
transform: `translateX(${translateX}%) translateY(${translateY}%) scale(${scale})`
|
|
308
|
+
},
|
|
309
|
+
children
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/components/standard.tsx
|
|
315
|
+
var import_remotion3 = require("remotion");
|
|
316
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
317
|
+
function TitleCard({ clip }) {
|
|
318
|
+
const { title, subtitle, backgroundColor, textColor } = clip.props;
|
|
319
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
320
|
+
import_remotion3.AbsoluteFill,
|
|
321
|
+
{
|
|
322
|
+
style: {
|
|
323
|
+
backgroundColor: backgroundColor || "#1a1a2e",
|
|
324
|
+
color: textColor || "#ffffff",
|
|
325
|
+
display: "flex",
|
|
326
|
+
flexDirection: "column",
|
|
327
|
+
alignItems: "center",
|
|
328
|
+
justifyContent: "center",
|
|
329
|
+
padding: 40
|
|
330
|
+
},
|
|
331
|
+
children: [
|
|
332
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
333
|
+
"div",
|
|
334
|
+
{
|
|
335
|
+
style: {
|
|
336
|
+
fontSize: 72,
|
|
337
|
+
fontWeight: "bold",
|
|
338
|
+
textAlign: "center",
|
|
339
|
+
marginBottom: 16
|
|
340
|
+
},
|
|
341
|
+
children: title
|
|
342
|
+
}
|
|
343
|
+
),
|
|
344
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
345
|
+
"div",
|
|
346
|
+
{
|
|
347
|
+
style: {
|
|
348
|
+
fontSize: 36,
|
|
349
|
+
opacity: 0.7,
|
|
350
|
+
textAlign: "center"
|
|
351
|
+
},
|
|
352
|
+
children: subtitle
|
|
353
|
+
}
|
|
354
|
+
)
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
) });
|
|
358
|
+
}
|
|
359
|
+
function ImageSlide({ clip }) {
|
|
360
|
+
const { src, alt, fit, backgroundColor } = clip.props;
|
|
361
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
362
|
+
import_remotion3.AbsoluteFill,
|
|
363
|
+
{
|
|
364
|
+
style: {
|
|
365
|
+
backgroundColor: backgroundColor || "#0a0a0a",
|
|
366
|
+
display: "flex",
|
|
367
|
+
alignItems: "center",
|
|
368
|
+
justifyContent: "center"
|
|
369
|
+
},
|
|
370
|
+
children: src ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
371
|
+
"img",
|
|
372
|
+
{
|
|
373
|
+
src,
|
|
374
|
+
alt,
|
|
375
|
+
style: {
|
|
376
|
+
width: "100%",
|
|
377
|
+
height: "100%",
|
|
378
|
+
objectFit: fit || "cover"
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { color: "rgba(255,255,255,0.5)", fontSize: 24 }, children: [
|
|
382
|
+
"[",
|
|
383
|
+
alt,
|
|
384
|
+
"]"
|
|
385
|
+
] })
|
|
386
|
+
}
|
|
387
|
+
) });
|
|
388
|
+
}
|
|
389
|
+
function SplitScreen({ clip }) {
|
|
390
|
+
const { leftTitle, rightTitle, leftColor, rightColor } = clip.props;
|
|
391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_remotion3.AbsoluteFill, { style: { display: "flex", flexDirection: "row" }, children: [
|
|
392
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
393
|
+
"div",
|
|
394
|
+
{
|
|
395
|
+
style: {
|
|
396
|
+
flex: 1,
|
|
397
|
+
backgroundColor: leftColor || "#1a1a2e",
|
|
398
|
+
display: "flex",
|
|
399
|
+
alignItems: "center",
|
|
400
|
+
justifyContent: "center",
|
|
401
|
+
color: "#ffffff"
|
|
402
|
+
},
|
|
403
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 48, fontWeight: "bold" }, children: leftTitle })
|
|
404
|
+
}
|
|
405
|
+
),
|
|
406
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
407
|
+
"div",
|
|
408
|
+
{
|
|
409
|
+
style: {
|
|
410
|
+
flex: 1,
|
|
411
|
+
backgroundColor: rightColor || "#2e1a1a",
|
|
412
|
+
display: "flex",
|
|
413
|
+
alignItems: "center",
|
|
414
|
+
justifyContent: "center",
|
|
415
|
+
color: "#ffffff"
|
|
416
|
+
},
|
|
417
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 48, fontWeight: "bold" }, children: rightTitle })
|
|
418
|
+
}
|
|
419
|
+
)
|
|
420
|
+
] }) });
|
|
421
|
+
}
|
|
422
|
+
function QuoteCard({ clip }) {
|
|
423
|
+
const { quote, author, backgroundColor } = clip.props;
|
|
424
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
425
|
+
import_remotion3.AbsoluteFill,
|
|
426
|
+
{
|
|
427
|
+
style: {
|
|
428
|
+
backgroundColor: backgroundColor || "#1a1a2e",
|
|
429
|
+
color: "#ffffff",
|
|
430
|
+
display: "flex",
|
|
431
|
+
flexDirection: "column",
|
|
432
|
+
alignItems: "center",
|
|
433
|
+
justifyContent: "center",
|
|
434
|
+
padding: 80
|
|
435
|
+
},
|
|
436
|
+
children: [
|
|
437
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
438
|
+
"div",
|
|
439
|
+
{
|
|
440
|
+
style: {
|
|
441
|
+
fontSize: 48,
|
|
442
|
+
fontStyle: "italic",
|
|
443
|
+
textAlign: "center",
|
|
444
|
+
marginBottom: 24
|
|
445
|
+
},
|
|
446
|
+
children: [
|
|
447
|
+
"\u201C",
|
|
448
|
+
quote,
|
|
449
|
+
"\u201D"
|
|
450
|
+
]
|
|
451
|
+
}
|
|
452
|
+
),
|
|
453
|
+
author && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { fontSize: 28, opacity: 0.7 }, children: [
|
|
454
|
+
"- ",
|
|
455
|
+
author
|
|
456
|
+
] })
|
|
457
|
+
]
|
|
458
|
+
}
|
|
459
|
+
) });
|
|
460
|
+
}
|
|
461
|
+
function StatCard({ clip }) {
|
|
462
|
+
const { value, label, prefix, suffix, backgroundColor } = clip.props;
|
|
463
|
+
const frame = (0, import_remotion3.useCurrentFrame)();
|
|
464
|
+
const { fps } = (0, import_remotion3.useVideoConfig)();
|
|
465
|
+
const animationProgress = (0, import_remotion3.spring)({
|
|
466
|
+
frame,
|
|
467
|
+
fps,
|
|
468
|
+
config: { damping: 100 },
|
|
469
|
+
durationInFrames: 30
|
|
470
|
+
});
|
|
471
|
+
const numValue = typeof value === "number" ? value : parseFloat(value) || 0;
|
|
472
|
+
const displayValue = Math.round(numValue * animationProgress);
|
|
473
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
474
|
+
import_remotion3.AbsoluteFill,
|
|
475
|
+
{
|
|
476
|
+
style: {
|
|
477
|
+
backgroundColor: backgroundColor || "#1a1a2e",
|
|
478
|
+
color: "#ffffff",
|
|
479
|
+
display: "flex",
|
|
480
|
+
flexDirection: "column",
|
|
481
|
+
alignItems: "center",
|
|
482
|
+
justifyContent: "center"
|
|
483
|
+
},
|
|
484
|
+
children: [
|
|
485
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { fontSize: 96, fontWeight: "bold", marginBottom: 16 }, children: [
|
|
486
|
+
prefix || "",
|
|
487
|
+
typeof value === "number" ? displayValue : value,
|
|
488
|
+
suffix || ""
|
|
489
|
+
] }),
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 32, opacity: 0.7 }, children: label })
|
|
491
|
+
]
|
|
492
|
+
}
|
|
493
|
+
) });
|
|
494
|
+
}
|
|
495
|
+
function LowerThird({ clip }) {
|
|
496
|
+
const { name, title } = clip.props;
|
|
497
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_remotion3.AbsoluteFill, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
498
|
+
"div",
|
|
499
|
+
{
|
|
500
|
+
style: {
|
|
501
|
+
position: "absolute",
|
|
502
|
+
bottom: 100,
|
|
503
|
+
left: 40,
|
|
504
|
+
backgroundColor: "rgba(0,0,0,0.8)",
|
|
505
|
+
color: "#ffffff",
|
|
506
|
+
padding: "16px 24px",
|
|
507
|
+
borderRadius: 8
|
|
508
|
+
},
|
|
509
|
+
children: [
|
|
510
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 28, fontWeight: "bold" }, children: name }),
|
|
511
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 20, opacity: 0.7 }, children: title })
|
|
512
|
+
]
|
|
513
|
+
}
|
|
514
|
+
) }) });
|
|
515
|
+
}
|
|
516
|
+
function TextOverlay({ clip }) {
|
|
517
|
+
const { text, position, fontSize } = clip.props;
|
|
518
|
+
const positionStyles = {
|
|
519
|
+
top: { top: 100, left: 0, right: 0 },
|
|
520
|
+
center: { top: "50%", left: 0, right: 0, transform: "translateY(-50%)" },
|
|
521
|
+
bottom: { bottom: 100, left: 0, right: 0 }
|
|
522
|
+
};
|
|
523
|
+
const fontSizes = {
|
|
524
|
+
small: 24,
|
|
525
|
+
medium: 36,
|
|
526
|
+
large: 56
|
|
527
|
+
};
|
|
528
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_remotion3.AbsoluteFill, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
529
|
+
"div",
|
|
530
|
+
{
|
|
531
|
+
style: {
|
|
532
|
+
position: "absolute",
|
|
533
|
+
...positionStyles[position || "center"],
|
|
534
|
+
textAlign: "center",
|
|
535
|
+
color: "#ffffff",
|
|
536
|
+
fontSize: fontSizes[fontSize || "medium"],
|
|
537
|
+
padding: 20,
|
|
538
|
+
textShadow: "2px 2px 4px rgba(0,0,0,0.5)"
|
|
539
|
+
},
|
|
540
|
+
children: text
|
|
541
|
+
}
|
|
542
|
+
) }) });
|
|
543
|
+
}
|
|
544
|
+
function TypingText({ clip }) {
|
|
545
|
+
const {
|
|
546
|
+
text,
|
|
547
|
+
backgroundColor,
|
|
548
|
+
textColor,
|
|
549
|
+
fontSize,
|
|
550
|
+
fontFamily,
|
|
551
|
+
showCursor = true,
|
|
552
|
+
cursorChar = "|",
|
|
553
|
+
charsPerSecond = 15
|
|
554
|
+
} = clip.props;
|
|
555
|
+
const frame = (0, import_remotion3.useCurrentFrame)();
|
|
556
|
+
const { fps } = (0, import_remotion3.useVideoConfig)();
|
|
557
|
+
const framesPerChar = fps / charsPerSecond;
|
|
558
|
+
const charsToShow = Math.min(Math.floor(frame / framesPerChar), text.length);
|
|
559
|
+
const displayedText = text.slice(0, charsToShow);
|
|
560
|
+
const isTypingComplete = charsToShow >= text.length;
|
|
561
|
+
const cursorVisible = showCursor && (Math.floor(frame / (fps / 2)) % 2 === 0 || !isTypingComplete);
|
|
562
|
+
const fontFamilyMap = {
|
|
563
|
+
monospace: "'Courier New', Consolas, monospace",
|
|
564
|
+
"sans-serif": "system-ui, -apple-system, sans-serif",
|
|
565
|
+
serif: "Georgia, 'Times New Roman', serif"
|
|
566
|
+
};
|
|
567
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
568
|
+
import_remotion3.AbsoluteFill,
|
|
569
|
+
{
|
|
570
|
+
style: {
|
|
571
|
+
backgroundColor: backgroundColor || "#1e1e1e",
|
|
572
|
+
display: "flex",
|
|
573
|
+
alignItems: "center",
|
|
574
|
+
justifyContent: "center",
|
|
575
|
+
padding: 60
|
|
576
|
+
},
|
|
577
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
578
|
+
"div",
|
|
579
|
+
{
|
|
580
|
+
style: {
|
|
581
|
+
color: textColor || "#00ff00",
|
|
582
|
+
fontSize: fontSize || 48,
|
|
583
|
+
fontFamily: fontFamilyMap[fontFamily || "monospace"],
|
|
584
|
+
whiteSpace: "pre-wrap",
|
|
585
|
+
wordBreak: "break-word",
|
|
586
|
+
maxWidth: "90%",
|
|
587
|
+
textAlign: "left"
|
|
588
|
+
},
|
|
589
|
+
children: [
|
|
590
|
+
displayedText,
|
|
591
|
+
cursorVisible && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
592
|
+
"span",
|
|
593
|
+
{
|
|
594
|
+
style: {
|
|
595
|
+
opacity: isTypingComplete ? Math.floor(frame / (fps / 2)) % 2 === 0 ? 1 : 0 : 1
|
|
596
|
+
},
|
|
597
|
+
children: cursorChar
|
|
598
|
+
}
|
|
599
|
+
)
|
|
600
|
+
]
|
|
601
|
+
}
|
|
602
|
+
)
|
|
603
|
+
}
|
|
604
|
+
) });
|
|
605
|
+
}
|
|
606
|
+
function LogoBug({ clip }) {
|
|
607
|
+
const { position, opacity: propOpacity } = clip.props;
|
|
608
|
+
const positionStyles = {
|
|
609
|
+
"top-left": { top: 20, left: 20 },
|
|
610
|
+
"top-right": { top: 20, right: 20 },
|
|
611
|
+
"bottom-left": { bottom: 20, left: 20 },
|
|
612
|
+
"bottom-right": { bottom: 20, right: 20 }
|
|
613
|
+
};
|
|
614
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_remotion3.AbsoluteFill, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
615
|
+
"div",
|
|
616
|
+
{
|
|
617
|
+
style: {
|
|
618
|
+
position: "absolute",
|
|
619
|
+
...positionStyles[position || "bottom-right"],
|
|
620
|
+
opacity: propOpacity ?? 0.5,
|
|
621
|
+
color: "#ffffff",
|
|
622
|
+
fontSize: 14,
|
|
623
|
+
fontWeight: "bold",
|
|
624
|
+
textShadow: "1px 1px 2px rgba(0,0,0,0.5)"
|
|
625
|
+
},
|
|
626
|
+
children: "LOGO"
|
|
627
|
+
}
|
|
628
|
+
) }) });
|
|
629
|
+
}
|
|
630
|
+
function VideoClip({ clip }) {
|
|
631
|
+
const { src } = clip.props;
|
|
632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
633
|
+
import_remotion3.AbsoluteFill,
|
|
634
|
+
{
|
|
635
|
+
style: {
|
|
636
|
+
backgroundColor: "#000000",
|
|
637
|
+
display: "flex",
|
|
638
|
+
alignItems: "center",
|
|
639
|
+
justifyContent: "center",
|
|
640
|
+
color: "rgba(255,255,255,0.5)"
|
|
641
|
+
},
|
|
642
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
643
|
+
"[Video: ",
|
|
644
|
+
src,
|
|
645
|
+
"]"
|
|
646
|
+
] })
|
|
647
|
+
}
|
|
648
|
+
) });
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// src/components/Renderer.tsx
|
|
652
|
+
var import_remotion4 = require("remotion");
|
|
653
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
654
|
+
var standardComponents = {
|
|
655
|
+
TitleCard,
|
|
656
|
+
ImageSlide,
|
|
657
|
+
SplitScreen,
|
|
658
|
+
QuoteCard,
|
|
659
|
+
StatCard,
|
|
660
|
+
LowerThird,
|
|
661
|
+
TextOverlay,
|
|
662
|
+
TypingText,
|
|
663
|
+
LogoBug,
|
|
664
|
+
VideoClip
|
|
665
|
+
};
|
|
666
|
+
function Renderer({
|
|
667
|
+
spec,
|
|
668
|
+
components: customComponents
|
|
669
|
+
}) {
|
|
670
|
+
const components = {
|
|
671
|
+
...standardComponents,
|
|
672
|
+
...customComponents
|
|
673
|
+
};
|
|
674
|
+
if (!spec.clips || spec.clips.length === 0) {
|
|
675
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
676
|
+
import_remotion4.AbsoluteFill,
|
|
677
|
+
{
|
|
678
|
+
style: {
|
|
679
|
+
backgroundColor: "#1a1a2e",
|
|
680
|
+
color: "#ffffff",
|
|
681
|
+
display: "flex",
|
|
682
|
+
alignItems: "center",
|
|
683
|
+
justifyContent: "center"
|
|
684
|
+
},
|
|
685
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontSize: 24, opacity: 0.5 }, children: "No clips" })
|
|
686
|
+
}
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
const mainClips = spec.clips.filter((c) => c.trackId === "main");
|
|
690
|
+
const overlayClips = spec.clips.filter((c) => c.trackId === "overlay");
|
|
691
|
+
const renderClip = (clip) => {
|
|
692
|
+
const Component = components[clip.component];
|
|
693
|
+
if (!Component) {
|
|
694
|
+
console.warn(`Unknown component: ${clip.component}`);
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
698
|
+
import_remotion4.Sequence,
|
|
699
|
+
{
|
|
700
|
+
from: clip.from,
|
|
701
|
+
durationInFrames: clip.durationInFrames,
|
|
702
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Component, { clip })
|
|
703
|
+
},
|
|
704
|
+
clip.id
|
|
705
|
+
);
|
|
706
|
+
};
|
|
707
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_remotion4.AbsoluteFill, { style: { backgroundColor: "#000000" }, children: [
|
|
708
|
+
mainClips.map(renderClip),
|
|
709
|
+
overlayClips.map(renderClip)
|
|
710
|
+
] });
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// src/catalog/definitions.ts
|
|
714
|
+
var import_zod = require("zod");
|
|
715
|
+
var standardComponentDefinitions = {
|
|
716
|
+
// ==========================================================================
|
|
717
|
+
// Scene Components (full-screen)
|
|
718
|
+
// ==========================================================================
|
|
719
|
+
TitleCard: {
|
|
720
|
+
props: import_zod.z.object({
|
|
721
|
+
title: import_zod.z.string(),
|
|
722
|
+
subtitle: import_zod.z.string().nullable(),
|
|
723
|
+
backgroundColor: import_zod.z.string().nullable(),
|
|
724
|
+
textColor: import_zod.z.string().nullable()
|
|
725
|
+
}),
|
|
726
|
+
type: "scene",
|
|
727
|
+
defaultDuration: 90,
|
|
728
|
+
description: "Full-screen title card with centered text. Use for intros, outros, and section breaks."
|
|
729
|
+
},
|
|
730
|
+
ImageSlide: {
|
|
731
|
+
props: import_zod.z.object({
|
|
732
|
+
src: import_zod.z.string(),
|
|
733
|
+
alt: import_zod.z.string(),
|
|
734
|
+
fit: import_zod.z.enum(["cover", "contain"]).nullable(),
|
|
735
|
+
backgroundColor: import_zod.z.string().nullable()
|
|
736
|
+
}),
|
|
737
|
+
type: "image",
|
|
738
|
+
defaultDuration: 150,
|
|
739
|
+
description: "Full-screen image display. Use for product shots, photos, and visual content."
|
|
740
|
+
},
|
|
741
|
+
SplitScreen: {
|
|
742
|
+
props: import_zod.z.object({
|
|
743
|
+
leftTitle: import_zod.z.string(),
|
|
744
|
+
rightTitle: import_zod.z.string(),
|
|
745
|
+
leftColor: import_zod.z.string().nullable(),
|
|
746
|
+
rightColor: import_zod.z.string().nullable()
|
|
747
|
+
}),
|
|
748
|
+
type: "scene",
|
|
749
|
+
defaultDuration: 120,
|
|
750
|
+
description: "Split screen with two sides. Use for comparisons or before/after."
|
|
751
|
+
},
|
|
752
|
+
QuoteCard: {
|
|
753
|
+
props: import_zod.z.object({
|
|
754
|
+
quote: import_zod.z.string(),
|
|
755
|
+
author: import_zod.z.string().nullable(),
|
|
756
|
+
backgroundColor: import_zod.z.string().nullable()
|
|
757
|
+
}),
|
|
758
|
+
type: "scene",
|
|
759
|
+
defaultDuration: 150,
|
|
760
|
+
description: "Quote display with attribution. Use for testimonials."
|
|
761
|
+
},
|
|
762
|
+
StatCard: {
|
|
763
|
+
props: import_zod.z.object({
|
|
764
|
+
value: import_zod.z.string(),
|
|
765
|
+
label: import_zod.z.string(),
|
|
766
|
+
prefix: import_zod.z.string().nullable(),
|
|
767
|
+
suffix: import_zod.z.string().nullable(),
|
|
768
|
+
backgroundColor: import_zod.z.string().nullable()
|
|
769
|
+
}),
|
|
770
|
+
type: "scene",
|
|
771
|
+
defaultDuration: 90,
|
|
772
|
+
description: "Large statistic display. Use for key metrics and numbers."
|
|
773
|
+
},
|
|
774
|
+
TypingText: {
|
|
775
|
+
props: import_zod.z.object({
|
|
776
|
+
text: import_zod.z.string(),
|
|
777
|
+
backgroundColor: import_zod.z.string().nullable(),
|
|
778
|
+
textColor: import_zod.z.string().nullable(),
|
|
779
|
+
fontSize: import_zod.z.number().nullable(),
|
|
780
|
+
fontFamily: import_zod.z.enum(["monospace", "sans-serif", "serif"]).nullable(),
|
|
781
|
+
showCursor: import_zod.z.boolean().nullable(),
|
|
782
|
+
cursorChar: import_zod.z.string().nullable(),
|
|
783
|
+
charsPerSecond: import_zod.z.number().nullable()
|
|
784
|
+
}),
|
|
785
|
+
type: "scene",
|
|
786
|
+
defaultDuration: 180,
|
|
787
|
+
description: "Terminal-style typing animation that reveals text character by character. Perfect for code demos, CLI commands, and dramatic text reveals."
|
|
788
|
+
},
|
|
789
|
+
// ==========================================================================
|
|
790
|
+
// Overlay Components
|
|
791
|
+
// ==========================================================================
|
|
792
|
+
LowerThird: {
|
|
793
|
+
props: import_zod.z.object({
|
|
794
|
+
name: import_zod.z.string(),
|
|
795
|
+
title: import_zod.z.string().nullable(),
|
|
796
|
+
backgroundColor: import_zod.z.string().nullable()
|
|
797
|
+
}),
|
|
798
|
+
type: "overlay",
|
|
799
|
+
defaultDuration: 120,
|
|
800
|
+
description: "Name/title overlay in lower third of screen. Use to identify speakers."
|
|
801
|
+
},
|
|
802
|
+
TextOverlay: {
|
|
803
|
+
props: import_zod.z.object({
|
|
804
|
+
text: import_zod.z.string(),
|
|
805
|
+
position: import_zod.z.enum(["top", "center", "bottom"]).nullable(),
|
|
806
|
+
fontSize: import_zod.z.enum(["small", "medium", "large"]).nullable()
|
|
807
|
+
}),
|
|
808
|
+
type: "overlay",
|
|
809
|
+
defaultDuration: 90,
|
|
810
|
+
description: "Simple text overlay. Use for captions and annotations."
|
|
811
|
+
},
|
|
812
|
+
LogoBug: {
|
|
813
|
+
props: import_zod.z.object({
|
|
814
|
+
position: import_zod.z.enum(["top-left", "top-right", "bottom-left", "bottom-right"]).nullable(),
|
|
815
|
+
opacity: import_zod.z.number().nullable()
|
|
816
|
+
}),
|
|
817
|
+
type: "overlay",
|
|
818
|
+
defaultDuration: 300,
|
|
819
|
+
description: "Corner logo watermark. Use for branding throughout video."
|
|
820
|
+
},
|
|
821
|
+
// ==========================================================================
|
|
822
|
+
// Video Components
|
|
823
|
+
// ==========================================================================
|
|
824
|
+
VideoClip: {
|
|
825
|
+
props: import_zod.z.object({
|
|
826
|
+
src: import_zod.z.string(),
|
|
827
|
+
startFrom: import_zod.z.number().nullable(),
|
|
828
|
+
volume: import_zod.z.number().nullable()
|
|
829
|
+
}),
|
|
830
|
+
type: "video",
|
|
831
|
+
defaultDuration: 150,
|
|
832
|
+
description: "Video file playback. Use for B-roll and footage."
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
var standardTransitionDefinitions = {
|
|
836
|
+
fade: {
|
|
837
|
+
defaultDuration: 15,
|
|
838
|
+
description: "Smooth fade in/out. Use for gentle transitions."
|
|
839
|
+
},
|
|
840
|
+
slideLeft: {
|
|
841
|
+
defaultDuration: 20,
|
|
842
|
+
description: "Slide from right to left. Use for forward progression."
|
|
843
|
+
},
|
|
844
|
+
slideRight: {
|
|
845
|
+
defaultDuration: 20,
|
|
846
|
+
description: "Slide from left to right. Use for backward progression."
|
|
847
|
+
},
|
|
848
|
+
slideUp: {
|
|
849
|
+
defaultDuration: 15,
|
|
850
|
+
description: "Slide from bottom to top. Use for overlays appearing."
|
|
851
|
+
},
|
|
852
|
+
slideDown: {
|
|
853
|
+
defaultDuration: 15,
|
|
854
|
+
description: "Slide from top to bottom. Use for overlays disappearing."
|
|
855
|
+
},
|
|
856
|
+
zoom: {
|
|
857
|
+
defaultDuration: 20,
|
|
858
|
+
description: "Zoom in/out effect. Use for emphasis."
|
|
859
|
+
},
|
|
860
|
+
wipe: {
|
|
861
|
+
defaultDuration: 15,
|
|
862
|
+
description: "Horizontal wipe. Use for scene changes."
|
|
863
|
+
},
|
|
864
|
+
none: {
|
|
865
|
+
defaultDuration: 0,
|
|
866
|
+
description: "No transition (hard cut)."
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
var standardEffectDefinitions = {
|
|
870
|
+
kenBurns: {
|
|
871
|
+
params: import_zod.z.object({
|
|
872
|
+
startScale: import_zod.z.number(),
|
|
873
|
+
endScale: import_zod.z.number(),
|
|
874
|
+
panX: import_zod.z.number().nullable(),
|
|
875
|
+
panY: import_zod.z.number().nullable()
|
|
876
|
+
}),
|
|
877
|
+
description: "Ken Burns pan and zoom effect for images."
|
|
878
|
+
},
|
|
879
|
+
pulse: {
|
|
880
|
+
params: import_zod.z.object({
|
|
881
|
+
intensity: import_zod.z.number()
|
|
882
|
+
}),
|
|
883
|
+
description: "Subtle pulsing scale effect for emphasis."
|
|
884
|
+
},
|
|
885
|
+
shake: {
|
|
886
|
+
params: import_zod.z.object({
|
|
887
|
+
intensity: import_zod.z.number()
|
|
888
|
+
}),
|
|
889
|
+
description: "Camera shake effect for energy."
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
893
|
+
0 && (module.exports = {
|
|
894
|
+
ClipWrapper,
|
|
895
|
+
ImageSlide,
|
|
896
|
+
LogoBug,
|
|
897
|
+
LowerThird,
|
|
898
|
+
QuoteCard,
|
|
899
|
+
Renderer,
|
|
900
|
+
SplitScreen,
|
|
901
|
+
StatCard,
|
|
902
|
+
TextOverlay,
|
|
903
|
+
TitleCard,
|
|
904
|
+
TypingText,
|
|
905
|
+
VideoClip,
|
|
906
|
+
schema,
|
|
907
|
+
standardComponentDefinitions,
|
|
908
|
+
standardComponents,
|
|
909
|
+
standardEffectDefinitions,
|
|
910
|
+
standardTransitionDefinitions,
|
|
911
|
+
useTransition
|
|
912
|
+
});
|
|
913
|
+
//# sourceMappingURL=index.js.map
|