reframe-video 0.6.32 → 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/dist/bin.js CHANGED
@@ -409,7 +409,119 @@ function easeOutBounce(u) {
409
409
  if (u < 2.5 / d1) return n1 * (u -= 2.25 / d1) * u + 0.9375;
410
410
  return n1 * (u -= 2.625 / d1) * u + 0.984375;
411
411
  }
412
- var BACK_C1, BACK_C2, BACK_C3, ELASTIC_C4, ELASTIC_C5, EASE_TABLE, EASE_NAMES;
412
+ function resolveEase(ease) {
413
+ if (ease === void 0) return EASE_TABLE.linear;
414
+ if (typeof ease === "string") {
415
+ const fn = EASE_TABLE[ease];
416
+ if (!fn) throw new Error(`unknown ease "${ease}" \u2014 valid: ${Object.keys(EASE_TABLE).join(", ")}`);
417
+ return fn;
418
+ }
419
+ if ("spring" in ease) {
420
+ const { stiffness = 100, damping = 10, velocity = 0 } = ease.spring;
421
+ return springEase(stiffness, damping, velocity);
422
+ }
423
+ return cubicBezierEase(...ease.cubicBezier);
424
+ }
425
+ function cubicBezierEase(x1, y1, x2, y2) {
426
+ const bez = (a, b) => (t) => 3 * a * t * (1 - t) ** 2 + 3 * b * t * t * (1 - t) + t ** 3;
427
+ const bx = bez(x1, x2);
428
+ const by = bez(y1, y2);
429
+ const dbx = (t) => 3 * x1 * (1 - t) * (1 - 3 * t) + 3 * x2 * t * (2 - 3 * t) + 3 * t * t;
430
+ return (u) => {
431
+ if (u <= 0) return 0;
432
+ if (u >= 1) return 1;
433
+ let t = u;
434
+ for (let i = 0; i < 8; i++) {
435
+ const err = bx(t) - u;
436
+ if (Math.abs(err) < 1e-6) return by(t);
437
+ const d = dbx(t);
438
+ if (Math.abs(d) < 1e-6) break;
439
+ t -= err / d;
440
+ }
441
+ let lo = 0;
442
+ let hi = 1;
443
+ t = u;
444
+ while (hi - lo > 1e-6) {
445
+ if (bx(t) < u) lo = t;
446
+ else hi = t;
447
+ t = (lo + hi) / 2;
448
+ }
449
+ return by(t);
450
+ };
451
+ }
452
+ function isColor(v) {
453
+ return typeof v === "string" && HEX_COLOR.test(v);
454
+ }
455
+ function parseColor(hex) {
456
+ let h = hex.slice(1);
457
+ if (h.length <= 4) h = [...h].map((c) => c + c).join("");
458
+ const n = parseInt(h.padEnd(8, "f"), 16);
459
+ return [n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, n & 255];
460
+ }
461
+ function formatColor([r, g, b, a]) {
462
+ const hex = (v) => Math.round(Math.max(0, Math.min(255, v))).toString(16).padStart(2, "0");
463
+ return a >= 255 ? `#${hex(r)}${hex(g)}${hex(b)}` : `#${hex(r)}${hex(g)}${hex(b)}${hex(a)}`;
464
+ }
465
+ function lerpValue(from, to, u) {
466
+ if (typeof from === "number" && typeof to === "number") {
467
+ return from + (to - from) * u;
468
+ }
469
+ if (isColor(from) && isColor(to)) {
470
+ const a = parseColor(from);
471
+ const b = parseColor(to);
472
+ return formatColor([
473
+ a[0] + (b[0] - a[0]) * u,
474
+ a[1] + (b[1] - a[1]) * u,
475
+ a[2] + (b[2] - a[2]) * u,
476
+ a[3] + (b[3] - a[3]) * u
477
+ ]);
478
+ }
479
+ if (looksLikePath(from) && looksLikePath(to)) {
480
+ const a = tokenizePath(from);
481
+ const b = tokenizePath(to);
482
+ if (a && b && morphCompatible(a, b)) return morphPath(a, b, u);
483
+ return u < 0.5 ? from : to;
484
+ }
485
+ return to;
486
+ }
487
+ function looksLikePath(v) {
488
+ return typeof v === "string" && /^\s*[Mm]/.test(v) && PATH_BODY.test(v);
489
+ }
490
+ function tokenizePath(d) {
491
+ const out = [];
492
+ let cur = null;
493
+ let m;
494
+ PATH_TOKEN.lastIndex = 0;
495
+ while (m = PATH_TOKEN.exec(d)) {
496
+ if (m[1]) out.push(cur = { cmd: m[1], nums: [] });
497
+ else if (m[2]) {
498
+ if (!cur) return null;
499
+ cur.nums.push(parseFloat(m[2]));
500
+ }
501
+ }
502
+ return out.length ? out : null;
503
+ }
504
+ function morphCompatible(a, b) {
505
+ if (a.length !== b.length) return false;
506
+ for (let i = 0; i < a.length; i++) {
507
+ const ca = a[i];
508
+ const cb = b[i];
509
+ if (ca.cmd !== cb.cmd || ca.nums.length !== cb.nums.length) return false;
510
+ if (ca.cmd === "A" || ca.cmd === "a") return false;
511
+ }
512
+ return true;
513
+ }
514
+ function morphPath(a, b, u) {
515
+ let s = "";
516
+ for (let i = 0; i < a.length; i++) {
517
+ const an = a[i].nums;
518
+ const bn = b[i].nums;
519
+ s += (i ? " " : "") + a[i].cmd;
520
+ for (let j = 0; j < an.length; j++) s += " " + fmtNum(an[j] + (bn[j] - an[j]) * u);
521
+ }
522
+ return s;
523
+ }
524
+ var BACK_C1, BACK_C2, BACK_C3, ELASTIC_C4, ELASTIC_C5, EASE_TABLE, EASE_NAMES, HEX_COLOR, PATH_BODY, PATH_TOKEN, fmtNum;
413
525
  var init_interpolate = __esm({
414
526
  "../core/src/interpolate.ts"() {
415
527
  "use strict";
@@ -451,6 +563,13 @@ var init_interpolate = __esm({
451
563
  springStiff: springEase(210, 26, 0)
452
564
  };
453
565
  EASE_NAMES = Object.keys(EASE_TABLE);
566
+ HEX_COLOR = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
567
+ PATH_BODY = /^[\sMmLlHhVvCcSsQqTtAaZz0-9.,eE+-]+$/;
568
+ PATH_TOKEN = /([MmLlHhVvCcSsQqTtAaZz])|(-?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?)/g;
569
+ fmtNum = (v) => {
570
+ const r = Number(v.toFixed(3));
571
+ return Object.is(r, -0) ? "0" : String(r);
572
+ };
454
573
  }
455
574
  });
456
575
 
@@ -1102,6 +1221,40 @@ var init_camera = __esm({
1102
1221
  }
1103
1222
  });
1104
1223
 
1224
+ // ../core/src/behaviors.ts
1225
+ function sampleBehavior(b, t) {
1226
+ switch (b.name) {
1227
+ case "oscillate": {
1228
+ const { amplitude, frequency, phase = 0 } = b.params;
1229
+ return amplitude * Math.sin(2 * Math.PI * frequency * t + phase);
1230
+ }
1231
+ case "wiggle": {
1232
+ const { amplitude, frequency, seed } = b.params;
1233
+ return amplitude * valueNoise(t * frequency, seed);
1234
+ }
1235
+ }
1236
+ }
1237
+ function valueNoise(x, seed) {
1238
+ const i = Math.floor(x);
1239
+ const f = x - i;
1240
+ const u = f * f * (3 - 2 * f);
1241
+ const a = hash01(i, seed) * 2 - 1;
1242
+ const b = hash01(i + 1, seed) * 2 - 1;
1243
+ return a + (b - a) * u;
1244
+ }
1245
+ function hash01(n, seed) {
1246
+ let h = n * 374761393 + seed * 668265263 | 0;
1247
+ h = h ^ h >>> 13 | 0;
1248
+ h = Math.imul(h, 1274126177);
1249
+ h = (h ^ h >>> 16) >>> 0;
1250
+ return h / 4294967295;
1251
+ }
1252
+ var init_behaviors = __esm({
1253
+ "../core/src/behaviors.ts"() {
1254
+ "use strict";
1255
+ }
1256
+ });
1257
+
1105
1258
  // ../core/src/gradient.ts
1106
1259
  var init_gradient = __esm({
1107
1260
  "../core/src/gradient.ts"() {
@@ -1109,6 +1262,182 @@ var init_gradient = __esm({
1109
1262
  }
1110
1263
  });
1111
1264
 
1265
+ // ../core/src/evaluate.ts
1266
+ function behaviorEnvelope(b, t) {
1267
+ const from = b.from ?? Number.NEGATIVE_INFINITY;
1268
+ const until = b.until ?? Number.POSITIVE_INFINITY;
1269
+ if (t < from || t > until) return 0;
1270
+ const ramp = b.ramp ?? 0.2;
1271
+ let envelope = 1;
1272
+ if (Number.isFinite(from) && ramp > 0) envelope = Math.min(envelope, (t - from) / ramp);
1273
+ if (Number.isFinite(until) && ramp > 0) envelope = Math.min(envelope, (until - t) / ramp);
1274
+ return Math.max(0, Math.min(1, envelope));
1275
+ }
1276
+ function sampleProp(compiled, t, target, prop, fallback) {
1277
+ let value = compiled.initialValues.get(`${target}.${prop}`) ?? fallback;
1278
+ let segStart = Number.NEGATIVE_INFINITY;
1279
+ const segs = compiled.segments.get(`${target}.${prop}`);
1280
+ if (segs) {
1281
+ let active;
1282
+ for (const seg of segs) {
1283
+ if (seg.t0 <= t) active = seg;
1284
+ else break;
1285
+ }
1286
+ if (active) {
1287
+ segStart = active.t0;
1288
+ if (t >= active.t1) {
1289
+ value = active.to;
1290
+ } else {
1291
+ const u = resolveEase(active.ease)((t - active.t0) / (active.t1 - active.t0));
1292
+ value = lerpValue(active.from, active.to, u);
1293
+ }
1294
+ }
1295
+ }
1296
+ if (prop === "x" || prop === "y" || prop === "rotation") {
1297
+ const drivers = compiled.motionPaths.get(target);
1298
+ if (drivers) {
1299
+ let active;
1300
+ for (const d of drivers) {
1301
+ if (d.t0 <= t) active = d;
1302
+ else break;
1303
+ }
1304
+ if (active && active.t0 >= segStart && (prop !== "rotation" || active.autoRotate) && active.points.length > 0) {
1305
+ const span = active.t1 - active.t0;
1306
+ const u = span <= 0 ? 1 : resolveEase(active.ease)(Math.max(0, Math.min(1, (t - active.t0) / span)));
1307
+ if (prop === "x") value = pathPoint(active.points, active.closed, u, active.curviness)[0];
1308
+ else if (prop === "y") value = pathPoint(active.points, active.closed, u, active.curviness)[1];
1309
+ else value = pathTangentAngle(active.points, active.closed, u, active.curviness) + active.rotateOffset;
1310
+ }
1311
+ }
1312
+ }
1313
+ for (const b of compiled.ir.behaviors ?? []) {
1314
+ if (b.target === target && b.prop === prop && typeof value === "number") {
1315
+ const envelope = behaviorEnvelope(b, t);
1316
+ if (envelope > 0) value = value + envelope * sampleBehavior(b.behavior, t);
1317
+ }
1318
+ }
1319
+ return value;
1320
+ }
1321
+ var DEG;
1322
+ var init_evaluate = __esm({
1323
+ "../core/src/evaluate.ts"() {
1324
+ "use strict";
1325
+ init_behaviors();
1326
+ init_camera();
1327
+ init_gradient();
1328
+ init_interpolate();
1329
+ init_path();
1330
+ DEG = Math.PI / 180;
1331
+ }
1332
+ });
1333
+
1334
+ // ../core/src/autoFoley.ts
1335
+ function nodeSize(node) {
1336
+ const p = node.props;
1337
+ return Math.max(p.width ?? 0, p.height ?? 0, (p.radius ?? 0) * 2, p.fontSize ?? 0, 0);
1338
+ }
1339
+ function autoFoley(compiled, opts = {}) {
1340
+ const master = opts.gain ?? 0.5;
1341
+ const sens = opts.sensitivity ?? 1;
1342
+ const wantWhoosh = opts.whoosh !== false;
1343
+ const wantImpact = opts.impact !== false;
1344
+ const wantPop = opts.pop !== false;
1345
+ const wantPan = opts.pan !== false;
1346
+ const vMin = V_MIN / sens, vStop = V_STOP, vDecel = V_DECEL / sens;
1347
+ const fps = compiled.ir.fps ?? 30;
1348
+ const N = Math.max(1, Math.ceil(compiled.duration * fps));
1349
+ const W = compiled.ir.size.width || 1920;
1350
+ const ids = opts.nodes ?? [...compiled.nodeById.keys()];
1351
+ const cands = [];
1352
+ const panOf = (x) => wantPan ? Math.max(-1, Math.min(1, x / W * 2 - 1)) : 0;
1353
+ const loud = (v) => Math.max(0.2, Math.min(1, (v - vMin) / (V_MAX - vMin)));
1354
+ for (const id of ids) {
1355
+ const node = compiled.nodeById.get(id);
1356
+ if (!node || node.type === "line") continue;
1357
+ const size = nodeSize(node);
1358
+ const xs = [], ys = [], ss = [], os = [];
1359
+ for (let i2 = 0; i2 <= N; i2++) {
1360
+ const t = i2 / fps;
1361
+ xs.push(num(compiled, t, id, "x", node.props.x ?? 0));
1362
+ ys.push(num(compiled, t, id, "y", node.props.y ?? 0));
1363
+ ss.push(num(compiled, t, id, "scale", node.props.scale ?? 1));
1364
+ os.push(num(compiled, t, id, "opacity", node.props.opacity ?? 1));
1365
+ }
1366
+ const speed = (i2) => i2 <= 0 ? 0 : Math.hypot(xs[i2] - xs[i2 - 1], ys[i2] - ys[i2 - 1]) * fps;
1367
+ let i = 1;
1368
+ while (i <= N) {
1369
+ if (speed(i) <= vMin) {
1370
+ i++;
1371
+ continue;
1372
+ }
1373
+ const a = i;
1374
+ let peak = i, peakV = speed(i);
1375
+ while (i <= N && speed(i) > vStop) {
1376
+ const s = speed(i);
1377
+ if (s > peakV) {
1378
+ peakV = s;
1379
+ peak = i;
1380
+ }
1381
+ i++;
1382
+ }
1383
+ const b = i - 1;
1384
+ const durS = (b - a + 1) / fps;
1385
+ const visible = os[peak] > 0.1;
1386
+ if (peakV > vMin && durS >= MIN_DUR && visible) {
1387
+ if (wantWhoosh) {
1388
+ const quickFlick = durS < 0.25;
1389
+ cands.push({ t: peak / fps, sfx: quickFlick ? "swish" : "whoosh", gain: master * loud(peakV), pan: panOf(xs[peak]), rank: peakV });
1390
+ }
1391
+ const stopped = b >= N || speed(b + 1) < vStop && speed(Math.min(N, b + 2)) < vStop;
1392
+ const landsOnScreen = xs[b] >= 0 && xs[b] <= W && os[b] > 0.1;
1393
+ if (wantImpact && peakV > vDecel && stopped && landsOnScreen && b < N) {
1394
+ cands.push({ t: (b + 1) / fps, sfx: size > 220 ? "thud" : "knock", gain: master * loud(peakV), pan: panOf(xs[b]), rank: peakV * 1.1 });
1395
+ }
1396
+ }
1397
+ }
1398
+ if (wantPop && ss[0] < 0.25) {
1399
+ for (let k = 1; k <= N; k++) {
1400
+ if (ss[k - 1] < 0.5 && ss[k] >= 0.5 && os[k] > 0.05) {
1401
+ cands.push({ t: k / fps, sfx: "pop", gain: master * 0.7, pan: panOf(xs[k]), rank: 600 });
1402
+ break;
1403
+ }
1404
+ }
1405
+ }
1406
+ }
1407
+ cands.sort((p, q) => q.rank - p.rank);
1408
+ const kept = [];
1409
+ for (const c of cands) {
1410
+ const fam = FAMILY[c.sfx] ?? c.sfx;
1411
+ if (kept.some((k) => (FAMILY[k.sfx] ?? k.sfx) === fam && Math.abs(k.t - c.t) < DEDUP_DT)) continue;
1412
+ kept.push(c);
1413
+ }
1414
+ const max = opts.maxCues ?? 32;
1415
+ return kept.slice(0, max).map((c) => ({
1416
+ at: Number(c.t.toFixed(3)),
1417
+ sfx: c.sfx,
1418
+ gain: Number(c.gain.toFixed(3)),
1419
+ ...c.pan !== 0 ? { pan: Number(c.pan.toFixed(3)) } : {}
1420
+ }));
1421
+ }
1422
+ var V_MIN, V_STOP, V_DECEL, V_MAX, MIN_DUR, num, FAMILY, DEDUP_DT;
1423
+ var init_autoFoley = __esm({
1424
+ "../core/src/autoFoley.ts"() {
1425
+ "use strict";
1426
+ init_evaluate();
1427
+ V_MIN = 360;
1428
+ V_STOP = 60;
1429
+ V_DECEL = 520;
1430
+ V_MAX = 2600;
1431
+ MIN_DUR = 0.1;
1432
+ num = (c, t, id, prop, fb) => {
1433
+ const v = sampleProp(c, t, id, prop, fb);
1434
+ return typeof v === "number" ? v : fb;
1435
+ };
1436
+ FAMILY = { whoosh: "move", swish: "move", thud: "hit", knock: "hit", pop: "pop" };
1437
+ DEDUP_DT = 0.09;
1438
+ }
1439
+ });
1440
+
1112
1441
  // ../core/src/effects.ts
1113
1442
  var init_effects = __esm({
1114
1443
  "../core/src/effects.ts"() {
@@ -1403,11 +1732,13 @@ function resolveAudioPlan(compiled) {
1403
1732
  const warnings = [];
1404
1733
  const duration = compiled.duration;
1405
1734
  const clipAudio = collectClipAudio(compiled.ir, duration, warnings);
1406
- if (!audio || !audio.bgm && (audio.cues ?? []).length === 0) {
1735
+ const autoCues = audio?.autoFoley ? autoFoley(compiled, audio.autoFoley === true ? {} : audio.autoFoley) : [];
1736
+ const manualCues = [...audio?.cues ?? [], ...autoCues];
1737
+ if (!audio || !audio.bgm && manualCues.length === 0) {
1407
1738
  return clipAudio.length === 0 ? null : { duration, bgm: null, cues: [], duckWindows: [], clipAudio, warnings };
1408
1739
  }
1409
1740
  const cues = [];
1410
- for (const [index, cue] of (audio.cues ?? []).entries()) {
1741
+ for (const [index, cue] of manualCues.entries()) {
1411
1742
  let anchor;
1412
1743
  if (typeof cue.at === "number") {
1413
1744
  anchor = cue.at;
@@ -1481,6 +1812,7 @@ var SFX_DURATION, FILE_CUE_DURATION;
1481
1812
  var init_audio = __esm({
1482
1813
  "../core/src/audio.ts"() {
1483
1814
  "use strict";
1815
+ init_autoFoley();
1484
1816
  SFX_DURATION = {
1485
1817
  // transition
1486
1818
  whoosh: 0.35,
@@ -1527,27 +1859,6 @@ var init_audio = __esm({
1527
1859
  }
1528
1860
  });
1529
1861
 
1530
- // ../core/src/behaviors.ts
1531
- var init_behaviors = __esm({
1532
- "../core/src/behaviors.ts"() {
1533
- "use strict";
1534
- }
1535
- });
1536
-
1537
- // ../core/src/evaluate.ts
1538
- var DEG;
1539
- var init_evaluate = __esm({
1540
- "../core/src/evaluate.ts"() {
1541
- "use strict";
1542
- init_behaviors();
1543
- init_camera();
1544
- init_gradient();
1545
- init_interpolate();
1546
- init_path();
1547
- DEG = Math.PI / 180;
1548
- }
1549
- });
1550
-
1551
1862
  // ../core/src/assets.ts
1552
1863
  function collectSrcs(ir, type) {
1553
1864
  const srcs = /* @__PURE__ */ new Set();
@@ -1611,6 +1922,7 @@ var init_src = __esm({
1611
1922
  init_compile();
1612
1923
  init_path();
1613
1924
  init_camera();
1925
+ init_autoFoley();
1614
1926
  init_gradient();
1615
1927
  init_effects();
1616
1928
  init_layout();
@@ -1810,7 +2122,7 @@ var init_wav = __esm({
1810
2122
  });
1811
2123
 
1812
2124
  // ../render-cli/src/audio/synth.ts
1813
- function hash01(n, seed) {
2125
+ function hash012(n, seed) {
1814
2126
  let h = n * 374761393 + seed * 668265263 | 0;
1815
2127
  h = h ^ h >>> 13 | 0;
1816
2128
  h = Math.imul(h, 1274126177);
@@ -2056,7 +2368,7 @@ function sparkle(seed, pitch) {
2056
2368
  const on = u * steps.length - g;
2057
2369
  if (on > 0 && on < 3) {
2058
2370
  const ge = Math.exp(-on * 1.8);
2059
- s += Math.sin(TAU * base * steps[g] * t + hash01(g, seed) * TAU) * ge;
2371
+ s += Math.sin(TAU * base * steps[g] * t + hash012(g, seed) * TAU) * ge;
2060
2372
  }
2061
2373
  }
2062
2374
  out[i] = s / 2.4 * Math.sin(Math.PI * u) ** 0.5 * 0.5;
@@ -2083,9 +2395,9 @@ function shimmer(seed, pitch) {
2083
2395
  const dur2 = 0.9;
2084
2396
  const { out, n } = buffer(dur2);
2085
2397
  const partials = Array.from({ length: 5 }, (_, p) => ({
2086
- freq: (2e3 + hash01(p, seed + 7) * 2e3) * pitch,
2087
- am: 0.5 + hash01(p, seed + 8) * 1.5,
2088
- phase: hash01(p, seed + 9) * TAU
2398
+ freq: (2e3 + hash012(p, seed + 7) * 2e3) * pitch,
2399
+ am: 0.5 + hash012(p, seed + 8) * 1.5,
2400
+ phase: hash012(p, seed + 9) * TAU
2089
2401
  }));
2090
2402
  for (let i = 0; i < n; i++) {
2091
2403
  const t = i / SAMPLE_RATE, u = t / dur2;
@@ -2146,8 +2458,8 @@ function glitch(seed, pitch) {
2146
2458
  for (let i = 0; i < n; i++) {
2147
2459
  const t = i / SAMPLE_RATE, u = t / dur2;
2148
2460
  const c = Math.floor(i / cell);
2149
- const on = hash01(c, seed) > 0.4 ? 1 : 0;
2150
- const freq = 400 * pitch * (1 + Math.floor(hash01(c, seed + 1) * 6));
2461
+ const on = hash012(c, seed) > 0.4 ? 1 : 0;
2462
+ const freq = 400 * pitch * (1 + Math.floor(hash012(c, seed + 1) * 6));
2151
2463
  phase += TAU * freq / SAMPLE_RATE;
2152
2464
  const crush = Math.round(square(phase) * 4) / 4;
2153
2465
  out[i] = (crush * 0.7 + noise(i, seed + c) * 0.3) * on * (1 - u * 0.3) * 0.55;
@@ -2306,8 +2618,8 @@ function synthSfx(name, params = {}) {
2306
2618
  function pad(freqs, duration, seed, opts) {
2307
2619
  const { out, n } = buffer(duration);
2308
2620
  const voices = freqs.flatMap((f, v) => [
2309
- { freq: f * (1 + (hash01(v, seed + 3) - 0.5) * 4e-3), am: opts.amBase + hash01(v, seed + 4) * 0.08, phase: hash01(v, seed + 5) * TAU },
2310
- { freq: f * (1 - (hash01(v, seed + 6) - 0.5) * 4e-3), am: opts.amBase + hash01(v, seed + 7) * 0.08, phase: hash01(v, seed + 8) * TAU }
2621
+ { 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 },
2622
+ { 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 }
2311
2623
  ]);
2312
2624
  for (let i = 0; i < n; i++) {
2313
2625
  const t = i / SAMPLE_RATE;
@@ -2346,8 +2658,8 @@ function synthTension(duration, seed = 0) {
2346
2658
  const drift = 1 + 0.03 * (t / Math.max(1e-3, duration));
2347
2659
  let s = 0;
2348
2660
  for (let v = 0; v < base.length; v++) {
2349
- const f = base[v] * drift * (1 + (hash01(v, seed) - 0.5) * 6e-3);
2350
- s += Math.sin(TAU * f * t + hash01(v, seed + 1) * TAU);
2661
+ const f = base[v] * drift * (1 + (hash012(v, seed) - 0.5) * 6e-3);
2662
+ s += Math.sin(TAU * f * t + hash012(v, seed + 1) * TAU);
2351
2663
  }
2352
2664
  const swell = 0.6 + 0.4 * Math.sin(TAU * 0.08 * t);
2353
2665
  out[i] = s / base.length * swell * 0.6;
@@ -2365,7 +2677,7 @@ var init_synth = __esm({
2365
2677
  "../render-cli/src/audio/synth.ts"() {
2366
2678
  "use strict";
2367
2679
  init_wav();
2368
- noise = (n, seed) => hash01(n, seed) * 2 - 1;
2680
+ noise = (n, seed) => hash012(n, seed) * 2 - 1;
2369
2681
  TAU = Math.PI * 2;
2370
2682
  expDecay = (t, dur2, k = 5) => Math.exp(-k * t / dur2);
2371
2683
  square = (ph) => (Math.sin(ph) + 0.33 * Math.sin(3 * ph) + 0.2 * Math.sin(5 * ph)) / 1.4;
@@ -3616,15 +3928,15 @@ ${USAGE}`);
3616
3928
  preflightFfmpeg();
3617
3929
  const { tmpdir: tmpdir6 } = await import("node:os");
3618
3930
  const { resolveLogo: resolveLogo2, buildLogoSting: buildLogoSting2 } = await Promise.resolve().then(() => (init_logoSting(), logoSting_exports));
3619
- const num = (k) => flags[k] !== void 0 ? Number(flags[k]) : void 0;
3931
+ const num2 = (k) => flags[k] !== void 0 ? Number(flags[k]) : void 0;
3620
3932
  console.log(`loading logo: ${arg} \u2026`);
3621
3933
  const { data, slug } = await resolveLogo2(arg, positional[1], {
3622
3934
  motion: flags.motion,
3623
- energy: num("energy"),
3624
- speed: num("speed"),
3625
- intensity: num("intensity"),
3935
+ energy: num2("energy"),
3936
+ speed: num2("speed"),
3937
+ intensity: num2("intensity"),
3626
3938
  from: flags.from,
3627
- seed: num("seed")
3939
+ seed: num2("seed")
3628
3940
  });
3629
3941
  const sceneIR = buildLogoSting2(data);
3630
3942
  const tmp = join9(tmpdir6(), `reframe-logo-${slug}-${process.pid}.json`);
@@ -549,14 +549,6 @@
549
549
  return [a, b, c, d, W / 2 - a * x - c * y, H / 2 - b * x - d * y];
550
550
  }
551
551
 
552
- // ../core/src/gradient.ts
553
- function isGradient(p) {
554
- return typeof p === "object" && p !== null && (p.kind === "linear" || p.kind === "radial" || p.kind === "conic");
555
- }
556
-
557
- // ../core/src/presets.ts
558
- var SET = 1 / 120;
559
-
560
552
  // ../core/src/behaviors.ts
561
553
  function sampleBehavior(b, t) {
562
554
  switch (b.name) {
@@ -586,6 +578,11 @@
586
578
  return h / 4294967295;
587
579
  }
588
580
 
581
+ // ../core/src/gradient.ts
582
+ function isGradient(p) {
583
+ return typeof p === "object" && p !== null && (p.kind === "linear" || p.kind === "radial" || p.kind === "conic");
584
+ }
585
+
589
586
  // ../core/src/evaluate.ts
590
587
  var IDENTITY = [1, 0, 0, 1, 0, 0];
591
588
  function multiply(m, n) {
@@ -986,6 +983,9 @@
986
983
  return ops;
987
984
  }
988
985
 
986
+ // ../core/src/presets.ts
987
+ var SET = 1 / 120;
988
+
989
989
  // ../renderer-canvas/src/index.ts
990
990
  function resolvePaint(ctx2, paint, box) {
991
991
  if (typeof paint === "string") return paint;