reframe-video 0.6.32 → 0.6.34
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 +418 -41
- package/dist/browserEntry.js +8 -8
- package/dist/cli.js +387 -17
- package/dist/compile-api.js +3 -3
- package/dist/compile.js +3 -3
- package/dist/diff.js +3 -3
- package/dist/frame.js +3 -3
- package/dist/index.js +2294 -2186
- package/dist/labels.js +3 -3
- package/dist/trace-cli.js +3 -3
- package/dist/types/autoFoley.d.ts +18 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/ir.d.ts +25 -0
- package/guides/edsl-guide.md +10 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -425,6 +425,125 @@ var EASE_TABLE = {
|
|
|
425
425
|
springStiff: springEase(210, 26, 0)
|
|
426
426
|
};
|
|
427
427
|
var EASE_NAMES = Object.keys(EASE_TABLE);
|
|
428
|
+
function resolveEase(ease) {
|
|
429
|
+
if (ease === void 0) return EASE_TABLE.linear;
|
|
430
|
+
if (typeof ease === "string") {
|
|
431
|
+
const fn = EASE_TABLE[ease];
|
|
432
|
+
if (!fn) throw new Error(`unknown ease "${ease}" \u2014 valid: ${Object.keys(EASE_TABLE).join(", ")}`);
|
|
433
|
+
return fn;
|
|
434
|
+
}
|
|
435
|
+
if ("spring" in ease) {
|
|
436
|
+
const { stiffness = 100, damping = 10, velocity = 0 } = ease.spring;
|
|
437
|
+
return springEase(stiffness, damping, velocity);
|
|
438
|
+
}
|
|
439
|
+
return cubicBezierEase(...ease.cubicBezier);
|
|
440
|
+
}
|
|
441
|
+
function cubicBezierEase(x1, y1, x2, y2) {
|
|
442
|
+
const bez = (a, b) => (t) => 3 * a * t * (1 - t) ** 2 + 3 * b * t * t * (1 - t) + t ** 3;
|
|
443
|
+
const bx = bez(x1, x2);
|
|
444
|
+
const by = bez(y1, y2);
|
|
445
|
+
const dbx = (t) => 3 * x1 * (1 - t) * (1 - 3 * t) + 3 * x2 * t * (2 - 3 * t) + 3 * t * t;
|
|
446
|
+
return (u) => {
|
|
447
|
+
if (u <= 0) return 0;
|
|
448
|
+
if (u >= 1) return 1;
|
|
449
|
+
let t = u;
|
|
450
|
+
for (let i = 0; i < 8; i++) {
|
|
451
|
+
const err = bx(t) - u;
|
|
452
|
+
if (Math.abs(err) < 1e-6) return by(t);
|
|
453
|
+
const d = dbx(t);
|
|
454
|
+
if (Math.abs(d) < 1e-6) break;
|
|
455
|
+
t -= err / d;
|
|
456
|
+
}
|
|
457
|
+
let lo = 0;
|
|
458
|
+
let hi = 1;
|
|
459
|
+
t = u;
|
|
460
|
+
while (hi - lo > 1e-6) {
|
|
461
|
+
if (bx(t) < u) lo = t;
|
|
462
|
+
else hi = t;
|
|
463
|
+
t = (lo + hi) / 2;
|
|
464
|
+
}
|
|
465
|
+
return by(t);
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
var HEX_COLOR = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
469
|
+
function isColor(v) {
|
|
470
|
+
return typeof v === "string" && HEX_COLOR.test(v);
|
|
471
|
+
}
|
|
472
|
+
function parseColor(hex) {
|
|
473
|
+
let h = hex.slice(1);
|
|
474
|
+
if (h.length <= 4) h = [...h].map((c) => c + c).join("");
|
|
475
|
+
const n = parseInt(h.padEnd(8, "f"), 16);
|
|
476
|
+
return [n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, n & 255];
|
|
477
|
+
}
|
|
478
|
+
function formatColor([r, g, b, a]) {
|
|
479
|
+
const hex = (v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0");
|
|
480
|
+
return a >= 255 ? `#${hex(r)}${hex(g)}${hex(b)}` : `#${hex(r)}${hex(g)}${hex(b)}${hex(a)}`;
|
|
481
|
+
}
|
|
482
|
+
function lerpValue(from, to, u) {
|
|
483
|
+
if (typeof from === "number" && typeof to === "number") {
|
|
484
|
+
return from + (to - from) * u;
|
|
485
|
+
}
|
|
486
|
+
if (isColor(from) && isColor(to)) {
|
|
487
|
+
const a = parseColor(from);
|
|
488
|
+
const b = parseColor(to);
|
|
489
|
+
return formatColor([
|
|
490
|
+
a[0] + (b[0] - a[0]) * u,
|
|
491
|
+
a[1] + (b[1] - a[1]) * u,
|
|
492
|
+
a[2] + (b[2] - a[2]) * u,
|
|
493
|
+
a[3] + (b[3] - a[3]) * u
|
|
494
|
+
]);
|
|
495
|
+
}
|
|
496
|
+
if (looksLikePath(from) && looksLikePath(to)) {
|
|
497
|
+
const a = tokenizePath(from);
|
|
498
|
+
const b = tokenizePath(to);
|
|
499
|
+
if (a && b && morphCompatible(a, b)) return morphPath(a, b, u);
|
|
500
|
+
return u < 0.5 ? from : to;
|
|
501
|
+
}
|
|
502
|
+
return to;
|
|
503
|
+
}
|
|
504
|
+
var PATH_BODY = /^[\sMmLlHhVvCcSsQqTtAaZz0-9.,eE+-]+$/;
|
|
505
|
+
function looksLikePath(v) {
|
|
506
|
+
return typeof v === "string" && /^\s*[Mm]/.test(v) && PATH_BODY.test(v);
|
|
507
|
+
}
|
|
508
|
+
var PATH_TOKEN = /([MmLlHhVvCcSsQqTtAaZz])|(-?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?)/g;
|
|
509
|
+
function tokenizePath(d) {
|
|
510
|
+
const out = [];
|
|
511
|
+
let cur = null;
|
|
512
|
+
let m;
|
|
513
|
+
PATH_TOKEN.lastIndex = 0;
|
|
514
|
+
while (m = PATH_TOKEN.exec(d)) {
|
|
515
|
+
if (m[1]) out.push(cur = { cmd: m[1], nums: [] });
|
|
516
|
+
else if (m[2]) {
|
|
517
|
+
if (!cur) return null;
|
|
518
|
+
cur.nums.push(parseFloat(m[2]));
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
return out.length ? out : null;
|
|
522
|
+
}
|
|
523
|
+
function morphCompatible(a, b) {
|
|
524
|
+
if (a.length !== b.length) return false;
|
|
525
|
+
for (let i = 0; i < a.length; i++) {
|
|
526
|
+
const ca = a[i];
|
|
527
|
+
const cb = b[i];
|
|
528
|
+
if (ca.cmd !== cb.cmd || ca.nums.length !== cb.nums.length) return false;
|
|
529
|
+
if (ca.cmd === "A" || ca.cmd === "a") return false;
|
|
530
|
+
}
|
|
531
|
+
return true;
|
|
532
|
+
}
|
|
533
|
+
var fmtNum = (v) => {
|
|
534
|
+
const r = Number(v.toFixed(3));
|
|
535
|
+
return Object.is(r, -0) ? "0" : String(r);
|
|
536
|
+
};
|
|
537
|
+
function morphPath(a, b, u) {
|
|
538
|
+
let s = "";
|
|
539
|
+
for (let i = 0; i < a.length; i++) {
|
|
540
|
+
const an = a[i].nums;
|
|
541
|
+
const bn = b[i].nums;
|
|
542
|
+
s += (i ? " " : "") + a[i].cmd;
|
|
543
|
+
for (let j = 0; j < an.length; j++) s += " " + fmtNum(an[j] + (bn[j] - an[j]) * u);
|
|
544
|
+
}
|
|
545
|
+
return s;
|
|
546
|
+
}
|
|
428
547
|
|
|
429
548
|
// ../core/src/validate.ts
|
|
430
549
|
var EASE_SET = new Set(EASE_NAMES);
|
|
@@ -1025,6 +1144,258 @@ function formatComposeReport(report) {
|
|
|
1025
1144
|
return lines.join("\n");
|
|
1026
1145
|
}
|
|
1027
1146
|
|
|
1147
|
+
// ../core/src/behaviors.ts
|
|
1148
|
+
function sampleBehavior(b, t) {
|
|
1149
|
+
switch (b.name) {
|
|
1150
|
+
case "oscillate": {
|
|
1151
|
+
const { amplitude, frequency, phase = 0 } = b.params;
|
|
1152
|
+
return amplitude * Math.sin(2 * Math.PI * frequency * t + phase);
|
|
1153
|
+
}
|
|
1154
|
+
case "wiggle": {
|
|
1155
|
+
const { amplitude, frequency, seed } = b.params;
|
|
1156
|
+
return amplitude * valueNoise(t * frequency, seed);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
function valueNoise(x, seed) {
|
|
1161
|
+
const i = Math.floor(x);
|
|
1162
|
+
const f = x - i;
|
|
1163
|
+
const u = f * f * (3 - 2 * f);
|
|
1164
|
+
const a = hash01(i, seed) * 2 - 1;
|
|
1165
|
+
const b = hash01(i + 1, seed) * 2 - 1;
|
|
1166
|
+
return a + (b - a) * u;
|
|
1167
|
+
}
|
|
1168
|
+
function hash01(n, seed) {
|
|
1169
|
+
let h = n * 374761393 + seed * 668265263 | 0;
|
|
1170
|
+
h = h ^ h >>> 13 | 0;
|
|
1171
|
+
h = Math.imul(h, 1274126177);
|
|
1172
|
+
h = (h ^ h >>> 16) >>> 0;
|
|
1173
|
+
return h / 4294967295;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// ../core/src/evaluate.ts
|
|
1177
|
+
var IDENTITY = [1, 0, 0, 1, 0, 0];
|
|
1178
|
+
function multiply(m, n) {
|
|
1179
|
+
return [
|
|
1180
|
+
m[0] * n[0] + m[2] * n[1],
|
|
1181
|
+
m[1] * n[0] + m[3] * n[1],
|
|
1182
|
+
m[0] * n[2] + m[2] * n[3],
|
|
1183
|
+
m[1] * n[2] + m[3] * n[3],
|
|
1184
|
+
m[0] * n[4] + m[2] * n[5] + m[4],
|
|
1185
|
+
m[1] * n[4] + m[3] * n[5] + m[5]
|
|
1186
|
+
];
|
|
1187
|
+
}
|
|
1188
|
+
var DEG = Math.PI / 180;
|
|
1189
|
+
function localMatrix(x, y, rotationDeg, scale, scaleX = 1, scaleY = 1, skewXDeg = 0, skewYDeg = 0) {
|
|
1190
|
+
const r = rotationDeg * Math.PI / 180;
|
|
1191
|
+
if (scaleX === 1 && scaleY === 1 && skewXDeg === 0 && skewYDeg === 0) {
|
|
1192
|
+
const cos = Math.cos(r) * scale;
|
|
1193
|
+
const sin = Math.sin(r) * scale;
|
|
1194
|
+
return [cos, sin, -sin, cos, x, y];
|
|
1195
|
+
}
|
|
1196
|
+
const c = Math.cos(r);
|
|
1197
|
+
const s = Math.sin(r);
|
|
1198
|
+
const tx = Math.tan(skewXDeg * Math.PI / 180);
|
|
1199
|
+
const ty = Math.tan(skewYDeg * Math.PI / 180);
|
|
1200
|
+
const R = [c, s, -s, c, 0, 0];
|
|
1201
|
+
const K = [1, ty, tx, 1, 0, 0];
|
|
1202
|
+
const S = [scale * scaleX, 0, 0, scale * scaleY, 0, 0];
|
|
1203
|
+
const m = multiply(R, multiply(K, S));
|
|
1204
|
+
return [m[0], m[1], m[2], m[3], x, y];
|
|
1205
|
+
}
|
|
1206
|
+
function behaviorEnvelope(b, t) {
|
|
1207
|
+
const from = b.from ?? Number.NEGATIVE_INFINITY;
|
|
1208
|
+
const until = b.until ?? Number.POSITIVE_INFINITY;
|
|
1209
|
+
if (t < from || t > until) return 0;
|
|
1210
|
+
const ramp = b.ramp ?? 0.2;
|
|
1211
|
+
let envelope = 1;
|
|
1212
|
+
if (Number.isFinite(from) && ramp > 0) envelope = Math.min(envelope, (t - from) / ramp);
|
|
1213
|
+
if (Number.isFinite(until) && ramp > 0) envelope = Math.min(envelope, (until - t) / ramp);
|
|
1214
|
+
return Math.max(0, Math.min(1, envelope));
|
|
1215
|
+
}
|
|
1216
|
+
function sampleProp(compiled, t, target, prop, fallback) {
|
|
1217
|
+
let value = compiled.initialValues.get(`${target}.${prop}`) ?? fallback;
|
|
1218
|
+
let segStart = Number.NEGATIVE_INFINITY;
|
|
1219
|
+
const segs = compiled.segments.get(`${target}.${prop}`);
|
|
1220
|
+
if (segs) {
|
|
1221
|
+
let active;
|
|
1222
|
+
for (const seg of segs) {
|
|
1223
|
+
if (seg.t0 <= t) active = seg;
|
|
1224
|
+
else break;
|
|
1225
|
+
}
|
|
1226
|
+
if (active) {
|
|
1227
|
+
segStart = active.t0;
|
|
1228
|
+
if (t >= active.t1) {
|
|
1229
|
+
value = active.to;
|
|
1230
|
+
} else {
|
|
1231
|
+
const u = resolveEase(active.ease)((t - active.t0) / (active.t1 - active.t0));
|
|
1232
|
+
value = lerpValue(active.from, active.to, u);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
if (prop === "x" || prop === "y" || prop === "rotation") {
|
|
1237
|
+
const drivers = compiled.motionPaths.get(target);
|
|
1238
|
+
if (drivers) {
|
|
1239
|
+
let active;
|
|
1240
|
+
for (const d of drivers) {
|
|
1241
|
+
if (d.t0 <= t) active = d;
|
|
1242
|
+
else break;
|
|
1243
|
+
}
|
|
1244
|
+
if (active && active.t0 >= segStart && (prop !== "rotation" || active.autoRotate) && active.points.length > 0) {
|
|
1245
|
+
const span = active.t1 - active.t0;
|
|
1246
|
+
const u = span <= 0 ? 1 : resolveEase(active.ease)(Math.max(0, Math.min(1, (t - active.t0) / span)));
|
|
1247
|
+
if (prop === "x") value = pathPoint(active.points, active.closed, u, active.curviness)[0];
|
|
1248
|
+
else if (prop === "y") value = pathPoint(active.points, active.closed, u, active.curviness)[1];
|
|
1249
|
+
else value = pathTangentAngle(active.points, active.closed, u, active.curviness) + active.rotateOffset;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
for (const b of compiled.ir.behaviors ?? []) {
|
|
1254
|
+
if (b.target === target && b.prop === prop && typeof value === "number") {
|
|
1255
|
+
const envelope = behaviorEnvelope(b, t);
|
|
1256
|
+
if (envelope > 0) value = value + envelope * sampleBehavior(b.behavior, t);
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
return value;
|
|
1260
|
+
}
|
|
1261
|
+
function nodeParentMatrix(compiled, id, t) {
|
|
1262
|
+
const num2 = (target, prop, fallback) => {
|
|
1263
|
+
const v = sampleProp(compiled, t, target, prop, fallback);
|
|
1264
|
+
return typeof v === "number" ? v : fallback;
|
|
1265
|
+
};
|
|
1266
|
+
let result = null;
|
|
1267
|
+
const walk = (node, parent) => {
|
|
1268
|
+
if (node.id === id) {
|
|
1269
|
+
result = parent;
|
|
1270
|
+
return true;
|
|
1271
|
+
}
|
|
1272
|
+
if (node.type === "group") {
|
|
1273
|
+
const m = multiply(
|
|
1274
|
+
parent,
|
|
1275
|
+
localMatrix(
|
|
1276
|
+
num2(node.id, "x", node.props.x),
|
|
1277
|
+
num2(node.id, "y", node.props.y),
|
|
1278
|
+
num2(node.id, "rotation", node.props.rotation ?? 0),
|
|
1279
|
+
num2(node.id, "scale", node.props.scale ?? 1),
|
|
1280
|
+
num2(node.id, "scaleX", node.props.scaleX ?? 1),
|
|
1281
|
+
num2(node.id, "scaleY", node.props.scaleY ?? 1),
|
|
1282
|
+
num2(node.id, "skewX", node.props.skewX ?? 0),
|
|
1283
|
+
num2(node.id, "skewY", node.props.skewY ?? 0)
|
|
1284
|
+
)
|
|
1285
|
+
);
|
|
1286
|
+
for (const child of node.children) if (walk(child, m)) return true;
|
|
1287
|
+
}
|
|
1288
|
+
return false;
|
|
1289
|
+
};
|
|
1290
|
+
for (const node of compiled.ir.nodes) if (walk(node, IDENTITY)) break;
|
|
1291
|
+
return result;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
// ../core/src/autoFoley.ts
|
|
1295
|
+
var V_MIN = 360;
|
|
1296
|
+
var V_STOP = 60;
|
|
1297
|
+
var V_DECEL = 520;
|
|
1298
|
+
var V_MAX = 2600;
|
|
1299
|
+
var MIN_DUR = 0.1;
|
|
1300
|
+
var num = (c, t, id, prop, fb) => {
|
|
1301
|
+
const v = sampleProp(c, t, id, prop, fb);
|
|
1302
|
+
return typeof v === "number" ? v : fb;
|
|
1303
|
+
};
|
|
1304
|
+
function nodeSize(node) {
|
|
1305
|
+
const p = node.props;
|
|
1306
|
+
return Math.max(p.width ?? 0, p.height ?? 0, (p.radius ?? 0) * 2, p.fontSize ?? 0, 0);
|
|
1307
|
+
}
|
|
1308
|
+
var FAMILY = { whoosh: "move", swish: "move", thud: "hit", knock: "hit", pop: "pop" };
|
|
1309
|
+
var DEDUP_DT = 0.09;
|
|
1310
|
+
function autoFoley(compiled, opts = {}) {
|
|
1311
|
+
const master = opts.gain ?? 0.5;
|
|
1312
|
+
const sens = opts.sensitivity ?? 1;
|
|
1313
|
+
const wantWhoosh = opts.whoosh !== false;
|
|
1314
|
+
const wantImpact = opts.impact !== false;
|
|
1315
|
+
const wantPop = opts.pop !== false;
|
|
1316
|
+
const wantPan = opts.pan !== false;
|
|
1317
|
+
const vMin = V_MIN / sens, vStop = V_STOP, vDecel = V_DECEL / sens;
|
|
1318
|
+
const fps = compiled.ir.fps ?? 30;
|
|
1319
|
+
const N = Math.max(1, Math.ceil(compiled.duration * fps));
|
|
1320
|
+
const W = compiled.ir.size.width || 1920;
|
|
1321
|
+
const ids = opts.nodes ?? [...compiled.nodeById.keys()];
|
|
1322
|
+
const cands = [];
|
|
1323
|
+
const panOf = (x) => wantPan ? Math.max(-1, Math.min(1, x / W * 2 - 1)) : 0;
|
|
1324
|
+
const loud = (v) => Math.max(0.2, Math.min(1, (v - vMin) / (V_MAX - vMin)));
|
|
1325
|
+
for (const id of ids) {
|
|
1326
|
+
const node = compiled.nodeById.get(id);
|
|
1327
|
+
if (!node || node.type === "line") continue;
|
|
1328
|
+
const size = nodeSize(node);
|
|
1329
|
+
const xs = [], ys = [], ss = [], os = [];
|
|
1330
|
+
for (let i2 = 0; i2 <= N; i2++) {
|
|
1331
|
+
const t = i2 / fps;
|
|
1332
|
+
xs.push(num(compiled, t, id, "x", node.props.x ?? 0));
|
|
1333
|
+
ys.push(num(compiled, t, id, "y", node.props.y ?? 0));
|
|
1334
|
+
ss.push(num(compiled, t, id, "scale", node.props.scale ?? 1));
|
|
1335
|
+
os.push(num(compiled, t, id, "opacity", node.props.opacity ?? 1));
|
|
1336
|
+
}
|
|
1337
|
+
const speed = (i2) => i2 <= 0 ? 0 : Math.hypot(xs[i2] - xs[i2 - 1], ys[i2] - ys[i2 - 1]) * fps;
|
|
1338
|
+
const worldX = (frame) => {
|
|
1339
|
+
const m = nodeParentMatrix(compiled, id, frame / fps);
|
|
1340
|
+
return m ? m[0] * xs[frame] + m[2] * ys[frame] + m[4] : xs[frame];
|
|
1341
|
+
};
|
|
1342
|
+
let i = 1;
|
|
1343
|
+
while (i <= N) {
|
|
1344
|
+
if (speed(i) <= vMin) {
|
|
1345
|
+
i++;
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1348
|
+
const a = i;
|
|
1349
|
+
let peak = i, peakV = speed(i);
|
|
1350
|
+
while (i <= N && speed(i) > vStop) {
|
|
1351
|
+
const s = speed(i);
|
|
1352
|
+
if (s > peakV) {
|
|
1353
|
+
peakV = s;
|
|
1354
|
+
peak = i;
|
|
1355
|
+
}
|
|
1356
|
+
i++;
|
|
1357
|
+
}
|
|
1358
|
+
const b = i - 1;
|
|
1359
|
+
const durS = (b - a + 1) / fps;
|
|
1360
|
+
const visible = os[peak] > 0.1;
|
|
1361
|
+
if (peakV > vMin && durS >= MIN_DUR && visible) {
|
|
1362
|
+
if (wantWhoosh) {
|
|
1363
|
+
const quickFlick = durS < 0.25;
|
|
1364
|
+
cands.push({ t: peak / fps, sfx: quickFlick ? "swish" : "whoosh", gain: master * loud(peakV), pan: panOf(worldX(peak)), rank: peakV });
|
|
1365
|
+
}
|
|
1366
|
+
const stopped = b >= N || speed(b + 1) < vStop && speed(Math.min(N, b + 2)) < vStop;
|
|
1367
|
+
const wxb = worldX(b);
|
|
1368
|
+
const landsOnScreen = wxb >= 0 && wxb <= W && os[b] > 0.1;
|
|
1369
|
+
if (wantImpact && peakV > vDecel && stopped && landsOnScreen && b < N) {
|
|
1370
|
+
cands.push({ t: (b + 1) / fps, sfx: size > 220 ? "thud" : "knock", gain: master * loud(peakV), pan: panOf(worldX(b)), rank: peakV * 1.1 });
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
if (wantPop && ss[0] < 0.25) {
|
|
1375
|
+
for (let k = 1; k <= N; k++) {
|
|
1376
|
+
if (ss[k - 1] < 0.5 && ss[k] >= 0.5 && os[k] > 0.05) {
|
|
1377
|
+
cands.push({ t: k / fps, sfx: "pop", gain: master * 0.7, pan: panOf(worldX(k)), rank: 600 });
|
|
1378
|
+
break;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
cands.sort((p, q) => q.rank - p.rank);
|
|
1384
|
+
const kept = [];
|
|
1385
|
+
for (const c of cands) {
|
|
1386
|
+
const fam = FAMILY[c.sfx] ?? c.sfx;
|
|
1387
|
+
if (kept.some((k) => (FAMILY[k.sfx] ?? k.sfx) === fam && Math.abs(k.t - c.t) < DEDUP_DT)) continue;
|
|
1388
|
+
kept.push(c);
|
|
1389
|
+
}
|
|
1390
|
+
const max = opts.maxCues ?? 32;
|
|
1391
|
+
return kept.slice(0, max).map((c) => ({
|
|
1392
|
+
at: Number(c.t.toFixed(3)),
|
|
1393
|
+
sfx: c.sfx,
|
|
1394
|
+
gain: Number(c.gain.toFixed(3)),
|
|
1395
|
+
...c.pan !== 0 ? { pan: Number(c.pan.toFixed(3)) } : {}
|
|
1396
|
+
}));
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1028
1399
|
// ../core/src/presets.ts
|
|
1029
1400
|
var SET = 1 / 120;
|
|
1030
1401
|
|
|
@@ -1097,11 +1468,13 @@ function resolveAudioPlan(compiled) {
|
|
|
1097
1468
|
const warnings = [];
|
|
1098
1469
|
const duration = compiled.duration;
|
|
1099
1470
|
const clipAudio = collectClipAudio(compiled.ir, duration, warnings);
|
|
1100
|
-
|
|
1471
|
+
const autoCues = audio?.autoFoley ? autoFoley(compiled, audio.autoFoley === true ? {} : audio.autoFoley) : [];
|
|
1472
|
+
const manualCues = [...audio?.cues ?? [], ...autoCues];
|
|
1473
|
+
if (!audio || !audio.bgm && manualCues.length === 0) {
|
|
1101
1474
|
return clipAudio.length === 0 ? null : { duration, bgm: null, cues: [], duckWindows: [], clipAudio, warnings };
|
|
1102
1475
|
}
|
|
1103
1476
|
const cues = [];
|
|
1104
|
-
for (const [index, cue] of
|
|
1477
|
+
for (const [index, cue] of manualCues.entries()) {
|
|
1105
1478
|
let anchor;
|
|
1106
1479
|
if (typeof cue.at === "number") {
|
|
1107
1480
|
anchor = cue.at;
|
|
@@ -1232,9 +1605,6 @@ function resolveCompositionAudioPlan(comp) {
|
|
|
1232
1605
|
};
|
|
1233
1606
|
}
|
|
1234
1607
|
|
|
1235
|
-
// ../core/src/evaluate.ts
|
|
1236
|
-
var DEG = Math.PI / 180;
|
|
1237
|
-
|
|
1238
1608
|
// ../core/src/assets.ts
|
|
1239
1609
|
function collectSrcs(ir, type) {
|
|
1240
1610
|
const srcs = /* @__PURE__ */ new Set();
|
|
@@ -1311,14 +1681,14 @@ function encodeWavMono16(samples, sampleRate = SAMPLE_RATE) {
|
|
|
1311
1681
|
}
|
|
1312
1682
|
|
|
1313
1683
|
// ../render-cli/src/audio/synth.ts
|
|
1314
|
-
function
|
|
1684
|
+
function hash012(n, seed) {
|
|
1315
1685
|
let h = n * 374761393 + seed * 668265263 | 0;
|
|
1316
1686
|
h = h ^ h >>> 13 | 0;
|
|
1317
1687
|
h = Math.imul(h, 1274126177);
|
|
1318
1688
|
h = (h ^ h >>> 16) >>> 0;
|
|
1319
1689
|
return h / 4294967295;
|
|
1320
1690
|
}
|
|
1321
|
-
var noise = (n, seed) =>
|
|
1691
|
+
var noise = (n, seed) => hash012(n, seed) * 2 - 1;
|
|
1322
1692
|
var TAU = Math.PI * 2;
|
|
1323
1693
|
var expDecay = (t, dur, k = 5) => Math.exp(-k * t / dur);
|
|
1324
1694
|
var square = (ph) => (Math.sin(ph) + 0.33 * Math.sin(3 * ph) + 0.2 * Math.sin(5 * ph)) / 1.4;
|
|
@@ -1562,7 +1932,7 @@ function sparkle(seed, pitch) {
|
|
|
1562
1932
|
const on = u * steps.length - g;
|
|
1563
1933
|
if (on > 0 && on < 3) {
|
|
1564
1934
|
const ge = Math.exp(-on * 1.8);
|
|
1565
|
-
s += Math.sin(TAU * base * steps[g] * t +
|
|
1935
|
+
s += Math.sin(TAU * base * steps[g] * t + hash012(g, seed) * TAU) * ge;
|
|
1566
1936
|
}
|
|
1567
1937
|
}
|
|
1568
1938
|
out[i] = s / 2.4 * Math.sin(Math.PI * u) ** 0.5 * 0.5;
|
|
@@ -1589,9 +1959,9 @@ function shimmer(seed, pitch) {
|
|
|
1589
1959
|
const dur = 0.9;
|
|
1590
1960
|
const { out, n } = buffer(dur);
|
|
1591
1961
|
const partials = Array.from({ length: 5 }, (_, p) => ({
|
|
1592
|
-
freq: (2e3 +
|
|
1593
|
-
am: 0.5 +
|
|
1594
|
-
phase:
|
|
1962
|
+
freq: (2e3 + hash012(p, seed + 7) * 2e3) * pitch,
|
|
1963
|
+
am: 0.5 + hash012(p, seed + 8) * 1.5,
|
|
1964
|
+
phase: hash012(p, seed + 9) * TAU
|
|
1595
1965
|
}));
|
|
1596
1966
|
for (let i = 0; i < n; i++) {
|
|
1597
1967
|
const t = i / SAMPLE_RATE, u = t / dur;
|
|
@@ -1652,8 +2022,8 @@ function glitch(seed, pitch) {
|
|
|
1652
2022
|
for (let i = 0; i < n; i++) {
|
|
1653
2023
|
const t = i / SAMPLE_RATE, u = t / dur;
|
|
1654
2024
|
const c = Math.floor(i / cell);
|
|
1655
|
-
const on =
|
|
1656
|
-
const freq = 400 * pitch * (1 + Math.floor(
|
|
2025
|
+
const on = hash012(c, seed) > 0.4 ? 1 : 0;
|
|
2026
|
+
const freq = 400 * pitch * (1 + Math.floor(hash012(c, seed + 1) * 6));
|
|
1657
2027
|
phase += TAU * freq / SAMPLE_RATE;
|
|
1658
2028
|
const crush = Math.round(square(phase) * 4) / 4;
|
|
1659
2029
|
out[i] = (crush * 0.7 + noise(i, seed + c) * 0.3) * on * (1 - u * 0.3) * 0.55;
|
|
@@ -1847,8 +2217,8 @@ function synthSfx(name, params = {}) {
|
|
|
1847
2217
|
function pad(freqs, duration, seed, opts) {
|
|
1848
2218
|
const { out, n } = buffer(duration);
|
|
1849
2219
|
const voices = freqs.flatMap((f, v) => [
|
|
1850
|
-
{ freq: f * (1 + (
|
|
1851
|
-
{ freq: f * (1 - (
|
|
2220
|
+
{ freq: f * (1 + (hash012(v, seed + 3) - 0.5) * 4e-3), am: opts.amBase + hash012(v, seed + 4) * 0.08, phase: hash012(v, seed + 5) * TAU },
|
|
2221
|
+
{ freq: f * (1 - (hash012(v, seed + 6) - 0.5) * 4e-3), am: opts.amBase + hash012(v, seed + 7) * 0.08, phase: hash012(v, seed + 8) * TAU }
|
|
1852
2222
|
]);
|
|
1853
2223
|
for (let i = 0; i < n; i++) {
|
|
1854
2224
|
const t = i / SAMPLE_RATE;
|
|
@@ -1887,8 +2257,8 @@ function synthTension(duration, seed = 0) {
|
|
|
1887
2257
|
const drift = 1 + 0.03 * (t / Math.max(1e-3, duration));
|
|
1888
2258
|
let s = 0;
|
|
1889
2259
|
for (let v = 0; v < base.length; v++) {
|
|
1890
|
-
const f = base[v] * drift * (1 + (
|
|
1891
|
-
s += Math.sin(TAU * f * t +
|
|
2260
|
+
const f = base[v] * drift * (1 + (hash012(v, seed) - 0.5) * 6e-3);
|
|
2261
|
+
s += Math.sin(TAU * f * t + hash012(v, seed + 1) * TAU);
|
|
1892
2262
|
}
|
|
1893
2263
|
const swell = 0.6 + 0.4 * Math.sin(TAU * 0.08 * t);
|
|
1894
2264
|
out[i] = s / base.length * swell * 0.6;
|
package/dist/compile-api.js
CHANGED
|
@@ -439,12 +439,12 @@ function validateComposition(comp) {
|
|
|
439
439
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
440
440
|
}
|
|
441
441
|
|
|
442
|
-
// ../core/src/presets.ts
|
|
443
|
-
var SET = 1 / 120;
|
|
444
|
-
|
|
445
442
|
// ../core/src/evaluate.ts
|
|
446
443
|
var DEG = Math.PI / 180;
|
|
447
444
|
|
|
445
|
+
// ../core/src/presets.ts
|
|
446
|
+
var SET = 1 / 120;
|
|
447
|
+
|
|
448
448
|
// ../render-cli/src/loadScene.ts
|
|
449
449
|
var HERE = dirname(fileURLToPath(import.meta.url));
|
|
450
450
|
var CORE_ENTRY = true ? resolve(HERE, "index.js") : resolve(HERE, "..", "..", "core", "src", "index.ts");
|
package/dist/compile.js
CHANGED
|
@@ -414,12 +414,12 @@ function validateScene(ir) {
|
|
|
414
414
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
415
415
|
}
|
|
416
416
|
|
|
417
|
-
// ../core/src/presets.ts
|
|
418
|
-
var SET = 1 / 120;
|
|
419
|
-
|
|
420
417
|
// ../core/src/evaluate.ts
|
|
421
418
|
var DEG = Math.PI / 180;
|
|
422
419
|
|
|
420
|
+
// ../core/src/presets.ts
|
|
421
|
+
var SET = 1 / 120;
|
|
422
|
+
|
|
423
423
|
// ../render-cli/src/loadScene.ts
|
|
424
424
|
var HERE = dirname(fileURLToPath(import.meta.url));
|
|
425
425
|
var CORE_ENTRY = true ? resolve(HERE, "index.js") : resolve(HERE, "..", "..", "core", "src", "index.ts");
|
package/dist/diff.js
CHANGED
|
@@ -770,12 +770,12 @@ function validateComposition(comp) {
|
|
|
770
770
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
771
771
|
}
|
|
772
772
|
|
|
773
|
-
// ../core/src/presets.ts
|
|
774
|
-
var SET = 1 / 120;
|
|
775
|
-
|
|
776
773
|
// ../core/src/evaluate.ts
|
|
777
774
|
var DEG = Math.PI / 180;
|
|
778
775
|
|
|
776
|
+
// ../core/src/presets.ts
|
|
777
|
+
var SET = 1 / 120;
|
|
778
|
+
|
|
779
779
|
// ../core/src/assets.ts
|
|
780
780
|
function collectSrcs(ir, type) {
|
|
781
781
|
const srcs = /* @__PURE__ */ new Set();
|
package/dist/frame.js
CHANGED
|
@@ -797,12 +797,12 @@ function validateComposition(comp) {
|
|
|
797
797
|
if (problems.length > 0) throw new SceneValidationError(problems);
|
|
798
798
|
}
|
|
799
799
|
|
|
800
|
-
// ../core/src/presets.ts
|
|
801
|
-
var SET = 1 / 120;
|
|
802
|
-
|
|
803
800
|
// ../core/src/evaluate.ts
|
|
804
801
|
var DEG = Math.PI / 180;
|
|
805
802
|
|
|
803
|
+
// ../core/src/presets.ts
|
|
804
|
+
var SET = 1 / 120;
|
|
805
|
+
|
|
806
806
|
// ../core/src/assets.ts
|
|
807
807
|
function collectSrcs(ir, type) {
|
|
808
808
|
const srcs = /* @__PURE__ */ new Set();
|