reframe-video 0.6.5 → 0.6.6

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
@@ -622,6 +622,7 @@ var init_validate = __esm({
622
622
  line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth", "opacity", "progress", ...FX_PROPS],
623
623
  text: [...COMMON_PROPS, "content", "contentDecimals", "contentThousands", "fontFamily", "fontSize", "fontWeight", "fill", "letterSpacing"],
624
624
  image: [...COMMON_PROPS, "src", "width", "height", "fit"],
625
+ video: [...COMMON_PROPS, "src", "width", "height", "fit", "start", "rate", "clipStart"],
625
626
  path: [...COMMON_PROPS, "d", "fill", "stroke", "strokeWidth", "progress", "originX", "originY"],
626
627
  group: COMMON_PROPS
627
628
  };
@@ -1363,13 +1364,13 @@ var init_evaluate = __esm({
1363
1364
  });
1364
1365
 
1365
1366
  // ../core/src/assets.ts
1366
- function collectImageSrcs(ir) {
1367
+ function collectSrcs(ir, type) {
1367
1368
  const srcs = /* @__PURE__ */ new Set();
1368
- const imageIds = /* @__PURE__ */ new Set();
1369
+ const ids = /* @__PURE__ */ new Set();
1369
1370
  const walkNodes = (nodes) => {
1370
1371
  for (const node of nodes) {
1371
- if (node.type === "image") {
1372
- imageIds.add(node.id);
1372
+ if (node.type === type) {
1373
+ ids.add(node.id);
1373
1374
  srcs.add(node.props.src);
1374
1375
  }
1375
1376
  if (node.type === "group") walkNodes(node.children);
@@ -1378,14 +1379,14 @@ function collectImageSrcs(ir) {
1378
1379
  walkNodes(ir.nodes);
1379
1380
  for (const overrides of Object.values(ir.states ?? {})) {
1380
1381
  for (const [nodeId, props] of Object.entries(overrides)) {
1381
- if (imageIds.has(nodeId) && typeof props.src === "string") srcs.add(props.src);
1382
+ if (ids.has(nodeId) && typeof props.src === "string") srcs.add(props.src);
1382
1383
  }
1383
1384
  }
1384
1385
  const walkTimeline = (step) => {
1385
1386
  if (!step) return;
1386
1387
  if (step.kind === "seq" || step.kind === "par" || step.kind === "stagger") {
1387
1388
  for (const child of step.children) walkTimeline(child);
1388
- } else if (step.kind === "tween" && imageIds.has(step.target)) {
1389
+ } else if (step.kind === "tween" && ids.has(step.target)) {
1389
1390
  const src = step.props.src;
1390
1391
  if (typeof src === "string") srcs.add(src);
1391
1392
  }
@@ -1393,6 +1394,12 @@ function collectImageSrcs(ir) {
1393
1394
  walkTimeline(ir.timeline);
1394
1395
  return [...srcs];
1395
1396
  }
1397
+ function collectImageSrcs(ir) {
1398
+ return collectSrcs(ir, "image");
1399
+ }
1400
+ function collectVideoSrcs(ir) {
1401
+ return collectSrcs(ir, "video");
1402
+ }
1396
1403
  var init_assets = __esm({
1397
1404
  "../core/src/assets.ts"() {
1398
1405
  "use strict";
@@ -1957,12 +1964,12 @@ async function encodeMp4(framesDir, fps, outFile) {
1957
1964
  "+faststart",
1958
1965
  outFile
1959
1966
  ];
1960
- await new Promise((resolve5, reject) => {
1967
+ await new Promise((resolve6, reject) => {
1961
1968
  const proc = spawn2("ffmpeg", args, { stdio: ["ignore", "ignore", "pipe"] });
1962
1969
  let stderr = "";
1963
1970
  proc.stderr.on("data", (d) => stderr += d.toString());
1964
1971
  proc.on("close", (code) => {
1965
- if (code === 0) resolve5();
1972
+ if (code === 0) resolve6();
1966
1973
  else reject(new Error(`ffmpeg exited with ${code}:
1967
1974
  ${stderr.slice(-2e3)}`));
1968
1975
  });
@@ -2044,6 +2051,103 @@ var init_images = __esm({
2044
2051
  }
2045
2052
  });
2046
2053
 
2054
+ // ../render-cli/src/videos.ts
2055
+ import { spawn as spawn3 } from "node:child_process";
2056
+ import { mkdtemp as mkdtemp2, readFile as readFile4, readdir, rm as rm2 } from "node:fs/promises";
2057
+ import { existsSync as existsSync4 } from "node:fs";
2058
+ import { tmpdir as tmpdir3 } from "node:os";
2059
+ import { extname as extname2, isAbsolute as isAbsolute3, join as join4, resolve as resolve3 } from "node:path";
2060
+ function runFfmpeg(args) {
2061
+ return new Promise((resolve6, reject) => {
2062
+ const proc = spawn3("ffmpeg", args, { stdio: ["ignore", "ignore", "pipe"] });
2063
+ let stderr = "";
2064
+ proc.stderr.on("data", (d) => stderr += d.toString());
2065
+ proc.on(
2066
+ "close",
2067
+ (code) => code === 0 ? resolve6() : reject(new Error(`ffmpeg exited ${code}:
2068
+ ${stderr.slice(-2e3)}`))
2069
+ );
2070
+ proc.on("error", reject);
2071
+ });
2072
+ }
2073
+ function neededSeconds(node, duration) {
2074
+ const start = node.props.start ?? 0;
2075
+ const rate = node.props.rate ?? 1;
2076
+ const clipStart = node.props.clipStart ?? 0;
2077
+ return clipStart + Math.max(0, duration - start) * Math.max(0, rate) + 1 / 30;
2078
+ }
2079
+ function videoNodes(ir) {
2080
+ const out = [];
2081
+ const walk = (nodes) => {
2082
+ for (const n of nodes) {
2083
+ if (n.type === "video") out.push(n);
2084
+ if (n.type === "group") walk(n.children);
2085
+ }
2086
+ };
2087
+ walk(ir.nodes);
2088
+ return out;
2089
+ }
2090
+ async function buildVideoFrameAssets(ir, sceneDir, fps, duration) {
2091
+ const srcs = collectVideoSrcs(ir);
2092
+ if (srcs.length === 0) return {};
2093
+ const nodes = videoNodes(ir);
2094
+ const reachBySrc = /* @__PURE__ */ new Map();
2095
+ for (const n of nodes) {
2096
+ const reach = neededSeconds(n, duration);
2097
+ reachBySrc.set(n.props.src, Math.max(reachBySrc.get(n.props.src) ?? 0, reach));
2098
+ }
2099
+ const assets = {};
2100
+ for (const src of srcs) {
2101
+ if (!VIDEO_EXT.has(extname2(src).toLowerCase())) {
2102
+ throw new Error(
2103
+ `video "${src}": unsupported format "${extname2(src)}" \u2014 supported: ${[...VIDEO_EXT].join(" ")}`
2104
+ );
2105
+ }
2106
+ const candidates = [isAbsolute3(src) ? src : null, resolve3(sceneDir, src)].filter(
2107
+ (c) => c !== null
2108
+ );
2109
+ const found = candidates.find((c) => existsSync4(c));
2110
+ if (!found) throw new Error(`video "${src}" not found (tried: ${candidates.join(", ")})`);
2111
+ const dir = await mkdtemp2(join4(tmpdir3(), "reframe-vframes-"));
2112
+ try {
2113
+ const seconds = Math.max(1 / fps, reachBySrc.get(src) ?? duration);
2114
+ await runFfmpeg([
2115
+ "-y",
2116
+ "-i",
2117
+ found,
2118
+ "-t",
2119
+ seconds.toFixed(3),
2120
+ "-vf",
2121
+ `fps=${fps},scale='min(iw,1280)':-2`,
2122
+ "-q:v",
2123
+ "4",
2124
+ join4(dir, "%05d.jpg")
2125
+ ]);
2126
+ const files = (await readdir(dir)).filter((f) => f.endsWith(".jpg")).sort();
2127
+ assets[src] = await Promise.all(
2128
+ files.map(async (f) => `data:image/jpeg;base64,${(await readFile4(join4(dir, f))).toString("base64")}`)
2129
+ );
2130
+ if (assets[src].length === 0) throw new Error(`video "${src}": ffmpeg extracted no frames`);
2131
+ } finally {
2132
+ await rm2(dir, { recursive: true, force: true });
2133
+ }
2134
+ }
2135
+ return assets;
2136
+ }
2137
+ function resolveTiming(ir, opts) {
2138
+ const fps = opts.fps ?? ir.fps ?? 30;
2139
+ const duration = opts.duration ?? compileScene(ir).duration;
2140
+ return { fps, duration };
2141
+ }
2142
+ var VIDEO_EXT;
2143
+ var init_videos = __esm({
2144
+ "../render-cli/src/videos.ts"() {
2145
+ "use strict";
2146
+ init_src();
2147
+ VIDEO_EXT = /* @__PURE__ */ new Set([".mp4", ".mov", ".webm", ".m4v", ".mkv"]);
2148
+ }
2149
+ });
2150
+
2047
2151
  // ../render-cli/src/vclock.ts
2048
2152
  var VCLOCK_SOURCE;
2049
2153
  var init_vclock = __esm({
@@ -2124,7 +2228,7 @@ var init_reframeGlobal = __esm({
2124
2228
 
2125
2229
  // ../render-cli/src/frameLoop.ts
2126
2230
  import { mkdir as mkdir2, writeFile as writeFile3 } from "node:fs/promises";
2127
- import { join as join4, dirname as dirname4 } from "node:path";
2231
+ import { join as join5, dirname as dirname4 } from "node:path";
2128
2232
  import { fileURLToPath as fileURLToPath3, pathToFileURL } from "node:url";
2129
2233
  import { build } from "esbuild";
2130
2234
  import { chromium } from "playwright";
@@ -2149,14 +2253,14 @@ async function withPage(size, fn) {
2149
2253
  async function browserBundle() {
2150
2254
  if (bundleCache) return bundleCache;
2151
2255
  if (true) {
2152
- const { readFile: readFile6 } = await import("node:fs/promises");
2153
- bundleCache = await readFile6(
2154
- join4(dirname4(fileURLToPath3(import.meta.url)), "browserEntry.js"),
2256
+ const { readFile: readFile7 } = await import("node:fs/promises");
2257
+ bundleCache = await readFile7(
2258
+ join5(dirname4(fileURLToPath3(import.meta.url)), "browserEntry.js"),
2155
2259
  "utf8"
2156
2260
  );
2157
2261
  return bundleCache;
2158
2262
  }
2159
- const entry = join4(dirname4(fileURLToPath3(import.meta.url)), "browserEntry.ts");
2263
+ const entry = join5(dirname4(fileURLToPath3(import.meta.url)), "browserEntry.ts");
2160
2264
  const result = await build({
2161
2265
  entryPoints: [entry],
2162
2266
  bundle: true,
@@ -2169,7 +2273,10 @@ async function browserBundle() {
2169
2273
  }
2170
2274
  async function captureIr(ir, opts) {
2171
2275
  await mkdir2(opts.framesDir, { recursive: true });
2172
- const assets = await buildImageAssets(ir, opts.sceneDir ?? process.cwd());
2276
+ const sceneDir = opts.sceneDir ?? process.cwd();
2277
+ const assets = await buildImageAssets(ir, sceneDir);
2278
+ const { fps, duration } = resolveTiming(ir, opts);
2279
+ const videoAssets = await buildVideoFrameAssets(ir, sceneDir, fps, duration);
2173
2280
  const bundle = await browserBundle();
2174
2281
  return withPage(ir.size, async (page) => {
2175
2282
  await page.setContent(
@@ -2177,12 +2284,10 @@ async function captureIr(ir, opts) {
2177
2284
  );
2178
2285
  await injectFonts(page);
2179
2286
  await page.addScriptTag({ content: bundle });
2180
- const info = await page.evaluate(
2181
- ([sceneIr, imageAssets]) => window.__reframe.init(sceneIr, imageAssets),
2182
- [ir, assets]
2287
+ await page.evaluate(
2288
+ ([sceneIr, imageAssets, vAssets]) => window.__reframe.init(sceneIr, imageAssets, vAssets),
2289
+ [ir, assets, videoAssets]
2183
2290
  );
2184
- const fps = opts.fps ?? info.fps;
2185
- const duration = opts.duration ?? info.duration;
2186
2291
  const frameCount = Math.max(1, Math.round(duration * fps));
2187
2292
  for (let f = 0; f < frameCount; f++) {
2188
2293
  const dataUrl = await page.evaluate((t) => window.__reframe.renderFrame(t), f / fps);
@@ -2197,9 +2302,10 @@ var init_frameLoop = __esm({
2197
2302
  "use strict";
2198
2303
  init_fonts();
2199
2304
  init_images();
2305
+ init_videos();
2200
2306
  init_vclock();
2201
2307
  init_reframeGlobal();
2202
- framePath = (dir, i) => join4(dir, `${String(i).padStart(5, "0")}.png`);
2308
+ framePath = (dir, i) => join5(dir, `${String(i).padStart(5, "0")}.png`);
2203
2309
  bundleCache = null;
2204
2310
  }
2205
2311
  });
@@ -2212,9 +2318,9 @@ __export(batch_exports, {
2212
2318
  parseCsv: () => parseCsv,
2213
2319
  runBatch: () => runBatch
2214
2320
  });
2215
- import { mkdir as mkdir3, mkdtemp as mkdtemp2, readFile as readFile4, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
2216
- import { tmpdir as tmpdir3 } from "node:os";
2217
- import { join as join5, dirname as dirname5 } from "node:path";
2321
+ import { mkdir as mkdir3, mkdtemp as mkdtemp3, readFile as readFile5, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
2322
+ import { tmpdir as tmpdir4 } from "node:os";
2323
+ import { join as join6, dirname as dirname5 } from "node:path";
2218
2324
  function overlayFromFlat(row, name) {
2219
2325
  const doc = { reframeOverlay: 1, name };
2220
2326
  for (const [key2, raw] of Object.entries(row)) {
@@ -2288,7 +2394,7 @@ function parseCsv(text2) {
2288
2394
  });
2289
2395
  }
2290
2396
  async function loadRows(path2) {
2291
- const text2 = await readFile4(path2, "utf8");
2397
+ const text2 = await readFile5(path2, "utf8");
2292
2398
  if (path2.endsWith(".csv")) return parseCsv(text2);
2293
2399
  const parsed = JSON.parse(text2);
2294
2400
  if (!Array.isArray(parsed)) throw new Error(`${path2}: expected a JSON array of row objects`);
@@ -2308,8 +2414,8 @@ async function runBatch(scene2, rows, opts) {
2308
2414
  try {
2309
2415
  const rowOverlay = overlayFromFlat(row, name);
2310
2416
  const { ir, report } = composeScene(scene2, ...opts.baseOverlays, rowOverlay);
2311
- const framesDir = await mkdtemp2(join5(tmpdir3(), `reframe-batch-${index}-`));
2312
- const output = join5(opts.outDir, `${name}.mp4`);
2417
+ const framesDir = await mkdtemp3(join6(tmpdir4(), `reframe-batch-${index}-`));
2418
+ const output = join6(opts.outDir, `${name}.mp4`);
2313
2419
  const plan = opts.noAudio ? null : resolveAudioPlan(compileScene(ir));
2314
2420
  try {
2315
2421
  const captured = await captureIr(ir, {
@@ -2321,12 +2427,12 @@ async function runBatch(scene2, rows, opts) {
2321
2427
  const videoTmp = `${output}.video.mp4`;
2322
2428
  await encodeMp4(captured.framesDir, captured.fps, videoTmp);
2323
2429
  await buildAudioTrack(plan, opts.scenePath ?? output, videoTmp, output);
2324
- await rm2(videoTmp, { force: true });
2430
+ await rm3(videoTmp, { force: true });
2325
2431
  } else {
2326
2432
  await encodeMp4(captured.framesDir, captured.fps, output);
2327
2433
  }
2328
2434
  } finally {
2329
- await rm2(framesDir, { recursive: true, force: true });
2435
+ await rm3(framesDir, { recursive: true, force: true });
2330
2436
  }
2331
2437
  result = {
2332
2438
  name,
@@ -2350,7 +2456,7 @@ async function runBatch(scene2, rows, opts) {
2350
2456
  };
2351
2457
  await Promise.all(Array.from({ length: Math.max(1, opts.concurrency) }, worker));
2352
2458
  await writeFile4(
2353
- join5(opts.outDir, "batch-report.json"),
2459
+ join6(opts.outDir, "batch-report.json"),
2354
2460
  JSON.stringify({ rows: results }, null, 2)
2355
2461
  );
2356
2462
  return results;
@@ -2375,11 +2481,11 @@ __export(loadScene_exports, {
2375
2481
  loadScene: () => loadScene
2376
2482
  });
2377
2483
  import { build as build2 } from "esbuild";
2378
- import { readFile as readFile5 } from "node:fs/promises";
2379
- import { dirname as dirname6, resolve as resolve3 } from "node:path";
2484
+ import { readFile as readFile6 } from "node:fs/promises";
2485
+ import { dirname as dirname6, resolve as resolve4 } from "node:path";
2380
2486
  import { fileURLToPath as fileURLToPath4 } from "node:url";
2381
2487
  async function loadDefault(path2) {
2382
- if (path2.endsWith(".json")) return JSON.parse(await readFile5(path2, "utf8"));
2488
+ if (path2.endsWith(".json")) return JSON.parse(await readFile6(path2, "utf8"));
2383
2489
  let code;
2384
2490
  try {
2385
2491
  const out = await build2({
@@ -2429,26 +2535,26 @@ var init_loadScene = __esm({
2429
2535
  "use strict";
2430
2536
  init_src();
2431
2537
  HERE = dirname6(fileURLToPath4(import.meta.url));
2432
- CORE_ENTRY = true ? resolve3(HERE, "index.js") : resolve3(HERE, "..", "..", "core", "src", "index.ts");
2538
+ CORE_ENTRY = true ? resolve4(HERE, "index.js") : resolve4(HERE, "..", "..", "core", "src", "index.ts");
2433
2539
  }
2434
2540
  });
2435
2541
 
2436
2542
  // ../render-cli/src/reframe.ts
2437
- import { spawn as spawn3, spawnSync } from "node:child_process";
2438
- import { existsSync as existsSync4 } from "node:fs";
2543
+ import { spawn as spawn4, spawnSync } from "node:child_process";
2544
+ import { existsSync as existsSync5 } from "node:fs";
2439
2545
  import { mkdir as mkdir4, writeFile as writeFile5 } from "node:fs/promises";
2440
- import { basename, isAbsolute as isAbsolute3, join as join6, resolve as resolve4 } from "node:path";
2546
+ import { basename, isAbsolute as isAbsolute4, join as join7, resolve as resolve5 } from "node:path";
2441
2547
  import { dirname as dirname7 } from "node:path";
2442
2548
  import { fileURLToPath as fileURLToPath5 } from "node:url";
2443
2549
  var PACKAGED = true;
2444
2550
  var HERE2 = dirname7(fileURLToPath5(import.meta.url));
2445
- var ROOT2 = PACKAGED ? resolve4(HERE2, "..") : resolve4(HERE2, "..", "..", "..");
2551
+ var ROOT2 = PACKAGED ? resolve5(HERE2, "..") : resolve5(HERE2, "..", "..", "..");
2446
2552
  var USER_CWD = process.env.INIT_CWD ?? process.cwd();
2447
- var RENDER_CLI = PACKAGED ? join6(ROOT2, "dist", "cli.js") : join6(ROOT2, "packages", "render-cli", "src", "cli.ts");
2448
- var LABELS = PACKAGED ? join6(ROOT2, "dist", "labels.js") : join6(ROOT2, "packages", "render-cli", "src", "labels.ts");
2449
- var PLAYER = PACKAGED ? join6(ROOT2, "dist", "player.js") : join6(ROOT2, "packages", "render-cli", "src", "player.ts");
2450
- var ANALYZE = PACKAGED ? join6(ROOT2, "dist", "analyze.js") : join6(ROOT2, "benchmark", "harness", "motion", "analyze.ts");
2451
- var TRACE = PACKAGED ? join6(ROOT2, "dist", "trace-cli.js") : join6(ROOT2, "benchmark", "harness", "motion", "trace-cli.ts");
2553
+ var RENDER_CLI = PACKAGED ? join7(ROOT2, "dist", "cli.js") : join7(ROOT2, "packages", "render-cli", "src", "cli.ts");
2554
+ var LABELS = PACKAGED ? join7(ROOT2, "dist", "labels.js") : join7(ROOT2, "packages", "render-cli", "src", "labels.ts");
2555
+ var PLAYER = PACKAGED ? join7(ROOT2, "dist", "player.js") : join7(ROOT2, "packages", "render-cli", "src", "player.ts");
2556
+ var ANALYZE = PACKAGED ? join7(ROOT2, "dist", "analyze.js") : join7(ROOT2, "benchmark", "harness", "motion", "analyze.ts");
2557
+ var TRACE = PACKAGED ? join7(ROOT2, "dist", "trace-cli.js") : join7(ROOT2, "benchmark", "harness", "motion", "trace-cli.ts");
2452
2558
  var CMD = PACKAGED ? "reframe" : "pnpm reframe";
2453
2559
  var USAGE = `reframe \u2014 declarative motion graphics
2454
2560
 
@@ -2468,7 +2574,7 @@ usage:
2468
2574
  ${CMD} guide [--regen] print the scene-authoring guide (for you or your AI)
2469
2575
  ${CMD} demo run the edit-survival demo (3 mp4s into out/)
2470
2576
  `;
2471
- var userPath = (p) => isAbsolute3(p) ? p : resolve4(USER_CWD, p);
2577
+ var userPath = (p) => isAbsolute4(p) ? p : resolve5(USER_CWD, p);
2472
2578
  function fail(message) {
2473
2579
  console.error(`error: ${message}`);
2474
2580
  process.exit(2);
@@ -2480,7 +2586,7 @@ function preflightFfmpeg() {
2480
2586
  }
2481
2587
  function run(cmd, args, opts = {}) {
2482
2588
  return new Promise((res) => {
2483
- const proc = spawn3(cmd, args, {
2589
+ const proc = spawn4(cmd, args, {
2484
2590
  cwd: opts.cwd ?? (PACKAGED ? USER_CWD : ROOT2),
2485
2591
  stdio: ["inherit", "inherit", "pipe"],
2486
2592
  ...opts.env && { env: { ...process.env, ...opts.env } }
@@ -2570,7 +2676,7 @@ async function main() {
2570
2676
 
2571
2677
  ${USAGE}`);
2572
2678
  const inputPath = userPath(input);
2573
- if (!existsSync4(inputPath)) fail(`no such file: ${inputPath}`);
2679
+ if (!existsSync5(inputPath)) fail(`no such file: ${inputPath}`);
2574
2680
  const mode = /\.(ts|json)$/.test(input) ? "ir" : /\.html$/.test(input) ? "html" : null;
2575
2681
  if (!mode) {
2576
2682
  fail(`cannot infer render mode from "${input}" \u2014 expected .ts/.json (reframe scene) or .html (GSAP page)`);
@@ -2580,11 +2686,11 @@ ${USAGE}`);
2580
2686
  fail("html render requires --duration <seconds> (the page does not declare its own length)");
2581
2687
  }
2582
2688
  preflightFfmpeg();
2583
- const outBase = PACKAGED ? join6(USER_CWD, "out") : join6(ROOT2, "out");
2689
+ const outBase = PACKAGED ? join7(USER_CWD, "out") : join7(ROOT2, "out");
2584
2690
  let outArgs = args;
2585
2691
  if (!args.includes("-o")) {
2586
2692
  await mkdir4(outBase, { recursive: true });
2587
- outArgs = [...args, "-o", join6(outBase, `${basename(input).replace(/\.[^.]+$/, "")}.mp4`)];
2693
+ outArgs = [...args, "-o", join7(outBase, `${basename(input).replace(/\.[^.]+$/, "")}.mp4`)];
2588
2694
  }
2589
2695
  outArgs = outArgs.map(
2590
2696
  (a, i) => outArgs[i - 1] === "--overlay" || outArgs[i - 1] === "-o" ? userPath(a) : a
@@ -2599,7 +2705,7 @@ ${USAGE}`);
2599
2705
 
2600
2706
  ${USAGE}`);
2601
2707
  const inputPath = userPath(input);
2602
- if (!existsSync4(inputPath)) fail(`no such file: ${inputPath}`);
2708
+ if (!existsSync5(inputPath)) fail(`no such file: ${inputPath}`);
2603
2709
  process.exit(
2604
2710
  await (PACKAGED ? run(process.execPath, [LABELS, inputPath]) : run("npx", ["tsx", LABELS, inputPath]))
2605
2711
  );
@@ -2610,10 +2716,10 @@ ${USAGE}`);
2610
2716
 
2611
2717
  ${USAGE}`);
2612
2718
  const inputPath = userPath(input);
2613
- if (!existsSync4(inputPath)) fail(`no such file: ${inputPath}`);
2719
+ if (!existsSync5(inputPath)) fail(`no such file: ${inputPath}`);
2614
2720
  const oIdx = rest.indexOf("-o");
2615
- const outBase = PACKAGED ? join6(USER_CWD, "out") : join6(ROOT2, "out");
2616
- const outPath = oIdx >= 0 && rest[oIdx + 1] ? userPath(rest[oIdx + 1]) : join6(outBase, `${basename(input).replace(/\.[^.]+$/, "")}.html`);
2721
+ const outBase = PACKAGED ? join7(USER_CWD, "out") : join7(ROOT2, "out");
2722
+ const outPath = oIdx >= 0 && rest[oIdx + 1] ? userPath(rest[oIdx + 1]) : join7(outBase, `${basename(input).replace(/\.[^.]+$/, "")}.html`);
2617
2723
  await mkdir4(dirname7(outPath), { recursive: true });
2618
2724
  process.exit(
2619
2725
  await (PACKAGED ? run(process.execPath, [PLAYER, inputPath, outPath]) : run("npx", ["tsx", PLAYER, inputPath, outPath]))
@@ -2633,7 +2739,7 @@ ${USAGE}`);
2633
2739
  fail(`usage: ${CMD} logo <logo.svg | brand-slug> ["Display Name"] [--motion <preset>] [--energy 0..1] [--speed n] [--intensity 0..1] [--from left|right|top|bottom] [--seed n] [-o out.mp4]`);
2634
2740
  }
2635
2741
  preflightFfmpeg();
2636
- const { tmpdir: tmpdir4 } = await import("node:os");
2742
+ const { tmpdir: tmpdir5 } = await import("node:os");
2637
2743
  const { resolveLogo: resolveLogo2, buildLogoSting: buildLogoSting2 } = await Promise.resolve().then(() => (init_logoSting(), logoSting_exports));
2638
2744
  const num = (k) => flags[k] !== void 0 ? Number(flags[k]) : void 0;
2639
2745
  console.log(`loading logo: ${arg} \u2026`);
@@ -2646,10 +2752,10 @@ ${USAGE}`);
2646
2752
  seed: num("seed")
2647
2753
  });
2648
2754
  const sceneIR = buildLogoSting2(data);
2649
- const tmp = join6(tmpdir4(), `reframe-logo-${slug}-${process.pid}.json`);
2755
+ const tmp = join7(tmpdir5(), `reframe-logo-${slug}-${process.pid}.json`);
2650
2756
  await writeFile5(tmp, JSON.stringify(sceneIR));
2651
- const outBase = PACKAGED ? join6(USER_CWD, "out") : join6(ROOT2, "out");
2652
- const out = flags.o ? userPath(flags.o) : join6(outBase, `logo-${slug}.mp4`);
2757
+ const outBase = PACKAGED ? join7(USER_CWD, "out") : join7(ROOT2, "out");
2758
+ const out = flags.o ? userPath(flags.o) : join7(outBase, `logo-${slug}.mp4`);
2653
2759
  await mkdir4(dirname7(out), { recursive: true });
2654
2760
  console.log(`rendering ${data.name} (${data.paths.length} path${data.paths.length > 1 ? "s" : ""}, motion: ${data.motion ?? "reveal-orbit"}) \u2192 ${out}`);
2655
2761
  process.exit(
@@ -2661,9 +2767,9 @@ ${USAGE}`);
2661
2767
  if (!sceneArg || !dataArg) fail(`usage: ${CMD} batch <scene.ts> <data.json|csv> [...]`);
2662
2768
  const scenePath = userPath(sceneArg);
2663
2769
  const dataPath = userPath(dataArg);
2664
- for (const p of [scenePath, dataPath]) if (!existsSync4(p)) fail(`no such file: ${p}`);
2770
+ for (const p of [scenePath, dataPath]) if (!existsSync5(p)) fail(`no such file: ${p}`);
2665
2771
  preflightFfmpeg();
2666
- let outDir = PACKAGED ? join6(USER_CWD, "out", "batch") : join6(ROOT2, "out", "batch");
2772
+ let outDir = PACKAGED ? join7(USER_CWD, "out", "batch") : join7(ROOT2, "out", "batch");
2667
2773
  let concurrency = 3;
2668
2774
  let fps;
2669
2775
  const baseOverlayPaths = [];
@@ -2676,10 +2782,10 @@ ${USAGE}`);
2676
2782
  }
2677
2783
  const { loadRows: loadRows2, runBatch: runBatch2 } = await Promise.resolve().then(() => (init_batch(), batch_exports));
2678
2784
  const { loadScene: loadScene2 } = await Promise.resolve().then(() => (init_loadScene(), loadScene_exports));
2679
- const { readFile: readFile6 } = await import("node:fs/promises");
2785
+ const { readFile: readFile7 } = await import("node:fs/promises");
2680
2786
  const scene2 = await loadScene2(scenePath);
2681
2787
  const baseOverlays = await Promise.all(
2682
- baseOverlayPaths.map(async (p) => JSON.parse(await readFile6(p, "utf8")))
2788
+ baseOverlayPaths.map(async (p) => JSON.parse(await readFile7(p, "utf8")))
2683
2789
  );
2684
2790
  const rows = await loadRows2(dataPath);
2685
2791
  if (rows.length === 0) fail(`${dataPath}: no data rows`);
@@ -2702,7 +2808,7 @@ ${USAGE}`);
2702
2808
  const orphaned = results.filter((r) => !r.error && r.orphans.length > 0).length;
2703
2809
  console.log(
2704
2810
  `
2705
- ${results.length - failed} rendered (${orphaned} with orphans), ${failed} failed \u2014 report: ${join6(outDir, "batch-report.json")}`
2811
+ ${results.length - failed} rendered (${orphaned} with orphans), ${failed} failed \u2014 report: ${join7(outDir, "batch-report.json")}`
2706
2812
  );
2707
2813
  process.exit(failed > 0 ? 1 : 0);
2708
2814
  }
@@ -2713,9 +2819,9 @@ ${results.length - failed} rendered (${orphaned} with orphans), ${failed} failed
2713
2819
  if (PACKAGED) {
2714
2820
  const { createRequire } = await import("node:module");
2715
2821
  const vitePkg = createRequire(import.meta.url).resolve("vite/package.json");
2716
- const viteBin = join6(dirname7(vitePkg), "bin", "vite.js");
2822
+ const viteBin = join7(dirname7(vitePkg), "bin", "vite.js");
2717
2823
  process.exit(
2718
- await run(process.execPath, [viteBin, join6(ROOT2, "preview")], {
2824
+ await run(process.execPath, [viteBin, join7(ROOT2, "preview")], {
2719
2825
  env: { REFRAME_SCENE_DIR: USER_CWD }
2720
2826
  })
2721
2827
  );
@@ -2733,10 +2839,10 @@ ${results.length - failed} rendered (${orphaned} with orphans), ${failed} failed
2733
2839
  fail(`scene name must be kebab-case (a-z, 0-9, -): got "${name}"`);
2734
2840
  }
2735
2841
  const inRepo = USER_CWD === ROOT2 || USER_CWD.startsWith(ROOT2 + "/");
2736
- const targetDir = inRepo ? join6(ROOT2, "examples", "scenes") : USER_CWD;
2737
- const target = join6(targetDir, `${name}.ts`);
2842
+ const targetDir = inRepo ? join7(ROOT2, "examples", "scenes") : USER_CWD;
2843
+ const target = join7(targetDir, `${name}.ts`);
2738
2844
  const shown = inRepo ? `examples/scenes/${name}.ts` : `${name}.ts`;
2739
- if (existsSync4(target)) fail(`${shown} already exists`);
2845
+ if (existsSync5(target)) fail(`${shown} already exists`);
2740
2846
  const id = name.split("-")[0] ?? name;
2741
2847
  await writeFile5(target, SCENE_TEMPLATE(name, id));
2742
2848
  console.log(`created ${shown}
@@ -2765,9 +2871,9 @@ ${results.length - failed} rendered (${orphaned} with orphans), ${failed} failed
2765
2871
  );
2766
2872
  }
2767
2873
  case "guide": {
2768
- const file = rest.includes("--regen") ? PACKAGED ? join6(ROOT2, "guides", "regen-contract.md") : join6(ROOT2, "docs", "regen-contract.md") : PACKAGED ? join6(ROOT2, "guides", "edsl-guide.md") : join6(ROOT2, "benchmark", "guides", "edsl-guide.md");
2769
- const { readFile: readFile6 } = await import("node:fs/promises");
2770
- process.stdout.write(await readFile6(file, "utf8"));
2874
+ const file = rest.includes("--regen") ? PACKAGED ? join7(ROOT2, "guides", "regen-contract.md") : join7(ROOT2, "docs", "regen-contract.md") : PACKAGED ? join7(ROOT2, "guides", "edsl-guide.md") : join7(ROOT2, "benchmark", "guides", "edsl-guide.md");
2875
+ const { readFile: readFile7 } = await import("node:fs/promises");
2876
+ process.stdout.write(await readFile7(file, "utf8"));
2771
2877
  return;
2772
2878
  }
2773
2879
  case "demo":
@@ -2778,7 +2884,7 @@ ${results.length - failed} rendered (${orphaned} with orphans), ${failed} failed
2778
2884
  }
2779
2885
  preflightFfmpeg();
2780
2886
  process.exit(
2781
- await run("npx", ["tsx", join6(ROOT2, "examples", "scripts", "demo-edit-survival.ts")])
2887
+ await run("npx", ["tsx", join7(ROOT2, "examples", "scripts", "demo-edit-survival.ts")])
2782
2888
  );
2783
2889
  default:
2784
2890
  console.log(USAGE);