@json-render/remotion 0.4.0 → 0.4.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/dist/{chunk-5C3GTKV7.mjs → chunk-VFMY2U5W.mjs} +95 -6
- package/dist/chunk-VFMY2U5W.mjs.map +1 -0
- package/dist/index.d.mts +88 -3
- package/dist/index.d.ts +88 -3
- package/dist/index.js +259 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +165 -15
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +57 -0
- package/dist/server.d.ts +57 -0
- package/dist/server.js +94 -5
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-5C3GTKV7.mjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ __export(index_exports, {
|
|
|
37
37
|
standardComponents: () => standardComponents,
|
|
38
38
|
standardEffectDefinitions: () => standardEffectDefinitions,
|
|
39
39
|
standardTransitionDefinitions: () => standardTransitionDefinitions,
|
|
40
|
+
useMotion: () => useMotion,
|
|
40
41
|
useTransition: () => useTransition
|
|
41
42
|
});
|
|
42
43
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -61,8 +62,8 @@ function remotionPromptTemplate(context) {
|
|
|
61
62
|
lines.push("");
|
|
62
63
|
lines.push(`{"op":"set","path":"/composition","value":{"id":"intro","fps":30,"width":1920,"height":1080,"durationInFrames":300}}
|
|
63
64
|
{"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}}
|
|
65
|
+
{"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},"motion":{"enter":{"opacity":0,"y":50,"scale":0.9,"duration":25},"spring":{"damping":15}}}}
|
|
66
|
+
{"op":"set","path":"/clips/1","value":{"id":"clip-2","trackId":"main","component":"TitleCard","props":{"title":"Features"},"from":90,"durationInFrames":90,"motion":{"enter":{"opacity":0,"x":-100,"duration":20},"exit":{"opacity":0,"x":100,"duration":15}}}}
|
|
66
67
|
{"op":"set","path":"/audio","value":{"tracks":[]}}`);
|
|
67
68
|
lines.push("");
|
|
68
69
|
const catalogData = catalog;
|
|
@@ -87,6 +88,36 @@ function remotionPromptTemplate(context) {
|
|
|
87
88
|
}
|
|
88
89
|
lines.push("");
|
|
89
90
|
}
|
|
91
|
+
lines.push("MOTION SYSTEM:");
|
|
92
|
+
lines.push(
|
|
93
|
+
"Clips can have a 'motion' field for declarative animations (optional, use for dynamic/engaging videos):"
|
|
94
|
+
);
|
|
95
|
+
lines.push("");
|
|
96
|
+
lines.push(
|
|
97
|
+
"- enter: {opacity?, scale?, x?, y?, rotate?, duration?} - animate FROM these values TO normal when clip starts"
|
|
98
|
+
);
|
|
99
|
+
lines.push(
|
|
100
|
+
"- exit: {opacity?, scale?, x?, y?, rotate?, duration?} - animate FROM normal TO these values when clip ends"
|
|
101
|
+
);
|
|
102
|
+
lines.push(
|
|
103
|
+
"- spring: {damping?, stiffness?, mass?} - physics config (lower damping = more bounce)"
|
|
104
|
+
);
|
|
105
|
+
lines.push(
|
|
106
|
+
'- loop: {property, from, to, duration, easing?} - continuous animation (property: "scale"|"rotate"|"x"|"y"|"opacity")'
|
|
107
|
+
);
|
|
108
|
+
lines.push("");
|
|
109
|
+
lines.push("Example motion configs:");
|
|
110
|
+
lines.push(' Fade up: {"enter":{"opacity":0,"y":30,"duration":20}}');
|
|
111
|
+
lines.push(
|
|
112
|
+
' Scale pop: {"enter":{"scale":0.5,"opacity":0,"duration":15},"spring":{"damping":10}}'
|
|
113
|
+
);
|
|
114
|
+
lines.push(
|
|
115
|
+
' Slide in/out: {"enter":{"x":-100,"duration":20},"exit":{"x":100,"duration":15}}'
|
|
116
|
+
);
|
|
117
|
+
lines.push(
|
|
118
|
+
' Gentle pulse: {"loop":{"property":"scale","from":1,"to":1.05,"duration":60,"easing":"ease"}}'
|
|
119
|
+
);
|
|
120
|
+
lines.push("");
|
|
90
121
|
lines.push("RULES:");
|
|
91
122
|
const baseRules = [
|
|
92
123
|
"Output ONLY JSONL patches - one JSON object per line, no markdown, no code fences",
|
|
@@ -97,7 +128,9 @@ function remotionPromptTemplate(context) {
|
|
|
97
128
|
"ONLY use components listed above",
|
|
98
129
|
"fps is always 30 (1 second = 30 frames, 10 seconds = 300 frames)",
|
|
99
130
|
`Clips on "main" track flow sequentially (from = previous clip's from + durationInFrames)`,
|
|
100
|
-
'Overlay clips (LowerThird, TextOverlay) go on "overlay" track'
|
|
131
|
+
'Overlay clips (LowerThird, TextOverlay) go on "overlay" track',
|
|
132
|
+
"Use motion.enter for engaging clip entrances, motion.exit for smooth departures",
|
|
133
|
+
"Spring damping: 20=smooth, 10=bouncy, 5=very bouncy"
|
|
101
134
|
];
|
|
102
135
|
const allRules = [...baseRules, ...customRules];
|
|
103
136
|
allRules.forEach((rule, i) => {
|
|
@@ -159,6 +192,61 @@ var schema = (0, import_core.defineSchema)(
|
|
|
159
192
|
transitionOut: s.object({
|
|
160
193
|
type: s.ref("catalog.transitions"),
|
|
161
194
|
durationInFrames: s.number()
|
|
195
|
+
}),
|
|
196
|
+
/** Declarative motion configuration for custom animations */
|
|
197
|
+
motion: s.object({
|
|
198
|
+
/** Enter animation - animates FROM these values TO neutral */
|
|
199
|
+
enter: s.object({
|
|
200
|
+
/** Starting opacity (0-1), animates to 1 */
|
|
201
|
+
opacity: s.number(),
|
|
202
|
+
/** Starting scale (e.g., 0.8 = 80%), animates to 1 */
|
|
203
|
+
scale: s.number(),
|
|
204
|
+
/** Starting X offset in pixels, animates to 0 */
|
|
205
|
+
x: s.number(),
|
|
206
|
+
/** Starting Y offset in pixels, animates to 0 */
|
|
207
|
+
y: s.number(),
|
|
208
|
+
/** Starting rotation in degrees, animates to 0 */
|
|
209
|
+
rotate: s.number(),
|
|
210
|
+
/** Duration of enter animation in frames (default: 20) */
|
|
211
|
+
duration: s.number()
|
|
212
|
+
}),
|
|
213
|
+
/** Exit animation - animates FROM neutral TO these values */
|
|
214
|
+
exit: s.object({
|
|
215
|
+
/** Ending opacity (0-1), animates from 1 */
|
|
216
|
+
opacity: s.number(),
|
|
217
|
+
/** Ending scale, animates from 1 */
|
|
218
|
+
scale: s.number(),
|
|
219
|
+
/** Ending X offset in pixels, animates from 0 */
|
|
220
|
+
x: s.number(),
|
|
221
|
+
/** Ending Y offset in pixels, animates from 0 */
|
|
222
|
+
y: s.number(),
|
|
223
|
+
/** Ending rotation in degrees, animates from 0 */
|
|
224
|
+
rotate: s.number(),
|
|
225
|
+
/** Duration of exit animation in frames (default: 20) */
|
|
226
|
+
duration: s.number()
|
|
227
|
+
}),
|
|
228
|
+
/** Spring physics configuration */
|
|
229
|
+
spring: s.object({
|
|
230
|
+
/** Damping coefficient (default: 20) */
|
|
231
|
+
damping: s.number(),
|
|
232
|
+
/** Stiffness (default: 100) */
|
|
233
|
+
stiffness: s.number(),
|
|
234
|
+
/** Mass (default: 1) */
|
|
235
|
+
mass: s.number()
|
|
236
|
+
}),
|
|
237
|
+
/** Continuous looping animation */
|
|
238
|
+
loop: s.object({
|
|
239
|
+
/** Property to animate: "scale" | "rotate" | "x" | "y" | "opacity" */
|
|
240
|
+
property: s.string(),
|
|
241
|
+
/** Starting value */
|
|
242
|
+
from: s.number(),
|
|
243
|
+
/** Ending value */
|
|
244
|
+
to: s.number(),
|
|
245
|
+
/** Duration of one cycle in frames */
|
|
246
|
+
duration: s.number(),
|
|
247
|
+
/** Easing type: "linear" | "ease" | "spring" (default: "ease") */
|
|
248
|
+
easing: s.string()
|
|
249
|
+
})
|
|
162
250
|
})
|
|
163
251
|
})
|
|
164
252
|
),
|
|
@@ -289,22 +377,158 @@ function useTransition(clip, frame) {
|
|
|
289
377
|
}
|
|
290
378
|
return { opacity, translateX, translateY, scale };
|
|
291
379
|
}
|
|
380
|
+
function useMotion(clip, frame) {
|
|
381
|
+
const { fps } = (0, import_remotion.useVideoConfig)();
|
|
382
|
+
const relativeFrame = frame - clip.from;
|
|
383
|
+
const clipEnd = clip.durationInFrames;
|
|
384
|
+
let opacity = 1;
|
|
385
|
+
let translateX = 0;
|
|
386
|
+
let translateY = 0;
|
|
387
|
+
let scale = 1;
|
|
388
|
+
let rotate = 0;
|
|
389
|
+
const motion = clip.motion;
|
|
390
|
+
if (!motion) {
|
|
391
|
+
return { opacity, translateX, translateY, scale, rotate };
|
|
392
|
+
}
|
|
393
|
+
const springConfig = {
|
|
394
|
+
damping: motion.spring?.damping ?? 20,
|
|
395
|
+
stiffness: motion.spring?.stiffness ?? 100,
|
|
396
|
+
mass: motion.spring?.mass ?? 1
|
|
397
|
+
};
|
|
398
|
+
if (motion.enter) {
|
|
399
|
+
const enterDuration = motion.enter.duration ?? 20;
|
|
400
|
+
if (relativeFrame < enterDuration) {
|
|
401
|
+
const progress = (0, import_remotion.spring)({
|
|
402
|
+
frame: relativeFrame,
|
|
403
|
+
fps,
|
|
404
|
+
config: springConfig,
|
|
405
|
+
durationInFrames: enterDuration
|
|
406
|
+
});
|
|
407
|
+
if (motion.enter.opacity !== void 0) {
|
|
408
|
+
opacity = (0, import_remotion.interpolate)(progress, [0, 1], [motion.enter.opacity, 1]);
|
|
409
|
+
}
|
|
410
|
+
if (motion.enter.scale !== void 0) {
|
|
411
|
+
scale = (0, import_remotion.interpolate)(progress, [0, 1], [motion.enter.scale, 1]);
|
|
412
|
+
}
|
|
413
|
+
if (motion.enter.x !== void 0) {
|
|
414
|
+
translateX = (0, import_remotion.interpolate)(progress, [0, 1], [motion.enter.x, 0]);
|
|
415
|
+
}
|
|
416
|
+
if (motion.enter.y !== void 0) {
|
|
417
|
+
translateY = (0, import_remotion.interpolate)(progress, [0, 1], [motion.enter.y, 0]);
|
|
418
|
+
}
|
|
419
|
+
if (motion.enter.rotate !== void 0) {
|
|
420
|
+
rotate = (0, import_remotion.interpolate)(progress, [0, 1], [motion.enter.rotate, 0]);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (motion.exit) {
|
|
425
|
+
const exitDuration = motion.exit.duration ?? 20;
|
|
426
|
+
const exitStart = clipEnd - exitDuration;
|
|
427
|
+
if (relativeFrame >= exitStart) {
|
|
428
|
+
const exitFrame = relativeFrame - exitStart;
|
|
429
|
+
const progress = (0, import_remotion.spring)({
|
|
430
|
+
frame: exitFrame,
|
|
431
|
+
fps,
|
|
432
|
+
config: springConfig,
|
|
433
|
+
durationInFrames: exitDuration
|
|
434
|
+
});
|
|
435
|
+
if (motion.exit.opacity !== void 0) {
|
|
436
|
+
const exitOpacity = (0, import_remotion.interpolate)(
|
|
437
|
+
progress,
|
|
438
|
+
[0, 1],
|
|
439
|
+
[1, motion.exit.opacity]
|
|
440
|
+
);
|
|
441
|
+
opacity = Math.min(opacity, exitOpacity);
|
|
442
|
+
}
|
|
443
|
+
if (motion.exit.scale !== void 0) {
|
|
444
|
+
const exitScale = (0, import_remotion.interpolate)(progress, [0, 1], [1, motion.exit.scale]);
|
|
445
|
+
scale = scale * exitScale;
|
|
446
|
+
}
|
|
447
|
+
if (motion.exit.x !== void 0) {
|
|
448
|
+
const exitX = (0, import_remotion.interpolate)(progress, [0, 1], [0, motion.exit.x]);
|
|
449
|
+
translateX = translateX + exitX;
|
|
450
|
+
}
|
|
451
|
+
if (motion.exit.y !== void 0) {
|
|
452
|
+
const exitY = (0, import_remotion.interpolate)(progress, [0, 1], [0, motion.exit.y]);
|
|
453
|
+
translateY = translateY + exitY;
|
|
454
|
+
}
|
|
455
|
+
if (motion.exit.rotate !== void 0) {
|
|
456
|
+
const exitRotate = (0, import_remotion.interpolate)(
|
|
457
|
+
progress,
|
|
458
|
+
[0, 1],
|
|
459
|
+
[0, motion.exit.rotate]
|
|
460
|
+
);
|
|
461
|
+
rotate = rotate + exitRotate;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if (motion.loop) {
|
|
466
|
+
const { property, from, to, duration, easing = "ease" } = motion.loop;
|
|
467
|
+
const loopFrame = relativeFrame % duration;
|
|
468
|
+
let loopProgress;
|
|
469
|
+
switch (easing) {
|
|
470
|
+
case "linear":
|
|
471
|
+
loopProgress = loopFrame / duration;
|
|
472
|
+
break;
|
|
473
|
+
case "spring":
|
|
474
|
+
loopProgress = (0, import_remotion.spring)({
|
|
475
|
+
frame: loopFrame,
|
|
476
|
+
fps,
|
|
477
|
+
config: springConfig,
|
|
478
|
+
durationInFrames: duration
|
|
479
|
+
});
|
|
480
|
+
break;
|
|
481
|
+
case "ease":
|
|
482
|
+
default:
|
|
483
|
+
loopProgress = (0, import_remotion.interpolate)(
|
|
484
|
+
loopFrame,
|
|
485
|
+
[0, duration / 2, duration],
|
|
486
|
+
[0, 1, 0],
|
|
487
|
+
{ extrapolateRight: "clamp" }
|
|
488
|
+
);
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
const loopValue = (0, import_remotion.interpolate)(loopProgress, [0, 1], [from, to]);
|
|
492
|
+
switch (property) {
|
|
493
|
+
case "opacity":
|
|
494
|
+
opacity = opacity * loopValue;
|
|
495
|
+
break;
|
|
496
|
+
case "scale":
|
|
497
|
+
scale = scale * loopValue;
|
|
498
|
+
break;
|
|
499
|
+
case "x":
|
|
500
|
+
translateX = translateX + loopValue;
|
|
501
|
+
break;
|
|
502
|
+
case "y":
|
|
503
|
+
translateY = translateY + loopValue;
|
|
504
|
+
break;
|
|
505
|
+
case "rotate":
|
|
506
|
+
rotate = rotate + loopValue;
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return { opacity, translateX, translateY, scale, rotate };
|
|
511
|
+
}
|
|
292
512
|
|
|
293
513
|
// src/components/ClipWrapper.tsx
|
|
294
514
|
var import_remotion2 = require("remotion");
|
|
295
515
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
296
516
|
function ClipWrapper({ clip, children }) {
|
|
297
517
|
const frame = (0, import_remotion2.useCurrentFrame)();
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
518
|
+
const absoluteFrame = frame + clip.from;
|
|
519
|
+
const transition = useTransition(clip, absoluteFrame);
|
|
520
|
+
const motion = useMotion(clip, absoluteFrame);
|
|
521
|
+
const composedOpacity = transition.opacity * motion.opacity;
|
|
522
|
+
const composedTranslateX = transition.translateX + motion.translateX;
|
|
523
|
+
const composedTranslateY = transition.translateY + motion.translateY;
|
|
524
|
+
const composedScale = transition.scale * motion.scale;
|
|
525
|
+
const composedRotate = motion.rotate;
|
|
302
526
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
303
527
|
import_remotion2.AbsoluteFill,
|
|
304
528
|
{
|
|
305
529
|
style: {
|
|
306
|
-
opacity,
|
|
307
|
-
transform: `translateX(${
|
|
530
|
+
opacity: composedOpacity,
|
|
531
|
+
transform: `translateX(${composedTranslateX}%) translateY(${composedTranslateY}%) scale(${composedScale}) rotate(${composedRotate}deg)`
|
|
308
532
|
},
|
|
309
533
|
children
|
|
310
534
|
}
|
|
@@ -420,13 +644,15 @@ function SplitScreen({ clip }) {
|
|
|
420
644
|
] }) });
|
|
421
645
|
}
|
|
422
646
|
function QuoteCard({ clip }) {
|
|
423
|
-
const { quote, author, backgroundColor } = clip.props;
|
|
647
|
+
const { quote, author, backgroundColor, textColor, transparent } = clip.props;
|
|
648
|
+
const bgColor = transparent ? "transparent" : backgroundColor || "#1a1a2e";
|
|
649
|
+
const color = textColor || "#ffffff";
|
|
424
650
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ClipWrapper, { clip, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
425
651
|
import_remotion3.AbsoluteFill,
|
|
426
652
|
{
|
|
427
653
|
style: {
|
|
428
|
-
backgroundColor:
|
|
429
|
-
color
|
|
654
|
+
backgroundColor: bgColor,
|
|
655
|
+
color,
|
|
430
656
|
display: "flex",
|
|
431
657
|
flexDirection: "column",
|
|
432
658
|
alignItems: "center",
|
|
@@ -441,7 +667,8 @@ function QuoteCard({ clip }) {
|
|
|
441
667
|
fontSize: 48,
|
|
442
668
|
fontStyle: "italic",
|
|
443
669
|
textAlign: "center",
|
|
444
|
-
marginBottom: 24
|
|
670
|
+
marginBottom: 24,
|
|
671
|
+
textShadow: transparent ? "2px 2px 8px rgba(0,0,0,0.8)" : "none"
|
|
445
672
|
},
|
|
446
673
|
children: [
|
|
447
674
|
"\u201C",
|
|
@@ -450,10 +677,20 @@ function QuoteCard({ clip }) {
|
|
|
450
677
|
]
|
|
451
678
|
}
|
|
452
679
|
),
|
|
453
|
-
author && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
454
|
-
"
|
|
455
|
-
|
|
456
|
-
|
|
680
|
+
author && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
681
|
+
"div",
|
|
682
|
+
{
|
|
683
|
+
style: {
|
|
684
|
+
fontSize: 28,
|
|
685
|
+
opacity: 0.9,
|
|
686
|
+
textShadow: transparent ? "1px 1px 4px rgba(0,0,0,0.8)" : "none"
|
|
687
|
+
},
|
|
688
|
+
children: [
|
|
689
|
+
"- ",
|
|
690
|
+
author
|
|
691
|
+
]
|
|
692
|
+
}
|
|
693
|
+
)
|
|
457
694
|
]
|
|
458
695
|
}
|
|
459
696
|
) });
|
|
@@ -753,11 +990,13 @@ var standardComponentDefinitions = {
|
|
|
753
990
|
props: import_zod.z.object({
|
|
754
991
|
quote: import_zod.z.string(),
|
|
755
992
|
author: import_zod.z.string().nullable(),
|
|
756
|
-
backgroundColor: import_zod.z.string().nullable()
|
|
993
|
+
backgroundColor: import_zod.z.string().nullable(),
|
|
994
|
+
textColor: import_zod.z.string().nullable(),
|
|
995
|
+
transparent: import_zod.z.boolean().nullable()
|
|
757
996
|
}),
|
|
758
997
|
type: "scene",
|
|
759
998
|
defaultDuration: 150,
|
|
760
|
-
description: "Quote display with
|
|
999
|
+
description: "Quote display with author. Props: quote, author, textColor, backgroundColor. Set transparent:true when using as overlay on images."
|
|
761
1000
|
},
|
|
762
1001
|
StatCard: {
|
|
763
1002
|
props: import_zod.z.object({
|
|
@@ -908,6 +1147,7 @@ var standardEffectDefinitions = {
|
|
|
908
1147
|
standardComponents,
|
|
909
1148
|
standardEffectDefinitions,
|
|
910
1149
|
standardTransitionDefinitions,
|
|
1150
|
+
useMotion,
|
|
911
1151
|
useTransition
|
|
912
1152
|
});
|
|
913
1153
|
//# sourceMappingURL=index.js.map
|