reframe-video 0.6.26 → 0.6.28
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/bin.js +588 -48
- package/dist/cli.js +590 -47
- package/dist/compile-api.js +42 -1
- package/dist/compile.js +42 -1
- package/dist/diff.js +40 -1
- package/dist/frame.js +40 -1
- package/dist/index.js +89 -6
- package/dist/labels.js +40 -1
- package/dist/types/audio.d.ts +2 -2
- package/dist/types/ir.d.ts +22 -4
- package/guides/edsl-guide.md +25 -6
- package/package.json +1 -1
package/dist/compile-api.js
CHANGED
|
@@ -4,6 +4,44 @@ import { readFile } from "node:fs/promises";
|
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
7
|
+
// ../core/src/ir.ts
|
|
8
|
+
var SFX_NAMES = [
|
|
9
|
+
"whoosh",
|
|
10
|
+
"swish",
|
|
11
|
+
"swoosh",
|
|
12
|
+
"rise",
|
|
13
|
+
"riser",
|
|
14
|
+
"warp",
|
|
15
|
+
"tick",
|
|
16
|
+
"click",
|
|
17
|
+
"blip",
|
|
18
|
+
"pop",
|
|
19
|
+
"select",
|
|
20
|
+
"thud",
|
|
21
|
+
"boom",
|
|
22
|
+
"knock",
|
|
23
|
+
"sub",
|
|
24
|
+
"chime",
|
|
25
|
+
"ding",
|
|
26
|
+
"coin",
|
|
27
|
+
"sparkle",
|
|
28
|
+
"shimmer",
|
|
29
|
+
"success",
|
|
30
|
+
"zap",
|
|
31
|
+
"error",
|
|
32
|
+
"glitch",
|
|
33
|
+
"static",
|
|
34
|
+
"scan",
|
|
35
|
+
"powerup",
|
|
36
|
+
"powerdown",
|
|
37
|
+
"snare",
|
|
38
|
+
"hat",
|
|
39
|
+
"bubble",
|
|
40
|
+
"notify",
|
|
41
|
+
"camera"
|
|
42
|
+
];
|
|
43
|
+
var BGM_SYNTHS = ["ambient-pad", "lofi", "pulse", "tension", "uplift"];
|
|
44
|
+
|
|
7
45
|
// ../core/src/interpolate.ts
|
|
8
46
|
var BACK_C1 = 1.70158;
|
|
9
47
|
var BACK_C2 = BACK_C1 * 1.525;
|
|
@@ -329,7 +367,6 @@ function validateScene(ir) {
|
|
|
329
367
|
}
|
|
330
368
|
}
|
|
331
369
|
}
|
|
332
|
-
const SFX_NAMES = ["whoosh", "pop", "tick", "rise", "shimmer", "thud"];
|
|
333
370
|
for (const [i, cue] of (ir.audio?.cues ?? []).entries()) {
|
|
334
371
|
if (typeof cue.at === "string" && !labels.has(cue.at)) {
|
|
335
372
|
problems.push(
|
|
@@ -365,6 +402,10 @@ function validateScene(ir) {
|
|
|
365
402
|
if (ir.audio?.bgm?.file !== void 0 && ir.audio.bgm.synth !== void 0) {
|
|
366
403
|
problems.push('audio.bgm: use either "file" or "synth", not both');
|
|
367
404
|
}
|
|
405
|
+
const bgmSynth = ir.audio?.bgm?.synth;
|
|
406
|
+
if (bgmSynth !== void 0 && !BGM_SYNTHS.includes(bgmSynth)) {
|
|
407
|
+
problems.push(`audio.bgm.synth: unknown synth "${bgmSynth}" \u2014 valid: ${BGM_SYNTHS.join(", ")}`);
|
|
408
|
+
}
|
|
368
409
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
369
410
|
}
|
|
370
411
|
var TRANSITIONS = ["cut", "crossfade"];
|
package/dist/compile.js
CHANGED
|
@@ -9,6 +9,44 @@ import { readFile } from "node:fs/promises";
|
|
|
9
9
|
import { dirname, resolve } from "node:path";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
|
|
12
|
+
// ../core/src/ir.ts
|
|
13
|
+
var SFX_NAMES = [
|
|
14
|
+
"whoosh",
|
|
15
|
+
"swish",
|
|
16
|
+
"swoosh",
|
|
17
|
+
"rise",
|
|
18
|
+
"riser",
|
|
19
|
+
"warp",
|
|
20
|
+
"tick",
|
|
21
|
+
"click",
|
|
22
|
+
"blip",
|
|
23
|
+
"pop",
|
|
24
|
+
"select",
|
|
25
|
+
"thud",
|
|
26
|
+
"boom",
|
|
27
|
+
"knock",
|
|
28
|
+
"sub",
|
|
29
|
+
"chime",
|
|
30
|
+
"ding",
|
|
31
|
+
"coin",
|
|
32
|
+
"sparkle",
|
|
33
|
+
"shimmer",
|
|
34
|
+
"success",
|
|
35
|
+
"zap",
|
|
36
|
+
"error",
|
|
37
|
+
"glitch",
|
|
38
|
+
"static",
|
|
39
|
+
"scan",
|
|
40
|
+
"powerup",
|
|
41
|
+
"powerdown",
|
|
42
|
+
"snare",
|
|
43
|
+
"hat",
|
|
44
|
+
"bubble",
|
|
45
|
+
"notify",
|
|
46
|
+
"camera"
|
|
47
|
+
];
|
|
48
|
+
var BGM_SYNTHS = ["ambient-pad", "lofi", "pulse", "tension", "uplift"];
|
|
49
|
+
|
|
12
50
|
// ../core/src/interpolate.ts
|
|
13
51
|
var BACK_C1 = 1.70158;
|
|
14
52
|
var BACK_C2 = BACK_C1 * 1.525;
|
|
@@ -334,7 +372,6 @@ function validateScene(ir) {
|
|
|
334
372
|
}
|
|
335
373
|
}
|
|
336
374
|
}
|
|
337
|
-
const SFX_NAMES = ["whoosh", "pop", "tick", "rise", "shimmer", "thud"];
|
|
338
375
|
for (const [i, cue] of (ir.audio?.cues ?? []).entries()) {
|
|
339
376
|
if (typeof cue.at === "string" && !labels.has(cue.at)) {
|
|
340
377
|
problems.push(
|
|
@@ -370,6 +407,10 @@ function validateScene(ir) {
|
|
|
370
407
|
if (ir.audio?.bgm?.file !== void 0 && ir.audio.bgm.synth !== void 0) {
|
|
371
408
|
problems.push('audio.bgm: use either "file" or "synth", not both');
|
|
372
409
|
}
|
|
410
|
+
const bgmSynth = ir.audio?.bgm?.synth;
|
|
411
|
+
if (bgmSynth !== void 0 && !BGM_SYNTHS.includes(bgmSynth)) {
|
|
412
|
+
problems.push(`audio.bgm.synth: unknown synth "${bgmSynth}" \u2014 valid: ${BGM_SYNTHS.join(", ")}`);
|
|
413
|
+
}
|
|
373
414
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
374
415
|
}
|
|
375
416
|
|
package/dist/diff.js
CHANGED
|
@@ -13,6 +13,42 @@ import { dirname, resolve } from "node:path";
|
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
14
|
|
|
15
15
|
// ../core/src/ir.ts
|
|
16
|
+
var SFX_NAMES = [
|
|
17
|
+
"whoosh",
|
|
18
|
+
"swish",
|
|
19
|
+
"swoosh",
|
|
20
|
+
"rise",
|
|
21
|
+
"riser",
|
|
22
|
+
"warp",
|
|
23
|
+
"tick",
|
|
24
|
+
"click",
|
|
25
|
+
"blip",
|
|
26
|
+
"pop",
|
|
27
|
+
"select",
|
|
28
|
+
"thud",
|
|
29
|
+
"boom",
|
|
30
|
+
"knock",
|
|
31
|
+
"sub",
|
|
32
|
+
"chime",
|
|
33
|
+
"ding",
|
|
34
|
+
"coin",
|
|
35
|
+
"sparkle",
|
|
36
|
+
"shimmer",
|
|
37
|
+
"success",
|
|
38
|
+
"zap",
|
|
39
|
+
"error",
|
|
40
|
+
"glitch",
|
|
41
|
+
"static",
|
|
42
|
+
"scan",
|
|
43
|
+
"powerup",
|
|
44
|
+
"powerdown",
|
|
45
|
+
"snare",
|
|
46
|
+
"hat",
|
|
47
|
+
"bubble",
|
|
48
|
+
"notify",
|
|
49
|
+
"camera"
|
|
50
|
+
];
|
|
51
|
+
var BGM_SYNTHS = ["ambient-pad", "lofi", "pulse", "tension", "uplift"];
|
|
16
52
|
var DEFAULT_TO_DURATION = 0.5;
|
|
17
53
|
var DEFAULT_TWEEN_DURATION = 0.5;
|
|
18
54
|
var DEFAULT_MOTIONPATH_DURATION = 1;
|
|
@@ -662,7 +698,6 @@ function validateScene(ir) {
|
|
|
662
698
|
}
|
|
663
699
|
}
|
|
664
700
|
}
|
|
665
|
-
const SFX_NAMES = ["whoosh", "pop", "tick", "rise", "shimmer", "thud"];
|
|
666
701
|
for (const [i, cue] of (ir.audio?.cues ?? []).entries()) {
|
|
667
702
|
if (typeof cue.at === "string" && !labels.has(cue.at)) {
|
|
668
703
|
problems.push(
|
|
@@ -698,6 +733,10 @@ function validateScene(ir) {
|
|
|
698
733
|
if (ir.audio?.bgm?.file !== void 0 && ir.audio.bgm.synth !== void 0) {
|
|
699
734
|
problems.push('audio.bgm: use either "file" or "synth", not both');
|
|
700
735
|
}
|
|
736
|
+
const bgmSynth = ir.audio?.bgm?.synth;
|
|
737
|
+
if (bgmSynth !== void 0 && !BGM_SYNTHS.includes(bgmSynth)) {
|
|
738
|
+
problems.push(`audio.bgm.synth: unknown synth "${bgmSynth}" \u2014 valid: ${BGM_SYNTHS.join(", ")}`);
|
|
739
|
+
}
|
|
701
740
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
702
741
|
}
|
|
703
742
|
var TRANSITIONS = ["cut", "crossfade"];
|
package/dist/frame.js
CHANGED
|
@@ -40,6 +40,42 @@ import { existsSync } from "node:fs";
|
|
|
40
40
|
import { extname, isAbsolute, resolve } from "node:path";
|
|
41
41
|
|
|
42
42
|
// ../core/src/ir.ts
|
|
43
|
+
var SFX_NAMES = [
|
|
44
|
+
"whoosh",
|
|
45
|
+
"swish",
|
|
46
|
+
"swoosh",
|
|
47
|
+
"rise",
|
|
48
|
+
"riser",
|
|
49
|
+
"warp",
|
|
50
|
+
"tick",
|
|
51
|
+
"click",
|
|
52
|
+
"blip",
|
|
53
|
+
"pop",
|
|
54
|
+
"select",
|
|
55
|
+
"thud",
|
|
56
|
+
"boom",
|
|
57
|
+
"knock",
|
|
58
|
+
"sub",
|
|
59
|
+
"chime",
|
|
60
|
+
"ding",
|
|
61
|
+
"coin",
|
|
62
|
+
"sparkle",
|
|
63
|
+
"shimmer",
|
|
64
|
+
"success",
|
|
65
|
+
"zap",
|
|
66
|
+
"error",
|
|
67
|
+
"glitch",
|
|
68
|
+
"static",
|
|
69
|
+
"scan",
|
|
70
|
+
"powerup",
|
|
71
|
+
"powerdown",
|
|
72
|
+
"snare",
|
|
73
|
+
"hat",
|
|
74
|
+
"bubble",
|
|
75
|
+
"notify",
|
|
76
|
+
"camera"
|
|
77
|
+
];
|
|
78
|
+
var BGM_SYNTHS = ["ambient-pad", "lofi", "pulse", "tension", "uplift"];
|
|
43
79
|
var DEFAULT_TO_DURATION = 0.5;
|
|
44
80
|
var DEFAULT_TWEEN_DURATION = 0.5;
|
|
45
81
|
var DEFAULT_MOTIONPATH_DURATION = 1;
|
|
@@ -689,7 +725,6 @@ function validateScene(ir) {
|
|
|
689
725
|
}
|
|
690
726
|
}
|
|
691
727
|
}
|
|
692
|
-
const SFX_NAMES = ["whoosh", "pop", "tick", "rise", "shimmer", "thud"];
|
|
693
728
|
for (const [i, cue] of (ir.audio?.cues ?? []).entries()) {
|
|
694
729
|
if (typeof cue.at === "string" && !labels.has(cue.at)) {
|
|
695
730
|
problems.push(
|
|
@@ -725,6 +760,10 @@ function validateScene(ir) {
|
|
|
725
760
|
if (ir.audio?.bgm?.file !== void 0 && ir.audio.bgm.synth !== void 0) {
|
|
726
761
|
problems.push('audio.bgm: use either "file" or "synth", not both');
|
|
727
762
|
}
|
|
763
|
+
const bgmSynth = ir.audio?.bgm?.synth;
|
|
764
|
+
if (bgmSynth !== void 0 && !BGM_SYNTHS.includes(bgmSynth)) {
|
|
765
|
+
problems.push(`audio.bgm.synth: unknown synth "${bgmSynth}" \u2014 valid: ${BGM_SYNTHS.join(", ")}`);
|
|
766
|
+
}
|
|
728
767
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
729
768
|
}
|
|
730
769
|
var TRANSITIONS = ["cut", "crossfade"];
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,40 @@
|
|
|
1
1
|
// ../core/src/ir.ts
|
|
2
|
+
var SFX_NAMES = [
|
|
3
|
+
"whoosh",
|
|
4
|
+
"swish",
|
|
5
|
+
"swoosh",
|
|
6
|
+
"rise",
|
|
7
|
+
"riser",
|
|
8
|
+
"warp",
|
|
9
|
+
"tick",
|
|
10
|
+
"click",
|
|
11
|
+
"blip",
|
|
12
|
+
"pop",
|
|
13
|
+
"select",
|
|
14
|
+
"thud",
|
|
15
|
+
"boom",
|
|
16
|
+
"knock",
|
|
17
|
+
"sub",
|
|
18
|
+
"chime",
|
|
19
|
+
"ding",
|
|
20
|
+
"coin",
|
|
21
|
+
"sparkle",
|
|
22
|
+
"shimmer",
|
|
23
|
+
"success",
|
|
24
|
+
"zap",
|
|
25
|
+
"error",
|
|
26
|
+
"glitch",
|
|
27
|
+
"static",
|
|
28
|
+
"scan",
|
|
29
|
+
"powerup",
|
|
30
|
+
"powerdown",
|
|
31
|
+
"snare",
|
|
32
|
+
"hat",
|
|
33
|
+
"bubble",
|
|
34
|
+
"notify",
|
|
35
|
+
"camera"
|
|
36
|
+
];
|
|
37
|
+
var BGM_SYNTHS = ["ambient-pad", "lofi", "pulse", "tension", "uplift"];
|
|
2
38
|
var DEFAULT_CROSSFADE = 0.5;
|
|
3
39
|
var DEFAULT_TO_DURATION = 0.5;
|
|
4
40
|
var DEFAULT_TWEEN_DURATION = 0.5;
|
|
@@ -785,7 +821,6 @@ function validateScene(ir) {
|
|
|
785
821
|
}
|
|
786
822
|
}
|
|
787
823
|
}
|
|
788
|
-
const SFX_NAMES = ["whoosh", "pop", "tick", "rise", "shimmer", "thud"];
|
|
789
824
|
for (const [i, cue] of (ir.audio?.cues ?? []).entries()) {
|
|
790
825
|
if (typeof cue.at === "string" && !labels.has(cue.at)) {
|
|
791
826
|
problems.push(
|
|
@@ -821,6 +856,10 @@ function validateScene(ir) {
|
|
|
821
856
|
if (ir.audio?.bgm?.file !== void 0 && ir.audio.bgm.synth !== void 0) {
|
|
822
857
|
problems.push('audio.bgm: use either "file" or "synth", not both');
|
|
823
858
|
}
|
|
859
|
+
const bgmSynth = ir.audio?.bgm?.synth;
|
|
860
|
+
if (bgmSynth !== void 0 && !BGM_SYNTHS.includes(bgmSynth)) {
|
|
861
|
+
problems.push(`audio.bgm.synth: unknown synth "${bgmSynth}" \u2014 valid: ${BGM_SYNTHS.join(", ")}`);
|
|
862
|
+
}
|
|
824
863
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
825
864
|
}
|
|
826
865
|
var TRANSITIONS = ["cut", "crossfade"];
|
|
@@ -2889,12 +2928,46 @@ function motionOp(name, target, opts = {}) {
|
|
|
2889
2928
|
|
|
2890
2929
|
// ../core/src/audio.ts
|
|
2891
2930
|
var SFX_DURATION = {
|
|
2931
|
+
// transition
|
|
2892
2932
|
whoosh: 0.35,
|
|
2893
|
-
|
|
2894
|
-
|
|
2933
|
+
swish: 0.32,
|
|
2934
|
+
swoosh: 0.35,
|
|
2895
2935
|
rise: 0.5,
|
|
2936
|
+
riser: 0.85,
|
|
2937
|
+
warp: 0.5,
|
|
2938
|
+
// ui
|
|
2939
|
+
tick: 0.03,
|
|
2940
|
+
click: 0.05,
|
|
2941
|
+
blip: 0.1,
|
|
2942
|
+
pop: 0.12,
|
|
2943
|
+
select: 0.18,
|
|
2944
|
+
// impact
|
|
2945
|
+
thud: 0.25,
|
|
2946
|
+
boom: 0.6,
|
|
2947
|
+
knock: 0.14,
|
|
2948
|
+
sub: 0.7,
|
|
2949
|
+
// positive
|
|
2950
|
+
chime: 0.7,
|
|
2951
|
+
ding: 0.5,
|
|
2952
|
+
coin: 0.3,
|
|
2953
|
+
sparkle: 0.6,
|
|
2896
2954
|
shimmer: 0.9,
|
|
2897
|
-
|
|
2955
|
+
success: 0.6,
|
|
2956
|
+
// alert
|
|
2957
|
+
zap: 0.22,
|
|
2958
|
+
error: 0.4,
|
|
2959
|
+
// tech
|
|
2960
|
+
glitch: 0.3,
|
|
2961
|
+
static: 0.18,
|
|
2962
|
+
scan: 0.45,
|
|
2963
|
+
powerup: 0.4,
|
|
2964
|
+
powerdown: 0.5,
|
|
2965
|
+
// rhythm / foley
|
|
2966
|
+
snare: 0.18,
|
|
2967
|
+
hat: 0.05,
|
|
2968
|
+
bubble: 0.16,
|
|
2969
|
+
notify: 0.45,
|
|
2970
|
+
camera: 0.18
|
|
2898
2971
|
};
|
|
2899
2972
|
var FILE_CUE_DURATION = 0.4;
|
|
2900
2973
|
function collectClipAudio(ir, duration, warnings) {
|
|
@@ -2954,7 +3027,11 @@ function resolveAudioPlan(compiled) {
|
|
|
2954
3027
|
fadeIn: cue.fadeIn ?? 0,
|
|
2955
3028
|
fadeOut: cue.fadeOut ?? 0,
|
|
2956
3029
|
pan: cue.pan ?? 0,
|
|
2957
|
-
source: cue.sfx ?
|
|
3030
|
+
source: cue.sfx ? (
|
|
3031
|
+
// auto-vary: default the seed to the cue's order so repeated sfx differ
|
|
3032
|
+
// (pitch/texture); an explicit params.seed always wins.
|
|
3033
|
+
{ kind: "sfx", name: cue.sfx, params: { seed: index, ...cue.params } }
|
|
3034
|
+
) : { kind: "file", path: cue.file }
|
|
2958
3035
|
});
|
|
2959
3036
|
}
|
|
2960
3037
|
cues.sort((a, b) => a.t - b.t);
|
|
@@ -3034,7 +3111,11 @@ function resolveCompositionAudioPlan(comp) {
|
|
|
3034
3111
|
fadeIn: cue.fadeIn ?? 0,
|
|
3035
3112
|
fadeOut: cue.fadeOut ?? 0,
|
|
3036
3113
|
pan: cue.pan ?? 0,
|
|
3037
|
-
source: cue.sfx ?
|
|
3114
|
+
source: cue.sfx ? (
|
|
3115
|
+
// auto-vary: default the seed to the cue's order so repeated sfx differ
|
|
3116
|
+
// (pitch/texture); an explicit params.seed always wins.
|
|
3117
|
+
{ kind: "sfx", name: cue.sfx, params: { seed: index, ...cue.params } }
|
|
3118
|
+
) : { kind: "file", path: cue.file }
|
|
3038
3119
|
});
|
|
3039
3120
|
}
|
|
3040
3121
|
if (!audio?.bgm && cues.length === 0 && clipAudio.length === 0) return null;
|
|
@@ -3593,6 +3674,7 @@ function sketchToTimeline(sketch, nodeIds) {
|
|
|
3593
3674
|
return par(...steps);
|
|
3594
3675
|
}
|
|
3595
3676
|
export {
|
|
3677
|
+
BGM_SYNTHS,
|
|
3596
3678
|
CAMERA_ID,
|
|
3597
3679
|
CAMERA_PROPS2 as CAMERA_PROPS,
|
|
3598
3680
|
CHARACTER_PRESET_NAMES,
|
|
@@ -3608,6 +3690,7 @@ export {
|
|
|
3608
3690
|
PRESET_NAMES,
|
|
3609
3691
|
PROPS_BY_TYPE,
|
|
3610
3692
|
SFX_DURATION,
|
|
3693
|
+
SFX_NAMES,
|
|
3611
3694
|
SceneValidationError,
|
|
3612
3695
|
beat,
|
|
3613
3696
|
cameraFit,
|
package/dist/labels.js
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env tsx
|
|
2
2
|
|
|
3
3
|
// ../core/src/ir.ts
|
|
4
|
+
var SFX_NAMES = [
|
|
5
|
+
"whoosh",
|
|
6
|
+
"swish",
|
|
7
|
+
"swoosh",
|
|
8
|
+
"rise",
|
|
9
|
+
"riser",
|
|
10
|
+
"warp",
|
|
11
|
+
"tick",
|
|
12
|
+
"click",
|
|
13
|
+
"blip",
|
|
14
|
+
"pop",
|
|
15
|
+
"select",
|
|
16
|
+
"thud",
|
|
17
|
+
"boom",
|
|
18
|
+
"knock",
|
|
19
|
+
"sub",
|
|
20
|
+
"chime",
|
|
21
|
+
"ding",
|
|
22
|
+
"coin",
|
|
23
|
+
"sparkle",
|
|
24
|
+
"shimmer",
|
|
25
|
+
"success",
|
|
26
|
+
"zap",
|
|
27
|
+
"error",
|
|
28
|
+
"glitch",
|
|
29
|
+
"static",
|
|
30
|
+
"scan",
|
|
31
|
+
"powerup",
|
|
32
|
+
"powerdown",
|
|
33
|
+
"snare",
|
|
34
|
+
"hat",
|
|
35
|
+
"bubble",
|
|
36
|
+
"notify",
|
|
37
|
+
"camera"
|
|
38
|
+
];
|
|
39
|
+
var BGM_SYNTHS = ["ambient-pad", "lofi", "pulse", "tension", "uplift"];
|
|
4
40
|
var DEFAULT_TO_DURATION = 0.5;
|
|
5
41
|
var DEFAULT_TWEEN_DURATION = 0.5;
|
|
6
42
|
var DEFAULT_MOTIONPATH_DURATION = 1;
|
|
@@ -650,7 +686,6 @@ function validateScene(ir) {
|
|
|
650
686
|
}
|
|
651
687
|
}
|
|
652
688
|
}
|
|
653
|
-
const SFX_NAMES = ["whoosh", "pop", "tick", "rise", "shimmer", "thud"];
|
|
654
689
|
for (const [i, cue] of (ir.audio?.cues ?? []).entries()) {
|
|
655
690
|
if (typeof cue.at === "string" && !labels.has(cue.at)) {
|
|
656
691
|
problems.push(
|
|
@@ -686,6 +721,10 @@ function validateScene(ir) {
|
|
|
686
721
|
if (ir.audio?.bgm?.file !== void 0 && ir.audio.bgm.synth !== void 0) {
|
|
687
722
|
problems.push('audio.bgm: use either "file" or "synth", not both');
|
|
688
723
|
}
|
|
724
|
+
const bgmSynth = ir.audio?.bgm?.synth;
|
|
725
|
+
if (bgmSynth !== void 0 && !BGM_SYNTHS.includes(bgmSynth)) {
|
|
726
|
+
problems.push(`audio.bgm.synth: unknown synth "${bgmSynth}" \u2014 valid: ${BGM_SYNTHS.join(", ")}`);
|
|
727
|
+
}
|
|
689
728
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
690
729
|
}
|
|
691
730
|
|
package/dist/types/audio.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { CompiledScene } from "./compile.js";
|
|
10
10
|
import type { CompiledComposition } from "./composeComposition.js";
|
|
11
|
-
import type { SfxName } from "./ir.js";
|
|
11
|
+
import type { BgmSynth, SfxName } from "./ir.js";
|
|
12
12
|
/** Nominal cue lengths (s) for duck-window math; file cues use a default. */
|
|
13
13
|
export declare const SFX_DURATION: Record<SfxName, number>;
|
|
14
14
|
export interface ResolvedCue {
|
|
@@ -55,7 +55,7 @@ export interface AudioPlan {
|
|
|
55
55
|
path: string;
|
|
56
56
|
} | {
|
|
57
57
|
kind: "synth";
|
|
58
|
-
name:
|
|
58
|
+
name: BgmSynth;
|
|
59
59
|
};
|
|
60
60
|
gain: number;
|
|
61
61
|
fadeIn: number;
|
package/dist/types/ir.d.ts
CHANGED
|
@@ -412,7 +412,21 @@ export interface BehaviorIR {
|
|
|
412
412
|
};
|
|
413
413
|
};
|
|
414
414
|
}
|
|
415
|
-
|
|
415
|
+
/**
|
|
416
|
+
* The procedural sfx palette — the single source of truth (the type, validation,
|
|
417
|
+
* and the render-cli synth recipes all key off this). Grouped by use:
|
|
418
|
+
* transition: whoosh swish swoosh rise riser warp · ui: tick click blip pop select
|
|
419
|
+
* impact: thud boom knock sub · positive: chime ding coin sparkle shimmer success
|
|
420
|
+
* alert: zap error · tech: glitch static scan powerup powerdown
|
|
421
|
+
* rhythm: snare hat · foley: bubble notify camera
|
|
422
|
+
* Every cue's pitch/texture varies with its `seed` (auto-seeded by cue order), so
|
|
423
|
+
* repeated cues sound different; `params.pitch` is an explicit multiplier.
|
|
424
|
+
*/
|
|
425
|
+
export declare const SFX_NAMES: readonly ["whoosh", "swish", "swoosh", "rise", "riser", "warp", "tick", "click", "blip", "pop", "select", "thud", "boom", "knock", "sub", "chime", "ding", "coin", "sparkle", "shimmer", "success", "zap", "error", "glitch", "static", "scan", "powerup", "powerdown", "snare", "hat", "bubble", "notify", "camera"];
|
|
426
|
+
export type SfxName = (typeof SFX_NAMES)[number];
|
|
427
|
+
/** Synthesized background-music beds (license-free). */
|
|
428
|
+
export declare const BGM_SYNTHS: readonly ["ambient-pad", "lofi", "pulse", "tension", "uplift"];
|
|
429
|
+
export type BgmSynth = (typeof BGM_SYNTHS)[number];
|
|
416
430
|
export interface AudioCueIR {
|
|
417
431
|
/** Anchor: a timeline label (the step's start) or absolute seconds. */
|
|
418
432
|
at: string | number;
|
|
@@ -430,14 +444,18 @@ export interface AudioCueIR {
|
|
|
430
444
|
fadeOut?: number;
|
|
431
445
|
/** Stereo balance: -1 full left, 0 centre (default), +1 full right. */
|
|
432
446
|
pan?: number;
|
|
433
|
-
/**
|
|
447
|
+
/**
|
|
448
|
+
* Synth parameter overrides — numbers only. `seed` varies pitch/texture
|
|
449
|
+
* (defaults to the cue's order so repeats differ); `pitch` is an explicit
|
|
450
|
+
* frequency multiplier (1 = unchanged, 2 = an octave up); `gainDb` trims level.
|
|
451
|
+
*/
|
|
434
452
|
params?: Record<string, number>;
|
|
435
453
|
}
|
|
436
454
|
export interface AudioIR {
|
|
437
455
|
bgm?: {
|
|
438
456
|
file?: string;
|
|
439
|
-
/** License-free synthesized bed. */
|
|
440
|
-
synth?:
|
|
457
|
+
/** License-free synthesized bed (see {@link BGM_SYNTHS}). */
|
|
458
|
+
synth?: BgmSynth;
|
|
441
459
|
gain?: number;
|
|
442
460
|
fadeIn?: number;
|
|
443
461
|
fadeOut?: number;
|
package/guides/edsl-guide.md
CHANGED
|
@@ -558,12 +558,31 @@ audio: {
|
|
|
558
558
|
}
|
|
559
559
|
```
|
|
560
560
|
|
|
561
|
-
Procedural sfx
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
561
|
+
**Procedural sfx palette** (deterministic; exactly one of `sfx`/`file` per cue):
|
|
562
|
+
|
|
563
|
+
| group | names |
|
|
564
|
+
| --- | --- |
|
|
565
|
+
| transition | `whoosh` `swish` `swoosh` `rise` `riser` `warp` |
|
|
566
|
+
| ui | `tick` `click` `blip` `pop` `select` |
|
|
567
|
+
| impact | `thud` `boom` `knock` `sub` |
|
|
568
|
+
| positive | `chime` `ding` `coin` `sparkle` `shimmer` `success` |
|
|
569
|
+
| alert | `zap` `error` |
|
|
570
|
+
| tech | `glitch` `static` `scan` `powerup` `powerdown` |
|
|
571
|
+
| rhythm | `snare` `hat` |
|
|
572
|
+
| foley | `bubble` `notify` `camera` |
|
|
573
|
+
|
|
574
|
+
**Variation — repeats don't sound the same.** Each cue's `seed` shifts the sound's
|
|
575
|
+
PITCH (a musical step) and texture, and it **defaults to the cue's order**, so a run of
|
|
576
|
+
the same sfx becomes a little phrase instead of a stuck note — no setup needed. Override
|
|
577
|
+
explicitly with `params`: `{ sfx: "blip", params: { seed: 4 } }` (pick the variant) or
|
|
578
|
+
`{ sfx: "tick", params: { pitch: 1.5 } }` (an explicit frequency multiplier; `2` = octave
|
|
579
|
+
up). `params.gainDb` trims a single hit.
|
|
580
|
+
|
|
581
|
+
**bgm beds** (`bgm.synth`): `ambient-pad` `lofi` `pulse` `tension` `uplift` — or
|
|
582
|
+
`bgm.file` for your own. **Mixing**: any cue takes `fadeIn`/`fadeOut` (seconds) and `pan`
|
|
583
|
+
(-1 left … 0 centre … +1 right). A `video` clip's audio takes `fadeIn` and `pan` too
|
|
584
|
+
(clip fade-out isn't supported yet). The bed auto-ducks under cues (`bgm.duck`). See
|
|
585
|
+
`examples/scenes/sfx-showcase.ts` to audition the whole palette.
|
|
567
586
|
|
|
568
587
|
## Rules
|
|
569
588
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reframe-video",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.28",
|
|
4
4
|
"description": "Declarative motion graphics that AI can write and humans can tweak — human edits survive AI regeneration. Deterministic mp4 renders from a plain-data scene format.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"motion-graphics",
|