reframe-video 0.1.3 → 0.3.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/assets/sfx/LICENSE.md +2 -1
- package/assets/sfx/bong_001.ogg +0 -0
- package/assets/sfx/click_001.ogg +0 -0
- package/assets/sfx/confirmation_002.ogg +0 -0
- package/assets/sfx/confirmation_003.ogg +0 -0
- package/assets/sfx/confirmation_004.ogg +0 -0
- package/assets/sfx/footstep_001.ogg +0 -0
- package/assets/sfx/footstep_002.ogg +0 -0
- package/assets/sfx/footstep_003.ogg +0 -0
- package/assets/sfx/glass_001.ogg +0 -0
- package/assets/sfx/maximize_001.ogg +0 -0
- package/assets/sfx/maximize_002.ogg +0 -0
- package/assets/sfx/maximize_005.ogg +0 -0
- package/assets/sfx/maximize_009.ogg +0 -0
- package/assets/sfx/open_001.ogg +0 -0
- package/assets/sfx/pluck_001.ogg +0 -0
- package/assets/sfx/pluck_002.ogg +0 -0
- package/assets/sfx/select_001.ogg +0 -0
- package/assets/sfx/select_002.ogg +0 -0
- package/assets/sfx/select_003.ogg +0 -0
- package/dist/bin.js +271 -49
- package/dist/browserEntry.js +179 -68
- package/dist/cli.js +445 -85
- package/dist/index.js +1187 -116
- package/dist/labels.js +606 -0
- package/dist/renderer-canvas.js +15 -0
- package/dist/trace-cli.js +9 -9
- package/dist/types/audio.d.ts +9 -0
- package/dist/types/characterPreset.d.ts +39 -0
- package/dist/types/compile.d.ts +1 -0
- package/dist/types/compose.d.ts +18 -2
- package/dist/types/composeComposition.d.ts +27 -0
- package/dist/types/devicePreset.d.ts +65 -0
- package/dist/types/dsl.d.ts +12 -1
- package/dist/types/evaluate.d.ts +32 -0
- package/dist/types/figure.d.ts +32 -0
- package/dist/types/index.d.ts +9 -3
- package/dist/types/interpolate.d.ts +3 -2
- package/dist/types/ir.d.ts +68 -0
- package/dist/types/motionOps.d.ts +36 -0
- package/dist/types/path.d.ts +7 -3
- package/dist/types/rig.d.ts +87 -0
- package/dist/types/validate.d.ts +4 -1
- package/guides/edsl-guide.md +54 -1
- package/guides/regen-contract.md +11 -0
- package/package.json +1 -1
- package/preview/index.html +56 -3
- package/preview/src/main.ts +1132 -46
- package/preview/src/panel.ts +478 -8
- package/preview/src/store.ts +323 -6
package/assets/sfx/LICENSE.md
CHANGED
|
@@ -5,11 +5,12 @@ Verified against each asset page's license field on 2026-06-11.
|
|
|
5
5
|
| files | source | author | license |
|
|
6
6
|
|---|---|---|---|
|
|
7
7
|
| keypress-001/004/007/010/014.wav | [Keyboard Soundpack #1](https://opengameart.org/content/keyboard-soundpack-1-typing-and-single-keystrokes) (Cherry KC 1000 recordings) | unicaegames | CC0 |
|
|
8
|
-
|
|
|
8
|
+
| click_001/002/003/004.ogg, confirmation_001/002/003/004.ogg, maximize_001/002/005/009.ogg, open_001.ogg, pluck_001/002.ogg, select_001/002/003.ogg, bong_001.ogg, glass_001.ogg | [Interface Sounds](https://kenney.nl/assets/interface-sounds) | Kenney (kenney.nl) | CC0 |
|
|
9
9
|
| tick.wav (tick_001), pop.wav (drop_002), shimmer.wav (glass_002 + echo tail) | [Interface Sounds](https://opengameart.org/content/interface-sounds) | Kenney (kenney.nl) | CC0 |
|
|
10
10
|
| whoosh.wav (wind body), rise.wav (reversed slice) | [Air whoosh](https://opengameart.org/content/air-whoosh) | qubodup | CC0 |
|
|
11
11
|
| whoosh.wav (transient layer: swish-9) | [Swishes Sound Pack](https://opengameart.org/content/swishes-sound-pack) | artisticdude | CC0 |
|
|
12
12
|
| thud.wav (trimmed) | [Muffled Distant Explosion](https://opengameart.org/content/muffled-distant-explosion) | NenadSimic | CC0 |
|
|
13
|
+
| footstep_001/002/003.ogg (footstep00/03/06) | [RPG Audio](https://kenney.nl/assets/rpg-audio) | Kenney (kenney.nl) | CC0 |
|
|
13
14
|
| bgm-song21.mp3 | [Mysterious Ambience (song21)](https://opengameart.org/content/mysterious-ambience-song21) | cynicmusic (pixelsphere.org) | multi-licensed; used under its CC0 option |
|
|
14
15
|
|
|
15
16
|
CC0 requires no attribution; this file records provenance anyway.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/bin.js
CHANGED
|
@@ -42,7 +42,7 @@ function segCountOf(points, closed) {
|
|
|
42
42
|
if (n < 2) return 0;
|
|
43
43
|
return closed ? n : n - 1;
|
|
44
44
|
}
|
|
45
|
-
function pathPoint(points, closed, u) {
|
|
45
|
+
function pathPoint(points, closed, u, curviness = 1) {
|
|
46
46
|
const n = points.length;
|
|
47
47
|
if (n === 0) return [0, 0];
|
|
48
48
|
if (n === 1) return [points[0][0], points[0][1]];
|
|
@@ -51,19 +51,41 @@ function pathPoint(points, closed, u) {
|
|
|
51
51
|
const [p0, p1, p2, p3] = controls(points, closed, i);
|
|
52
52
|
const t2 = t * t;
|
|
53
53
|
const t3 = t2 * t;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
if (curviness === 1) {
|
|
55
|
+
const f = (a, b, c, d) => 0.5 * (2 * b + (-a + c) * t + (2 * a - 5 * b + 4 * c - d) * t2 + (-a + 3 * b - 3 * c + d) * t3);
|
|
56
|
+
return [f(p0[0], p1[0], p2[0], p3[0]), f(p0[1], p1[1], p2[1], p3[1])];
|
|
57
|
+
}
|
|
58
|
+
const h00 = 2 * t3 - 3 * t2 + 1;
|
|
59
|
+
const h10 = t3 - 2 * t2 + t;
|
|
60
|
+
const h01 = -2 * t3 + 3 * t2;
|
|
61
|
+
const h11 = t3 - t2;
|
|
62
|
+
const k = curviness * 0.5;
|
|
63
|
+
const H = (a, b, c, d) => h00 * b + h10 * k * (c - a) + h01 * c + h11 * k * (d - b);
|
|
64
|
+
return [H(p0[0], p1[0], p2[0], p3[0]), H(p0[1], p1[1], p2[1], p3[1])];
|
|
65
|
+
}
|
|
66
|
+
function pathTangentAngle(points, closed, u, curviness = 1) {
|
|
58
67
|
const n = points.length;
|
|
59
68
|
if (n < 2) return 0;
|
|
60
69
|
const segs = segCountOf(points, closed);
|
|
61
70
|
const { i, t } = locate(segs, u);
|
|
62
71
|
const [p0, p1, p2, p3] = controls(points, closed, i);
|
|
63
72
|
const t2 = t * t;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
let dx;
|
|
74
|
+
let dy;
|
|
75
|
+
if (curviness === 1) {
|
|
76
|
+
const d = (a, b, c, e) => 0.5 * (-a + c + 2 * (2 * a - 5 * b + 4 * c - e) * t + 3 * (-a + 3 * b - 3 * c + e) * t2);
|
|
77
|
+
dx = d(p0[0], p1[0], p2[0], p3[0]);
|
|
78
|
+
dy = d(p0[1], p1[1], p2[1], p3[1]);
|
|
79
|
+
} else {
|
|
80
|
+
const g00 = 6 * t2 - 6 * t;
|
|
81
|
+
const g10 = 3 * t2 - 4 * t + 1;
|
|
82
|
+
const g01 = -6 * t2 + 6 * t;
|
|
83
|
+
const g11 = 3 * t2 - 2 * t;
|
|
84
|
+
const k = curviness * 0.5;
|
|
85
|
+
const D = (a, b, c, e) => g00 * b + g10 * k * (c - a) + g01 * c + g11 * k * (e - b);
|
|
86
|
+
dx = D(p0[0], p1[0], p2[0], p3[0]);
|
|
87
|
+
dy = D(p0[1], p1[1], p2[1], p3[1]);
|
|
88
|
+
}
|
|
67
89
|
if (dx === 0 && dy === 0) return 0;
|
|
68
90
|
return Math.atan2(dy, dx) * 180 / Math.PI;
|
|
69
91
|
}
|
|
@@ -144,8 +166,8 @@ function compileScene(ir) {
|
|
|
144
166
|
const currentValue = (target, prop) => {
|
|
145
167
|
const v = current.get(key(target, prop));
|
|
146
168
|
if (v !== void 0) return v;
|
|
147
|
-
if (prop === "opacity" || prop === "scale" || prop === "progress") return 1;
|
|
148
|
-
if (prop === "rotation") return 0;
|
|
169
|
+
if (prop === "opacity" || prop === "scale" || prop === "progress" || prop === "scaleX" || prop === "scaleY") return 1;
|
|
170
|
+
if (prop === "rotation" || prop === "skewX" || prop === "skewY") return 0;
|
|
149
171
|
throw new Error(`cannot animate "${prop}" of "${target}": no base value to start from`);
|
|
150
172
|
};
|
|
151
173
|
const labelTimes = /* @__PURE__ */ new Map();
|
|
@@ -248,16 +270,17 @@ function compileScene(ir) {
|
|
|
248
270
|
const duration = tl.duration ?? DEFAULT_MOTIONPATH_DURATION;
|
|
249
271
|
const points = tl.points;
|
|
250
272
|
const closed = tl.closed ?? false;
|
|
273
|
+
const curviness = tl.curviness ?? 1;
|
|
251
274
|
const autoRotate = tl.autoRotate ?? false;
|
|
252
275
|
const rotateOffset = tl.rotateOffset ?? 0;
|
|
253
276
|
let list = motionPaths.get(tl.target);
|
|
254
277
|
if (!list) motionPaths.set(tl.target, list = []);
|
|
255
|
-
list.push({ t0: start, t1: start + duration, points, closed, autoRotate, rotateOffset, ...tl.ease !== void 0 && { ease: tl.ease } });
|
|
278
|
+
list.push({ t0: start, t1: start + duration, points, closed, curviness, autoRotate, rotateOffset, ...tl.ease !== void 0 && { ease: tl.ease } });
|
|
256
279
|
if (points.length > 0) {
|
|
257
|
-
const [ex, ey] = pathPoint(points, closed, 1);
|
|
280
|
+
const [ex, ey] = pathPoint(points, closed, 1, curviness);
|
|
258
281
|
current.set(key(tl.target, "x"), ex);
|
|
259
282
|
current.set(key(tl.target, "y"), ey);
|
|
260
|
-
if (autoRotate) current.set(key(tl.target, "rotation"), pathTangentAngle(points, closed, 1) + rotateOffset);
|
|
283
|
+
if (autoRotate) current.set(key(tl.target, "rotation"), pathTangentAngle(points, closed, 1, curviness) + rotateOffset);
|
|
261
284
|
}
|
|
262
285
|
return start + duration;
|
|
263
286
|
}
|
|
@@ -322,7 +345,18 @@ function validateScene(ir) {
|
|
|
322
345
|
problems.push(`duplicate node id "${node.id}" \u2014 every node id must be unique`);
|
|
323
346
|
}
|
|
324
347
|
nodeById.set(node.id, node);
|
|
325
|
-
if (node.type === "group")
|
|
348
|
+
if (node.type === "group") {
|
|
349
|
+
const clip = node.props.clip;
|
|
350
|
+
if (clip) {
|
|
351
|
+
if (clip.kind !== "rect" && clip.kind !== "ellipse") {
|
|
352
|
+
problems.push(`group "${node.id}" clip: unknown kind "${clip.kind}" \u2014 use "rect" or "ellipse"`);
|
|
353
|
+
}
|
|
354
|
+
if (!(clip.width > 0) || !(clip.height > 0)) {
|
|
355
|
+
problems.push(`group "${node.id}" clip: width and height must be > 0`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
collect(node.children);
|
|
359
|
+
}
|
|
326
360
|
}
|
|
327
361
|
};
|
|
328
362
|
collect(ir.nodes);
|
|
@@ -405,6 +439,9 @@ function validateScene(ir) {
|
|
|
405
439
|
if (tl.duration !== void 0 && tl.duration <= 0) {
|
|
406
440
|
problems.push(`${path2}: motionPath "${tl.target}" duration must be > 0`);
|
|
407
441
|
}
|
|
442
|
+
if (tl.curviness !== void 0 && tl.curviness < 0) {
|
|
443
|
+
problems.push(`${path2}: motionPath "${tl.target}" curviness must be >= 0`);
|
|
444
|
+
}
|
|
408
445
|
break;
|
|
409
446
|
}
|
|
410
447
|
case "wait":
|
|
@@ -423,6 +460,13 @@ function validateScene(ir) {
|
|
|
423
460
|
if (tl.scale !== void 0 && tl.scale <= 0) {
|
|
424
461
|
problems.push(`${path2}: beat "${tl.name}" scale must be > 0`);
|
|
425
462
|
}
|
|
463
|
+
for (const id of tl.nodes ?? []) {
|
|
464
|
+
if (!nodeById.has(id)) {
|
|
465
|
+
problems.push(
|
|
466
|
+
`${path2}: beat "${tl.name}" owns unknown node "${id}" \u2014 known ids: ${[...nodeById.keys()].join(", ")}`
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
426
470
|
tl.children.forEach((c, i) => checkTimeline(c, `${path2}.beat(${tl.name})[${i}]`));
|
|
427
471
|
break;
|
|
428
472
|
}
|
|
@@ -463,11 +507,40 @@ function validateScene(ir) {
|
|
|
463
507
|
}
|
|
464
508
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
465
509
|
}
|
|
466
|
-
|
|
510
|
+
function validateComposition(comp) {
|
|
511
|
+
const problems = [];
|
|
512
|
+
if (comp.scenes.length === 0) problems.push("composition has no scenes");
|
|
513
|
+
const seen = /* @__PURE__ */ new Set();
|
|
514
|
+
for (const [i, entry] of comp.scenes.entries()) {
|
|
515
|
+
const where = `scenes[${i}]`;
|
|
516
|
+
try {
|
|
517
|
+
validateScene(entry.scene);
|
|
518
|
+
} catch (err) {
|
|
519
|
+
if (err instanceof SceneValidationError) {
|
|
520
|
+
for (const p of err.problems) problems.push(`${where} (scene "${entry.scene.id}"): ${p}`);
|
|
521
|
+
} else throw err;
|
|
522
|
+
}
|
|
523
|
+
if (seen.has(entry.scene.id)) {
|
|
524
|
+
problems.push(`${where}: duplicate scene id "${entry.scene.id}" \u2014 scene ids must be unique in a composition`);
|
|
525
|
+
}
|
|
526
|
+
seen.add(entry.scene.id);
|
|
527
|
+
if (entry.transition !== void 0 && !TRANSITIONS.includes(entry.transition)) {
|
|
528
|
+
problems.push(`${where}: unknown transition "${entry.transition}" \u2014 valid: ${TRANSITIONS.join(", ")}`);
|
|
529
|
+
}
|
|
530
|
+
if (typeof entry.at === "string" && Number.isNaN(Number(entry.at))) {
|
|
531
|
+
problems.push(`${where}: "at" string "${entry.at}" is not a number (use "-0.5"/"+0.5" or a number)`);
|
|
532
|
+
}
|
|
533
|
+
if (typeof entry.at === "number" && entry.at < 0) {
|
|
534
|
+
problems.push(`${where}: absolute "at" must be >= 0`);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
538
|
+
}
|
|
539
|
+
var COMMON_PROPS, PROPS_BY_TYPE, SceneValidationError, TRANSITIONS;
|
|
467
540
|
var init_validate = __esm({
|
|
468
541
|
"../core/src/validate.ts"() {
|
|
469
542
|
"use strict";
|
|
470
|
-
COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "anchor"];
|
|
543
|
+
COMMON_PROPS = ["x", "y", "opacity", "rotation", "scale", "scaleX", "scaleY", "skewX", "skewY", "anchor"];
|
|
471
544
|
PROPS_BY_TYPE = {
|
|
472
545
|
rect: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth", "radius"],
|
|
473
546
|
ellipse: [...COMMON_PROPS, "width", "height", "fill", "stroke", "strokeWidth"],
|
|
@@ -486,6 +559,7 @@ ${problems.map((p) => ` - ${p}`).join("\n")}`);
|
|
|
486
559
|
}
|
|
487
560
|
problems;
|
|
488
561
|
};
|
|
562
|
+
TRANSITIONS = ["cut", "crossfade"];
|
|
489
563
|
}
|
|
490
564
|
});
|
|
491
565
|
|
|
@@ -543,10 +617,27 @@ var init_dsl = __esm({
|
|
|
543
617
|
}
|
|
544
618
|
});
|
|
545
619
|
|
|
620
|
+
// ../core/src/composeComposition.ts
|
|
621
|
+
var init_composeComposition = __esm({
|
|
622
|
+
"../core/src/composeComposition.ts"() {
|
|
623
|
+
"use strict";
|
|
624
|
+
init_compile();
|
|
625
|
+
init_ir();
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
|
|
546
629
|
// ../core/src/compose.ts
|
|
547
630
|
function composeScene(base, ...overlays) {
|
|
548
631
|
const ir = structuredClone(base);
|
|
549
632
|
const report = { applied: [], orphans: [], warnings: [] };
|
|
633
|
+
const baseNodeIds = /* @__PURE__ */ new Set();
|
|
634
|
+
const collectBase = (nodes) => {
|
|
635
|
+
for (const node of nodes) {
|
|
636
|
+
baseNodeIds.add(node.id);
|
|
637
|
+
if (node.type === "group") collectBase(node.children);
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
collectBase(base.nodes);
|
|
550
641
|
overlays.forEach((overlay, index) => {
|
|
551
642
|
const layer = overlay.name ?? `overlay-${index}`;
|
|
552
643
|
if (overlay.target !== void 0 && overlay.target !== ir.id) {
|
|
@@ -554,12 +645,12 @@ function composeScene(base, ...overlays) {
|
|
|
554
645
|
`${layer}: authored against scene "${overlay.target}" but composing onto "${ir.id}"`
|
|
555
646
|
);
|
|
556
647
|
}
|
|
557
|
-
applyOverlay(ir, overlay, layer, report);
|
|
648
|
+
applyOverlay(ir, overlay, layer, report, baseNodeIds);
|
|
558
649
|
});
|
|
559
650
|
validateScene(ir);
|
|
560
651
|
return { ir, report };
|
|
561
652
|
}
|
|
562
|
-
function applyOverlay(ir, overlay, layer, report) {
|
|
653
|
+
function applyOverlay(ir, overlay, layer, report, baseNodeIds) {
|
|
563
654
|
const nodeById = /* @__PURE__ */ new Map();
|
|
564
655
|
const collect = (nodes) => {
|
|
565
656
|
for (const node of nodes) {
|
|
@@ -674,7 +765,7 @@ function applyOverlay(ir, overlay, layer, report) {
|
|
|
674
765
|
to: ["duration", "ease", "stagger"],
|
|
675
766
|
tween: ["duration", "ease"],
|
|
676
767
|
wait: ["duration"],
|
|
677
|
-
motionPath: ["points", "duration", "ease"],
|
|
768
|
+
motionPath: ["points", "duration", "ease", "curviness", "autoRotate"],
|
|
678
769
|
beat: ["at", "gap", "scale", "duration", "order"]
|
|
679
770
|
};
|
|
680
771
|
let timingPatched = false;
|
|
@@ -712,6 +803,49 @@ function applyOverlay(ir, overlay, layer, report) {
|
|
|
712
803
|
nodeById.set(node.id, node);
|
|
713
804
|
applied(`addNodes.${node.id}`, "add-node");
|
|
714
805
|
}
|
|
806
|
+
for (const id of overlay.removeNodes ?? []) {
|
|
807
|
+
if (baseNodeIds.has(id)) {
|
|
808
|
+
orphan(
|
|
809
|
+
`removeNodes.${id}`,
|
|
810
|
+
`"${id}" is a base scene node \u2014 the scene owns it; hide it with opacity: 0 instead of removing`
|
|
811
|
+
);
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
const index = ir.nodes.findIndex((n) => n.id === id);
|
|
815
|
+
if (index < 0) {
|
|
816
|
+
orphan(
|
|
817
|
+
`removeNodes.${id}`,
|
|
818
|
+
`unknown overlay-added node "${id}" \u2014 nothing to remove`
|
|
819
|
+
);
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
ir.nodes.splice(index, 1);
|
|
823
|
+
nodeById.delete(id);
|
|
824
|
+
applied(`removeNodes.${id}`, "remove-node");
|
|
825
|
+
}
|
|
826
|
+
if (overlay.addTimeline && overlay.addTimeline.length > 0) {
|
|
827
|
+
const collectTargets = (tl, out) => {
|
|
828
|
+
if (tl.kind === "tween" || tl.kind === "motionPath") out.add(tl.target);
|
|
829
|
+
if ("children" in tl) tl.children.forEach((c) => collectTargets(c, out));
|
|
830
|
+
};
|
|
831
|
+
const valid = [];
|
|
832
|
+
overlay.addTimeline.forEach((frag, i) => {
|
|
833
|
+
const targets = /* @__PURE__ */ new Set();
|
|
834
|
+
collectTargets(frag, targets);
|
|
835
|
+
const missing = [...targets].filter((id) => !nodeById.has(id));
|
|
836
|
+
if (missing.length > 0) {
|
|
837
|
+
orphan(`addTimeline[${i}]`, `targets unknown node(s) ${missing.join(", ")} \u2014 known ids: ${knownIds()}`);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
valid.push(structuredClone(frag));
|
|
841
|
+
applied(`addTimeline[${i}]`, "add-timeline");
|
|
842
|
+
});
|
|
843
|
+
if (valid.length > 0) {
|
|
844
|
+
ir.timeline = ir.timeline ? { kind: "par", children: [ir.timeline, ...valid] } : valid.length === 1 ? valid[0] : { kind: "par", children: valid };
|
|
845
|
+
delete ir.duration;
|
|
846
|
+
ir.duration = compileScene(ir).duration;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
715
849
|
}
|
|
716
850
|
var SCENE_PATCHABLE;
|
|
717
851
|
var init_compose = __esm({
|
|
@@ -902,6 +1036,48 @@ var init_presets = __esm({
|
|
|
902
1036
|
}
|
|
903
1037
|
});
|
|
904
1038
|
|
|
1039
|
+
// ../core/src/devicePreset.ts
|
|
1040
|
+
var init_devicePreset = __esm({
|
|
1041
|
+
"../core/src/devicePreset.ts"() {
|
|
1042
|
+
"use strict";
|
|
1043
|
+
init_dsl();
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
// ../core/src/rig.ts
|
|
1048
|
+
var init_rig = __esm({
|
|
1049
|
+
"../core/src/rig.ts"() {
|
|
1050
|
+
"use strict";
|
|
1051
|
+
init_dsl();
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
|
|
1055
|
+
// ../core/src/characterPreset.ts
|
|
1056
|
+
var init_characterPreset = __esm({
|
|
1057
|
+
"../core/src/characterPreset.ts"() {
|
|
1058
|
+
"use strict";
|
|
1059
|
+
init_dsl();
|
|
1060
|
+
init_rig();
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
// ../core/src/figure.ts
|
|
1065
|
+
var init_figure = __esm({
|
|
1066
|
+
"../core/src/figure.ts"() {
|
|
1067
|
+
"use strict";
|
|
1068
|
+
init_dsl();
|
|
1069
|
+
init_rig();
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
// ../core/src/motionOps.ts
|
|
1074
|
+
var init_motionOps = __esm({
|
|
1075
|
+
"../core/src/motionOps.ts"() {
|
|
1076
|
+
"use strict";
|
|
1077
|
+
init_dsl();
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
|
|
905
1081
|
// ../core/src/audio.ts
|
|
906
1082
|
function resolveAudioPlan(compiled) {
|
|
907
1083
|
const audio = compiled.ir.audio;
|
|
@@ -938,6 +1114,15 @@ function resolveAudioPlan(compiled) {
|
|
|
938
1114
|
});
|
|
939
1115
|
}
|
|
940
1116
|
cues.sort((a, b) => a.t - b.t);
|
|
1117
|
+
return {
|
|
1118
|
+
duration,
|
|
1119
|
+
bgm: resolveBgm(audio.bgm),
|
|
1120
|
+
cues,
|
|
1121
|
+
duckWindows: mergeDuckWindows(cues, duration),
|
|
1122
|
+
warnings
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
function mergeDuckWindows(cues, duration) {
|
|
941
1126
|
const duckWindows = [];
|
|
942
1127
|
for (const cue of cues) {
|
|
943
1128
|
const window2 = { t0: cue.t, t1: Math.min(duration, cue.t + cue.duration) };
|
|
@@ -945,23 +1130,22 @@ function resolveAudioPlan(compiled) {
|
|
|
945
1130
|
if (last && window2.t0 <= last.t1 + 0.1) last.t1 = Math.max(last.t1, window2.t1);
|
|
946
1131
|
else duckWindows.push(window2);
|
|
947
1132
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
}
|
|
964
|
-
return { duration, bgm, cues, duckWindows, warnings };
|
|
1133
|
+
return duckWindows;
|
|
1134
|
+
}
|
|
1135
|
+
function resolveBgm(b) {
|
|
1136
|
+
if (!b) return null;
|
|
1137
|
+
const duck = b.duck === false ? null : {
|
|
1138
|
+
depth: b.duck?.depth ?? 0.5,
|
|
1139
|
+
attack: b.duck?.attack ?? 0.05,
|
|
1140
|
+
release: b.duck?.release ?? 0.25
|
|
1141
|
+
};
|
|
1142
|
+
return {
|
|
1143
|
+
source: b.file ? { kind: "file", path: b.file } : { kind: "synth", name: b.synth ?? "ambient-pad" },
|
|
1144
|
+
gain: b.gain ?? 0.5,
|
|
1145
|
+
fadeIn: b.fadeIn ?? 0,
|
|
1146
|
+
fadeOut: b.fadeOut ?? 0,
|
|
1147
|
+
duck
|
|
1148
|
+
};
|
|
965
1149
|
}
|
|
966
1150
|
var SFX_DURATION, FILE_CUE_DURATION;
|
|
967
1151
|
var init_audio = __esm({
|
|
@@ -1098,10 +1282,16 @@ var init_src = __esm({
|
|
|
1098
1282
|
init_ir();
|
|
1099
1283
|
init_dsl();
|
|
1100
1284
|
init_validate();
|
|
1285
|
+
init_composeComposition();
|
|
1101
1286
|
init_compose();
|
|
1102
1287
|
init_compile();
|
|
1103
1288
|
init_path();
|
|
1104
1289
|
init_presets();
|
|
1290
|
+
init_devicePreset();
|
|
1291
|
+
init_rig();
|
|
1292
|
+
init_characterPreset();
|
|
1293
|
+
init_figure();
|
|
1294
|
+
init_motionOps();
|
|
1105
1295
|
init_audio();
|
|
1106
1296
|
init_evaluate();
|
|
1107
1297
|
init_interpolate();
|
|
@@ -1200,7 +1390,7 @@ function buildLogoSting(d) {
|
|
|
1200
1390
|
const inks = d.paths.map(
|
|
1201
1391
|
(p, i) => path({ id: `ink-${i}`, d: p.d, originX: vcx, originY: vcy, x: 0, y: 0, stroke: p.fill, strokeWidth: sw, progress: 0 })
|
|
1202
1392
|
);
|
|
1203
|
-
const
|
|
1393
|
+
const rig2 = {
|
|
1204
1394
|
group: "logo",
|
|
1205
1395
|
center: [CX, CY],
|
|
1206
1396
|
baseScale: fit,
|
|
@@ -1220,7 +1410,7 @@ function buildLogoSting(d) {
|
|
|
1220
1410
|
],
|
|
1221
1411
|
timeline: seq(
|
|
1222
1412
|
motionPreset(d.motion ?? "reveal-orbit", {
|
|
1223
|
-
target:
|
|
1413
|
+
target: rig2,
|
|
1224
1414
|
...d.energy !== void 0 && { energy: d.energy },
|
|
1225
1415
|
...d.speed !== void 0 && { speed: d.speed },
|
|
1226
1416
|
...d.intensity !== void 0 && { intensity: d.intensity },
|
|
@@ -2042,18 +2232,16 @@ var init_batch = __esm({
|
|
|
2042
2232
|
// ../render-cli/src/loadScene.ts
|
|
2043
2233
|
var loadScene_exports = {};
|
|
2044
2234
|
__export(loadScene_exports, {
|
|
2235
|
+
isComposition: () => isComposition,
|
|
2236
|
+
loadModule: () => loadModule,
|
|
2045
2237
|
loadScene: () => loadScene
|
|
2046
2238
|
});
|
|
2047
2239
|
import { build as build2 } from "esbuild";
|
|
2048
2240
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
2049
2241
|
import { dirname as dirname6, resolve as resolve3 } from "node:path";
|
|
2050
2242
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
2051
|
-
async function
|
|
2052
|
-
if (path2.endsWith(".json"))
|
|
2053
|
-
const ir = JSON.parse(await readFile5(path2, "utf8"));
|
|
2054
|
-
validateScene(ir);
|
|
2055
|
-
return ir;
|
|
2056
|
-
}
|
|
2243
|
+
async function loadDefault(path2) {
|
|
2244
|
+
if (path2.endsWith(".json")) return JSON.parse(await readFile5(path2, "utf8"));
|
|
2057
2245
|
let code;
|
|
2058
2246
|
try {
|
|
2059
2247
|
const out = await build2({
|
|
@@ -2070,15 +2258,33 @@ async function loadScene(path2) {
|
|
|
2070
2258
|
});
|
|
2071
2259
|
code = out.outputFiles[0].text;
|
|
2072
2260
|
} catch (err) {
|
|
2073
|
-
throw new Error(
|
|
2074
|
-
|
|
2075
|
-
${err instanceof Error ? err.message : String(err)}`
|
|
2076
|
-
);
|
|
2261
|
+
throw new Error(`failed to bundle ${path2}:
|
|
2262
|
+
${err instanceof Error ? err.message : String(err)}`);
|
|
2077
2263
|
}
|
|
2078
2264
|
const mod = await import(`data:text/javascript;base64,${Buffer.from(code).toString("base64")}`);
|
|
2079
|
-
if (
|
|
2265
|
+
if (mod.default === void 0) throw new Error(`${path2} must default-export a scene or composition`);
|
|
2080
2266
|
return mod.default;
|
|
2081
2267
|
}
|
|
2268
|
+
function isComposition(def) {
|
|
2269
|
+
return typeof def === "object" && def !== null && Array.isArray(def.scenes);
|
|
2270
|
+
}
|
|
2271
|
+
async function loadScene(path2) {
|
|
2272
|
+
const def = await loadDefault(path2);
|
|
2273
|
+
if (isComposition(def)) {
|
|
2274
|
+
throw new Error(`${path2} is a composition \u2014 render it directly, not as a single scene`);
|
|
2275
|
+
}
|
|
2276
|
+
validateScene(def);
|
|
2277
|
+
return def;
|
|
2278
|
+
}
|
|
2279
|
+
async function loadModule(path2) {
|
|
2280
|
+
const def = await loadDefault(path2);
|
|
2281
|
+
if (isComposition(def)) {
|
|
2282
|
+
validateComposition(def);
|
|
2283
|
+
return { kind: "composition", ir: def };
|
|
2284
|
+
}
|
|
2285
|
+
validateScene(def);
|
|
2286
|
+
return { kind: "scene", ir: def };
|
|
2287
|
+
}
|
|
2082
2288
|
var HERE, CORE_ENTRY;
|
|
2083
2289
|
var init_loadScene = __esm({
|
|
2084
2290
|
"../render-cli/src/loadScene.ts"() {
|
|
@@ -2101,6 +2307,7 @@ var HERE2 = dirname7(fileURLToPath5(import.meta.url));
|
|
|
2101
2307
|
var ROOT2 = PACKAGED ? resolve4(HERE2, "..") : resolve4(HERE2, "..", "..", "..");
|
|
2102
2308
|
var USER_CWD = process.env.INIT_CWD ?? process.cwd();
|
|
2103
2309
|
var RENDER_CLI = PACKAGED ? join6(ROOT2, "dist", "cli.js") : join6(ROOT2, "packages", "render-cli", "src", "cli.ts");
|
|
2310
|
+
var LABELS = PACKAGED ? join6(ROOT2, "dist", "labels.js") : join6(ROOT2, "packages", "render-cli", "src", "labels.ts");
|
|
2104
2311
|
var ANALYZE = PACKAGED ? join6(ROOT2, "dist", "analyze.js") : join6(ROOT2, "benchmark", "harness", "motion", "analyze.ts");
|
|
2105
2312
|
var TRACE = PACKAGED ? join6(ROOT2, "dist", "trace-cli.js") : join6(ROOT2, "benchmark", "harness", "motion", "trace-cli.ts");
|
|
2106
2313
|
var CMD = PACKAGED ? "reframe" : "pnpm reframe";
|
|
@@ -2114,6 +2321,7 @@ usage:
|
|
|
2114
2321
|
rise-settle, slide-bank, reveal-orbit, spin-forge)
|
|
2115
2322
|
${CMD} preview open the scrub/edit UI (lists scenes in your directory)
|
|
2116
2323
|
${CMD} new <scene-name> scaffold <scene-name>.ts in your directory
|
|
2324
|
+
${CMD} labels <scene.ts|.json> print the event clock (label \u2192 exact seconds; for sound design / timing)
|
|
2117
2325
|
${CMD} motion <mp4|framesDir> motion-profile a rendered clip
|
|
2118
2326
|
${CMD} trace <ref.mp4> [--apply scene.ts] extract a video's motion structure \u2192 MotionSketch / timeline
|
|
2119
2327
|
${CMD} guide [--regen] print the scene-authoring guide (for you or your AI)
|
|
@@ -2244,6 +2452,17 @@ ${USAGE}`);
|
|
|
2244
2452
|
await (PACKAGED ? run(process.execPath, [RENDER_CLI, mode, inputPath, ...outArgs]) : run("npx", ["tsx", RENDER_CLI, mode, inputPath, ...outArgs]))
|
|
2245
2453
|
);
|
|
2246
2454
|
}
|
|
2455
|
+
case "labels": {
|
|
2456
|
+
const input = rest[0];
|
|
2457
|
+
if (!input || input.startsWith("-")) fail(`labels needs a scene file
|
|
2458
|
+
|
|
2459
|
+
${USAGE}`);
|
|
2460
|
+
const inputPath = userPath(input);
|
|
2461
|
+
if (!existsSync4(inputPath)) fail(`no such file: ${inputPath}`);
|
|
2462
|
+
process.exit(
|
|
2463
|
+
await (PACKAGED ? run(process.execPath, [LABELS, inputPath]) : run("npx", ["tsx", LABELS, inputPath]))
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2247
2466
|
case "logo": {
|
|
2248
2467
|
const positional = [];
|
|
2249
2468
|
const flags = {};
|
|
@@ -2332,6 +2551,9 @@ ${results.length - failed} rendered (${orphaned} with orphans), ${failed} failed
|
|
|
2332
2551
|
process.exit(failed > 0 ? 1 : 0);
|
|
2333
2552
|
}
|
|
2334
2553
|
case "preview": {
|
|
2554
|
+
console.log(
|
|
2555
|
+
"preview: drag waypoints/nodes; double-click a path to add a waypoint or a handle to remove it;\n \u270E reshapes an ease curve; 'vary \xD74' proposes motion variants.\ndeep-link a scene + time: http://localhost:5173/?scene=<scene-name>&t=<seconds>"
|
|
2556
|
+
);
|
|
2335
2557
|
if (PACKAGED) {
|
|
2336
2558
|
const { createRequire } = await import("node:module");
|
|
2337
2559
|
const vitePkg = createRequire(import.meta.url).resolve("vite/package.json");
|