reframe-video 0.6.31 → 0.6.33
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 +5 -4
- package/dist/bin.js +359 -42
- package/dist/browserEntry.js +8 -8
- package/dist/cli.js +327 -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 +2289 -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 +13 -2
- 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,193 @@ 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 DEG = Math.PI / 180;
|
|
1178
|
+
function behaviorEnvelope(b, t) {
|
|
1179
|
+
const from = b.from ?? Number.NEGATIVE_INFINITY;
|
|
1180
|
+
const until = b.until ?? Number.POSITIVE_INFINITY;
|
|
1181
|
+
if (t < from || t > until) return 0;
|
|
1182
|
+
const ramp = b.ramp ?? 0.2;
|
|
1183
|
+
let envelope = 1;
|
|
1184
|
+
if (Number.isFinite(from) && ramp > 0) envelope = Math.min(envelope, (t - from) / ramp);
|
|
1185
|
+
if (Number.isFinite(until) && ramp > 0) envelope = Math.min(envelope, (until - t) / ramp);
|
|
1186
|
+
return Math.max(0, Math.min(1, envelope));
|
|
1187
|
+
}
|
|
1188
|
+
function sampleProp(compiled, t, target, prop, fallback) {
|
|
1189
|
+
let value = compiled.initialValues.get(`${target}.${prop}`) ?? fallback;
|
|
1190
|
+
let segStart = Number.NEGATIVE_INFINITY;
|
|
1191
|
+
const segs = compiled.segments.get(`${target}.${prop}`);
|
|
1192
|
+
if (segs) {
|
|
1193
|
+
let active;
|
|
1194
|
+
for (const seg of segs) {
|
|
1195
|
+
if (seg.t0 <= t) active = seg;
|
|
1196
|
+
else break;
|
|
1197
|
+
}
|
|
1198
|
+
if (active) {
|
|
1199
|
+
segStart = active.t0;
|
|
1200
|
+
if (t >= active.t1) {
|
|
1201
|
+
value = active.to;
|
|
1202
|
+
} else {
|
|
1203
|
+
const u = resolveEase(active.ease)((t - active.t0) / (active.t1 - active.t0));
|
|
1204
|
+
value = lerpValue(active.from, active.to, u);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
if (prop === "x" || prop === "y" || prop === "rotation") {
|
|
1209
|
+
const drivers = compiled.motionPaths.get(target);
|
|
1210
|
+
if (drivers) {
|
|
1211
|
+
let active;
|
|
1212
|
+
for (const d of drivers) {
|
|
1213
|
+
if (d.t0 <= t) active = d;
|
|
1214
|
+
else break;
|
|
1215
|
+
}
|
|
1216
|
+
if (active && active.t0 >= segStart && (prop !== "rotation" || active.autoRotate) && active.points.length > 0) {
|
|
1217
|
+
const span = active.t1 - active.t0;
|
|
1218
|
+
const u = span <= 0 ? 1 : resolveEase(active.ease)(Math.max(0, Math.min(1, (t - active.t0) / span)));
|
|
1219
|
+
if (prop === "x") value = pathPoint(active.points, active.closed, u, active.curviness)[0];
|
|
1220
|
+
else if (prop === "y") value = pathPoint(active.points, active.closed, u, active.curviness)[1];
|
|
1221
|
+
else value = pathTangentAngle(active.points, active.closed, u, active.curviness) + active.rotateOffset;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
for (const b of compiled.ir.behaviors ?? []) {
|
|
1226
|
+
if (b.target === target && b.prop === prop && typeof value === "number") {
|
|
1227
|
+
const envelope = behaviorEnvelope(b, t);
|
|
1228
|
+
if (envelope > 0) value = value + envelope * sampleBehavior(b.behavior, t);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return value;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// ../core/src/autoFoley.ts
|
|
1235
|
+
var V_MIN = 360;
|
|
1236
|
+
var V_STOP = 60;
|
|
1237
|
+
var V_DECEL = 520;
|
|
1238
|
+
var V_MAX = 2600;
|
|
1239
|
+
var MIN_DUR = 0.1;
|
|
1240
|
+
var num = (c, t, id, prop, fb) => {
|
|
1241
|
+
const v = sampleProp(c, t, id, prop, fb);
|
|
1242
|
+
return typeof v === "number" ? v : fb;
|
|
1243
|
+
};
|
|
1244
|
+
function nodeSize(node) {
|
|
1245
|
+
const p = node.props;
|
|
1246
|
+
return Math.max(p.width ?? 0, p.height ?? 0, (p.radius ?? 0) * 2, p.fontSize ?? 0, 0);
|
|
1247
|
+
}
|
|
1248
|
+
var FAMILY = { whoosh: "move", swish: "move", thud: "hit", knock: "hit", pop: "pop" };
|
|
1249
|
+
var DEDUP_DT = 0.09;
|
|
1250
|
+
function autoFoley(compiled, opts = {}) {
|
|
1251
|
+
const master = opts.gain ?? 0.5;
|
|
1252
|
+
const sens = opts.sensitivity ?? 1;
|
|
1253
|
+
const wantWhoosh = opts.whoosh !== false;
|
|
1254
|
+
const wantImpact = opts.impact !== false;
|
|
1255
|
+
const wantPop = opts.pop !== false;
|
|
1256
|
+
const wantPan = opts.pan !== false;
|
|
1257
|
+
const vMin = V_MIN / sens, vStop = V_STOP, vDecel = V_DECEL / sens;
|
|
1258
|
+
const fps = compiled.ir.fps ?? 30;
|
|
1259
|
+
const N = Math.max(1, Math.ceil(compiled.duration * fps));
|
|
1260
|
+
const W = compiled.ir.size.width || 1920;
|
|
1261
|
+
const ids = opts.nodes ?? [...compiled.nodeById.keys()];
|
|
1262
|
+
const cands = [];
|
|
1263
|
+
const panOf = (x) => wantPan ? Math.max(-1, Math.min(1, x / W * 2 - 1)) : 0;
|
|
1264
|
+
const loud = (v) => Math.max(0.2, Math.min(1, (v - vMin) / (V_MAX - vMin)));
|
|
1265
|
+
for (const id of ids) {
|
|
1266
|
+
const node = compiled.nodeById.get(id);
|
|
1267
|
+
if (!node || node.type === "line") continue;
|
|
1268
|
+
const size = nodeSize(node);
|
|
1269
|
+
const xs = [], ys = [], ss = [], os = [];
|
|
1270
|
+
for (let i2 = 0; i2 <= N; i2++) {
|
|
1271
|
+
const t = i2 / fps;
|
|
1272
|
+
xs.push(num(compiled, t, id, "x", node.props.x ?? 0));
|
|
1273
|
+
ys.push(num(compiled, t, id, "y", node.props.y ?? 0));
|
|
1274
|
+
ss.push(num(compiled, t, id, "scale", node.props.scale ?? 1));
|
|
1275
|
+
os.push(num(compiled, t, id, "opacity", node.props.opacity ?? 1));
|
|
1276
|
+
}
|
|
1277
|
+
const speed = (i2) => i2 <= 0 ? 0 : Math.hypot(xs[i2] - xs[i2 - 1], ys[i2] - ys[i2 - 1]) * fps;
|
|
1278
|
+
let i = 1;
|
|
1279
|
+
while (i <= N) {
|
|
1280
|
+
if (speed(i) <= vMin) {
|
|
1281
|
+
i++;
|
|
1282
|
+
continue;
|
|
1283
|
+
}
|
|
1284
|
+
const a = i;
|
|
1285
|
+
let peak = i, peakV = speed(i);
|
|
1286
|
+
while (i <= N && speed(i) > vStop) {
|
|
1287
|
+
const s = speed(i);
|
|
1288
|
+
if (s > peakV) {
|
|
1289
|
+
peakV = s;
|
|
1290
|
+
peak = i;
|
|
1291
|
+
}
|
|
1292
|
+
i++;
|
|
1293
|
+
}
|
|
1294
|
+
const b = i - 1;
|
|
1295
|
+
const durS = (b - a + 1) / fps;
|
|
1296
|
+
const visible = os[peak] > 0.1;
|
|
1297
|
+
if (peakV > vMin && durS >= MIN_DUR && visible) {
|
|
1298
|
+
if (wantWhoosh) {
|
|
1299
|
+
const quickFlick = durS < 0.25;
|
|
1300
|
+
cands.push({ t: peak / fps, sfx: quickFlick ? "swish" : "whoosh", gain: master * loud(peakV), pan: panOf(xs[peak]), rank: peakV });
|
|
1301
|
+
}
|
|
1302
|
+
const stopped = b >= N || speed(b + 1) < vStop && speed(Math.min(N, b + 2)) < vStop;
|
|
1303
|
+
const landsOnScreen = xs[b] >= 0 && xs[b] <= W && os[b] > 0.1;
|
|
1304
|
+
if (wantImpact && peakV > vDecel && stopped && landsOnScreen && b < N) {
|
|
1305
|
+
cands.push({ t: (b + 1) / fps, sfx: size > 220 ? "thud" : "knock", gain: master * loud(peakV), pan: panOf(xs[b]), rank: peakV * 1.1 });
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
if (wantPop && ss[0] < 0.25) {
|
|
1310
|
+
for (let k = 1; k <= N; k++) {
|
|
1311
|
+
if (ss[k - 1] < 0.5 && ss[k] >= 0.5 && os[k] > 0.05) {
|
|
1312
|
+
cands.push({ t: k / fps, sfx: "pop", gain: master * 0.7, pan: panOf(xs[k]), rank: 600 });
|
|
1313
|
+
break;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
cands.sort((p, q) => q.rank - p.rank);
|
|
1319
|
+
const kept = [];
|
|
1320
|
+
for (const c of cands) {
|
|
1321
|
+
const fam = FAMILY[c.sfx] ?? c.sfx;
|
|
1322
|
+
if (kept.some((k) => (FAMILY[k.sfx] ?? k.sfx) === fam && Math.abs(k.t - c.t) < DEDUP_DT)) continue;
|
|
1323
|
+
kept.push(c);
|
|
1324
|
+
}
|
|
1325
|
+
const max = opts.maxCues ?? 32;
|
|
1326
|
+
return kept.slice(0, max).map((c) => ({
|
|
1327
|
+
at: Number(c.t.toFixed(3)),
|
|
1328
|
+
sfx: c.sfx,
|
|
1329
|
+
gain: Number(c.gain.toFixed(3)),
|
|
1330
|
+
...c.pan !== 0 ? { pan: Number(c.pan.toFixed(3)) } : {}
|
|
1331
|
+
}));
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1028
1334
|
// ../core/src/presets.ts
|
|
1029
1335
|
var SET = 1 / 120;
|
|
1030
1336
|
|
|
@@ -1097,11 +1403,13 @@ function resolveAudioPlan(compiled) {
|
|
|
1097
1403
|
const warnings = [];
|
|
1098
1404
|
const duration = compiled.duration;
|
|
1099
1405
|
const clipAudio = collectClipAudio(compiled.ir, duration, warnings);
|
|
1100
|
-
|
|
1406
|
+
const autoCues = audio?.autoFoley ? autoFoley(compiled, audio.autoFoley === true ? {} : audio.autoFoley) : [];
|
|
1407
|
+
const manualCues = [...audio?.cues ?? [], ...autoCues];
|
|
1408
|
+
if (!audio || !audio.bgm && manualCues.length === 0) {
|
|
1101
1409
|
return clipAudio.length === 0 ? null : { duration, bgm: null, cues: [], duckWindows: [], clipAudio, warnings };
|
|
1102
1410
|
}
|
|
1103
1411
|
const cues = [];
|
|
1104
|
-
for (const [index, cue] of
|
|
1412
|
+
for (const [index, cue] of manualCues.entries()) {
|
|
1105
1413
|
let anchor;
|
|
1106
1414
|
if (typeof cue.at === "number") {
|
|
1107
1415
|
anchor = cue.at;
|
|
@@ -1232,9 +1540,6 @@ function resolveCompositionAudioPlan(comp) {
|
|
|
1232
1540
|
};
|
|
1233
1541
|
}
|
|
1234
1542
|
|
|
1235
|
-
// ../core/src/evaluate.ts
|
|
1236
|
-
var DEG = Math.PI / 180;
|
|
1237
|
-
|
|
1238
1543
|
// ../core/src/assets.ts
|
|
1239
1544
|
function collectSrcs(ir, type) {
|
|
1240
1545
|
const srcs = /* @__PURE__ */ new Set();
|
|
@@ -1311,14 +1616,14 @@ function encodeWavMono16(samples, sampleRate = SAMPLE_RATE) {
|
|
|
1311
1616
|
}
|
|
1312
1617
|
|
|
1313
1618
|
// ../render-cli/src/audio/synth.ts
|
|
1314
|
-
function
|
|
1619
|
+
function hash012(n, seed) {
|
|
1315
1620
|
let h = n * 374761393 + seed * 668265263 | 0;
|
|
1316
1621
|
h = h ^ h >>> 13 | 0;
|
|
1317
1622
|
h = Math.imul(h, 1274126177);
|
|
1318
1623
|
h = (h ^ h >>> 16) >>> 0;
|
|
1319
1624
|
return h / 4294967295;
|
|
1320
1625
|
}
|
|
1321
|
-
var noise = (n, seed) =>
|
|
1626
|
+
var noise = (n, seed) => hash012(n, seed) * 2 - 1;
|
|
1322
1627
|
var TAU = Math.PI * 2;
|
|
1323
1628
|
var expDecay = (t, dur, k = 5) => Math.exp(-k * t / dur);
|
|
1324
1629
|
var square = (ph) => (Math.sin(ph) + 0.33 * Math.sin(3 * ph) + 0.2 * Math.sin(5 * ph)) / 1.4;
|
|
@@ -1562,7 +1867,7 @@ function sparkle(seed, pitch) {
|
|
|
1562
1867
|
const on = u * steps.length - g;
|
|
1563
1868
|
if (on > 0 && on < 3) {
|
|
1564
1869
|
const ge = Math.exp(-on * 1.8);
|
|
1565
|
-
s += Math.sin(TAU * base * steps[g] * t +
|
|
1870
|
+
s += Math.sin(TAU * base * steps[g] * t + hash012(g, seed) * TAU) * ge;
|
|
1566
1871
|
}
|
|
1567
1872
|
}
|
|
1568
1873
|
out[i] = s / 2.4 * Math.sin(Math.PI * u) ** 0.5 * 0.5;
|
|
@@ -1589,9 +1894,9 @@ function shimmer(seed, pitch) {
|
|
|
1589
1894
|
const dur = 0.9;
|
|
1590
1895
|
const { out, n } = buffer(dur);
|
|
1591
1896
|
const partials = Array.from({ length: 5 }, (_, p) => ({
|
|
1592
|
-
freq: (2e3 +
|
|
1593
|
-
am: 0.5 +
|
|
1594
|
-
phase:
|
|
1897
|
+
freq: (2e3 + hash012(p, seed + 7) * 2e3) * pitch,
|
|
1898
|
+
am: 0.5 + hash012(p, seed + 8) * 1.5,
|
|
1899
|
+
phase: hash012(p, seed + 9) * TAU
|
|
1595
1900
|
}));
|
|
1596
1901
|
for (let i = 0; i < n; i++) {
|
|
1597
1902
|
const t = i / SAMPLE_RATE, u = t / dur;
|
|
@@ -1652,8 +1957,8 @@ function glitch(seed, pitch) {
|
|
|
1652
1957
|
for (let i = 0; i < n; i++) {
|
|
1653
1958
|
const t = i / SAMPLE_RATE, u = t / dur;
|
|
1654
1959
|
const c = Math.floor(i / cell);
|
|
1655
|
-
const on =
|
|
1656
|
-
const freq = 400 * pitch * (1 + Math.floor(
|
|
1960
|
+
const on = hash012(c, seed) > 0.4 ? 1 : 0;
|
|
1961
|
+
const freq = 400 * pitch * (1 + Math.floor(hash012(c, seed + 1) * 6));
|
|
1657
1962
|
phase += TAU * freq / SAMPLE_RATE;
|
|
1658
1963
|
const crush = Math.round(square(phase) * 4) / 4;
|
|
1659
1964
|
out[i] = (crush * 0.7 + noise(i, seed + c) * 0.3) * on * (1 - u * 0.3) * 0.55;
|
|
@@ -1847,8 +2152,8 @@ function synthSfx(name, params = {}) {
|
|
|
1847
2152
|
function pad(freqs, duration, seed, opts) {
|
|
1848
2153
|
const { out, n } = buffer(duration);
|
|
1849
2154
|
const voices = freqs.flatMap((f, v) => [
|
|
1850
|
-
{ freq: f * (1 + (
|
|
1851
|
-
{ freq: f * (1 - (
|
|
2155
|
+
{ 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 },
|
|
2156
|
+
{ 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
2157
|
]);
|
|
1853
2158
|
for (let i = 0; i < n; i++) {
|
|
1854
2159
|
const t = i / SAMPLE_RATE;
|
|
@@ -1887,8 +2192,8 @@ function synthTension(duration, seed = 0) {
|
|
|
1887
2192
|
const drift = 1 + 0.03 * (t / Math.max(1e-3, duration));
|
|
1888
2193
|
let s = 0;
|
|
1889
2194
|
for (let v = 0; v < base.length; v++) {
|
|
1890
|
-
const f = base[v] * drift * (1 + (
|
|
1891
|
-
s += Math.sin(TAU * f * t +
|
|
2195
|
+
const f = base[v] * drift * (1 + (hash012(v, seed) - 0.5) * 6e-3);
|
|
2196
|
+
s += Math.sin(TAU * f * t + hash012(v, seed + 1) * TAU);
|
|
1892
2197
|
}
|
|
1893
2198
|
const swell = 0.6 + 0.4 * Math.sin(TAU * 0.08 * t);
|
|
1894
2199
|
out[i] = s / base.length * swell * 0.6;
|
|
@@ -1913,6 +2218,7 @@ function synthBgm(name, duration, seed = 0) {
|
|
|
1913
2218
|
var ROOT = true ? resolve(dirname(fileURLToPath(import.meta.url)), "..") : resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "..");
|
|
1914
2219
|
var VENDORED = join(ROOT, "assets", "sfx");
|
|
1915
2220
|
var CACHE = join(tmpdir(), "reframe-sfx-cache");
|
|
2221
|
+
var SAMPLE_DEFAULT = /* @__PURE__ */ new Set(["whoosh", "rise", "shimmer", "thud", "pop", "tick"]);
|
|
1916
2222
|
function fnv1a(text2) {
|
|
1917
2223
|
let h = 2166136261;
|
|
1918
2224
|
for (let i = 0; i < text2.length; i++) {
|
|
@@ -1945,6 +2251,10 @@ async function resolveCueFile(cue, sceneDir) {
|
|
|
1945
2251
|
);
|
|
1946
2252
|
}
|
|
1947
2253
|
const { name, params } = cue.source;
|
|
2254
|
+
if (SAMPLE_DEFAULT.has(name) && !params.synth) {
|
|
2255
|
+
const vendored = join(VENDORED, `${name}.wav`);
|
|
2256
|
+
if (existsSync(vendored)) return vendored;
|
|
2257
|
+
}
|
|
1948
2258
|
return writeCached(`${name}-${fnv1a(JSON.stringify(params))}`, () => synthSfx(name, params));
|
|
1949
2259
|
}
|
|
1950
2260
|
async function resolveBgmFile(source, duration, sceneDir) {
|
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();
|