hyperframes 0.4.24 → 0.5.0-alpha.2

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/cli.js CHANGED
@@ -54,7 +54,7 @@ var VERSION;
54
54
  var init_version = __esm({
55
55
  "src/version.ts"() {
56
56
  "use strict";
57
- VERSION = true ? "0.4.24" : "0.0.0-dev";
57
+ VERSION = true ? "0.5.0-alpha.2" : "0.0.0-dev";
58
58
  }
59
59
  });
60
60
 
@@ -5994,6 +5994,18 @@ function rewriteAssetPaths(elements, compSrcPath, getAttr2, setAttr) {
5994
5994
  }
5995
5995
  }
5996
5996
  }
5997
+ function rewriteInlineStyleAssetUrls(elements, compSrcPath, getStyle, setStyle) {
5998
+ const compDir = dirname(compSrcPath);
5999
+ if (!compDir || compDir === ".") return;
6000
+ for (const el of elements) {
6001
+ const style = getStyle(el);
6002
+ if (!style) continue;
6003
+ const rewritten = rewriteCssAssetUrls(style, compSrcPath);
6004
+ if (rewritten !== style) {
6005
+ setStyle(el, rewritten);
6006
+ }
6007
+ }
6008
+ }
5997
6009
  function rewriteCssAssetUrls(cssText, compSrcPath) {
5998
6010
  if (!cssText) return cssText;
5999
6011
  return cssText.replace(CSS_URL_RE, (full, quote, rawUrl) => {
@@ -24416,6 +24428,14 @@ function buildSubCompositionHtml(projectDir, compPath, runtimeUrl, baseHref) {
24416
24428
  el.setAttribute(attr, value);
24417
24429
  }
24418
24430
  );
24431
+ rewriteInlineStyleAssetUrls(
24432
+ contentDoc.querySelectorAll("[style]"),
24433
+ compPath,
24434
+ (el) => el.getAttribute("style"),
24435
+ (el, value) => {
24436
+ el.setAttribute("style", value);
24437
+ }
24438
+ );
24419
24439
  for (const styleEl of contentDoc.querySelectorAll("style")) {
24420
24440
  styleEl.textContent = rewriteCssAssetUrls(styleEl.textContent || "", compPath);
24421
24441
  }
@@ -24810,7 +24830,7 @@ var init_render = __esm({
24810
24830
  });
24811
24831
 
24812
24832
  // ../core/src/studio-api/routes/thumbnail.ts
24813
- import { existsSync as existsSync13, readFileSync as readFileSync14, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
24833
+ import { existsSync as existsSync13, readFileSync as readFileSync14, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, statSync as statSync4 } from "fs";
24814
24834
  import { join as join16 } from "path";
24815
24835
  function registerThumbnailRoutes(api, adapter2) {
24816
24836
  api.get("/projects/:id/thumbnail/*", async (c2) => {
@@ -24828,11 +24848,14 @@ function registerThumbnailRoutes(api, adapter2) {
24828
24848
  const vpWidth = parseInt(url.searchParams.get("w") || "0") || 0;
24829
24849
  const vpHeight = parseInt(url.searchParams.get("h") || "0") || 0;
24830
24850
  const selector = url.searchParams.get("selector") || void 0;
24851
+ const urlVersion = url.searchParams.get("v") || "";
24831
24852
  let compW = vpWidth || 1920;
24832
24853
  let compH = vpHeight || 1080;
24854
+ let sourceMtime = 0;
24833
24855
  if (!vpWidth) {
24834
24856
  const htmlFile = join16(project.dir, compPath);
24835
24857
  if (existsSync13(htmlFile)) {
24858
+ sourceMtime = Math.round(statSync4(htmlFile).mtimeMs);
24836
24859
  const html = readFileSync14(htmlFile, "utf-8");
24837
24860
  const wMatch = html.match(/data-width=["'](\d+)["']/);
24838
24861
  const hMatch = html.match(/data-height=["'](\d+)["']/);
@@ -24843,7 +24866,8 @@ function registerThumbnailRoutes(api, adapter2) {
24843
24866
  const previewUrl = compPath === "index.html" ? `http://${c2.req.header("host")}/api/projects/${project.id}/preview` : `http://${c2.req.header("host")}/api/projects/${project.id}/preview/comp/${compPath}`;
24844
24867
  const cacheDir = join16(project.dir, ".thumbnails");
24845
24868
  const selectorKey = selector ? `_${selector.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 80)}` : "";
24846
- const cacheKey = `${THUMBNAIL_CACHE_VERSION}_${compPath.replace(/\//g, "_")}_${seekTime.toFixed(2)}${selectorKey}.jpg`;
24869
+ const urlVersionKey = urlVersion ? `_${urlVersion.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32)}` : "";
24870
+ const cacheKey = `${THUMBNAIL_CACHE_VERSION}${urlVersionKey}_${compPath.replace(/\//g, "_")}_${compW}x${compH}_${sourceMtime}_${seekTime.toFixed(2)}${selectorKey}.jpg`;
24847
24871
  const cachePath2 = join16(cacheDir, cacheKey);
24848
24872
  if (existsSync13(cachePath2)) {
24849
24873
  return new Response(new Uint8Array(readFileSync14(cachePath2)), {
@@ -24878,7 +24902,219 @@ var THUMBNAIL_CACHE_VERSION;
24878
24902
  var init_thumbnail = __esm({
24879
24903
  "../core/src/studio-api/routes/thumbnail.ts"() {
24880
24904
  "use strict";
24881
- THUMBNAIL_CACHE_VERSION = "v2";
24905
+ THUMBNAIL_CACHE_VERSION = "v3";
24906
+ }
24907
+ });
24908
+
24909
+ // ../core/src/studio-api/routes/fonts.ts
24910
+ import { execFileSync as execFileSync4 } from "child_process";
24911
+ import { existsSync as existsSync14, readdirSync as readdirSync6, statSync as statSync5 } from "fs";
24912
+ import { homedir as homedir4, platform as platform3 } from "os";
24913
+ import { join as join17 } from "path";
24914
+ function isRecord(value) {
24915
+ return typeof value === "object" && value !== null;
24916
+ }
24917
+ function fontDirectories() {
24918
+ const home = homedir4();
24919
+ if (platform3() === "darwin") {
24920
+ return [
24921
+ join17(home, "Library", "Fonts"),
24922
+ "/Library/Fonts",
24923
+ "/System/Library/Fonts",
24924
+ "/System/Library/Fonts/Supplemental"
24925
+ ];
24926
+ }
24927
+ if (platform3() === "win32") {
24928
+ return [join17(process.env.WINDIR || "C:\\Windows", "Fonts")];
24929
+ }
24930
+ return [
24931
+ join17(home, ".fonts"),
24932
+ join17(home, ".local", "share", "fonts"),
24933
+ "/usr/local/share/fonts",
24934
+ "/usr/share/fonts"
24935
+ ];
24936
+ }
24937
+ function toFamilyName(fileName) {
24938
+ const withoutExt = fileName.replace(FONT_EXT_RE, "");
24939
+ if (!withoutExt || withoutExt.startsWith(".")) return null;
24940
+ const spaced = withoutExt.replace(/[_-]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/\s+/g, " ").trim();
24941
+ const words = spaced.split(" ").filter(Boolean);
24942
+ while (words.length > 1 && STYLE_SUFFIXES.has((words.at(-1) ?? "").toLowerCase())) {
24943
+ words.pop();
24944
+ }
24945
+ const family = words.join(" ").trim();
24946
+ return family.length >= 2 ? family : null;
24947
+ }
24948
+ function collectMacSystemProfilerFonts() {
24949
+ if (platform3() !== "darwin") return [];
24950
+ let parsed;
24951
+ try {
24952
+ const raw = execFileSync4("system_profiler", ["SPFontsDataType", "-json"], {
24953
+ encoding: "utf8",
24954
+ maxBuffer: 12 * 1024 * 1024,
24955
+ timeout: 5e3
24956
+ });
24957
+ parsed = JSON.parse(raw);
24958
+ } catch {
24959
+ return [];
24960
+ }
24961
+ if (!isRecord(parsed) || !Array.isArray(parsed.SPFontsDataType)) return [];
24962
+ const fonts = [];
24963
+ for (const fontEntry of parsed.SPFontsDataType) {
24964
+ if (!isRecord(fontEntry)) continue;
24965
+ const typefaces = fontEntry.typefaces;
24966
+ if (!Array.isArray(typefaces)) continue;
24967
+ for (const typeface of typefaces) {
24968
+ if (!isRecord(typeface)) continue;
24969
+ const family = typeface.family;
24970
+ const fullName = typeface.fullname;
24971
+ const name = typeface._name;
24972
+ if (typeof family === "string" && family.trim()) {
24973
+ fonts.push(family.trim());
24974
+ } else if (typeof fullName === "string" && fullName.trim()) {
24975
+ fonts.push(fullName.trim());
24976
+ } else if (typeof name === "string" && name.trim()) {
24977
+ fonts.push(name.trim());
24978
+ }
24979
+ }
24980
+ }
24981
+ return fonts;
24982
+ }
24983
+ function collectFontsFromDir(dir, depth = 0) {
24984
+ if (!existsSync14(dir) || depth > 2) return [];
24985
+ const fonts = [];
24986
+ for (const entry of readdirSync6(dir, { withFileTypes: true })) {
24987
+ const fullPath = join17(dir, entry.name);
24988
+ if (entry.isDirectory()) {
24989
+ fonts.push(...collectFontsFromDir(fullPath, depth + 1));
24990
+ continue;
24991
+ }
24992
+ if (!entry.isFile() || !FONT_EXT_RE.test(entry.name)) continue;
24993
+ try {
24994
+ if (!statSync5(fullPath).isFile()) continue;
24995
+ } catch {
24996
+ continue;
24997
+ }
24998
+ const family = toFamilyName(entry.name);
24999
+ if (family) fonts.push(family);
25000
+ }
25001
+ return fonts;
25002
+ }
25003
+ function listInstalledFontFamilies() {
25004
+ if (cachedFonts) return cachedFonts;
25005
+ const families = /* @__PURE__ */ new Set();
25006
+ for (const family of collectMacSystemProfilerFonts()) {
25007
+ families.add(family);
25008
+ if (families.size >= MAX_FONT_RESULTS) break;
25009
+ }
25010
+ for (const dir of fontDirectories()) {
25011
+ for (const family of collectFontsFromDir(dir)) {
25012
+ families.add(family);
25013
+ if (families.size >= MAX_FONT_RESULTS) break;
25014
+ }
25015
+ if (families.size >= MAX_FONT_RESULTS) break;
25016
+ }
25017
+ cachedFonts = Array.from(families).sort((a, b) => a.localeCompare(b));
25018
+ return cachedFonts;
25019
+ }
25020
+ function parseGoogleFontMetadata(value) {
25021
+ if (!isRecord(value) || !Array.isArray(value.familyMetadataList)) return [];
25022
+ const families = [];
25023
+ for (const entry of value.familyMetadataList) {
25024
+ if (!isRecord(entry) || typeof entry.family !== "string") continue;
25025
+ families.push(entry.family);
25026
+ }
25027
+ return families;
25028
+ }
25029
+ function stripGoogleJsonGuard(raw) {
25030
+ const prefix = ")]}'";
25031
+ if (!raw.startsWith(prefix)) return raw;
25032
+ let index = prefix.length;
25033
+ while (index < raw.length && (raw[index] === " " || raw[index] === "\n" || raw[index] === "\r" || raw[index] === " " || raw[index] === "\f")) {
25034
+ index += 1;
25035
+ }
25036
+ return raw.slice(index);
25037
+ }
25038
+ async function listGoogleFontFamilies() {
25039
+ if (cachedGoogleFonts) return cachedGoogleFonts;
25040
+ const controller = new AbortController();
25041
+ const timer = setTimeout(() => controller.abort(), GOOGLE_FONTS_FETCH_TIMEOUT_MS);
25042
+ try {
25043
+ const response = await fetch(GOOGLE_FONTS_METADATA_URL, { signal: controller.signal });
25044
+ if (!response.ok) {
25045
+ cachedGoogleFonts = GOOGLE_FONT_FALLBACKS;
25046
+ return cachedGoogleFonts;
25047
+ }
25048
+ const raw = await response.text();
25049
+ const jsonText = stripGoogleJsonGuard(raw);
25050
+ const families = parseGoogleFontMetadata(JSON.parse(jsonText));
25051
+ cachedGoogleFonts = families.length > 0 ? families : GOOGLE_FONT_FALLBACKS;
25052
+ } catch {
25053
+ cachedGoogleFonts = GOOGLE_FONT_FALLBACKS;
25054
+ } finally {
25055
+ clearTimeout(timer);
25056
+ }
25057
+ return cachedGoogleFonts;
25058
+ }
25059
+ function registerFontRoutes(api) {
25060
+ api.get("/fonts", (c2) => c2.json({ fonts: listInstalledFontFamilies() }));
25061
+ api.get("/fonts/google", async (c2) => c2.json({ fonts: await listGoogleFontFamilies() }));
25062
+ }
25063
+ var FONT_EXT_RE, MAX_FONT_RESULTS, GOOGLE_FONTS_METADATA_URL, GOOGLE_FONTS_FETCH_TIMEOUT_MS, cachedFonts, cachedGoogleFonts, STYLE_SUFFIXES, GOOGLE_FONT_FALLBACKS;
25064
+ var init_fonts = __esm({
25065
+ "../core/src/studio-api/routes/fonts.ts"() {
25066
+ "use strict";
25067
+ FONT_EXT_RE = /\.(otf|ttf|ttc|woff2?)$/i;
25068
+ MAX_FONT_RESULTS = 2e3;
25069
+ GOOGLE_FONTS_METADATA_URL = "https://fonts.google.com/metadata/fonts";
25070
+ GOOGLE_FONTS_FETCH_TIMEOUT_MS = 3e3;
25071
+ cachedFonts = null;
25072
+ cachedGoogleFonts = null;
25073
+ STYLE_SUFFIXES = /* @__PURE__ */ new Set([
25074
+ "black",
25075
+ "bold",
25076
+ "book",
25077
+ "condensed",
25078
+ "demi",
25079
+ "demibold",
25080
+ "display",
25081
+ "extra",
25082
+ "extrabold",
25083
+ "hairline",
25084
+ "heavy",
25085
+ "italic",
25086
+ "light",
25087
+ "medium",
25088
+ "normal",
25089
+ "regular",
25090
+ "roman",
25091
+ "semibold",
25092
+ "thin",
25093
+ "ultra",
25094
+ "ultralight"
25095
+ ]);
25096
+ GOOGLE_FONT_FALLBACKS = [
25097
+ "Inter",
25098
+ "Roboto",
25099
+ "Open Sans",
25100
+ "Montserrat",
25101
+ "Poppins",
25102
+ "Lato",
25103
+ "Oswald",
25104
+ "Raleway",
25105
+ "Nunito",
25106
+ "Playfair Display",
25107
+ "Merriweather",
25108
+ "Source Sans 3",
25109
+ "Source Serif 4",
25110
+ "Source Code Pro",
25111
+ "DM Sans",
25112
+ "Space Grotesk",
25113
+ "Space Mono",
25114
+ "Bebas Neue",
25115
+ "Outfit",
25116
+ "JetBrains Mono"
25117
+ ];
24882
25118
  }
24883
25119
  });
24884
25120
 
@@ -24892,6 +25128,7 @@ function createStudioApi(adapter2) {
24892
25128
  registerLintRoutes(api, adapter2);
24893
25129
  registerRenderRoutes(api, adapter2);
24894
25130
  registerThumbnailRoutes(api, adapter2);
25131
+ registerFontRoutes(api);
24895
25132
  return api;
24896
25133
  }
24897
25134
  var init_createStudioApi = __esm({
@@ -24903,6 +25140,7 @@ var init_createStudioApi = __esm({
24903
25140
  init_lint2();
24904
25141
  init_render();
24905
25142
  init_thumbnail();
25143
+ init_fonts();
24906
25144
  }
24907
25145
  });
24908
25146
 
@@ -24937,9 +25175,9 @@ __export(manager_exports2, {
24937
25175
  setBrowserPath: () => setBrowserPath
24938
25176
  });
24939
25177
  import { execSync } from "child_process";
24940
- import { existsSync as existsSync14, rmSync as rmSync4 } from "fs";
24941
- import { homedir as homedir4 } from "os";
24942
- import { join as join17 } from "path";
25178
+ import { existsSync as existsSync15, rmSync as rmSync4 } from "fs";
25179
+ import { homedir as homedir5 } from "os";
25180
+ import { join as join18 } from "path";
24943
25181
  import { Browser, detectBrowserPlatform, getInstalledBrowsers, install } from "@puppeteer/browsers";
24944
25182
  function setBrowserPath(path2) {
24945
25183
  _browserPathOverride = path2;
@@ -24959,17 +25197,17 @@ function whichBinary2(name) {
24959
25197
  }
24960
25198
  }
24961
25199
  function findFromEnv2() {
24962
- if (_browserPathOverride && existsSync14(_browserPathOverride)) {
25200
+ if (_browserPathOverride && existsSync15(_browserPathOverride)) {
24963
25201
  return { executablePath: _browserPathOverride, source: "env" };
24964
25202
  }
24965
25203
  const envPath = process.env["HYPERFRAMES_BROWSER_PATH"];
24966
- if (envPath && existsSync14(envPath)) {
25204
+ if (envPath && existsSync15(envPath)) {
24967
25205
  return { executablePath: envPath, source: "env" };
24968
25206
  }
24969
25207
  return void 0;
24970
25208
  }
24971
25209
  async function findFromCache() {
24972
- if (!existsSync14(CACHE_DIR2)) {
25210
+ if (!existsSync15(CACHE_DIR2)) {
24973
25211
  return void 0;
24974
25212
  }
24975
25213
  const installed = await getInstalledBrowsers({ cacheDir: CACHE_DIR2 });
@@ -24981,7 +25219,7 @@ async function findFromCache() {
24981
25219
  }
24982
25220
  function findFromSystem2() {
24983
25221
  for (const p of SYSTEM_CHROME_PATHS) {
24984
- if (existsSync14(p)) {
25222
+ if (existsSync15(p)) {
24985
25223
  return { executablePath: p, source: "system" };
24986
25224
  }
24987
25225
  }
@@ -25001,21 +25239,21 @@ async function findBrowser() {
25001
25239
  async function ensureBrowser(options) {
25002
25240
  const existing = await findBrowser();
25003
25241
  if (existing) return existing;
25004
- const platform5 = detectBrowserPlatform();
25005
- if (!platform5) {
25242
+ const platform6 = detectBrowserPlatform();
25243
+ if (!platform6) {
25006
25244
  throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`);
25007
25245
  }
25008
25246
  const installed = await install({
25009
25247
  cacheDir: CACHE_DIR2,
25010
25248
  browser: Browser.CHROMEHEADLESSSHELL,
25011
25249
  buildId: CHROME_VERSION,
25012
- platform: platform5,
25250
+ platform: platform6,
25013
25251
  downloadProgressCallback: options?.onProgress
25014
25252
  });
25015
25253
  return { executablePath: installed.executablePath, source: "download" };
25016
25254
  }
25017
25255
  function clearBrowser() {
25018
- if (!existsSync14(CACHE_DIR2)) {
25256
+ if (!existsSync15(CACHE_DIR2)) {
25019
25257
  return false;
25020
25258
  }
25021
25259
  rmSync4(CACHE_DIR2, { recursive: true, force: true });
@@ -25026,7 +25264,7 @@ var init_manager2 = __esm({
25026
25264
  "src/browser/manager.ts"() {
25027
25265
  "use strict";
25028
25266
  CHROME_VERSION = "131.0.6778.85";
25029
- CACHE_DIR2 = join17(homedir4(), ".cache", "hyperframes", "chrome");
25267
+ CACHE_DIR2 = join18(homedir5(), ".cache", "hyperframes", "chrome");
25030
25268
  SYSTEM_CHROME_PATHS = process.platform === "darwin" ? ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"] : [
25031
25269
  "/usr/bin/google-chrome",
25032
25270
  "/usr/bin/google-chrome-stable",
@@ -25153,9 +25391,9 @@ var init_config2 = __esm({
25153
25391
  });
25154
25392
 
25155
25393
  // ../engine/src/services/browserManager.ts
25156
- import { existsSync as existsSync15, readdirSync as readdirSync6 } from "fs";
25157
- import { join as join18 } from "path";
25158
- import { homedir as homedir5 } from "os";
25394
+ import { existsSync as existsSync16, readdirSync as readdirSync7 } from "fs";
25395
+ import { join as join19 } from "path";
25396
+ import { homedir as homedir6 } from "os";
25159
25397
  async function getPuppeteer() {
25160
25398
  if (_puppeteer) return _puppeteer;
25161
25399
  try {
@@ -25175,19 +25413,19 @@ function resolveHeadlessShellPath(config) {
25175
25413
  if (process.env.PRODUCER_HEADLESS_SHELL_PATH) {
25176
25414
  return process.env.PRODUCER_HEADLESS_SHELL_PATH;
25177
25415
  }
25178
- const baseDir = join18(homedir5(), ".cache", "puppeteer", "chrome-headless-shell");
25179
- if (!existsSync15(baseDir)) return void 0;
25416
+ const baseDir = join19(homedir6(), ".cache", "puppeteer", "chrome-headless-shell");
25417
+ if (!existsSync16(baseDir)) return void 0;
25180
25418
  try {
25181
- const versions = readdirSync6(baseDir).sort().reverse();
25419
+ const versions = readdirSync7(baseDir).sort().reverse();
25182
25420
  for (const version of versions) {
25183
25421
  const candidates = [
25184
- join18(baseDir, version, "chrome-headless-shell-linux64", "chrome-headless-shell"),
25185
- join18(baseDir, version, "chrome-headless-shell-mac-arm64", "chrome-headless-shell"),
25186
- join18(baseDir, version, "chrome-headless-shell-mac-x64", "chrome-headless-shell"),
25187
- join18(baseDir, version, "chrome-headless-shell-win64", "chrome-headless-shell.exe")
25422
+ join19(baseDir, version, "chrome-headless-shell-linux64", "chrome-headless-shell"),
25423
+ join19(baseDir, version, "chrome-headless-shell-mac-arm64", "chrome-headless-shell"),
25424
+ join19(baseDir, version, "chrome-headless-shell-mac-x64", "chrome-headless-shell"),
25425
+ join19(baseDir, version, "chrome-headless-shell-win64", "chrome-headless-shell.exe")
25188
25426
  ];
25189
25427
  for (const binary of candidates) {
25190
- if (existsSync15(binary)) return binary;
25428
+ if (existsSync16(binary)) return binary;
25191
25429
  }
25192
25430
  }
25193
25431
  } catch {
@@ -25650,10 +25888,10 @@ var init_screenshotService = __esm({
25650
25888
  });
25651
25889
 
25652
25890
  // ../engine/src/services/frameCapture.ts
25653
- import { existsSync as existsSync16, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
25654
- import { join as join19 } from "path";
25891
+ import { existsSync as existsSync17, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
25892
+ import { join as join20 } from "path";
25655
25893
  async function createCaptureSession(serverUrl, outputDir, options, onBeforeCapture = null, config) {
25656
- if (!existsSync16(outputDir)) mkdirSync8(outputDir, { recursive: true });
25894
+ if (!existsSync17(outputDir)) mkdirSync8(outputDir, { recursive: true });
25657
25895
  const headlessShell = resolveHeadlessShellPath(config);
25658
25896
  const isLinux = process.platform === "linux";
25659
25897
  const forceScreenshot = config?.forceScreenshot ?? DEFAULT_CONFIG2.forceScreenshot;
@@ -25857,9 +26095,9 @@ async function initializeSession(session) {
25857
26095
  }
25858
26096
  async function captureFrameErrorDiagnostics(session, frameIndex, time, error) {
25859
26097
  try {
25860
- const diagnosticsDir = join19(session.outputDir, "diagnostics");
25861
- if (!existsSync16(diagnosticsDir)) mkdirSync8(diagnosticsDir, { recursive: true });
25862
- const base = join19(diagnosticsDir, `frame-error-${frameIndex}`);
26098
+ const diagnosticsDir = join20(session.outputDir, "diagnostics");
26099
+ if (!existsSync17(diagnosticsDir)) mkdirSync8(diagnosticsDir, { recursive: true });
26100
+ const base = join20(diagnosticsDir, `frame-error-${frameIndex}`);
25863
26101
  await session.page.screenshot({ path: `${base}.png`, type: "png", fullPage: true });
25864
26102
  const html = await session.page.content();
25865
26103
  writeFileSync8(`${base}.html`, html, "utf-8");
@@ -25957,7 +26195,7 @@ async function captureFrame(session, frameIndex, time) {
25957
26195
  );
25958
26196
  const ext = options.format === "png" ? "png" : "jpg";
25959
26197
  const frameName = `frame_${String(frameIndex).padStart(6, "0")}.${ext}`;
25960
- const framePath = join19(outputDir, frameName);
26198
+ const framePath = join20(outputDir, frameName);
25961
26199
  writeFileSync8(framePath, buffer);
25962
26200
  return { frameIndex, time: quantizedTime, path: framePath, captureTimeMs };
25963
26201
  }
@@ -25978,7 +26216,7 @@ async function closeCaptureSession(session) {
25978
26216
  session.isInitialized = false;
25979
26217
  }
25980
26218
  function prepareCaptureSessionForReuse(session, outputDir, onBeforeCapture) {
25981
- if (!existsSync16(outputDir)) {
26219
+ if (!existsSync17(outputDir)) {
25982
26220
  mkdirSync8(outputDir, { recursive: true });
25983
26221
  }
25984
26222
  session.outputDir = outputDir;
@@ -26216,8 +26454,8 @@ var init_runFfmpeg = __esm({
26216
26454
 
26217
26455
  // ../engine/src/services/chunkEncoder.ts
26218
26456
  import { spawn as spawn4 } from "child_process";
26219
- import { copyFileSync, existsSync as existsSync17, mkdirSync as mkdirSync9, readdirSync as readdirSync7, statSync as statSync4, writeFileSync as writeFileSync9 } from "fs";
26220
- import { join as join20, dirname as dirname6 } from "path";
26457
+ import { copyFileSync, existsSync as existsSync18, mkdirSync as mkdirSync9, readdirSync as readdirSync8, statSync as statSync6, writeFileSync as writeFileSync9 } from "fs";
26458
+ import { join as join21, dirname as dirname6 } from "path";
26221
26459
  function getEncoderPreset(quality, format = "mp4", hdr) {
26222
26460
  const base = ENCODER_PRESETS[quality];
26223
26461
  if (format === "webm") {
@@ -26368,8 +26606,8 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
26368
26606
  async function encodeFramesFromDir(framesDir, framePattern, outputPath, options, signal, config) {
26369
26607
  const startTime = Date.now();
26370
26608
  const outputDir = dirname6(outputPath);
26371
- if (!existsSync17(outputDir)) mkdirSync9(outputDir, { recursive: true });
26372
- const files = readdirSync7(framesDir).filter((f3) => f3.match(/\.(jpg|jpeg|png)$/i));
26609
+ if (!existsSync18(outputDir)) mkdirSync9(outputDir, { recursive: true });
26610
+ const files = readdirSync8(framesDir).filter((f3) => f3.match(/\.(jpg|jpeg|png)$/i));
26373
26611
  const frameCount = files.length;
26374
26612
  if (frameCount === 0) {
26375
26613
  return {
@@ -26385,7 +26623,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
26385
26623
  if (options.useGpu) {
26386
26624
  gpuEncoder = await getCachedGpuEncoder();
26387
26625
  }
26388
- const inputPath = join20(framesDir, framePattern);
26626
+ const inputPath = join21(framesDir, framePattern);
26389
26627
  const inputArgs = ["-framerate", String(options.fps), "-i", inputPath];
26390
26628
  const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
26391
26629
  return new Promise((resolve39) => {
@@ -26434,7 +26672,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
26434
26672
  });
26435
26673
  return;
26436
26674
  }
26437
- const fileSize = existsSync17(outputPath) ? statSync4(outputPath).size : 0;
26675
+ const fileSize = existsSync18(outputPath) ? statSync6(outputPath).size : 0;
26438
26676
  resolve39({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
26439
26677
  });
26440
26678
  ffmpeg.on("error", (err) => {
@@ -26453,7 +26691,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
26453
26691
  }
26454
26692
  async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, options, chunkSizeFrames, signal) {
26455
26693
  const start = Date.now();
26456
- const files = readdirSync7(framesDir).filter((f3) => f3.match(/\.(jpg|jpeg|png)$/i)).sort();
26694
+ const files = readdirSync8(framesDir).filter((f3) => f3.match(/\.(jpg|jpeg|png)$/i)).sort();
26457
26695
  if (files.length === 0) {
26458
26696
  return {
26459
26697
  success: false,
@@ -26466,8 +26704,8 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26466
26704
  }
26467
26705
  const chunkSize = Math.max(30, Math.floor(chunkSizeFrames));
26468
26706
  const chunkCount = Math.ceil(files.length / chunkSize);
26469
- const chunkDir = join20(dirname6(outputPath), "chunk-encode");
26470
- if (!existsSync17(chunkDir)) mkdirSync9(chunkDir, { recursive: true });
26707
+ const chunkDir = join21(dirname6(outputPath), "chunk-encode");
26708
+ if (!existsSync18(chunkDir)) mkdirSync9(chunkDir, { recursive: true });
26471
26709
  const chunkPaths = [];
26472
26710
  for (let i2 = 0; i2 < chunkCount; i2++) {
26473
26711
  if (signal?.aborted) {
@@ -26483,8 +26721,8 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26483
26721
  const startNumber = i2 * chunkSize;
26484
26722
  const framesInChunk = Math.min(chunkSize, files.length - startNumber);
26485
26723
  const ext = outputPath.endsWith(".webm") ? ".webm" : outputPath.endsWith(".mov") ? ".mov" : ".mp4";
26486
- const chunkPath = join20(chunkDir, `chunk_${String(i2).padStart(4, "0")}${ext}`);
26487
- const inputPath = join20(framesDir, framePattern);
26724
+ const chunkPath = join21(chunkDir, `chunk_${String(i2).padStart(4, "0")}${ext}`);
26725
+ const inputPath = join21(framesDir, framePattern);
26488
26726
  const inputArgs = [
26489
26727
  "-framerate",
26490
26728
  String(options.fps),
@@ -26524,7 +26762,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26524
26762
  }
26525
26763
  chunkPaths.push(chunkPath);
26526
26764
  }
26527
- const concatListPath = join20(chunkDir, "concat-list.txt");
26765
+ const concatListPath = join21(chunkDir, "concat-list.txt");
26528
26766
  const concatInput = chunkPaths.map((path2) => `file '${path2.replace(/'/g, "'\\''")}'`).join("\n");
26529
26767
  writeFileSync9(concatListPath, concatInput, "utf-8");
26530
26768
  const concatArgs = [
@@ -26563,7 +26801,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26563
26801
  error: concatResult.error
26564
26802
  };
26565
26803
  }
26566
- const fileSize = existsSync17(outputPath) ? statSync4(outputPath).size : 0;
26804
+ const fileSize = existsSync18(outputPath) ? statSync6(outputPath).size : 0;
26567
26805
  return {
26568
26806
  success: true,
26569
26807
  outputPath,
@@ -26574,7 +26812,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
26574
26812
  }
26575
26813
  async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, config) {
26576
26814
  const outputDir = dirname6(outputPath);
26577
- if (!existsSync17(outputDir)) mkdirSync9(outputDir, { recursive: true });
26815
+ if (!existsSync18(outputDir)) mkdirSync9(outputDir, { recursive: true });
26578
26816
  const isWebm = outputPath.endsWith(".webm");
26579
26817
  const isMov = outputPath.endsWith(".mov");
26580
26818
  const args = ["-i", videoPath, "-i", audioPath, "-c:v", "copy"];
@@ -26645,7 +26883,7 @@ var init_chunkEncoder = __esm({
26645
26883
 
26646
26884
  // ../engine/src/services/streamingEncoder.ts
26647
26885
  import { spawn as spawn5 } from "child_process";
26648
- import { existsSync as existsSync18, mkdirSync as mkdirSync10, statSync as statSync5 } from "fs";
26886
+ import { existsSync as existsSync19, mkdirSync as mkdirSync10, statSync as statSync7 } from "fs";
26649
26887
  import { dirname as dirname7 } from "path";
26650
26888
  function createFrameReorderBuffer(startFrame, endFrame) {
26651
26889
  let cursor = startFrame;
@@ -26828,7 +27066,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
26828
27066
  }
26829
27067
  async function spawnStreamingEncoder(outputPath, options, signal, config) {
26830
27068
  const outputDir = dirname7(outputPath);
26831
- if (!existsSync18(outputDir)) mkdirSync10(outputDir, { recursive: true });
27069
+ if (!existsSync19(outputDir)) mkdirSync10(outputDir, { recursive: true });
26832
27070
  let gpuEncoder = null;
26833
27071
  if (options.useGpu) {
26834
27072
  gpuEncoder = await getCachedGpuEncoder();
@@ -26910,7 +27148,7 @@ Process error: ${err.message}`;
26910
27148
  error: formatFfmpegError(exitCode, stderr)
26911
27149
  };
26912
27150
  }
26913
- const fileSize = existsSync18(outputPath) ? statSync5(outputPath).size : 0;
27151
+ const fileSize = existsSync19(outputPath) ? statSync7(outputPath).size : 0;
26914
27152
  return { success: true, durationMs, fileSize };
26915
27153
  },
26916
27154
  getExitStatus: () => exitStatus
@@ -27202,9 +27440,9 @@ var init_ffprobe = __esm({
27202
27440
  });
27203
27441
 
27204
27442
  // ../engine/src/utils/urlDownloader.ts
27205
- import { createWriteStream as createWriteStream2, existsSync as existsSync19, mkdirSync as mkdirSync11 } from "fs";
27443
+ import { createWriteStream as createWriteStream2, existsSync as existsSync20, mkdirSync as mkdirSync11 } from "fs";
27206
27444
  import { createHash } from "crypto";
27207
- import { join as join21, extname as extname5 } from "path";
27445
+ import { join as join22, extname as extname5 } from "path";
27208
27446
  import { Readable } from "stream";
27209
27447
  import { finished } from "stream/promises";
27210
27448
  function getFilenameFromUrl(url) {
@@ -27215,19 +27453,19 @@ function getFilenameFromUrl(url) {
27215
27453
  }
27216
27454
  async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
27217
27455
  const cachedPath = downloadPathCache.get(url);
27218
- if (cachedPath && existsSync19(cachedPath)) {
27456
+ if (cachedPath && existsSync20(cachedPath)) {
27219
27457
  return cachedPath;
27220
27458
  }
27221
27459
  const inFlight = inFlightDownloads.get(url);
27222
27460
  if (inFlight) {
27223
27461
  return inFlight;
27224
27462
  }
27225
- if (!existsSync19(destDir)) {
27463
+ if (!existsSync20(destDir)) {
27226
27464
  mkdirSync11(destDir, { recursive: true });
27227
27465
  }
27228
27466
  const filename = getFilenameFromUrl(url);
27229
- const localPath = join21(destDir, filename);
27230
- if (existsSync19(localPath)) {
27467
+ const localPath = join22(destDir, filename);
27468
+ if (existsSync20(localPath)) {
27231
27469
  downloadPathCache.set(url, localPath);
27232
27470
  return localPath;
27233
27471
  }
@@ -27319,12 +27557,12 @@ var init_htmlTemplate = __esm({
27319
27557
 
27320
27558
  // ../engine/src/services/extractionCache.ts
27321
27559
  import { createHash as createHash2 } from "crypto";
27322
- import { mkdirSync as mkdirSync12, readdirSync as readdirSync8, statSync as statSync6, writeFileSync as writeFileSync10 } from "fs";
27323
- import { existsSync as existsSync20 } from "fs";
27324
- import { join as join22 } from "path";
27560
+ import { mkdirSync as mkdirSync12, readdirSync as readdirSync9, statSync as statSync8, writeFileSync as writeFileSync10 } from "fs";
27561
+ import { existsSync as existsSync21 } from "fs";
27562
+ import { join as join23 } from "path";
27325
27563
  function readKeyStat(videoPath) {
27326
27564
  try {
27327
- const stat3 = statSync6(videoPath);
27565
+ const stat3 = statSync8(videoPath);
27328
27566
  return { mtimeMs: Math.floor(stat3.mtimeMs), size: stat3.size };
27329
27567
  } catch {
27330
27568
  return null;
@@ -27350,23 +27588,23 @@ function cacheEntryDirName(keyHash) {
27350
27588
  }
27351
27589
  function lookupCacheEntry(rootDir, input) {
27352
27590
  const keyHash = computeCacheKey(input);
27353
- const dir = join22(rootDir, cacheEntryDirName(keyHash));
27354
- const complete = existsSync20(join22(dir, COMPLETE_SENTINEL));
27591
+ const dir = join23(rootDir, cacheEntryDirName(keyHash));
27592
+ const complete = existsSync21(join23(dir, COMPLETE_SENTINEL));
27355
27593
  return { entry: { dir, keyHash }, hit: complete };
27356
27594
  }
27357
27595
  function ensureCacheEntryDir(entry) {
27358
27596
  mkdirSync12(entry.dir, { recursive: true });
27359
27597
  }
27360
27598
  function markCacheEntryComplete(entry) {
27361
- writeFileSync10(join22(entry.dir, COMPLETE_SENTINEL), "", "utf-8");
27599
+ writeFileSync10(join23(entry.dir, COMPLETE_SENTINEL), "", "utf-8");
27362
27600
  }
27363
27601
  function rehydrateCacheEntry(entry, options) {
27364
27602
  const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${options.format}`;
27365
27603
  const framePaths = /* @__PURE__ */ new Map();
27366
27604
  const suffix = `.${options.format}`;
27367
- const files = readdirSync8(entry.dir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(suffix)).sort();
27605
+ const files = readdirSync9(entry.dir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(suffix)).sort();
27368
27606
  files.forEach((file, idx) => {
27369
- framePaths.set(idx, join22(entry.dir, file));
27607
+ framePaths.set(idx, join23(entry.dir, file));
27370
27608
  });
27371
27609
  return {
27372
27610
  videoId: options.videoId,
@@ -27392,8 +27630,8 @@ var init_extractionCache = __esm({
27392
27630
 
27393
27631
  // ../engine/src/services/videoFrameExtractor.ts
27394
27632
  import { spawn as spawn7 } from "child_process";
27395
- import { existsSync as existsSync21, mkdirSync as mkdirSync13, readdirSync as readdirSync9, rmSync as rmSync5 } from "fs";
27396
- import { isAbsolute as isAbsolute2, join as join23 } from "path";
27633
+ import { existsSync as existsSync22, mkdirSync as mkdirSync13, readdirSync as readdirSync10, rmSync as rmSync5 } from "fs";
27634
+ import { isAbsolute as isAbsolute2, join as join24 } from "path";
27397
27635
  function parseVideoElements(html) {
27398
27636
  const videos = [];
27399
27637
  const { document: document2 } = parseHTML(unwrapTemplate(html));
@@ -27463,12 +27701,12 @@ function parseImageElements(html) {
27463
27701
  async function extractVideoFramesRange(videoPath, videoId, startTime, duration, options, signal, config, outputDirOverride) {
27464
27702
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
27465
27703
  const { fps, outputDir, quality = 95 } = options;
27466
- const videoOutputDir = outputDirOverride ?? join23(outputDir, videoId);
27467
- if (!existsSync21(videoOutputDir)) mkdirSync13(videoOutputDir, { recursive: true });
27704
+ const videoOutputDir = outputDirOverride ?? join24(outputDir, videoId);
27705
+ if (!existsSync22(videoOutputDir)) mkdirSync13(videoOutputDir, { recursive: true });
27468
27706
  const metadata = await extractMediaMetadata(videoPath);
27469
27707
  const format = resolveFrameFormat(metadata, options.format);
27470
27708
  const framePattern = `${FRAME_FILENAME_PREFIX}%05d.${format}`;
27471
- const outputPattern = join23(videoOutputDir, framePattern);
27709
+ const outputPattern = join24(videoOutputDir, framePattern);
27472
27710
  const isHdr = isHdrColorSpace(metadata.colorSpace);
27473
27711
  const isMacOS = process.platform === "darwin";
27474
27712
  const args = [];
@@ -27519,9 +27757,9 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
27519
27757
  return;
27520
27758
  }
27521
27759
  const framePaths = /* @__PURE__ */ new Map();
27522
- const files = readdirSync9(videoOutputDir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(`.${format}`)).sort();
27760
+ const files = readdirSync10(videoOutputDir).filter((f3) => f3.startsWith(FRAME_FILENAME_PREFIX) && f3.endsWith(`.${format}`)).sort();
27523
27761
  files.forEach((file, index) => {
27524
- framePaths.set(index, join23(videoOutputDir, file));
27762
+ framePaths.set(index, join24(videoOutputDir, file));
27525
27763
  });
27526
27764
  resolve39({
27527
27765
  videoId,
@@ -27648,15 +27886,15 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
27648
27886
  try {
27649
27887
  let videoPath = video.src;
27650
27888
  if (!isAbsolute2(videoPath) && !isHttpUrl(videoPath)) {
27651
- const fromCompiled = compiledDir ? join23(compiledDir, videoPath) : null;
27652
- videoPath = fromCompiled && existsSync21(fromCompiled) ? fromCompiled : join23(baseDir, videoPath);
27889
+ const fromCompiled = compiledDir ? join24(compiledDir, videoPath) : null;
27890
+ videoPath = fromCompiled && existsSync22(fromCompiled) ? fromCompiled : join24(baseDir, videoPath);
27653
27891
  }
27654
27892
  if (isHttpUrl(videoPath)) {
27655
- const downloadDir = join23(options.outputDir, "_downloads");
27893
+ const downloadDir = join24(options.outputDir, "_downloads");
27656
27894
  mkdirSync13(downloadDir, { recursive: true });
27657
27895
  videoPath = await downloadToTemp(videoPath, downloadDir);
27658
27896
  }
27659
- if (!existsSync21(videoPath)) {
27897
+ if (!existsSync22(videoPath)) {
27660
27898
  errors.push({ videoId: video.id, error: `Video file not found: ${videoPath}` });
27661
27899
  continue;
27662
27900
  }
@@ -27689,7 +27927,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
27689
27927
  const hdrSkippedIndices = /* @__PURE__ */ new Set();
27690
27928
  if (hdrInfo.hasHdr && hdrInfo.dominantTransfer) {
27691
27929
  const targetTransfer = hdrInfo.dominantTransfer;
27692
- const convertDir = join23(options.outputDir, "_hdr_normalized");
27930
+ const convertDir = join24(options.outputDir, "_hdr_normalized");
27693
27931
  mkdirSync13(convertDir, { recursive: true });
27694
27932
  for (let i2 = 0; i2 < resolvedVideos.length; i2++) {
27695
27933
  if (signal?.aborted) break;
@@ -27711,7 +27949,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
27711
27949
  const sourceRemaining = metadata.durationSeconds - entry.video.mediaStart;
27712
27950
  segDuration = sourceRemaining > 0 ? sourceRemaining : metadata.durationSeconds;
27713
27951
  }
27714
- const convertedPath = join23(convertDir, `${entry.video.id}_hdr.mp4`);
27952
+ const convertedPath = join24(convertDir, `${entry.video.id}_hdr.mp4`);
27715
27953
  try {
27716
27954
  await convertSdrToHdr(
27717
27955
  entry.videoPath,
@@ -27746,7 +27984,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
27746
27984
  }
27747
27985
  }
27748
27986
  const vfrPreflightStart = Date.now();
27749
- const vfrNormDir = join23(options.outputDir, "_vfr_normalized");
27987
+ const vfrNormDir = join24(options.outputDir, "_vfr_normalized");
27750
27988
  for (let i2 = 0; i2 < resolvedVideos.length; i2++) {
27751
27989
  if (signal?.aborted) break;
27752
27990
  const entry = resolvedVideos[i2];
@@ -27761,7 +27999,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config, c
27761
27999
  segDuration = sourceRemaining > 0 ? sourceRemaining : metadata.durationSeconds;
27762
28000
  }
27763
28001
  mkdirSync13(vfrNormDir, { recursive: true });
27764
- const normalizedPath = join23(vfrNormDir, `${entry.video.id}_cfr.mp4`);
28002
+ const normalizedPath = join24(vfrNormDir, `${entry.video.id}_cfr.mp4`);
27765
28003
  try {
27766
28004
  await convertVfrToCfr(
27767
28005
  entry.videoPath,
@@ -28017,7 +28255,7 @@ var init_videoFrameExtractor = __esm({
28017
28255
  cleanup() {
28018
28256
  for (const video of this.videos.values()) {
28019
28257
  if (video.extracted.ownedByLookup) continue;
28020
- if (existsSync21(video.extracted.outputDir)) {
28258
+ if (existsSync22(video.extracted.outputDir)) {
28021
28259
  rmSync5(video.extracted.outputDir, { recursive: true, force: true });
28022
28260
  }
28023
28261
  }
@@ -28325,8 +28563,8 @@ var init_videoFrameInjector = __esm({
28325
28563
  });
28326
28564
 
28327
28565
  // ../engine/src/services/audioMixer.ts
28328
- import { existsSync as existsSync22, mkdirSync as mkdirSync14, rmSync as rmSync6 } from "fs";
28329
- import { isAbsolute as isAbsolute3, join as join24, dirname as dirname8 } from "path";
28566
+ import { existsSync as existsSync23, mkdirSync as mkdirSync14, rmSync as rmSync6 } from "fs";
28567
+ import { isAbsolute as isAbsolute3, join as join25, dirname as dirname8 } from "path";
28330
28568
  function parseAudioElements(html) {
28331
28569
  const elements = [];
28332
28570
  const { document: document2 } = parseHTML(unwrapTemplate(html));
@@ -28377,7 +28615,7 @@ function parseAudioElements(html) {
28377
28615
  async function extractAudioFromVideo(videoPath, outputPath, options, signal, config) {
28378
28616
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
28379
28617
  const outputDir = dirname8(outputPath);
28380
- if (!existsSync22(outputDir)) mkdirSync14(outputDir, { recursive: true });
28618
+ if (!existsSync23(outputDir)) mkdirSync14(outputDir, { recursive: true });
28381
28619
  const args = ["-i", videoPath];
28382
28620
  if (options?.startTime !== void 0) args.push("-ss", String(options.startTime));
28383
28621
  if (options?.duration !== void 0) args.push("-t", String(options.duration));
@@ -28404,7 +28642,7 @@ async function extractAudioFromVideo(videoPath, outputPath, options, signal, con
28404
28642
  async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, signal, config) {
28405
28643
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
28406
28644
  const outputDir = dirname8(outputPath);
28407
- if (!existsSync22(outputDir)) mkdirSync14(outputDir, { recursive: true });
28645
+ if (!existsSync23(outputDir)) mkdirSync14(outputDir, { recursive: true });
28408
28646
  const args = [
28409
28647
  "-ss",
28410
28648
  String(mediaStart),
@@ -28440,7 +28678,7 @@ async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, sign
28440
28678
  async function generateSilence(outputPath, duration, signal, config) {
28441
28679
  const ffmpegProcessTimeout = config?.ffmpegProcessTimeout ?? DEFAULT_CONFIG2.ffmpegProcessTimeout;
28442
28680
  const outputDir = dirname8(outputPath);
28443
- if (!existsSync22(outputDir)) mkdirSync14(outputDir, { recursive: true });
28681
+ if (!existsSync23(outputDir)) mkdirSync14(outputDir, { recursive: true });
28444
28682
  const args = [
28445
28683
  "-f",
28446
28684
  "lavfi",
@@ -28483,7 +28721,7 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config)
28483
28721
  };
28484
28722
  }
28485
28723
  const outputDir = dirname8(outputPath);
28486
- if (!existsSync22(outputDir)) mkdirSync14(outputDir, { recursive: true });
28724
+ if (!existsSync23(outputDir)) mkdirSync14(outputDir, { recursive: true });
28487
28725
  const inputs = [];
28488
28726
  const filterParts = [];
28489
28727
  tracks.forEach((track, i2) => {
@@ -28544,7 +28782,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
28544
28782
  const startMs = Date.now();
28545
28783
  const tracks = [];
28546
28784
  const errors = [];
28547
- if (!existsSync22(workDir)) mkdirSync14(workDir, { recursive: true });
28785
+ if (!existsSync23(workDir)) mkdirSync14(workDir, { recursive: true });
28548
28786
  await Promise.all(
28549
28787
  elements.map(async (element) => {
28550
28788
  if (signal?.aborted) {
@@ -28554,8 +28792,8 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
28554
28792
  try {
28555
28793
  let srcPath = element.src;
28556
28794
  if (!isAbsolute3(srcPath) && !isHttpUrl(srcPath)) {
28557
- const fromCompiled = compiledDir ? join24(compiledDir, srcPath) : null;
28558
- srcPath = fromCompiled && existsSync22(fromCompiled) ? fromCompiled : join24(baseDir, srcPath);
28795
+ const fromCompiled = compiledDir ? join25(compiledDir, srcPath) : null;
28796
+ srcPath = fromCompiled && existsSync23(fromCompiled) ? fromCompiled : join25(baseDir, srcPath);
28559
28797
  }
28560
28798
  if (isHttpUrl(srcPath)) {
28561
28799
  try {
@@ -28567,7 +28805,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
28567
28805
  return;
28568
28806
  }
28569
28807
  }
28570
- if (!existsSync22(srcPath)) {
28808
+ if (!existsSync23(srcPath)) {
28571
28809
  errors.push(`Source not found: ${element.id} (${element.src})`);
28572
28810
  return;
28573
28811
  }
@@ -28578,7 +28816,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
28578
28816
  }
28579
28817
  let audioSrcPath = srcPath;
28580
28818
  if (element.type === "video") {
28581
- const extractedPath = join24(workDir, `${element.id}-extracted.wav`);
28819
+ const extractedPath = join25(workDir, `${element.id}-extracted.wav`);
28582
28820
  const extractResult = await extractAudioFromVideo(
28583
28821
  srcPath,
28584
28822
  extractedPath,
@@ -28595,7 +28833,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
28595
28833
  }
28596
28834
  audioSrcPath = extractedPath;
28597
28835
  } else {
28598
- const trimmedPath = join24(workDir, `${element.id}-trimmed.wav`);
28836
+ const trimmedPath = join25(workDir, `${element.id}-trimmed.wav`);
28599
28837
  const prepResult = await prepareAudioTrack(
28600
28838
  srcPath,
28601
28839
  trimmedPath,
@@ -28649,9 +28887,9 @@ var init_audioMixer = __esm({
28649
28887
 
28650
28888
  // ../engine/src/services/parallelCoordinator.ts
28651
28889
  import { cpus as cpus2, freemem, totalmem as totalmem2 } from "os";
28652
- import { existsSync as existsSync23, mkdirSync as mkdirSync15, readdirSync as readdirSync10 } from "fs";
28890
+ import { existsSync as existsSync24, mkdirSync as mkdirSync15, readdirSync as readdirSync11 } from "fs";
28653
28891
  import { copyFile, rename } from "fs/promises";
28654
- import { join as join25 } from "path";
28892
+ import { join as join26 } from "path";
28655
28893
  function calculateOptimalWorkers(totalFrames, requested, config) {
28656
28894
  const effectiveMaxWorkers = (() => {
28657
28895
  const concurrency = config?.concurrency ?? DEFAULT_CONFIG2.concurrency;
@@ -28694,7 +28932,7 @@ function distributeFrames(totalFrames, workerCount, workDir) {
28694
28932
  workerId: i2,
28695
28933
  startFrame,
28696
28934
  endFrame,
28697
- outputDir: join25(workDir, `worker-${i2}`)
28935
+ outputDir: join26(workDir, `worker-${i2}`)
28698
28936
  });
28699
28937
  }
28700
28938
  return tasks;
@@ -28702,7 +28940,7 @@ function distributeFrames(totalFrames, workerCount, workDir) {
28702
28940
  async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCaptureHook, signal, onFrameCaptured, onFrameBuffer, config) {
28703
28941
  const startTime = Date.now();
28704
28942
  let framesCaptured = 0;
28705
- if (!existsSync23(task.outputDir)) mkdirSync15(task.outputDir, { recursive: true });
28943
+ if (!existsSync24(task.outputDir)) mkdirSync15(task.outputDir, { recursive: true });
28706
28944
  let session = null;
28707
28945
  let perf;
28708
28946
  try {
@@ -28792,17 +29030,17 @@ async function executeParallelCapture(serverUrl, workDir, tasks, captureOptions,
28792
29030
  return results;
28793
29031
  }
28794
29032
  async function mergeWorkerFrames(workDir, tasks, outputDir) {
28795
- if (!existsSync23(outputDir)) mkdirSync15(outputDir, { recursive: true });
29033
+ if (!existsSync24(outputDir)) mkdirSync15(outputDir, { recursive: true });
28796
29034
  let totalFrames = 0;
28797
29035
  const sortedTasks = [...tasks].sort((a, b) => a.startFrame - b.startFrame);
28798
29036
  for (const task of sortedTasks) {
28799
- if (!existsSync23(task.outputDir)) {
29037
+ if (!existsSync24(task.outputDir)) {
28800
29038
  continue;
28801
29039
  }
28802
- const files = readdirSync10(task.outputDir).filter((f3) => f3.startsWith("frame_") && (f3.endsWith(".jpg") || f3.endsWith(".png"))).sort();
29040
+ const files = readdirSync11(task.outputDir).filter((f3) => f3.startsWith("frame_") && (f3.endsWith(".jpg") || f3.endsWith(".png"))).sort();
28803
29041
  const copyTasks = files.map(async (file) => {
28804
- const sourcePath = join25(task.outputDir, file);
28805
- const targetPath = join25(outputDir, file);
29042
+ const sourcePath = join26(task.outputDir, file);
29043
+ const targetPath = join26(outputDir, file);
28806
29044
  try {
28807
29045
  await rename(sourcePath, targetPath);
28808
29046
  } catch {
@@ -28839,8 +29077,8 @@ var init_parallelCoordinator = __esm({
28839
29077
  // ../engine/src/services/fileServer.ts
28840
29078
  import { Hono as Hono2 } from "hono";
28841
29079
  import { serve } from "@hono/node-server";
28842
- import { readFileSync as readFileSync16, existsSync as existsSync24, statSync as statSync7 } from "fs";
28843
- import { join as join26, extname as extname6 } from "path";
29080
+ import { readFileSync as readFileSync16, existsSync as existsSync25, statSync as statSync9 } from "fs";
29081
+ import { join as join27, extname as extname6 } from "path";
28844
29082
  function stripEmbeddedRuntimeScripts(html) {
28845
29083
  if (!html) return html;
28846
29084
  const scriptRe = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
@@ -28909,12 +29147,12 @@ function createFileServer(options) {
28909
29147
  let requestPath = c2.req.path;
28910
29148
  if (requestPath === "/") requestPath = "/index.html";
28911
29149
  const relativePath = requestPath.replace(/^\//, "");
28912
- const compiledPath = compiledDir ? join26(compiledDir, relativePath) : null;
29150
+ const compiledPath = compiledDir ? join27(compiledDir, relativePath) : null;
28913
29151
  const hasCompiledFile = Boolean(
28914
- compiledPath && existsSync24(compiledPath) && statSync7(compiledPath).isFile()
29152
+ compiledPath && existsSync25(compiledPath) && statSync9(compiledPath).isFile()
28915
29153
  );
28916
- const filePath = hasCompiledFile ? compiledPath : join26(projectDir, relativePath);
28917
- if (!existsSync24(filePath) || !statSync7(filePath).isFile()) {
29154
+ const filePath = hasCompiledFile ? compiledPath : join27(projectDir, relativePath);
29155
+ if (!existsSync25(filePath) || !statSync9(filePath).isFile()) {
28918
29156
  return c2.text("Not found", 404);
28919
29157
  }
28920
29158
  const ext = extname6(filePath).toLowerCase();
@@ -30192,9 +30430,9 @@ var init_shaderTransitions = __esm({
30192
30430
  });
30193
30431
 
30194
30432
  // ../engine/src/services/hdrCapture.ts
30195
- import { existsSync as existsSync25, readdirSync as readdirSync11 } from "fs";
30196
- import { join as join27 } from "path";
30197
- import { homedir as homedir6 } from "os";
30433
+ import { existsSync as existsSync26, readdirSync as readdirSync12 } from "fs";
30434
+ import { join as join28 } from "path";
30435
+ import { homedir as homedir7 } from "os";
30198
30436
  function linearToPQ(L2) {
30199
30437
  const Lp = Math.max(0, L2 * SDR_NITS / PQ_MAX_NITS);
30200
30438
  const Lm1 = Math.pow(Lp, PQ_M12);
@@ -30309,12 +30547,12 @@ function float16ToPqRgb(rawBuffer, bytesPerRow, width, height) {
30309
30547
  return output;
30310
30548
  }
30311
30549
  function resolveHeadedChromePath() {
30312
- const baseDir = join27(homedir6(), ".cache", "puppeteer", "chrome");
30313
- if (!existsSync25(baseDir)) return void 0;
30314
- const versions = readdirSync11(baseDir).sort().reverse();
30550
+ const baseDir = join28(homedir7(), ".cache", "puppeteer", "chrome");
30551
+ if (!existsSync26(baseDir)) return void 0;
30552
+ const versions = readdirSync12(baseDir).sort().reverse();
30315
30553
  for (const version of versions) {
30316
30554
  const candidates = [
30317
- join27(
30555
+ join28(
30318
30556
  baseDir,
30319
30557
  version,
30320
30558
  "chrome-mac-arm64",
@@ -30323,7 +30561,7 @@ function resolveHeadedChromePath() {
30323
30561
  "MacOS",
30324
30562
  "Google Chrome for Testing"
30325
30563
  ),
30326
- join27(
30564
+ join28(
30327
30565
  baseDir,
30328
30566
  version,
30329
30567
  "chrome-mac-x64",
@@ -30332,11 +30570,11 @@ function resolveHeadedChromePath() {
30332
30570
  "MacOS",
30333
30571
  "Google Chrome for Testing"
30334
30572
  ),
30335
- join27(baseDir, version, "chrome-linux64", "chrome"),
30336
- join27(baseDir, version, "chrome-win64", "chrome.exe")
30573
+ join28(baseDir, version, "chrome-linux64", "chrome"),
30574
+ join28(baseDir, version, "chrome-win64", "chrome.exe")
30337
30575
  ];
30338
30576
  for (const binary of candidates) {
30339
- if (existsSync25(binary)) return binary;
30577
+ if (existsSync26(binary)) return binary;
30340
30578
  }
30341
30579
  }
30342
30580
  return void 0;
@@ -30608,8 +30846,8 @@ var init_staticGuard = __esm({
30608
30846
  });
30609
30847
 
30610
30848
  // ../core/src/compiler/htmlBundler.ts
30611
- import { readFileSync as readFileSync17, existsSync as existsSync26 } from "fs";
30612
- import { join as join28, resolve as resolve12, isAbsolute as isAbsolute4, sep as sep2 } from "path";
30849
+ import { readFileSync as readFileSync17, existsSync as existsSync27 } from "fs";
30850
+ import { join as join29, resolve as resolve12, isAbsolute as isAbsolute4, sep as sep2 } from "path";
30613
30851
  import { transformSync } from "esbuild";
30614
30852
  function parseHTMLContent2(html) {
30615
30853
  const trimmed = html.trimStart().toLowerCase();
@@ -30677,7 +30915,7 @@ function isRelativeUrl(url) {
30677
30915
  return !url.startsWith("http://") && !url.startsWith("https://") && !url.startsWith("//") && !url.startsWith("data:") && !isAbsolute4(url);
30678
30916
  }
30679
30917
  function safeReadFile(filePath) {
30680
- if (!existsSync26(filePath)) return null;
30918
+ if (!existsSync27(filePath)) return null;
30681
30919
  try {
30682
30920
  return readFileSync17(filePath, "utf-8");
30683
30921
  } catch {
@@ -30685,7 +30923,7 @@ function safeReadFile(filePath) {
30685
30923
  }
30686
30924
  }
30687
30925
  function safeReadFileBuffer(filePath) {
30688
- if (!existsSync26(filePath)) return null;
30926
+ if (!existsSync27(filePath)) return null;
30689
30927
  try {
30690
30928
  return readFileSync17(filePath);
30691
30929
  } catch {
@@ -30878,8 +31116,8 @@ function stripJsCommentsParserSafe(source) {
30878
31116
  }
30879
31117
  }
30880
31118
  async function bundleToSingleHtml(projectDir, options) {
30881
- const indexPath = join28(projectDir, "index.html");
30882
- if (!existsSync26(indexPath)) throw new Error("index.html not found in project directory");
31119
+ const indexPath = join29(projectDir, "index.html");
31120
+ if (!existsSync27(indexPath)) throw new Error("index.html not found in project directory");
30883
31121
  const rawHtml = readFileSync17(indexPath, "utf-8");
30884
31122
  const compiled = await compileHtml(rawHtml, projectDir, options?.probeMediaDuration);
30885
31123
  const staticGuard = validateHyperframeHtmlContract(compiled);
@@ -31003,6 +31241,15 @@ async function bundleToSingleHtml(projectDir, options) {
31003
31241
  el.setAttribute(attr, val);
31004
31242
  }
31005
31243
  );
31244
+ const styledEls = innerRoot ? innerRoot.querySelectorAll("[style]") : contentDoc.querySelectorAll("[style]");
31245
+ rewriteInlineStyleAssetUrls(
31246
+ styledEls,
31247
+ src,
31248
+ (el) => el.getAttribute("style"),
31249
+ (el, val) => {
31250
+ el.setAttribute("style", val);
31251
+ }
31252
+ );
31006
31253
  if (innerRoot) {
31007
31254
  const innerCompId = innerRoot.getAttribute("data-composition-id");
31008
31255
  const innerW = innerRoot.getAttribute("data-width");
@@ -31155,7 +31402,7 @@ var init_compiler = __esm({
31155
31402
 
31156
31403
  // ../producer/src/services/hyperframeRuntimeLoader.ts
31157
31404
  import { createHash as createHash3 } from "crypto";
31158
- import { existsSync as existsSync27, readFileSync as readFileSync18 } from "fs";
31405
+ import { existsSync as existsSync28, readFileSync as readFileSync18 } from "fs";
31159
31406
  import { dirname as dirname9, resolve as resolve13 } from "path";
31160
31407
  import { fileURLToPath as fileURLToPath2 } from "url";
31161
31408
  function resolveHyperframeManifestPath() {
@@ -31168,7 +31415,7 @@ function resolveHyperframeManifestPath() {
31168
31415
  MODULE_RELATIVE_MANIFEST_PATH
31169
31416
  ];
31170
31417
  for (const candidate of candidates) {
31171
- if (existsSync27(candidate)) {
31418
+ if (existsSync28(candidate)) {
31172
31419
  return candidate;
31173
31420
  }
31174
31421
  }
@@ -31179,7 +31426,7 @@ function getVerifiedHyperframeRuntimeSource() {
31179
31426
  }
31180
31427
  function resolveVerifiedHyperframeRuntime() {
31181
31428
  const manifestPath = resolveHyperframeManifestPath();
31182
- if (!existsSync27(manifestPath)) {
31429
+ if (!existsSync28(manifestPath)) {
31183
31430
  throw new Error(
31184
31431
  `[HyperframeRuntimeLoader] Missing manifest at ${manifestPath}. Build core runtime artifacts before rendering.`
31185
31432
  );
@@ -31193,7 +31440,7 @@ function resolveVerifiedHyperframeRuntime() {
31193
31440
  );
31194
31441
  }
31195
31442
  const runtimePath = resolve13(dirname9(manifestPath), runtimeFileName);
31196
- if (!existsSync27(runtimePath)) {
31443
+ if (!existsSync28(runtimePath)) {
31197
31444
  throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
31198
31445
  }
31199
31446
  const runtimeSource = readFileSync18(runtimePath, "utf8");
@@ -31235,16 +31482,16 @@ var init_hyperframeRuntimeLoader = __esm({
31235
31482
  // ../producer/src/services/fileServer.ts
31236
31483
  import { Hono as Hono3 } from "hono";
31237
31484
  import { serve as serve2 } from "@hono/node-server";
31238
- import { readFileSync as readFileSync19, existsSync as existsSync28, realpathSync, statSync as statSync8 } from "fs";
31239
- import { join as join29, extname as extname7, resolve as resolve14, sep as sep3 } from "path";
31485
+ import { readFileSync as readFileSync19, existsSync as existsSync29, realpathSync, statSync as statSync10 } from "fs";
31486
+ import { join as join30, extname as extname7, resolve as resolve14, sep as sep3 } from "path";
31240
31487
  function isPathInside(child, parent, options = {}) {
31241
31488
  const { resolveSymlinks = false, pathModule } = options;
31242
31489
  const resolveFn = pathModule?.resolve ?? resolve14;
31243
31490
  const separator = pathModule?.sep ?? sep3;
31244
31491
  const resolvedChild = resolveFn(child);
31245
31492
  const resolvedParent = resolveFn(parent);
31246
- const normalizedChild = resolveSymlinks && existsSync28(resolvedChild) ? realpathSync.native(resolvedChild) : resolvedChild;
31247
- const normalizedParent = resolveSymlinks && existsSync28(resolvedParent) ? realpathSync.native(resolvedParent) : resolvedParent;
31493
+ const normalizedChild = resolveSymlinks && existsSync29(resolvedChild) ? realpathSync.native(resolvedChild) : resolvedChild;
31494
+ const normalizedParent = resolveSymlinks && existsSync29(resolvedParent) ? realpathSync.native(resolvedParent) : resolvedParent;
31248
31495
  if (normalizedChild === normalizedParent) return true;
31249
31496
  const parentWithSep = normalizedParent.endsWith(separator) ? normalizedParent : normalizedParent + separator;
31250
31497
  return normalizedChild.startsWith(parentWithSep);
@@ -31333,14 +31580,14 @@ function createFileServer2(options) {
31333
31580
  const relativePath = requestPath.replace(/^\//, "");
31334
31581
  let filePath = null;
31335
31582
  if (compiledDir) {
31336
- const candidate = join29(compiledDir, relativePath);
31337
- if (existsSync28(candidate) && isPathInside(candidate, compiledDir) && statSync8(candidate).isFile()) {
31583
+ const candidate = join30(compiledDir, relativePath);
31584
+ if (existsSync29(candidate) && isPathInside(candidate, compiledDir) && statSync10(candidate).isFile()) {
31338
31585
  filePath = candidate;
31339
31586
  }
31340
31587
  }
31341
31588
  if (!filePath) {
31342
- const candidate = join29(projectDir, relativePath);
31343
- if (existsSync28(candidate) && isPathInside(candidate, projectDir) && statSync8(candidate).isFile()) {
31589
+ const candidate = join30(projectDir, relativePath);
31590
+ if (existsSync29(candidate) && isPathInside(candidate, projectDir) && statSync10(candidate).isFile()) {
31344
31591
  filePath = candidate;
31345
31592
  }
31346
31593
  }
@@ -31714,7 +31961,7 @@ var init_ffprobe2 = __esm({
31714
31961
  });
31715
31962
 
31716
31963
  // ../producer/src/utils/paths.ts
31717
- import { resolve as resolve15, basename as basename2, join as join30, relative as relative2, isAbsolute as isAbsolute5 } from "path";
31964
+ import { resolve as resolve15, basename as basename2, join as join31, relative as relative2, isAbsolute as isAbsolute5 } from "path";
31718
31965
  function isPathInside2(childPath, parentPath) {
31719
31966
  const absChild = resolve15(childPath);
31720
31967
  const absParent = resolve15(parentPath);
@@ -31735,7 +31982,7 @@ function toExternalAssetKey(absPath) {
31735
31982
  function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
31736
31983
  const absoluteProjectDir = resolve15(projectDir);
31737
31984
  const projectName = basename2(absoluteProjectDir);
31738
- const resolvedOutputPath = outputPath ?? join30(rendersDir, `${projectName}.mp4`);
31985
+ const resolvedOutputPath = outputPath ?? join31(rendersDir, `${projectName}.mp4`);
31739
31986
  const absoluteOutputPath = resolve15(resolvedOutputPath);
31740
31987
  return { absoluteProjectDir, absoluteOutputPath };
31741
31988
  }
@@ -31808,9 +32055,9 @@ var init_fontData_generated = __esm({
31808
32055
  });
31809
32056
 
31810
32057
  // ../producer/src/services/deterministicFonts.ts
31811
- import { existsSync as existsSync29, mkdirSync as mkdirSync16, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
31812
- import { homedir as homedir7 } from "os";
31813
- import { join as join31 } from "path";
32058
+ import { existsSync as existsSync30, mkdirSync as mkdirSync16, readFileSync as readFileSync20, writeFileSync as writeFileSync11 } from "fs";
32059
+ import { homedir as homedir8 } from "os";
32060
+ import { join as join32 } from "path";
31814
32061
  function normalizeFamilyName(family) {
31815
32062
  return family.trim().replace(/^['"]|['"]$/g, "").trim().toLowerCase();
31816
32063
  }
@@ -31921,14 +32168,14 @@ function fontSlug(familyName) {
31921
32168
  return familyName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
31922
32169
  }
31923
32170
  function fontCacheDir(slug) {
31924
- const dir = join31(GOOGLE_FONTS_CACHE_DIR, slug);
31925
- if (!existsSync29(dir)) {
32171
+ const dir = join32(GOOGLE_FONTS_CACHE_DIR, slug);
32172
+ if (!existsSync30(dir)) {
31926
32173
  mkdirSync16(dir, { recursive: true });
31927
32174
  }
31928
32175
  return dir;
31929
32176
  }
31930
32177
  function cachedWoff2Path(slug, weight, style) {
31931
- return join31(fontCacheDir(slug), `${weight}-${style}.woff2`);
32178
+ return join32(fontCacheDir(slug), `${weight}-${style}.woff2`);
31932
32179
  }
31933
32180
  async function fetchGoogleFont(familyName) {
31934
32181
  const slug = fontSlug(familyName);
@@ -31954,7 +32201,7 @@ async function fetchGoogleFont(familyName) {
31954
32201
  const woff2Url = match[3] || "";
31955
32202
  if (!woff2Url) continue;
31956
32203
  const cachePath2 = cachedWoff2Path(slug, weight, style);
31957
- if (!existsSync29(cachePath2)) {
32204
+ if (!existsSync30(cachePath2)) {
31958
32205
  try {
31959
32206
  const fontRes = await fetch(woff2Url);
31960
32207
  if (!fontRes.ok) continue;
@@ -32140,14 +32387,14 @@ var init_deterministicFonts = __esm({
32140
32387
  poppins: "poppins",
32141
32388
  "segoe ui": "roboto"
32142
32389
  };
32143
- GOOGLE_FONTS_CACHE_DIR = join31(homedir7(), ".cache", "hyperframes", "fonts");
32390
+ GOOGLE_FONTS_CACHE_DIR = join32(homedir8(), ".cache", "hyperframes", "fonts");
32144
32391
  WOFF2_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
32145
32392
  }
32146
32393
  });
32147
32394
 
32148
32395
  // ../producer/src/services/htmlCompiler.ts
32149
- import { readFileSync as readFileSync21, existsSync as existsSync30, mkdirSync as mkdirSync17 } from "fs";
32150
- import { join as join32, dirname as dirname10, resolve as resolve16 } from "path";
32396
+ import { readFileSync as readFileSync21, existsSync as existsSync31, mkdirSync as mkdirSync17 } from "fs";
32397
+ import { join as join33, dirname as dirname10, resolve as resolve16 } from "path";
32151
32398
  import postcss from "postcss";
32152
32399
  function dedupeElementsById(elements) {
32153
32400
  const deduped = /* @__PURE__ */ new Map();
@@ -32198,16 +32445,16 @@ function detectRenderModeHints(html) {
32198
32445
  async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagName19) {
32199
32446
  let filePath = src;
32200
32447
  if (isHttpUrl(src)) {
32201
- if (!existsSync30(downloadDir)) mkdirSync17(downloadDir, { recursive: true });
32448
+ if (!existsSync31(downloadDir)) mkdirSync17(downloadDir, { recursive: true });
32202
32449
  try {
32203
32450
  filePath = await downloadToTemp(src, downloadDir);
32204
32451
  } catch {
32205
32452
  return { duration: 0, resolvedPath: src };
32206
32453
  }
32207
32454
  } else if (!filePath.startsWith("/")) {
32208
- filePath = join32(baseDir, filePath);
32455
+ filePath = join33(baseDir, filePath);
32209
32456
  }
32210
- if (!existsSync30(filePath)) {
32457
+ if (!existsSync31(filePath)) {
32211
32458
  return { duration: 0, resolvedPath: filePath };
32212
32459
  }
32213
32460
  const metadata = tagName19 === "video" ? await extractMediaMetadata(filePath) : await extractAudioMetadata(filePath);
@@ -32276,7 +32523,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
32276
32523
  if (visited.has(filePath)) {
32277
32524
  continue;
32278
32525
  }
32279
- if (!existsSync30(filePath)) {
32526
+ if (!existsSync31(filePath)) {
32280
32527
  continue;
32281
32528
  }
32282
32529
  const rawSubHtml = readFileSync21(filePath, "utf-8");
@@ -32486,7 +32733,7 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
32486
32733
  let compHtml = subCompositions.get(srcPath) || null;
32487
32734
  if (!compHtml) {
32488
32735
  const filePath = resolve16(projectDir, srcPath);
32489
- if (existsSync30(filePath)) {
32736
+ if (existsSync31(filePath)) {
32490
32737
  compHtml = readFileSync21(filePath, "utf-8");
32491
32738
  }
32492
32739
  }
@@ -32714,7 +32961,7 @@ function collectExternalAssets(html, projectDir) {
32714
32961
  if (isPathInside2(absPath, absProjectDir)) {
32715
32962
  return null;
32716
32963
  }
32717
- if (!existsSync30(absPath)) return null;
32964
+ if (!existsSync31(absPath)) return null;
32718
32965
  const safeKey = toExternalAssetKey(absPath);
32719
32966
  externalAssets.set(safeKey, absPath);
32720
32967
  return safeKey;
@@ -32993,7 +33240,7 @@ var init_logger = __esm({
32993
33240
  });
32994
33241
 
32995
33242
  // ../producer/src/services/frameDirCache.ts
32996
- import { readdirSync as readdirSync12 } from "fs";
33243
+ import { readdirSync as readdirSync13 } from "fs";
32997
33244
  function getMaxFrameIndex(frameDir) {
32998
33245
  const cached2 = cache.get(frameDir);
32999
33246
  if (cached2 !== void 0) {
@@ -33003,7 +33250,7 @@ function getMaxFrameIndex(frameDir) {
33003
33250
  }
33004
33251
  let max = 0;
33005
33252
  try {
33006
- for (const name of readdirSync12(frameDir)) {
33253
+ for (const name of readdirSync13(frameDir)) {
33007
33254
  const m2 = FRAME_FILENAME_RE.exec(name);
33008
33255
  if (!m2) continue;
33009
33256
  const n = Number(m2[1]);
@@ -33099,17 +33346,17 @@ var init_hdrImageTransferCache = __esm({
33099
33346
 
33100
33347
  // ../producer/src/services/renderOrchestrator.ts
33101
33348
  import {
33102
- existsSync as existsSync31,
33349
+ existsSync as existsSync32,
33103
33350
  mkdirSync as mkdirSync18,
33104
33351
  rmSync as rmSync7,
33105
33352
  readFileSync as readFileSync22,
33106
- readdirSync as readdirSync13,
33107
- statSync as statSync9,
33353
+ readdirSync as readdirSync14,
33354
+ statSync as statSync11,
33108
33355
  writeFileSync as writeFileSync12,
33109
33356
  copyFileSync as copyFileSync2,
33110
33357
  appendFileSync
33111
33358
  } from "fs";
33112
- import { join as join33, dirname as dirname11, resolve as resolve17 } from "path";
33359
+ import { join as join34, dirname as dirname11, resolve as resolve17 } from "path";
33113
33360
  import { randomUUID as randomUUID2 } from "crypto";
33114
33361
  import { freemem as freemem2 } from "os";
33115
33362
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -33130,14 +33377,14 @@ function sampleDirectoryBytes(dir) {
33130
33377
  if (!current) continue;
33131
33378
  let entries2 = [];
33132
33379
  try {
33133
- entries2 = readdirSync13(current);
33380
+ entries2 = readdirSync14(current);
33134
33381
  } catch {
33135
33382
  continue;
33136
33383
  }
33137
33384
  for (const name of entries2) {
33138
- const full = join33(current, name);
33385
+ const full = join34(current, name);
33139
33386
  try {
33140
- const st2 = statSync9(full);
33387
+ const st2 = statSync11(full);
33141
33388
  if (st2.isDirectory()) {
33142
33389
  stack.push(full);
33143
33390
  } else if (st2.isFile()) {
@@ -33210,16 +33457,16 @@ function installDebugLogger(logPath, log2 = defaultLogger) {
33210
33457
  };
33211
33458
  }
33212
33459
  function writeCompiledArtifacts(compiled, workDir, includeSummary) {
33213
- const compileDir = join33(workDir, "compiled");
33460
+ const compileDir = join34(workDir, "compiled");
33214
33461
  mkdirSync18(compileDir, { recursive: true });
33215
- writeFileSync12(join33(compileDir, "index.html"), compiled.html, "utf-8");
33462
+ writeFileSync12(join34(compileDir, "index.html"), compiled.html, "utf-8");
33216
33463
  for (const [srcPath, html] of compiled.subCompositions) {
33217
- const outPath = join33(compileDir, srcPath);
33464
+ const outPath = join34(compileDir, srcPath);
33218
33465
  mkdirSync18(dirname11(outPath), { recursive: true });
33219
33466
  writeFileSync12(outPath, html, "utf-8");
33220
33467
  }
33221
33468
  for (const [relativePath, absolutePath] of compiled.externalAssets) {
33222
- const outPath = resolve17(join33(compileDir, relativePath));
33469
+ const outPath = resolve17(join34(compileDir, relativePath));
33223
33470
  if (!isPathInside2(outPath, compileDir)) {
33224
33471
  console.warn(`[Render] Skipping external asset with unsafe path: ${relativePath}`);
33225
33472
  continue;
@@ -33249,7 +33496,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
33249
33496
  subCompositions: Array.from(compiled.subCompositions.keys()),
33250
33497
  renderModeHints: compiled.renderModeHints
33251
33498
  };
33252
- writeFileSync12(join33(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
33499
+ writeFileSync12(join34(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
33253
33500
  }
33254
33501
  }
33255
33502
  function applyRenderModeHints(cfg, compiled, log2 = defaultLogger) {
@@ -33270,8 +33517,8 @@ function blitHdrVideoLayer(canvas, el, time, fps, hdrFrameDirs, hdrStartTimes, w
33270
33517
  if (videoFrameIndex < 1) return;
33271
33518
  const maxIndex = getMaxFrameIndex(frameDir);
33272
33519
  const effectiveIndex = maxIndex > 0 ? Math.min(videoFrameIndex, maxIndex) : videoFrameIndex;
33273
- const framePath = join33(frameDir, `frame_${String(effectiveIndex).padStart(4, "0")}.png`);
33274
- if (!existsSync31(framePath)) {
33520
+ const framePath = join34(frameDir, `frame_${String(effectiveIndex).padStart(4, "0")}.png`);
33521
+ if (!existsSync32(framePath)) {
33275
33522
  return;
33276
33523
  }
33277
33524
  try {
@@ -33454,7 +33701,7 @@ async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter,
33454
33701
  const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
33455
33702
  const localTime = time - startTime;
33456
33703
  const frameNum = Math.floor(localTime * fps) + 1;
33457
- const expectedFrame = frameDir ? join33(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
33704
+ const expectedFrame = frameDir ? join34(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
33458
33705
  log2.info("[diag] hdr layer blit", {
33459
33706
  frame: debugFrameIndex,
33460
33707
  layerIdx,
@@ -33466,7 +33713,7 @@ async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter,
33466
33713
  localTime: localTime.toFixed(3),
33467
33714
  hdrFrameNum: frameNum,
33468
33715
  expectedFrame,
33469
- expectedFrameExists: expectedFrame ? existsSync31(expectedFrame) : false
33716
+ expectedFrameExists: expectedFrame ? existsSync32(expectedFrame) : false
33470
33717
  });
33471
33718
  }
33472
33719
  }
@@ -33491,7 +33738,7 @@ async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter,
33491
33738
  if (shouldLog && debugDumpDir) {
33492
33739
  const after2 = countNonZeroRgb48(canvas);
33493
33740
  const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
33494
- const dumpPath = join33(debugDumpDir, dumpName);
33741
+ const dumpPath = join34(debugDumpDir, dumpName);
33495
33742
  writeFileSync12(dumpPath, domPng);
33496
33743
  log2.info("[diag] dom layer blit", {
33497
33744
  frame: debugFrameIndex,
@@ -33565,8 +33812,8 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
33565
33812
  async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
33566
33813
  const moduleDir = dirname11(fileURLToPath3(import.meta.url));
33567
33814
  const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve17(process.env.PRODUCER_RENDERS_DIR, "..") : resolve17(moduleDir, "../..");
33568
- const debugDir = join33(producerRoot, ".debug");
33569
- const workDir = job.config.debug ? join33(debugDir, job.id) : join33(dirname11(outputPath), `work-${job.id}`);
33815
+ const debugDir = join34(producerRoot, ".debug");
33816
+ const workDir = job.config.debug ? join34(debugDir, job.id) : join34(dirname11(outputPath), `work-${job.id}`);
33570
33817
  const pipelineStart = Date.now();
33571
33818
  const log2 = job.config.logger ?? defaultLogger;
33572
33819
  let fileServer = null;
@@ -33578,7 +33825,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33578
33825
  videoExtractionFailures: 0,
33579
33826
  imageDecodeFailures: 0
33580
33827
  };
33581
- const perfOutputPath = join33(workDir, "perf-summary.json");
33828
+ const perfOutputPath = join34(workDir, "perf-summary.json");
33582
33829
  const cfg = { ...job.config.producerConfig ?? resolveConfig() };
33583
33830
  const outputFormat = job.config.format ?? "mp4";
33584
33831
  const isWebm = outputFormat === "webm";
@@ -33611,22 +33858,22 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33611
33858
  };
33612
33859
  job.startedAt = /* @__PURE__ */ new Date();
33613
33860
  assertNotAborted();
33614
- if (!existsSync31(workDir)) mkdirSync18(workDir, { recursive: true });
33861
+ if (!existsSync32(workDir)) mkdirSync18(workDir, { recursive: true });
33615
33862
  if (job.config.debug) {
33616
- const logPath = join33(workDir, "render.log");
33863
+ const logPath = join34(workDir, "render.log");
33617
33864
  restoreLogger = installDebugLogger(logPath, log2);
33618
33865
  }
33619
33866
  const entryFile = job.config.entryFile || "index.html";
33620
- let htmlPath = join33(projectDir, entryFile);
33621
- if (!existsSync31(htmlPath)) {
33867
+ let htmlPath = join34(projectDir, entryFile);
33868
+ if (!existsSync32(htmlPath)) {
33622
33869
  throw new Error(`Entry file not found: ${htmlPath}`);
33623
33870
  }
33624
33871
  assertNotAborted();
33625
33872
  const rawEntry = readFileSync22(htmlPath, "utf-8");
33626
33873
  if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
33627
- const wrapperPath = join33(workDir, "standalone-entry.html");
33628
- const projectIndexPath = join33(projectDir, "index.html");
33629
- if (!existsSync31(projectIndexPath)) {
33874
+ const wrapperPath = join34(workDir, "standalone-entry.html");
33875
+ const projectIndexPath = join34(projectDir, "index.html");
33876
+ if (!existsSync32(projectIndexPath)) {
33630
33877
  throw new Error(
33631
33878
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
33632
33879
  );
@@ -33649,7 +33896,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33649
33896
  const stage1Start = Date.now();
33650
33897
  updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
33651
33898
  const compileStart = Date.now();
33652
- let compiled = await compileForRender(projectDir, htmlPath, join33(workDir, "downloads"));
33899
+ let compiled = await compileForRender(projectDir, htmlPath, join34(workDir, "downloads"));
33653
33900
  assertNotAborted();
33654
33901
  perfStages.compileOnlyMs = Date.now() - compileStart;
33655
33902
  applyRenderModeHints(cfg, compiled, log2);
@@ -33681,7 +33928,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33681
33928
  reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
33682
33929
  fileServer = await createFileServer2({
33683
33930
  projectDir,
33684
- compiledDir: join33(workDir, "compiled"),
33931
+ compiledDir: join34(workDir, "compiled"),
33685
33932
  port: 0,
33686
33933
  preHeadScripts: [VIRTUAL_TIME_SHIM]
33687
33934
  });
@@ -33695,7 +33942,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33695
33942
  };
33696
33943
  probeSession = await createCaptureSession(
33697
33944
  fileServer.url,
33698
- join33(workDir, "probe"),
33945
+ join34(workDir, "probe"),
33699
33946
  captureOpts,
33700
33947
  null,
33701
33948
  cfg
@@ -33727,7 +33974,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33727
33974
  compiled,
33728
33975
  resolutions,
33729
33976
  projectDir,
33730
- join33(workDir, "downloads")
33977
+ join34(workDir, "downloads")
33731
33978
  );
33732
33979
  assertNotAborted();
33733
33980
  composition.videos = compiled.videos;
@@ -33881,7 +34128,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33881
34128
  const stage2Start = Date.now();
33882
34129
  updateJobStatus(job, "preprocessing", "Extracting video frames", 10, onProgress);
33883
34130
  let frameLookup = null;
33884
- const compiledDir = join33(workDir, "compiled");
34131
+ const compiledDir = join34(workDir, "compiled");
33885
34132
  let extractionResult = null;
33886
34133
  const nativeHdrVideoIds = /* @__PURE__ */ new Set();
33887
34134
  const videoTransfers = /* @__PURE__ */ new Map();
@@ -33890,10 +34137,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33890
34137
  composition.videos.map(async (v) => {
33891
34138
  let videoPath = v.src;
33892
34139
  if (!videoPath.startsWith("/")) {
33893
- const fromCompiled = existsSync31(join33(compiledDir, videoPath)) ? join33(compiledDir, videoPath) : join33(projectDir, videoPath);
34140
+ const fromCompiled = existsSync32(join34(compiledDir, videoPath)) ? join34(compiledDir, videoPath) : join34(projectDir, videoPath);
33894
34141
  videoPath = fromCompiled;
33895
34142
  }
33896
- if (!existsSync31(videoPath)) return;
34143
+ if (!existsSync32(videoPath)) return;
33897
34144
  const meta = await extractMediaMetadata(videoPath);
33898
34145
  if (isHdrColorSpace(meta.colorSpace)) {
33899
34146
  nativeHdrVideoIds.add(v.id);
@@ -33911,10 +34158,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33911
34158
  composition.images.map(async (img) => {
33912
34159
  let imgPath = img.src;
33913
34160
  if (!imgPath.startsWith("/")) {
33914
- const fromCompiled = existsSync31(join33(compiledDir, imgPath)) ? join33(compiledDir, imgPath) : join33(projectDir, imgPath);
34161
+ const fromCompiled = existsSync32(join34(compiledDir, imgPath)) ? join34(compiledDir, imgPath) : join34(projectDir, imgPath);
33915
34162
  imgPath = fromCompiled;
33916
34163
  }
33917
- if (!existsSync31(imgPath)) return null;
34164
+ if (!existsSync32(imgPath)) return null;
33918
34165
  const meta = await extractMediaMetadata(imgPath);
33919
34166
  if (isHdrColorSpace(meta.colorSpace)) {
33920
34167
  nativeHdrImageIds.add(img.id);
@@ -33930,7 +34177,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33930
34177
  extractionResult = await extractAllVideoFrames(
33931
34178
  composition.videos,
33932
34179
  projectDir,
33933
- { fps: job.config.fps, outputDir: join33(workDir, "video-frames") },
34180
+ { fps: job.config.fps, outputDir: join34(workDir, "video-frames") },
33934
34181
  abortSignal,
33935
34182
  { extractCacheDir: cfg.extractCacheDir },
33936
34183
  compiledDir
@@ -33988,13 +34235,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
33988
34235
  }
33989
34236
  const stage3Start = Date.now();
33990
34237
  updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
33991
- const audioOutputPath = join33(workDir, "audio.aac");
34238
+ const audioOutputPath = join34(workDir, "audio.aac");
33992
34239
  let hasAudio = false;
33993
34240
  if (composition.audios.length > 0) {
33994
34241
  const audioResult = await processCompositionAudio(
33995
34242
  composition.audios,
33996
34243
  projectDir,
33997
- join33(workDir, "audio-work"),
34244
+ join34(workDir, "audio-work"),
33998
34245
  audioOutputPath,
33999
34246
  job.duration,
34000
34247
  abortSignal,
@@ -34012,14 +34259,14 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34012
34259
  if (!fileServer) {
34013
34260
  fileServer = await createFileServer2({
34014
34261
  projectDir,
34015
- compiledDir: join33(workDir, "compiled"),
34262
+ compiledDir: join34(workDir, "compiled"),
34016
34263
  port: 0,
34017
34264
  preHeadScripts: [VIRTUAL_TIME_SHIM]
34018
34265
  });
34019
34266
  assertNotAborted();
34020
34267
  }
34021
- const framesDir = join33(workDir, "captured-frames");
34022
- if (!existsSync31(framesDir)) mkdirSync18(framesDir, { recursive: true });
34268
+ const framesDir = join34(workDir, "captured-frames");
34269
+ if (!existsSync32(framesDir)) mkdirSync18(framesDir, { recursive: true });
34023
34270
  const captureOptions = {
34024
34271
  width,
34025
34272
  height,
@@ -34034,7 +34281,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34034
34281
  const workerCount = calculateOptimalWorkers(totalFrames, job.config.workers, cfg);
34035
34282
  const FORMAT_EXT2 = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
34036
34283
  const videoExt = FORMAT_EXT2[outputFormat] ?? ".mp4";
34037
- const videoOnlyPath = join33(workDir, `video-only${videoExt}`);
34284
+ const videoOnlyPath = join34(workDir, `video-only${videoExt}`);
34038
34285
  const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
34039
34286
  const hasHdrContent = effectiveHdr && nativeHdrIds.size > 0;
34040
34287
  const encoderHdr = hasHdrContent ? effectiveHdr : void 0;
@@ -34056,8 +34303,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34056
34303
  if (!hdrVideoIds.includes(v.id)) continue;
34057
34304
  let srcPath = v.src;
34058
34305
  if (!srcPath.startsWith("/")) {
34059
- const fromCompiled = join33(compiledDir, srcPath);
34060
- srcPath = existsSync31(fromCompiled) ? fromCompiled : join33(projectDir, srcPath);
34306
+ const fromCompiled = join34(compiledDir, srcPath);
34307
+ srcPath = existsSync32(fromCompiled) ? fromCompiled : join34(projectDir, srcPath);
34061
34308
  }
34062
34309
  hdrVideoSrcPaths.set(v.id, srcPath);
34063
34310
  }
@@ -34187,7 +34434,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34187
34434
  for (const [videoId, srcPath] of hdrVideoSrcPaths) {
34188
34435
  const video = composition.videos.find((v) => v.id === videoId);
34189
34436
  if (!video) continue;
34190
- const frameDir = join33(framesDir, `hdr_${videoId}`);
34437
+ const frameDir = join34(framesDir, `hdr_${videoId}`);
34191
34438
  mkdirSync18(frameDir, { recursive: true });
34192
34439
  const duration = video.end - video.start;
34193
34440
  const dims = hdrExtractionDims.get(videoId) ?? { width, height };
@@ -34207,7 +34454,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34207
34454
  "-c:v",
34208
34455
  "png",
34209
34456
  "-y",
34210
- join33(frameDir, "frame_%04d.png")
34457
+ join34(frameDir, "frame_%04d.png")
34211
34458
  ];
34212
34459
  const result = await runFfmpeg(ffmpegArgs, { signal: abortSignal });
34213
34460
  if (!result.success) {
@@ -34275,8 +34522,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34275
34522
  }
34276
34523
  }
34277
34524
  const debugDumpEnabled = process.env.KEEP_TEMP === "1";
34278
- const debugDumpDir = debugDumpEnabled ? join33(framesDir, "debug-composite") : null;
34279
- if (debugDumpDir && !existsSync31(debugDumpDir)) {
34525
+ const debugDumpDir = debugDumpEnabled ? join34(framesDir, "debug-composite") : null;
34526
+ if (debugDumpDir && !existsSync32(debugDumpDir)) {
34280
34527
  mkdirSync18(debugDumpDir, { recursive: true });
34281
34528
  }
34282
34529
  if (!effectiveHdr) {
@@ -34423,7 +34670,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34423
34670
  i2
34424
34671
  );
34425
34672
  if (debugDumpEnabled && debugDumpDir && i2 % 30 === 0) {
34426
- const previewPath = join33(
34673
+ const previewPath = join34(
34427
34674
  debugDumpDir,
34428
34675
  `frame_${String(i2).padStart(4, "0")}_final_rgb48le.bin`
34429
34676
  );
@@ -34770,7 +35017,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34770
35017
  updateJobStatus(job, "complete", "Render complete", 100, onProgress);
34771
35018
  const totalElapsed = Date.now() - pipelineStart;
34772
35019
  sampleMemory();
34773
- const tmpPeakBytes = existsSync31(workDir) ? sampleDirectoryBytes(workDir) : 0;
35020
+ const tmpPeakBytes = existsSync32(workDir) ? sampleDirectoryBytes(workDir) : 0;
34774
35021
  const perfSummary = {
34775
35022
  renderId: job.id,
34776
35023
  totalElapsedMs: totalElapsed,
@@ -34804,8 +35051,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34804
35051
  }
34805
35052
  }
34806
35053
  if (job.config.debug) {
34807
- if (existsSync31(outputPath)) {
34808
- const debugOutput = join33(workDir, `output${videoExt}`);
35054
+ if (existsSync32(outputPath)) {
35055
+ const debugOutput = join34(workDir, `output${videoExt}`);
34809
35056
  copyFileSync2(outputPath, debugOutput);
34810
35057
  }
34811
35058
  } else if (process.env.KEEP_TEMP === "1") {
@@ -34891,7 +35138,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
34891
35138
  await safeCleanup(
34892
35139
  "remove workDir (error)",
34893
35140
  () => {
34894
- if (existsSync31(workDir)) rmSync7(workDir, { recursive: true, force: true });
35141
+ if (existsSync32(workDir)) rmSync7(workDir, { recursive: true, force: true });
34895
35142
  },
34896
35143
  log2
34897
35144
  );
@@ -34951,8 +35198,8 @@ var init_config3 = __esm({
34951
35198
  });
34952
35199
 
34953
35200
  // ../producer/src/services/hyperframeLint.ts
34954
- import { existsSync as existsSync32, readFileSync as readFileSync23, statSync as statSync10 } from "fs";
34955
- import { resolve as resolve18, join as join34 } from "path";
35201
+ import { existsSync as existsSync33, readFileSync as readFileSync23, statSync as statSync12 } from "fs";
35202
+ import { resolve as resolve18, join as join35 } from "path";
34956
35203
  function isStringRecord(value) {
34957
35204
  if (!value || typeof value !== "object" || Array.isArray(value)) {
34958
35205
  return false;
@@ -34980,7 +35227,7 @@ function pickEntryFile(files, preferredEntryFile) {
34980
35227
  }
34981
35228
  function readProjectEntryFile(projectDir, preferredEntryFile) {
34982
35229
  const absProjectDir = resolve18(projectDir);
34983
- if (!existsSync32(absProjectDir) || !statSync10(absProjectDir).isDirectory()) {
35230
+ if (!existsSync33(absProjectDir) || !statSync12(absProjectDir).isDirectory()) {
34984
35231
  return { error: `Project directory not found: ${absProjectDir}` };
34985
35232
  }
34986
35233
  const entryCandidates = [preferredEntryFile, "index.html", "src/index.html"].filter(
@@ -34991,7 +35238,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
34991
35238
  if (!absoluteEntryPath.startsWith(absProjectDir)) {
34992
35239
  return { error: `Entry file must stay inside project directory: ${entryFile}` };
34993
35240
  }
34994
- if (existsSync32(absoluteEntryPath) && statSync10(absoluteEntryPath).isFile()) {
35241
+ if (existsSync33(absoluteEntryPath) && statSync12(absoluteEntryPath).isFile()) {
34995
35242
  return {
34996
35243
  entryFile,
34997
35244
  html: readFileSync23(absoluteEntryPath, "utf-8"),
@@ -35000,7 +35247,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
35000
35247
  }
35001
35248
  }
35002
35249
  return {
35003
- error: `No HTML entry file found in project directory: ${join34(absProjectDir, preferredEntryFile || "index.html")}`
35250
+ error: `No HTML entry file found in project directory: ${join35(absProjectDir, preferredEntryFile || "index.html")}`
35004
35251
  };
35005
35252
  }
35006
35253
  function prepareHyperframeLintBody(body) {
@@ -35088,15 +35335,15 @@ var init_semaphore = __esm({
35088
35335
 
35089
35336
  // ../producer/src/server.ts
35090
35337
  import {
35091
- existsSync as existsSync33,
35338
+ existsSync as existsSync34,
35092
35339
  mkdirSync as mkdirSync19,
35093
- statSync as statSync11,
35340
+ statSync as statSync13,
35094
35341
  mkdtempSync as mkdtempSync2,
35095
35342
  writeFileSync as writeFileSync13,
35096
35343
  rmSync as rmSync8,
35097
35344
  createReadStream
35098
35345
  } from "fs";
35099
- import { resolve as resolve19, dirname as dirname12, join as join35 } from "path";
35346
+ import { resolve as resolve19, dirname as dirname12, join as join36 } from "path";
35100
35347
  import { tmpdir as tmpdir3 } from "os";
35101
35348
  import { parseArgs as parseArgs2 } from "util";
35102
35349
  import crypto2 from "crypto";
@@ -35119,11 +35366,11 @@ async function prepareRenderBody(body) {
35119
35366
  const projectDir = typeof body.projectDir === "string" ? body.projectDir : void 0;
35120
35367
  if (projectDir) {
35121
35368
  const absProjectDir = resolve19(projectDir);
35122
- if (!existsSync33(absProjectDir) || !statSync11(absProjectDir).isDirectory()) {
35369
+ if (!existsSync34(absProjectDir) || !statSync13(absProjectDir).isDirectory()) {
35123
35370
  return { error: `Project directory not found: ${absProjectDir}` };
35124
35371
  }
35125
35372
  const entry = options.entryFile || "index.html";
35126
- if (!existsSync33(resolve19(absProjectDir, entry))) {
35373
+ if (!existsSync34(resolve19(absProjectDir, entry))) {
35127
35374
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
35128
35375
  }
35129
35376
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -35148,8 +35395,8 @@ async function prepareRenderBody(body) {
35148
35395
  }
35149
35396
  }
35150
35397
  const tempRoot = process.env.PRODUCER_TMP_PROJECT_DIR || tmpdir3();
35151
- const tempProjectDir = mkdtempSync2(join35(tempRoot, "producer-project-"));
35152
- writeFileSync13(join35(tempProjectDir, "index.html"), htmlContent, "utf-8");
35398
+ const tempProjectDir = mkdtempSync2(join36(tempRoot, "producer-project-"));
35399
+ writeFileSync13(join36(tempProjectDir, "index.html"), htmlContent, "utf-8");
35153
35400
  return {
35154
35401
  prepared: {
35155
35402
  input: {
@@ -35272,7 +35519,7 @@ function createRenderHandlers(options = {}) {
35272
35519
  log2
35273
35520
  );
35274
35521
  const outputDir = dirname12(absoluteOutputPath);
35275
- if (!existsSync33(outputDir)) mkdirSync19(outputDir, { recursive: true });
35522
+ if (!existsSync34(outputDir)) mkdirSync19(outputDir, { recursive: true });
35276
35523
  const release2 = await renderSemaphore.acquire();
35277
35524
  log2.info("render started", {
35278
35525
  requestId,
@@ -35299,7 +35546,7 @@ function createRenderHandlers(options = {}) {
35299
35546
  log2.info(`render progress ${pct}%`, { requestId, stage: j2.currentStage, message });
35300
35547
  }
35301
35548
  });
35302
- const fileSize = existsSync33(absoluteOutputPath) ? statSync11(absoluteOutputPath).size : 0;
35549
+ const fileSize = existsSync34(absoluteOutputPath) ? statSync13(absoluteOutputPath).size : 0;
35303
35550
  const durationMs = Date.now() - t0;
35304
35551
  const outputToken = store.register(absoluteOutputPath);
35305
35552
  const outputUrl = `${outputUrlPrefix}/${outputToken}`;
@@ -35383,7 +35630,7 @@ function createRenderHandlers(options = {}) {
35383
35630
  log2
35384
35631
  );
35385
35632
  const outputDir = dirname12(absoluteOutputPath);
35386
- if (!existsSync33(outputDir)) mkdirSync19(outputDir, { recursive: true });
35633
+ if (!existsSync34(outputDir)) mkdirSync19(outputDir, { recursive: true });
35387
35634
  log2.info("render-stream started", { requestId, projectDir: input.projectDir });
35388
35635
  const job = createRenderJob({
35389
35636
  fps: input.fps,
@@ -35428,7 +35675,7 @@ function createRenderHandlers(options = {}) {
35428
35675
  },
35429
35676
  abortController.signal
35430
35677
  );
35431
- const fileSize = existsSync33(absoluteOutputPath) ? statSync11(absoluteOutputPath).size : 0;
35678
+ const fileSize = existsSync34(absoluteOutputPath) ? statSync13(absoluteOutputPath).size : 0;
35432
35679
  const outputToken = store.register(absoluteOutputPath);
35433
35680
  const outputUrl = `${outputUrlPrefix}/${outputToken}`;
35434
35681
  log2.info("render-stream completed", { requestId, fileSize, perf: job.perfSummary ?? null });
@@ -35487,11 +35734,11 @@ function createRenderHandlers(options = {}) {
35487
35734
  if (!artifact) {
35488
35735
  return c2.json({ success: false, error: "Output artifact not found or expired" }, 404);
35489
35736
  }
35490
- if (!existsSync33(artifact.path)) {
35737
+ if (!existsSync34(artifact.path)) {
35491
35738
  store.delete(token);
35492
35739
  return c2.json({ success: false, error: "Output artifact file missing" }, 404);
35493
35740
  }
35494
- const stats = statSync11(artifact.path);
35741
+ const stats = statSync13(artifact.path);
35495
35742
  return new Response(createReadStream(artifact.path), {
35496
35743
  headers: {
35497
35744
  "content-type": "video/mp4",
@@ -35625,20 +35872,20 @@ __export(studioServer_exports, {
35625
35872
  });
35626
35873
  import { Hono as Hono5 } from "hono";
35627
35874
  import { streamSSE as streamSSE3 } from "hono/streaming";
35628
- import { existsSync as existsSync34, readFileSync as readFileSync24, writeFileSync as writeFileSync14, statSync as statSync12 } from "fs";
35629
- import { resolve as resolve20, join as join36, basename as basename3 } from "path";
35875
+ import { existsSync as existsSync35, readFileSync as readFileSync24, writeFileSync as writeFileSync14, statSync as statSync14 } from "fs";
35876
+ import { resolve as resolve20, join as join37, basename as basename3 } from "path";
35630
35877
  function resolveDistDir() {
35631
35878
  return resolveStudioBundle().dir;
35632
35879
  }
35633
35880
  function resolveStudioBundle() {
35634
35881
  const builtPath = resolve20(__dirname, "studio");
35635
35882
  const builtIndex = resolve20(builtPath, "index.html");
35636
- if (existsSync34(builtIndex)) {
35883
+ if (existsSync35(builtIndex)) {
35637
35884
  return { dir: builtPath, indexPath: builtIndex, available: true, checkedPaths: [builtIndex] };
35638
35885
  }
35639
35886
  const devPath = resolve20(__dirname, "..", "..", "..", "studio", "dist");
35640
35887
  const devIndex = resolve20(devPath, "index.html");
35641
- if (existsSync34(devIndex)) {
35888
+ if (existsSync35(devIndex)) {
35642
35889
  return {
35643
35890
  dir: devPath,
35644
35891
  indexPath: devIndex,
@@ -35655,9 +35902,9 @@ function resolveStudioBundle() {
35655
35902
  }
35656
35903
  function resolveRuntimePath() {
35657
35904
  const builtPath = resolve20(__dirname, "hyperframe-runtime.js");
35658
- if (existsSync34(builtPath)) return builtPath;
35905
+ if (existsSync35(builtPath)) return builtPath;
35659
35906
  const iifePath = resolve20(__dirname, "hyperframe.runtime.iife.js");
35660
- if (existsSync34(iifePath)) return iifePath;
35907
+ if (existsSync35(iifePath)) return iifePath;
35661
35908
  const devPath = resolve20(
35662
35909
  __dirname,
35663
35910
  "..",
@@ -35667,7 +35914,7 @@ function resolveRuntimePath() {
35667
35914
  "dist",
35668
35915
  "hyperframe.runtime.iife.js"
35669
35916
  );
35670
- if (existsSync34(devPath)) return devPath;
35917
+ if (existsSync35(devPath)) return devPath;
35671
35918
  return builtPath;
35672
35919
  }
35673
35920
  async function getThumbnailBrowser() {
@@ -35729,7 +35976,7 @@ function createStudioServer(options) {
35729
35976
  return lintHyperframeHtml2(html, opts);
35730
35977
  },
35731
35978
  runtimeUrl: "/api/runtime.js",
35732
- rendersDir: () => join36(projectDir, "renders"),
35979
+ rendersDir: () => join37(projectDir, "renders"),
35733
35980
  startRender(opts) {
35734
35981
  const state = {
35735
35982
  id: opts.jobId,
@@ -35844,7 +36091,7 @@ function createStudioServer(options) {
35844
36091
  });
35845
36092
  app.get("/api/runtime.js", (c2) => {
35846
36093
  const serve4 = async () => {
35847
- const runtimeSource = await loadRuntimeSource() ?? (existsSync34(runtimePath) ? readFileSync24(runtimePath, "utf-8") : null);
36094
+ const runtimeSource = await loadRuntimeSource() ?? (existsSync35(runtimePath) ? readFileSync24(runtimePath, "utf-8") : null);
35848
36095
  if (!runtimeSource) return c2.text("runtime not available", 404);
35849
36096
  return c2.body(runtimeSource, 200, {
35850
36097
  "Content-Type": "text/javascript",
@@ -35880,7 +36127,7 @@ function createStudioServer(options) {
35880
36127
  });
35881
36128
  app.get("/assets/*", (c2) => {
35882
36129
  const filePath = resolve20(studioDir, c2.req.path.slice(1));
35883
- if (!existsSync34(filePath) || !statSync12(filePath).isFile()) return c2.text("not found", 404);
36130
+ if (!existsSync35(filePath) || !statSync14(filePath).isFile()) return c2.text("not found", 404);
35884
36131
  const content = readFileSync24(filePath);
35885
36132
  return new Response(content, {
35886
36133
  headers: { "Content-Type": getMimeType(filePath), "Cache-Control": "no-store" }
@@ -35888,7 +36135,7 @@ function createStudioServer(options) {
35888
36135
  });
35889
36136
  app.get("/icons/*", (c2) => {
35890
36137
  const filePath = resolve20(studioDir, c2.req.path.slice(1));
35891
- if (!existsSync34(filePath) || !statSync12(filePath).isFile()) return c2.text("not found", 404);
36138
+ if (!existsSync35(filePath) || !statSync14(filePath).isFile()) return c2.text("not found", 404);
35892
36139
  const content = readFileSync24(filePath);
35893
36140
  return new Response(content, {
35894
36141
  headers: { "Content-Type": getMimeType(filePath), "Cache-Control": "no-store" }
@@ -35896,7 +36143,7 @@ function createStudioServer(options) {
35896
36143
  });
35897
36144
  app.get("*", (c2) => {
35898
36145
  const indexPath = resolve20(studioDir, "index.html");
35899
- if (!existsSync34(indexPath)) {
36146
+ if (!existsSync35(indexPath)) {
35900
36147
  return c2.html(
35901
36148
  `<!doctype html>
35902
36149
  <html>
@@ -35976,20 +36223,20 @@ __export(preview_exports, {
35976
36223
  examples: () => examples
35977
36224
  });
35978
36225
  import { spawn as spawn8 } from "child_process";
35979
- import { existsSync as existsSync35, lstatSync, symlinkSync, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync20 } from "fs";
35980
- import { resolve as resolve21, dirname as dirname13, basename as basename4, join as join37 } from "path";
36226
+ import { existsSync as existsSync36, lstatSync, symlinkSync, unlinkSync as unlinkSync5, readlinkSync, mkdirSync as mkdirSync20 } from "fs";
36227
+ import { resolve as resolve21, dirname as dirname13, basename as basename4, join as join38 } from "path";
35981
36228
  import { fileURLToPath as fileURLToPath4 } from "url";
35982
36229
  import { createRequire } from "module";
35983
36230
  async function runDevMode(dir, projectName) {
35984
36231
  const thisFile = fileURLToPath4(import.meta.url);
35985
36232
  const repoRoot = resolve21(dirname13(thisFile), "..", "..", "..", "..");
35986
- const projectsDir = join37(repoRoot, "packages", "studio", "data", "projects");
36233
+ const projectsDir = join38(repoRoot, "packages", "studio", "data", "projects");
35987
36234
  const pName = projectName ?? basename4(dir);
35988
- const symlinkPath = join37(projectsDir, pName);
36235
+ const symlinkPath = join38(projectsDir, pName);
35989
36236
  mkdirSync20(projectsDir, { recursive: true });
35990
36237
  let createdSymlink = false;
35991
36238
  if (dir !== symlinkPath) {
35992
- if (existsSync35(symlinkPath)) {
36239
+ if (existsSync36(symlinkPath)) {
35993
36240
  try {
35994
36241
  const stat3 = lstatSync(symlinkPath);
35995
36242
  if (stat3.isSymbolicLink()) {
@@ -36001,7 +36248,7 @@ async function runDevMode(dir, projectName) {
36001
36248
  } catch {
36002
36249
  }
36003
36250
  }
36004
- if (!existsSync35(symlinkPath)) {
36251
+ if (!existsSync36(symlinkPath)) {
36005
36252
  symlinkSync(dir, symlinkPath, "dir");
36006
36253
  createdSymlink = true;
36007
36254
  }
@@ -36009,7 +36256,7 @@ async function runDevMode(dir, projectName) {
36009
36256
  Wt2(c.bold("hyperframes preview"));
36010
36257
  const s2 = be();
36011
36258
  s2.start("Starting studio...");
36012
- const studioPkgDir = join37(repoRoot, "packages", "studio");
36259
+ const studioPkgDir = join38(repoRoot, "packages", "studio");
36013
36260
  const child = spawn8("pnpm", ["exec", "vite"], {
36014
36261
  cwd: studioPkgDir,
36015
36262
  stdio: ["ignore", "pipe", "pipe"]
@@ -36043,7 +36290,7 @@ async function runDevMode(dir, projectName) {
36043
36290
  if (createdSymlink) {
36044
36291
  process.on("exit", () => {
36045
36292
  try {
36046
- if (existsSync35(symlinkPath)) unlinkSync5(symlinkPath);
36293
+ if (existsSync36(symlinkPath)) unlinkSync5(symlinkPath);
36047
36294
  } catch {
36048
36295
  }
36049
36296
  });
@@ -36054,7 +36301,7 @@ async function runDevMode(dir, projectName) {
36054
36301
  }
36055
36302
  function hasLocalStudio(dir) {
36056
36303
  try {
36057
- const req = createRequire(join37(dir, "package.json"));
36304
+ const req = createRequire(join38(dir, "package.json"));
36058
36305
  req.resolve("@hyperframes/studio/package.json");
36059
36306
  return true;
36060
36307
  } catch {
@@ -36062,20 +36309,20 @@ function hasLocalStudio(dir) {
36062
36309
  }
36063
36310
  }
36064
36311
  async function runLocalStudioMode(dir, projectName) {
36065
- const req = createRequire(join37(dir, "package.json"));
36312
+ const req = createRequire(join38(dir, "package.json"));
36066
36313
  const studioPkgPath = dirname13(req.resolve("@hyperframes/studio/package.json"));
36067
36314
  const pName = projectName ?? basename4(dir);
36068
- const projectsDir = join37(studioPkgPath, "data", "projects");
36069
- const symlinkPath = join37(projectsDir, pName);
36315
+ const projectsDir = join38(studioPkgPath, "data", "projects");
36316
+ const symlinkPath = join38(projectsDir, pName);
36070
36317
  mkdirSync20(projectsDir, { recursive: true });
36071
36318
  let createdSymlink = false;
36072
36319
  if (dir !== symlinkPath) {
36073
- if (existsSync35(symlinkPath) && lstatSync(symlinkPath).isSymbolicLink()) {
36320
+ if (existsSync36(symlinkPath) && lstatSync(symlinkPath).isSymbolicLink()) {
36074
36321
  if (resolve21(readlinkSync(symlinkPath)) !== resolve21(dir)) {
36075
36322
  unlinkSync5(symlinkPath);
36076
36323
  }
36077
36324
  }
36078
- if (!existsSync35(symlinkPath)) {
36325
+ if (!existsSync36(symlinkPath)) {
36079
36326
  symlinkSync(dir, symlinkPath, "dir");
36080
36327
  createdSymlink = true;
36081
36328
  }
@@ -36114,7 +36361,7 @@ async function runLocalStudioMode(dir, projectName) {
36114
36361
  if (createdSymlink) {
36115
36362
  process.on("exit", () => {
36116
36363
  try {
36117
- if (existsSync35(symlinkPath)) unlinkSync5(symlinkPath);
36364
+ if (existsSync36(symlinkPath)) unlinkSync5(symlinkPath);
36118
36365
  } catch {
36119
36366
  }
36120
36367
  });
@@ -36290,8 +36537,8 @@ var init_preview2 = __esm({
36290
36537
  const dir = resolve21(rawArg ?? ".");
36291
36538
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
36292
36539
  const projectName = isImplicitCwd ? basename4(process.env.PWD ?? dir) : basename4(dir);
36293
- const indexPath = join37(dir, "index.html");
36294
- if (existsSync35(indexPath)) {
36540
+ const indexPath = join38(dir, "index.html");
36541
+ if (existsSync36(indexPath)) {
36295
36542
  const project = { dir, name: projectName, indexPath };
36296
36543
  const lintResult = lintProject(project);
36297
36544
  if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
@@ -36320,20 +36567,20 @@ __export(init_exports, {
36320
36567
  examples: () => examples2
36321
36568
  });
36322
36569
  import {
36323
- existsSync as existsSync36,
36570
+ existsSync as existsSync37,
36324
36571
  mkdirSync as mkdirSync21,
36325
36572
  copyFileSync as copyFileSync3,
36326
36573
  cpSync,
36327
36574
  writeFileSync as writeFileSync15,
36328
36575
  readFileSync as readFileSync25,
36329
- readdirSync as readdirSync14
36576
+ readdirSync as readdirSync15
36330
36577
  } from "fs";
36331
- import { resolve as resolve22, basename as basename5, join as join38, dirname as dirname14 } from "path";
36578
+ import { resolve as resolve22, basename as basename5, join as join39, dirname as dirname14 } from "path";
36332
36579
  import { fileURLToPath as fileURLToPath5 } from "url";
36333
- import { execFileSync as execFileSync4, spawn as spawn9 } from "child_process";
36580
+ import { execFileSync as execFileSync5, spawn as spawn9 } from "child_process";
36334
36581
  function probeVideo(filePath) {
36335
36582
  try {
36336
- const raw = execFileSync4(
36583
+ const raw = execFileSync5(
36337
36584
  "ffprobe",
36338
36585
  ["-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", filePath],
36339
36586
  { encoding: "utf-8", timeout: 15e3 }
@@ -36400,7 +36647,7 @@ function resolveAssetDir(devSegments, builtSegments) {
36400
36647
  const base = dirname14(fileURLToPath5(import.meta.url));
36401
36648
  const devPath = resolve22(base, ...devSegments);
36402
36649
  const builtPath = resolve22(base, ...builtSegments);
36403
- return existsSync36(devPath) ? devPath : builtPath;
36650
+ return existsSync37(devPath) ? devPath : builtPath;
36404
36651
  }
36405
36652
  function getStaticTemplateDir(templateId) {
36406
36653
  return resolveAssetDir(["..", "templates", templateId], ["templates", templateId]);
@@ -36409,7 +36656,7 @@ function getSharedTemplateDir() {
36409
36656
  return resolveAssetDir(["..", "templates", "_shared"], ["templates", "_shared"]);
36410
36657
  }
36411
36658
  function patchVideoSrc(dir, videoFilename, durationSeconds) {
36412
- const htmlFiles = readdirSync14(dir, { withFileTypes: true, recursive: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".html")).map((e2) => join38(e2.parentPath ?? e2.path, e2.name));
36659
+ const htmlFiles = readdirSync15(dir, { withFileTypes: true, recursive: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".html")).map((e2) => join39(e2.parentPath ?? e2.path, e2.name));
36413
36660
  for (const file of htmlFiles) {
36414
36661
  let content = readFileSync25(file, "utf-8");
36415
36662
  if (videoFilename) {
@@ -36516,7 +36763,7 @@ async function handleVideoFile(videoPath, destDir, interactive) {
36516
36763
  async function scaffoldProject(destDir, name, templateId, localVideoName, durationSeconds) {
36517
36764
  mkdirSync21(destDir, { recursive: true });
36518
36765
  const templateDir = getStaticTemplateDir(templateId);
36519
- if (existsSync36(templateDir)) {
36766
+ if (existsSync37(templateDir)) {
36520
36767
  cpSync(templateDir, destDir, { recursive: true });
36521
36768
  } else {
36522
36769
  await fetchRemoteTemplate(templateId, destDir);
@@ -36535,14 +36782,14 @@ async function scaffoldProject(destDir, name, templateId, localVideoName, durati
36535
36782
  ),
36536
36783
  "utf-8"
36537
36784
  );
36538
- if (!existsSync36(resolve22(destDir, "hyperframes.json"))) {
36785
+ if (!existsSync37(resolve22(destDir, "hyperframes.json"))) {
36539
36786
  const { writeProjectConfig: writeProjectConfig2, DEFAULT_PROJECT_CONFIG: DEFAULT_PROJECT_CONFIG2 } = await Promise.resolve().then(() => (init_projectConfig(), projectConfig_exports));
36540
36787
  writeProjectConfig2(destDir, DEFAULT_PROJECT_CONFIG2);
36541
36788
  }
36542
36789
  const sharedDir = getSharedTemplateDir();
36543
- if (existsSync36(sharedDir)) {
36544
- for (const entry of readdirSync14(sharedDir, { withFileTypes: true })) {
36545
- const src = join38(sharedDir, entry.name);
36790
+ if (existsSync37(sharedDir)) {
36791
+ for (const entry of readdirSync15(sharedDir, { withFileTypes: true })) {
36792
+ const src = join39(sharedDir, entry.name);
36546
36793
  const dest = resolve22(destDir, entry.name);
36547
36794
  if (entry.isFile() || entry.isSymbolicLink()) {
36548
36795
  copyFileSync3(src, dest);
@@ -36656,7 +36903,7 @@ var init_init = __esm({
36656
36903
  const templateId2 = exampleFlag ?? "blank";
36657
36904
  const name2 = args.name ?? "my-video";
36658
36905
  const destDir2 = resolve22(name2);
36659
- if (existsSync36(destDir2) && readdirSync14(destDir2).length > 0) {
36906
+ if (existsSync37(destDir2) && readdirSync15(destDir2).length > 0) {
36660
36907
  console.error(c.error(`Directory already exists and is not empty: ${name2}`));
36661
36908
  process.exit(1);
36662
36909
  }
@@ -36670,7 +36917,7 @@ var init_init = __esm({
36670
36917
  }
36671
36918
  if (videoFlag) {
36672
36919
  const videoPath = resolve22(videoFlag);
36673
- if (!existsSync36(videoPath)) {
36920
+ if (!existsSync37(videoPath)) {
36674
36921
  console.error(c.error(`Video file not found: ${videoFlag}`));
36675
36922
  process.exit(1);
36676
36923
  }
@@ -36684,7 +36931,7 @@ var init_init = __esm({
36684
36931
  }
36685
36932
  if (audioFlag) {
36686
36933
  const audioPath = resolve22(audioFlag);
36687
- if (!existsSync36(audioPath)) {
36934
+ if (!existsSync37(audioPath)) {
36688
36935
  console.error(c.error(`Audio file not found: ${audioFlag}`));
36689
36936
  process.exit(1);
36690
36937
  }
@@ -36730,11 +36977,11 @@ var init_init = __esm({
36730
36977
  }
36731
36978
  trackInitTemplate(templateId2);
36732
36979
  const transcriptFile2 = resolve22(destDir2, "transcript.json");
36733
- if (existsSync36(transcriptFile2)) {
36980
+ if (existsSync37(transcriptFile2)) {
36734
36981
  await patchTranscript(destDir2, transcriptFile2);
36735
36982
  }
36736
36983
  console.log(c.success(`Created ${c.accent(name2 + "/")}`));
36737
- for (const f3 of readdirSync14(destDir2).filter((f4) => !f4.startsWith("."))) {
36984
+ for (const f3 of readdirSync15(destDir2).filter((f4) => !f4.startsWith("."))) {
36738
36985
  console.log(` ${c.accent(f3)}`);
36739
36986
  }
36740
36987
  console.log();
@@ -36782,7 +37029,7 @@ var init_init = __esm({
36782
37029
  name = nameResult;
36783
37030
  }
36784
37031
  const destDir = resolve22(name);
36785
- if (existsSync36(destDir) && readdirSync14(destDir).length > 0) {
37032
+ if (existsSync37(destDir) && readdirSync15(destDir).length > 0) {
36786
37033
  const overwrite = await Rt({
36787
37034
  message: `Directory ${c.accent(name)} already exists and is not empty. Overwrite?`,
36788
37035
  initialValue: false
@@ -36797,7 +37044,7 @@ var init_init = __esm({
36797
37044
  let videoDuration;
36798
37045
  if (videoFlag) {
36799
37046
  const videoPath = resolve22(videoFlag);
36800
- if (!existsSync36(videoPath)) {
37047
+ if (!existsSync37(videoPath)) {
36801
37048
  R2.error(`File not found: ${videoFlag}`);
36802
37049
  Nt("Setup cancelled.");
36803
37050
  process.exit(1);
@@ -36809,7 +37056,7 @@ var init_init = __esm({
36809
37056
  videoDuration = result.meta.durationSeconds;
36810
37057
  } else if (audioFlag) {
36811
37058
  const audioPath = resolve22(audioFlag);
36812
- if (!existsSync36(audioPath)) {
37059
+ if (!existsSync37(audioPath)) {
36813
37060
  R2.error(`File not found: ${audioFlag}`);
36814
37061
  Nt("Setup cancelled.");
36815
37062
  process.exit(1);
@@ -36902,10 +37149,10 @@ ${c.dim("Use --example blank for offline use.")}`
36902
37149
  }
36903
37150
  trackInitTemplate(templateId);
36904
37151
  const transcriptFile = resolve22(destDir, "transcript.json");
36905
- if (existsSync36(transcriptFile)) {
37152
+ if (existsSync37(transcriptFile)) {
36906
37153
  await patchTranscript(destDir, transcriptFile);
36907
37154
  }
36908
- const files = readdirSync14(destDir);
37155
+ const files = readdirSync15(destDir);
36909
37156
  Vt2(files.map((f3) => c.accent(f3)).join("\n"), c.success(`Created ${name}/`));
36910
37157
  if (!skipSkills) {
36911
37158
  const installSkills = await Rt({
@@ -36934,9 +37181,9 @@ ${c.dim("Use --example blank for offline use.")}`
36934
37181
 
36935
37182
  // src/utils/clipboard.ts
36936
37183
  import { spawnSync as spawnSync2 } from "child_process";
36937
- import { platform as platform3 } from "os";
37184
+ import { platform as platform4 } from "os";
36938
37185
  function detectProvider() {
36939
- const os = platform3();
37186
+ const os = platform4();
36940
37187
  if (os === "darwin") {
36941
37188
  return { cmd: "pbcopy", args: [] };
36942
37189
  }
@@ -36988,7 +37235,7 @@ __export(add_exports, {
36988
37235
  remapTarget: () => remapTarget,
36989
37236
  runAdd: () => runAdd
36990
37237
  });
36991
- import { existsSync as existsSync37 } from "fs";
37238
+ import { existsSync as existsSync38 } from "fs";
36992
37239
  import { resolve as resolve23, relative as relative3 } from "path";
36993
37240
  function remapTarget(item, originalTarget, paths) {
36994
37241
  if (item.type === "hyperframes:block") {
@@ -37014,8 +37261,8 @@ function buildSnippet(item, relativeTarget) {
37014
37261
  async function runAdd(opts) {
37015
37262
  const projectDir = resolve23(opts.projectDir);
37016
37263
  let config = loadProjectConfig(projectDir);
37017
- const hasConfig = existsSync37(projectConfigPath(projectDir));
37018
- if (!hasConfig && existsSync37(resolve23(projectDir, "index.html"))) {
37264
+ const hasConfig = existsSync38(projectConfigPath(projectDir));
37265
+ if (!hasConfig && existsSync38(resolve23(projectDir, "index.html"))) {
37019
37266
  writeProjectConfig(projectDir, DEFAULT_PROJECT_CONFIG);
37020
37267
  config = DEFAULT_PROJECT_CONFIG;
37021
37268
  }
@@ -37114,10 +37361,10 @@ var init_add = __esm({
37114
37361
  const projectDir = resolve23(args.dir ?? process.cwd());
37115
37362
  const json = args.json === true;
37116
37363
  const skipClipboard = args["no-clipboard"] === true;
37117
- const hasConfigBefore = existsSync37(projectConfigPath(projectDir));
37364
+ const hasConfigBefore = existsSync38(projectConfigPath(projectDir));
37118
37365
  try {
37119
37366
  const result = await runAdd({ name: args.name, projectDir, skipClipboard });
37120
- const wroteConfig = !hasConfigBefore && existsSync37(projectConfigPath(projectDir));
37367
+ const wroteConfig = !hasConfigBefore && existsSync38(projectConfigPath(projectDir));
37121
37368
  if (json) {
37122
37369
  console.log(JSON.stringify(result));
37123
37370
  return;
@@ -37327,17 +37574,17 @@ var init_format = __esm({
37327
37574
  });
37328
37575
 
37329
37576
  // src/utils/project.ts
37330
- import { existsSync as existsSync38, statSync as statSync13 } from "fs";
37577
+ import { existsSync as existsSync39, statSync as statSync15 } from "fs";
37331
37578
  import { resolve as resolve25, basename as basename6 } from "path";
37332
37579
  function resolveProject(dirArg) {
37333
37580
  const dir = resolve25(dirArg ?? ".");
37334
37581
  const name = basename6(dir);
37335
37582
  const indexPath = resolve25(dir, "index.html");
37336
- if (!existsSync38(dir) || !statSync13(dir).isDirectory()) {
37583
+ if (!existsSync39(dir) || !statSync15(dir).isDirectory()) {
37337
37584
  errorBox("Not a directory: " + dir);
37338
37585
  process.exit(1);
37339
37586
  }
37340
- if (!existsSync38(indexPath)) {
37587
+ if (!existsSync39(indexPath)) {
37341
37588
  errorBox(
37342
37589
  "No composition found in " + dir,
37343
37590
  "No index.html file found.",
@@ -37360,7 +37607,7 @@ __export(play_exports, {
37360
37607
  default: () => play_default,
37361
37608
  examples: () => examples5
37362
37609
  });
37363
- import { existsSync as existsSync39, readFileSync as readFileSync26 } from "fs";
37610
+ import { existsSync as existsSync40, readFileSync as readFileSync26 } from "fs";
37364
37611
  import { resolve as resolve26, dirname as dirname15 } from "path";
37365
37612
  function commandDir() {
37366
37613
  return dirname15(new URL(import.meta.url).pathname);
@@ -37375,7 +37622,7 @@ function resolveRuntimePath2() {
37375
37622
  resolve26(d, "..", "..", "..", "core", "dist", "hyperframe.runtime.iife.js")
37376
37623
  ];
37377
37624
  for (const p of candidates) {
37378
- if (existsSync39(p)) return p;
37625
+ if (existsSync40(p)) return p;
37379
37626
  }
37380
37627
  return null;
37381
37628
  }
@@ -37389,7 +37636,7 @@ function resolvePlayerPath() {
37389
37636
  resolve26(d, "..", "hyperframes-player.global.js")
37390
37637
  ];
37391
37638
  for (const p of candidates) {
37392
- if (existsSync39(p)) return p;
37639
+ if (existsSync40(p)) return p;
37393
37640
  }
37394
37641
  return null;
37395
37642
  }
@@ -37491,7 +37738,7 @@ var init_play = __esm({
37491
37738
  const reqPath = ctx.req.path.replace("/composition/", "");
37492
37739
  const filePath = resolve26(project.dir, reqPath);
37493
37740
  if (!filePath.startsWith(project.dir)) return ctx.text("Forbidden", 403);
37494
- if (!existsSync39(filePath)) return ctx.text("Not found", 404);
37741
+ if (!existsSync40(filePath)) return ctx.text("Not found", 404);
37495
37742
  const content = readFileSync26(filePath, "utf-8");
37496
37743
  if (filePath.endsWith(".html")) {
37497
37744
  const injected = injectRuntime(content);
@@ -37567,23 +37814,23 @@ var init_play = __esm({
37567
37814
  });
37568
37815
 
37569
37816
  // src/utils/publishProject.ts
37570
- import { basename as basename7, join as join39, relative as relative4 } from "path";
37571
- import { readdirSync as readdirSync15, readFileSync as readFileSync27, statSync as statSync14 } from "fs";
37817
+ import { basename as basename7, join as join40, relative as relative4 } from "path";
37818
+ import { readdirSync as readdirSync16, readFileSync as readFileSync27, statSync as statSync16 } from "fs";
37572
37819
  import AdmZip from "adm-zip";
37573
37820
  function shouldIgnoreSegment(segment) {
37574
37821
  return segment.startsWith(".") || IGNORED_DIRS.has(segment) || IGNORED_FILES.has(segment);
37575
37822
  }
37576
37823
  function collectProjectFiles(rootDir, currentDir, paths) {
37577
- for (const entry of readdirSync15(currentDir, { withFileTypes: true })) {
37824
+ for (const entry of readdirSync16(currentDir, { withFileTypes: true })) {
37578
37825
  if (shouldIgnoreSegment(entry.name)) continue;
37579
- const absolutePath = join39(currentDir, entry.name);
37826
+ const absolutePath = join40(currentDir, entry.name);
37580
37827
  const relativePath = relative4(rootDir, absolutePath).replaceAll("\\", "/");
37581
37828
  if (!relativePath) continue;
37582
37829
  if (entry.isDirectory()) {
37583
37830
  collectProjectFiles(rootDir, absolutePath, paths);
37584
37831
  continue;
37585
37832
  }
37586
- if (!statSync14(absolutePath).isFile()) continue;
37833
+ if (!statSync16(absolutePath).isFile()) continue;
37587
37834
  paths.push(relativePath);
37588
37835
  }
37589
37836
  }
@@ -37595,7 +37842,7 @@ function createPublishArchive(projectDir) {
37595
37842
  }
37596
37843
  const archive = new AdmZip();
37597
37844
  for (const filePath of filePaths) {
37598
- archive.addFile(filePath, readFileSync27(join39(projectDir, filePath)));
37845
+ archive.addFile(filePath, readFileSync27(join40(projectDir, filePath)));
37599
37846
  }
37600
37847
  return {
37601
37848
  buffer: archive.toBuffer(),
@@ -37651,8 +37898,8 @@ __export(publish_exports, {
37651
37898
  examples: () => examples6
37652
37899
  });
37653
37900
  import { basename as basename8, resolve as resolve27 } from "path";
37654
- import { existsSync as existsSync40 } from "fs";
37655
- import { join as join40 } from "path";
37901
+ import { existsSync as existsSync41 } from "fs";
37902
+ import { join as join41 } from "path";
37656
37903
  var examples6, publish_default;
37657
37904
  var init_publish = __esm({
37658
37905
  "src/commands/publish.ts"() {
@@ -37687,8 +37934,8 @@ var init_publish = __esm({
37687
37934
  const dir = resolve27(rawArg ?? ".");
37688
37935
  const isImplicitCwd = !rawArg || rawArg === "." || rawArg === "./";
37689
37936
  const projectName = isImplicitCwd ? basename8(process.env["PWD"] ?? dir) : basename8(dir);
37690
- const indexPath = join40(dir, "index.html");
37691
- if (existsSync40(indexPath)) {
37937
+ const indexPath = join41(dir, "index.html");
37938
+ if (existsSync41(indexPath)) {
37692
37939
  const lintResult = lintProject({ dir, name: projectName, indexPath });
37693
37940
  if (lintResult.totalErrors > 0 || lintResult.totalWarnings > 0) {
37694
37941
  console.log();
@@ -37859,10 +38106,10 @@ __export(render_exports, {
37859
38106
  default: () => render_default,
37860
38107
  examples: () => examples7
37861
38108
  });
37862
- import { mkdirSync as mkdirSync22, readFileSync as readFileSync28, statSync as statSync15, writeFileSync as writeFileSync16, rmSync as rmSync9 } from "fs";
38109
+ import { mkdirSync as mkdirSync22, readFileSync as readFileSync28, statSync as statSync17, writeFileSync as writeFileSync16, rmSync as rmSync9 } from "fs";
37863
38110
  import { cpus as cpus3, freemem as freemem3, tmpdir as tmpdir4 } from "os";
37864
- import { resolve as resolve28, dirname as dirname16, join as join41, basename as basename9 } from "path";
37865
- import { execFileSync as execFileSync5, spawn as spawn10 } from "child_process";
38111
+ import { resolve as resolve28, dirname as dirname16, join as join42, basename as basename9 } from "path";
38112
+ import { execFileSync as execFileSync6, spawn as spawn10 } from "child_process";
37866
38113
  function defaultWorkerCount() {
37867
38114
  return Math.max(1, Math.min(Math.floor(CPU_CORE_COUNT * 3 / 4), 8));
37868
38115
  }
@@ -37874,7 +38121,7 @@ function resolveDockerfilePath() {
37874
38121
  const devPath = resolve28(__dirname, "..", "src", "docker", "Dockerfile.render");
37875
38122
  for (const p of [builtPath, devPath]) {
37876
38123
  try {
37877
- statSync15(p);
38124
+ statSync17(p);
37878
38125
  return p;
37879
38126
  } catch {
37880
38127
  continue;
@@ -37884,7 +38131,7 @@ function resolveDockerfilePath() {
37884
38131
  }
37885
38132
  function dockerImageExists(tag) {
37886
38133
  try {
37887
- execFileSync5("docker", ["image", "inspect", tag], { stdio: "pipe", timeout: 1e4 });
38134
+ execFileSync6("docker", ["image", "inspect", tag], { stdio: "pipe", timeout: 1e4 });
37888
38135
  return true;
37889
38136
  } catch {
37890
38137
  return false;
@@ -37898,11 +38145,11 @@ function ensureDockerImage(version, quiet) {
37898
38145
  }
37899
38146
  if (!quiet) console.log(c.dim(` Building Docker image: ${tag}...`));
37900
38147
  const dockerfilePath = resolveDockerfilePath();
37901
- const tmpDir = join41(tmpdir4(), `hyperframes-docker-${Date.now()}`);
38148
+ const tmpDir = join42(tmpdir4(), `hyperframes-docker-${Date.now()}`);
37902
38149
  mkdirSync22(tmpDir, { recursive: true });
37903
- writeFileSync16(join41(tmpDir, "Dockerfile"), readFileSync28(dockerfilePath));
38150
+ writeFileSync16(join42(tmpDir, "Dockerfile"), readFileSync28(dockerfilePath));
37904
38151
  try {
37905
- execFileSync5(
38152
+ execFileSync6(
37906
38153
  "docker",
37907
38154
  [
37908
38155
  "build",
@@ -38087,7 +38334,7 @@ function printRenderComplete(outputPath, elapsedMs, quiet) {
38087
38334
  if (quiet) return;
38088
38335
  let fileSize = "unknown";
38089
38336
  try {
38090
- fileSize = formatBytes(statSync15(outputPath).size);
38337
+ fileSize = formatBytes(statSync17(outputPath).size);
38091
38338
  } catch {
38092
38339
  }
38093
38340
  const duration = formatDuration(elapsedMs);
@@ -38248,7 +38495,7 @@ var init_render2 = __esm({
38248
38495
  const now = /* @__PURE__ */ new Date();
38249
38496
  const datePart = now.toISOString().slice(0, 10);
38250
38497
  const timePart = now.toTimeString().slice(0, 8).replace(/:/g, "-");
38251
- const outputPath = args.output ? resolve28(args.output) : join41(rendersDir, `${project.name}_${datePart}_${timePart}${ext}`);
38498
+ const outputPath = args.output ? resolve28(args.output) : join42(rendersDir, `${project.name}_${datePart}_${timePart}${ext}`);
38252
38499
  mkdirSync22(dirname16(outputPath), { recursive: true });
38253
38500
  const useDocker = args.docker ?? false;
38254
38501
  const useGpu = args.gpu ?? false;
@@ -38724,8 +38971,8 @@ __export(layout_exports, {
38724
38971
  examples: () => examples9
38725
38972
  });
38726
38973
  import { createServer } from "http";
38727
- import { existsSync as existsSync41, readFileSync as readFileSync29 } from "fs";
38728
- import { dirname as dirname17, isAbsolute as isAbsolute6, join as join42, relative as relative5, resolve as resolve29 } from "path";
38974
+ import { existsSync as existsSync42, readFileSync as readFileSync29 } from "fs";
38975
+ import { dirname as dirname17, isAbsolute as isAbsolute6, join as join43, relative as relative5, resolve as resolve29 } from "path";
38729
38976
  import { fileURLToPath as fileURLToPath6 } from "url";
38730
38977
  async function getCompositionDuration2(page) {
38731
38978
  return page.evaluate(() => {
@@ -38795,7 +39042,7 @@ async function bundleProjectHtml(projectDir) {
38795
39042
  "dist",
38796
39043
  "hyperframe.runtime.iife.js"
38797
39044
  );
38798
- if (existsSync41(runtimePath)) {
39045
+ if (existsSync42(runtimePath)) {
38799
39046
  const runtimeSource = readFileSync29(runtimePath, "utf-8");
38800
39047
  html = html.replace(
38801
39048
  /<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
@@ -38820,7 +39067,7 @@ async function serveProject(projectDir, html) {
38820
39067
  res.end();
38821
39068
  return;
38822
39069
  }
38823
- if (existsSync41(filePath)) {
39070
+ if (existsSync42(filePath)) {
38824
39071
  res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
38825
39072
  res.end(readFileSync29(filePath));
38826
39073
  return;
@@ -38924,11 +39171,11 @@ async function runLayoutAudit(projectDir, opts) {
38924
39171
  }
38925
39172
  function loadLayoutAuditScript() {
38926
39173
  const candidates = [
38927
- join42(__dirname2, "layout-audit.browser.js"),
38928
- join42(__dirname2, "commands", "layout-audit.browser.js")
39174
+ join43(__dirname2, "layout-audit.browser.js"),
39175
+ join43(__dirname2, "commands", "layout-audit.browser.js")
38929
39176
  ];
38930
39177
  for (const candidate of candidates) {
38931
- if (existsSync41(candidate)) return readFileSync29(candidate, "utf-8");
39178
+ if (existsSync42(candidate)) return readFileSync29(candidate, "utf-8");
38932
39179
  }
38933
39180
  throw new Error("Missing layout audit browser script");
38934
39181
  }
@@ -39148,16 +39395,16 @@ __export(info_exports, {
39148
39395
  default: () => info_default,
39149
39396
  examples: () => examples11
39150
39397
  });
39151
- import { readFileSync as readFileSync30, readdirSync as readdirSync16, statSync as statSync16 } from "fs";
39152
- import { join as join43 } from "path";
39398
+ import { readFileSync as readFileSync30, readdirSync as readdirSync17, statSync as statSync18 } from "fs";
39399
+ import { join as join44 } from "path";
39153
39400
  function totalSize(dir) {
39154
39401
  let total = 0;
39155
- for (const entry of readdirSync16(dir, { withFileTypes: true })) {
39156
- const path2 = join43(dir, entry.name);
39402
+ for (const entry of readdirSync17(dir, { withFileTypes: true })) {
39403
+ const path2 = join44(dir, entry.name);
39157
39404
  if (entry.isDirectory()) {
39158
39405
  total += totalSize(path2);
39159
39406
  } else {
39160
- total += statSync16(path2).size;
39407
+ total += statSync18(path2).size;
39161
39408
  }
39162
39409
  }
39163
39410
  return total;
@@ -39241,7 +39488,7 @@ __export(compositions_exports, {
39241
39488
  default: () => compositions_default,
39242
39489
  examples: () => examples12
39243
39490
  });
39244
- import { existsSync as existsSync42, readFileSync as readFileSync31 } from "fs";
39491
+ import { existsSync as existsSync43, readFileSync as readFileSync31 } from "fs";
39245
39492
  import { resolve as resolve30, dirname as dirname18 } from "path";
39246
39493
  function parseCompositions(html, baseDir) {
39247
39494
  const parser = new DOMParser();
@@ -39255,7 +39502,7 @@ function parseCompositions(html, baseDir) {
39255
39502
  const compositionSrc = div.getAttribute("data-composition-src");
39256
39503
  if (compositionSrc) {
39257
39504
  const subPath = resolve30(baseDir, compositionSrc);
39258
- if (existsSync42(subPath)) {
39505
+ if (existsSync43(subPath)) {
39259
39506
  const subHtml = readFileSync31(subPath, "utf-8");
39260
39507
  const subInfo = parseSubComposition(subHtml, id, width, height);
39261
39508
  compositions.push({ ...subInfo, source: compositionSrc });
@@ -39388,8 +39635,8 @@ __export(benchmark_exports, {
39388
39635
  default: () => benchmark_default,
39389
39636
  examples: () => examples13
39390
39637
  });
39391
- import { existsSync as existsSync43, statSync as statSync17 } from "fs";
39392
- import { resolve as resolve31, join as join44 } from "path";
39638
+ import { existsSync as existsSync44, statSync as statSync19 } from "fs";
39639
+ import { resolve as resolve31, join as join45 } from "path";
39393
39640
  var examples13, DEFAULT_CONFIGS, benchmark_default;
39394
39641
  var init_benchmark = __esm({
39395
39642
  "src/commands/benchmark.ts"() {
@@ -39464,7 +39711,7 @@ var init_benchmark = __esm({
39464
39711
  s2?.start(`Benchmarking ${config.label}...`);
39465
39712
  for (let i2 = 0; i2 < runsPerConfig; i2++) {
39466
39713
  s2?.message(`${config.label} \u2014 run ${i2 + 1}/${runsPerConfig}`);
39467
- const outputPath = join44(
39714
+ const outputPath = join45(
39468
39715
  benchDir,
39469
39716
  `${config.label.replace(/[^a-zA-Z0-9]/g, "_")}_run${i2}.mp4`
39470
39717
  );
@@ -39478,8 +39725,8 @@ var init_benchmark = __esm({
39478
39725
  await producer.executeRenderJob(job, project.dir, outputPath);
39479
39726
  const elapsedMs = Date.now() - startTime;
39480
39727
  let fileSize = null;
39481
- if (existsSync43(outputPath)) {
39482
- const stat3 = statSync17(outputPath);
39728
+ if (existsSync44(outputPath)) {
39729
+ const stat3 = statSync19(outputPath);
39483
39730
  fileSize = stat3.size;
39484
39731
  }
39485
39732
  runs.push({ elapsedMs, fileSize });
@@ -39694,8 +39941,8 @@ __export(transcribe_exports2, {
39694
39941
  default: () => transcribe_default,
39695
39942
  examples: () => examples15
39696
39943
  });
39697
- import { existsSync as existsSync44, writeFileSync as writeFileSync17 } from "fs";
39698
- import { resolve as resolve32, join as join45, extname as extname8 } from "path";
39944
+ import { existsSync as existsSync45, writeFileSync as writeFileSync17 } from "fs";
39945
+ import { resolve as resolve32, join as join46, extname as extname8 } from "path";
39699
39946
  async function importTranscript(inputPath, dir, json) {
39700
39947
  const { loadTranscript: loadTranscript2, patchCaptionHtml: patchCaptionHtml2 } = await Promise.resolve().then(() => (init_normalize(), normalize_exports));
39701
39948
  const { words, format } = loadTranscript2(inputPath);
@@ -39703,7 +39950,7 @@ async function importTranscript(inputPath, dir, json) {
39703
39950
  console.error(c.error("No words found in transcript."));
39704
39951
  process.exit(1);
39705
39952
  }
39706
- const outPath = join45(dir, "transcript.json");
39953
+ const outPath = join46(dir, "transcript.json");
39707
39954
  writeFileSync17(outPath, JSON.stringify(words, null, 2));
39708
39955
  patchCaptionHtml2(dir, words);
39709
39956
  if (json) {
@@ -39820,7 +40067,7 @@ var init_transcribe2 = __esm({
39820
40067
  },
39821
40068
  async run({ args }) {
39822
40069
  const inputPath = resolve32(args.input);
39823
- if (!existsSync44(inputPath)) {
40070
+ if (!existsSync45(inputPath)) {
39824
40071
  console.error(c.error(`File not found: ${args.input}`));
39825
40072
  process.exit(1);
39826
40073
  }
@@ -39841,9 +40088,9 @@ var init_transcribe2 = __esm({
39841
40088
  });
39842
40089
 
39843
40090
  // src/tts/manager.ts
39844
- import { existsSync as existsSync45, mkdirSync as mkdirSync23 } from "fs";
39845
- import { homedir as homedir8 } from "os";
39846
- import { join as join46 } from "path";
40091
+ import { existsSync as existsSync46, mkdirSync as mkdirSync23 } from "fs";
40092
+ import { homedir as homedir9 } from "os";
40093
+ import { join as join47 } from "path";
39847
40094
  function inferLangFromVoiceId(voiceId) {
39848
40095
  const first = voiceId.charAt(0).toLowerCase();
39849
40096
  return VOICE_PREFIX_LANG[first] ?? "en-us";
@@ -39852,8 +40099,8 @@ function isSupportedLang(value) {
39852
40099
  return SUPPORTED_LANGS.includes(value);
39853
40100
  }
39854
40101
  async function ensureModel2(model = DEFAULT_MODEL2, options) {
39855
- const modelPath = join46(MODELS_DIR2, `${model}.onnx`);
39856
- if (existsSync45(modelPath)) return modelPath;
40102
+ const modelPath = join47(MODELS_DIR2, `${model}.onnx`);
40103
+ if (existsSync46(modelPath)) return modelPath;
39857
40104
  const url = MODEL_URLS[model];
39858
40105
  if (!url) {
39859
40106
  throw new Error(
@@ -39863,18 +40110,18 @@ async function ensureModel2(model = DEFAULT_MODEL2, options) {
39863
40110
  mkdirSync23(MODELS_DIR2, { recursive: true });
39864
40111
  options?.onProgress?.(`Downloading TTS model ${model} (~311 MB)...`);
39865
40112
  await downloadFile(url, modelPath);
39866
- if (!existsSync45(modelPath)) {
40113
+ if (!existsSync46(modelPath)) {
39867
40114
  throw new Error(`Model download failed: ${model}`);
39868
40115
  }
39869
40116
  return modelPath;
39870
40117
  }
39871
40118
  async function ensureVoices(options) {
39872
- const voicesPath = join46(VOICES_DIR, "voices-v1.0.bin");
39873
- if (existsSync45(voicesPath)) return voicesPath;
40119
+ const voicesPath = join47(VOICES_DIR, "voices-v1.0.bin");
40120
+ if (existsSync46(voicesPath)) return voicesPath;
39874
40121
  mkdirSync23(VOICES_DIR, { recursive: true });
39875
40122
  options?.onProgress?.("Downloading voice data (~27 MB)...");
39876
40123
  await downloadFile(VOICES_URL, voicesPath);
39877
- if (!existsSync45(voicesPath)) {
40124
+ if (!existsSync46(voicesPath)) {
39878
40125
  throw new Error("Voice data download failed");
39879
40126
  }
39880
40127
  return voicesPath;
@@ -39884,9 +40131,9 @@ var init_manager3 = __esm({
39884
40131
  "src/tts/manager.ts"() {
39885
40132
  "use strict";
39886
40133
  init_download();
39887
- CACHE_DIR3 = join46(homedir8(), ".cache", "hyperframes", "tts");
39888
- MODELS_DIR2 = join46(CACHE_DIR3, "models");
39889
- VOICES_DIR = join46(CACHE_DIR3, "voices");
40134
+ CACHE_DIR3 = join47(homedir9(), ".cache", "hyperframes", "tts");
40135
+ MODELS_DIR2 = join47(CACHE_DIR3, "models");
40136
+ VOICES_DIR = join47(CACHE_DIR3, "voices");
39890
40137
  DEFAULT_MODEL2 = "kokoro-v1.0";
39891
40138
  MODEL_URLS = {
39892
40139
  "kokoro-v1.0": "https://github.com/thewh1teagle/kokoro-onnx/releases/download/model-files-v1.0/kokoro-v1.0.onnx"
@@ -39946,22 +40193,22 @@ var synthesize_exports = {};
39946
40193
  __export(synthesize_exports, {
39947
40194
  synthesize: () => synthesize
39948
40195
  });
39949
- import { execFileSync as execFileSync6 } from "child_process";
39950
- import { existsSync as existsSync46, writeFileSync as writeFileSync18, mkdirSync as mkdirSync24, readdirSync as readdirSync17, unlinkSync as unlinkSync6 } from "fs";
39951
- import { join as join47, dirname as dirname19, basename as basename10 } from "path";
39952
- import { homedir as homedir9 } from "os";
40196
+ import { execFileSync as execFileSync7 } from "child_process";
40197
+ import { existsSync as existsSync47, writeFileSync as writeFileSync18, mkdirSync as mkdirSync24, readdirSync as readdirSync18, unlinkSync as unlinkSync6 } from "fs";
40198
+ import { join as join48, dirname as dirname19, basename as basename10 } from "path";
40199
+ import { homedir as homedir10 } from "os";
39953
40200
  function findPython() {
39954
40201
  for (const name of ["python3", "python"]) {
39955
40202
  try {
39956
40203
  const cmd = process.platform === "win32" ? "where" : "which";
39957
- const output = execFileSync6(cmd, [name], {
40204
+ const output = execFileSync7(cmd, [name], {
39958
40205
  encoding: "utf-8",
39959
40206
  stdio: ["pipe", "pipe", "pipe"],
39960
40207
  timeout: 5e3
39961
40208
  });
39962
40209
  const first = output.split(/\r?\n/).map((s2) => s2.trim()).find(Boolean);
39963
40210
  if (!first) continue;
39964
- const version = execFileSync6(first, ["--version"], {
40211
+ const version = execFileSync7(first, ["--version"], {
39965
40212
  encoding: "utf-8",
39966
40213
  stdio: ["pipe", "pipe", "pipe"],
39967
40214
  timeout: 5e3
@@ -39974,7 +40221,7 @@ function findPython() {
39974
40221
  }
39975
40222
  function hasPythonPackage(python, pkg) {
39976
40223
  try {
39977
- execFileSync6(python, ["-c", `import ${pkg}`], {
40224
+ execFileSync7(python, ["-c", `import ${pkg}`], {
39978
40225
  stdio: ["pipe", "pipe", "pipe"],
39979
40226
  timeout: 1e4
39980
40227
  });
@@ -39984,15 +40231,15 @@ function hasPythonPackage(python, pkg) {
39984
40231
  }
39985
40232
  }
39986
40233
  function ensureSynthScript() {
39987
- if (!existsSync46(SCRIPT_PATH)) {
40234
+ if (!existsSync47(SCRIPT_PATH)) {
39988
40235
  mkdirSync24(SCRIPT_DIR, { recursive: true });
39989
40236
  writeFileSync18(SCRIPT_PATH, SYNTH_SCRIPT);
39990
40237
  const currentName = basename10(SCRIPT_PATH);
39991
40238
  try {
39992
- for (const entry of readdirSync17(SCRIPT_DIR)) {
40239
+ for (const entry of readdirSync18(SCRIPT_DIR)) {
39993
40240
  if (entry !== currentName && /^synth(-v\d+)?\.py$/.test(entry)) {
39994
40241
  try {
39995
- unlinkSync6(join47(SCRIPT_DIR, entry));
40242
+ unlinkSync6(join48(SCRIPT_DIR, entry));
39996
40243
  } catch {
39997
40244
  }
39998
40245
  }
@@ -40029,7 +40276,7 @@ async function synthesize(text, outputPath, options) {
40029
40276
  mkdirSync24(dirname19(outputPath), { recursive: true });
40030
40277
  options?.onProgress?.(`Generating speech with voice ${voice} (${lang})...`);
40031
40278
  try {
40032
- const stdout2 = execFileSync6(
40279
+ const stdout2 = execFileSync7(
40033
40280
  python,
40034
40281
  [scriptPath, modelPath, voicesPath, text, voice, String(speed), outputPath, lang],
40035
40282
  {
@@ -40038,7 +40285,7 @@ async function synthesize(text, outputPath, options) {
40038
40285
  stdio: ["pipe", "pipe", "pipe"]
40039
40286
  }
40040
40287
  );
40041
- if (!existsSync46(outputPath)) {
40288
+ if (!existsSync47(outputPath)) {
40042
40289
  throw new Error("Synthesis completed but no output file was created");
40043
40290
  }
40044
40291
  const lines = stdout2.trim().split("\n");
@@ -40051,7 +40298,7 @@ async function synthesize(text, outputPath, options) {
40051
40298
  langApplied: result.langApplied
40052
40299
  };
40053
40300
  } catch (err) {
40054
- if (err instanceof SyntaxError && existsSync46(outputPath)) {
40301
+ if (err instanceof SyntaxError && existsSync47(outputPath)) {
40055
40302
  throw new Error(
40056
40303
  "Speech was generated but metadata could not be read. Check the output file manually."
40057
40304
  );
@@ -40102,8 +40349,8 @@ print(json.dumps({
40102
40349
  "langApplied": bool(lang and supports_lang),
40103
40350
  }))
40104
40351
  `;
40105
- SCRIPT_DIR = join47(homedir9(), ".cache", "hyperframes", "tts");
40106
- SCRIPT_PATH = join47(SCRIPT_DIR, "synth-v2.py");
40352
+ SCRIPT_DIR = join48(homedir10(), ".cache", "hyperframes", "tts");
40353
+ SCRIPT_PATH = join48(SCRIPT_DIR, "synth-v2.py");
40107
40354
  }
40108
40355
  });
40109
40356
 
@@ -40113,7 +40360,7 @@ __export(tts_exports, {
40113
40360
  default: () => tts_default,
40114
40361
  examples: () => examples16
40115
40362
  });
40116
- import { existsSync as existsSync47, readFileSync as readFileSync32 } from "fs";
40363
+ import { existsSync as existsSync48, readFileSync as readFileSync32 } from "fs";
40117
40364
  import { resolve as resolve33, extname as extname9 } from "path";
40118
40365
  function listVoices(json) {
40119
40366
  const rows = BUNDLED_VOICES.map((v) => ({ ...v, defaultLang: inferLangFromVoiceId(v.id) }));
@@ -40223,7 +40470,7 @@ var init_tts = __esm({
40223
40470
  }
40224
40471
  let text;
40225
40472
  const maybeFile = resolve33(args.input);
40226
- if (existsSync47(maybeFile) && extname9(maybeFile).toLowerCase() === ".txt") {
40473
+ if (existsSync48(maybeFile) && extname9(maybeFile).toLowerCase() === ".txt") {
40227
40474
  text = readFileSync32(maybeFile, "utf-8").trim();
40228
40475
  if (!text) {
40229
40476
  console.error(c.error("File is empty."));
@@ -40316,15 +40563,15 @@ __export(docs_exports, {
40316
40563
  default: () => docs_default,
40317
40564
  examples: () => examples17
40318
40565
  });
40319
- import { readFileSync as readFileSync33, existsSync as existsSync48 } from "fs";
40320
- import { resolve as resolve34, dirname as dirname20, join as join48 } from "path";
40566
+ import { readFileSync as readFileSync33, existsSync as existsSync49 } from "fs";
40567
+ import { resolve as resolve34, dirname as dirname20, join as join49 } from "path";
40321
40568
  import { fileURLToPath as fileURLToPath7 } from "url";
40322
40569
  function docsDir() {
40323
40570
  const thisFile = fileURLToPath7(import.meta.url);
40324
40571
  const dir = dirname20(thisFile);
40325
40572
  const devPath = resolve34(dir, "..", "docs");
40326
40573
  const builtPath = resolve34(dir, "docs");
40327
- return existsSync48(devPath) ? devPath : builtPath;
40574
+ return existsSync49(devPath) ? devPath : builtPath;
40328
40575
  }
40329
40576
  function formatInlineCode(line) {
40330
40577
  return line.replace(/`([^`]+)`/g, (_match, code) => c.accent(code));
@@ -40421,8 +40668,8 @@ var init_docs = __esm({
40421
40668
  }
40422
40669
  process.exit(1);
40423
40670
  }
40424
- const filePath = join48(docsDir(), entry.file);
40425
- if (!existsSync48(filePath)) {
40671
+ const filePath = join49(docsDir(), entry.file);
40672
+ if (!existsSync49(filePath)) {
40426
40673
  console.error(c.error(`Doc file not found: ${filePath}`));
40427
40674
  process.exit(1);
40428
40675
  }
@@ -40441,7 +40688,7 @@ __export(doctor_exports, {
40441
40688
  examples: () => examples18
40442
40689
  });
40443
40690
  import { execSync as execSync3 } from "child_process";
40444
- import { freemem as freemem4, platform as platform4 } from "os";
40691
+ import { freemem as freemem4, platform as platform5 } from "os";
40445
40692
  function checkFFmpeg() {
40446
40693
  const path2 = findFFmpeg();
40447
40694
  if (path2) {
@@ -40606,7 +40853,7 @@ var init_doctor = __esm({
40606
40853
  { name: "Memory", run: checkMemory },
40607
40854
  { name: "Disk", run: checkDisk }
40608
40855
  ];
40609
- if (platform4() === "linux") {
40856
+ if (platform5() === "linux") {
40610
40857
  checks.push({ name: "/dev/shm", run: checkShm });
40611
40858
  }
40612
40859
  checks.push(
@@ -40852,8 +41099,8 @@ var validate_exports = {};
40852
41099
  __export(validate_exports, {
40853
41100
  default: () => validate_default
40854
41101
  });
40855
- import { existsSync as existsSync49, readFileSync as readFileSync34 } from "fs";
40856
- import { resolve as resolve35, join as join49, dirname as dirname21 } from "path";
41102
+ import { existsSync as existsSync50, readFileSync as readFileSync34 } from "fs";
41103
+ import { resolve as resolve35, join as join50, dirname as dirname21 } from "path";
40857
41104
  import { fileURLToPath as fileURLToPath8 } from "url";
40858
41105
  async function getCompositionDuration3(page) {
40859
41106
  return page.evaluate(() => {
@@ -40908,7 +41155,7 @@ async function validateInBrowser(projectDir, opts) {
40908
41155
  "dist",
40909
41156
  "hyperframe.runtime.iife.js"
40910
41157
  );
40911
- if (existsSync49(runtimePath)) {
41158
+ if (existsSync50(runtimePath)) {
40912
41159
  const runtimeSource = readFileSync34(runtimePath, "utf-8");
40913
41160
  html = html.replace(
40914
41161
  /<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
@@ -40924,8 +41171,8 @@ async function validateInBrowser(projectDir, opts) {
40924
41171
  res.end(html);
40925
41172
  return;
40926
41173
  }
40927
- const filePath = join49(projectDir, decodeURIComponent(url));
40928
- if (existsSync49(filePath)) {
41174
+ const filePath = join50(projectDir, decodeURIComponent(url));
41175
+ if (existsSync50(filePath)) {
40929
41176
  res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
40930
41177
  res.end(readFileSync34(filePath));
40931
41178
  return;
@@ -41118,13 +41365,13 @@ __export(snapshot_exports, {
41118
41365
  examples: () => examples21
41119
41366
  });
41120
41367
  import { spawn as spawn11 } from "child_process";
41121
- import { existsSync as existsSync50, mkdtempSync as mkdtempSync3, readFileSync as readFileSync35, mkdirSync as mkdirSync25, rmSync as rmSync10 } from "fs";
41368
+ import { existsSync as existsSync51, mkdtempSync as mkdtempSync3, readFileSync as readFileSync35, mkdirSync as mkdirSync25, rmSync as rmSync10 } from "fs";
41122
41369
  import { tmpdir as tmpdir5 } from "os";
41123
- import { resolve as resolve36, join as join50, dirname as dirname22, relative as relative6, isAbsolute as isAbsolute7 } from "path";
41370
+ import { resolve as resolve36, join as join51, dirname as dirname22, relative as relative6, isAbsolute as isAbsolute7 } from "path";
41124
41371
  import { fileURLToPath as fileURLToPath9 } from "url";
41125
41372
  async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDecoder = false) {
41126
- const tmp = mkdtempSync3(join50(tmpdir5(), "hf-snapshot-frame-"));
41127
- const outPath = join50(tmp, "frame.png");
41373
+ const tmp = mkdtempSync3(join51(tmpdir5(), "hf-snapshot-frame-"));
41374
+ const outPath = join51(tmp, "frame.png");
41128
41375
  try {
41129
41376
  const result = await new Promise(
41130
41377
  (resolvePromise) => {
@@ -41164,7 +41411,7 @@ async function extractVideoFrameToBuffer(videoPath, timeSeconds, useVp9AlphaDeco
41164
41411
  });
41165
41412
  }
41166
41413
  );
41167
- if (result.code !== 0 || result.timedOut || !existsSync50(outPath)) return null;
41414
+ if (result.code !== 0 || result.timedOut || !existsSync51(outPath)) return null;
41168
41415
  return readFileSync35(outPath);
41169
41416
  } finally {
41170
41417
  try {
@@ -41187,7 +41434,7 @@ async function captureSnapshots(projectDir, opts) {
41187
41434
  "dist",
41188
41435
  "hyperframe.runtime.iife.js"
41189
41436
  );
41190
- if (existsSync50(runtimePath)) {
41437
+ if (existsSync51(runtimePath)) {
41191
41438
  const runtimeSource = readFileSync35(runtimePath, "utf-8");
41192
41439
  html = html.replace(
41193
41440
  /<script[^>]*data-hyperframes-preview-runtime[^>]*src="[^"]*"[^>]*><\/script>/,
@@ -41210,7 +41457,7 @@ async function captureSnapshots(projectDir, opts) {
41210
41457
  res.end();
41211
41458
  return;
41212
41459
  }
41213
- if (existsSync50(filePath)) {
41460
+ if (existsSync51(filePath)) {
41214
41461
  res.writeHead(200, { "Content-Type": getMimeType2(filePath) });
41215
41462
  res.end(readFileSync35(filePath));
41216
41463
  return;
@@ -41285,7 +41532,7 @@ async function captureSnapshots(projectDir, opts) {
41285
41532
  return [];
41286
41533
  }
41287
41534
  const positions = opts.at?.length ? opts.at : numFrames === 1 ? [duration / 2] : Array.from({ length: numFrames }, (_2, i2) => i2 / (numFrames - 1) * duration);
41288
- const snapshotDir = join50(projectDir, "snapshots");
41535
+ const snapshotDir = join51(projectDir, "snapshots");
41289
41536
  mkdirSync25(snapshotDir, { recursive: true });
41290
41537
  let injectVideoFramesBatch2 = null;
41291
41538
  let syncVideoFrameVisibility2 = null;
@@ -41360,7 +41607,7 @@ async function captureSnapshots(projectDir, opts) {
41360
41607
  const decodedPath = decodeURIComponent(url.pathname).replace(/^\//, "");
41361
41608
  const candidate = resolve36(projectDir, decodedPath);
41362
41609
  const rel = relative6(projectDir, candidate);
41363
- if (!rel.startsWith("..") && !isAbsolute7(rel) && existsSync50(candidate)) {
41610
+ if (!rel.startsWith("..") && !isAbsolute7(rel) && existsSync51(candidate)) {
41364
41611
  filePath = candidate;
41365
41612
  }
41366
41613
  } catch {
@@ -41390,7 +41637,7 @@ async function captureSnapshots(projectDir, opts) {
41390
41637
  }
41391
41638
  const timeLabel = opts.at?.length ? `${time.toFixed(1)}s` : `${Math.round(time / duration * 100)}pct`;
41392
41639
  const filename = `frame-${String(i2).padStart(2, "0")}-at-${timeLabel}.png`;
41393
- const framePath = join50(snapshotDir, filename);
41640
+ const framePath = join51(snapshotDir, filename);
41394
41641
  await page.screenshot({ path: framePath, type: "png" });
41395
41642
  savedPaths.push(`snapshots/${filename}`);
41396
41643
  }
@@ -41476,13 +41723,13 @@ ${c.error("\u2717")} Snapshot failed: ${msg}`);
41476
41723
 
41477
41724
  // src/capture/assetDownloader.ts
41478
41725
  import { writeFileSync as writeFileSync19, mkdirSync as mkdirSync26 } from "fs";
41479
- import { join as join51, extname as extname10 } from "path";
41726
+ import { join as join52, extname as extname10 } from "path";
41480
41727
  async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks) {
41481
- const assetsDir = join51(outputDir, "assets");
41728
+ const assetsDir = join52(outputDir, "assets");
41482
41729
  mkdirSync26(assetsDir, { recursive: true });
41483
41730
  const assets = [];
41484
41731
  const downloadedUrls = /* @__PURE__ */ new Set();
41485
- mkdirSync26(join51(outputDir, "assets", "svgs"), { recursive: true });
41732
+ mkdirSync26(join52(outputDir, "assets", "svgs"), { recursive: true });
41486
41733
  for (let i2 = 0; i2 < tokens.svgs.length && i2 < 30; i2++) {
41487
41734
  const svg = tokens.svgs[i2];
41488
41735
  if (!svg.outerHTML || svg.outerHTML.length < 50) continue;
@@ -41490,7 +41737,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
41490
41737
  const name = label2 ? slugify(label2) + ".svg" : svg.isLogo ? `logo-${i2}.svg` : `icon-${i2}.svg`;
41491
41738
  const localPath = `assets/svgs/${name}`;
41492
41739
  try {
41493
- writeFileSync19(join51(outputDir, localPath), svg.outerHTML, "utf-8");
41740
+ writeFileSync19(join52(outputDir, localPath), svg.outerHTML, "utf-8");
41494
41741
  assets.push({ url: "", localPath, type: "svg" });
41495
41742
  } catch {
41496
41743
  }
@@ -41503,7 +41750,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
41503
41750
  const localPath = `assets/${name}`;
41504
41751
  const buffer = await fetchBuffer(icon.href);
41505
41752
  if (buffer) {
41506
- writeFileSync19(join51(outputDir, localPath), buffer);
41753
+ writeFileSync19(join52(outputDir, localPath), buffer);
41507
41754
  assets.push({ url: icon.href, localPath, type: "favicon" });
41508
41755
  break;
41509
41756
  }
@@ -41560,7 +41807,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
41560
41807
  const slug = isMeaningful ? slugify(rawName) : `${prefix}-${imgIdx}`;
41561
41808
  const name = `${slug}${ext}`;
41562
41809
  const localPath = `assets/${name}`;
41563
- writeFileSync19(join51(outputDir, localPath), buffer);
41810
+ writeFileSync19(join52(outputDir, localPath), buffer);
41564
41811
  assets.push({ url, localPath, type: "image" });
41565
41812
  imgIdx++;
41566
41813
  } catch {
@@ -41573,7 +41820,7 @@ async function downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks)
41573
41820
  const localPath = `assets/og-image${ext}`;
41574
41821
  const buffer = await fetchBuffer(tokens.ogImage);
41575
41822
  if (buffer && buffer.length > 5e3) {
41576
- writeFileSync19(join51(outputDir, localPath), buffer);
41823
+ writeFileSync19(join52(outputDir, localPath), buffer);
41577
41824
  assets.push({ url: tokens.ogImage, localPath, type: "image" });
41578
41825
  }
41579
41826
  } catch {
@@ -41596,7 +41843,7 @@ function normalizeUrl(u) {
41596
41843
  }
41597
41844
  }
41598
41845
  async function downloadAndRewriteFonts(css, outputDir) {
41599
- const assetsDir = join51(outputDir, "assets", "fonts");
41846
+ const assetsDir = join52(outputDir, "assets", "fonts");
41600
41847
  mkdirSync26(assetsDir, { recursive: true });
41601
41848
  const fontUrlRegex = /url\(['"]?(https?:\/\/[^'")\s]+\.(?:woff2?|ttf|otf)[^'")\s]*?)['"]?\)/g;
41602
41849
  const fontUrls = /* @__PURE__ */ new Set();
@@ -41632,7 +41879,7 @@ async function downloadAndRewriteFonts(css, outputDir) {
41632
41879
  try {
41633
41880
  const urlObj = new URL(fontUrl);
41634
41881
  const filename = urlObj.pathname.split("/").pop() || `font-${count}.woff2`;
41635
- const localPath = join51(assetsDir, filename);
41882
+ const localPath = join52(assetsDir, filename);
41636
41883
  const relativePath = `assets/fonts/${filename}`;
41637
41884
  const buffer = await fetchBuffer(fontUrl);
41638
41885
  if (buffer) {
@@ -42429,8 +42676,8 @@ var init_animationCataloger = __esm({
42429
42676
  });
42430
42677
 
42431
42678
  // src/capture/mediaCapture.ts
42432
- import { mkdirSync as mkdirSync27, writeFileSync as writeFileSync20, readdirSync as readdirSync18, readFileSync as readFileSync36, statSync as statSync18 } from "fs";
42433
- import { join as join52 } from "path";
42679
+ import { mkdirSync as mkdirSync27, writeFileSync as writeFileSync20, readdirSync as readdirSync19, readFileSync as readFileSync36, statSync as statSync20 } from "fs";
42680
+ import { join as join53 } from "path";
42434
42681
  async function saveLottieAnimations(discoveredLotties, lottieDir) {
42435
42682
  let savedCount = 0;
42436
42683
  const savedHashes = /* @__PURE__ */ new Set();
@@ -42463,7 +42710,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
42463
42710
  const hash2 = buf.toString("base64").slice(0, 100);
42464
42711
  if (savedHashes.has(hash2)) continue;
42465
42712
  savedHashes.add(hash2);
42466
- writeFileSync20(join52(lottieDir, `animation-${savedCount}.lottie`), buf);
42713
+ writeFileSync20(join53(lottieDir, `animation-${savedCount}.lottie`), buf);
42467
42714
  savedCount++;
42468
42715
  continue;
42469
42716
  }
@@ -42481,7 +42728,7 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
42481
42728
  } catch {
42482
42729
  continue;
42483
42730
  }
42484
- writeFileSync20(join52(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
42731
+ writeFileSync20(join53(lottieDir, `animation-${savedCount}.json`), jsonData, "utf-8");
42485
42732
  savedCount++;
42486
42733
  }
42487
42734
  } catch {
@@ -42491,22 +42738,22 @@ async function saveLottieAnimations(discoveredLotties, lottieDir) {
42491
42738
  }
42492
42739
  async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
42493
42740
  const manifest = [];
42494
- const previewDir = join52(lottieDir, "previews");
42741
+ const previewDir = join53(lottieDir, "previews");
42495
42742
  mkdirSync27(previewDir, { recursive: true });
42496
- for (const file of readdirSync18(lottieDir)) {
42743
+ for (const file of readdirSync19(lottieDir)) {
42497
42744
  if (!file.endsWith(".json")) continue;
42498
42745
  try {
42499
- const raw = JSON.parse(readFileSync36(join52(lottieDir, file), "utf-8"));
42746
+ const raw = JSON.parse(readFileSync36(join53(lottieDir, file), "utf-8"));
42500
42747
  const fr = raw.fr || 30;
42501
42748
  const dur = ((raw.op || 0) - (raw.ip || 0)) / fr;
42502
42749
  const previewName = file.replace(".json", "-preview.png");
42503
- const fileSize = statSync18(join52(lottieDir, file)).size;
42750
+ const fileSize = statSync20(join53(lottieDir, file)).size;
42504
42751
  if (fileSize > 2e6) continue;
42505
42752
  let previewPage;
42506
42753
  try {
42507
42754
  previewPage = await chromeBrowser.newPage();
42508
42755
  await previewPage.setViewport({ width: 400, height: 400 });
42509
- const animData = JSON.parse(readFileSync36(join52(lottieDir, file), "utf-8"));
42756
+ const animData = JSON.parse(readFileSync36(join53(lottieDir, file), "utf-8"));
42510
42757
  const midFrame = Math.floor(((raw.op || 0) - (raw.ip || 0)) * 0.3);
42511
42758
  await previewPage.setContent(
42512
42759
  `<!DOCTYPE html>
@@ -42536,7 +42783,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
42536
42783
  await previewPage.waitForFunction(() => window.__READY === true, { timeout: 5e3 }).catch(() => {
42537
42784
  });
42538
42785
  await previewPage.screenshot({
42539
- path: join52(previewDir, previewName),
42786
+ path: join53(previewDir, previewName),
42540
42787
  type: "png",
42541
42788
  omitBackground: true
42542
42789
  });
@@ -42560,7 +42807,7 @@ async function renderLottiePreviews(chromeBrowser, lottieDir, outputDir) {
42560
42807
  }
42561
42808
  if (manifest.length > 0) {
42562
42809
  writeFileSync20(
42563
- join52(outputDir, "extracted", "lottie-manifest.json"),
42810
+ join53(outputDir, "extracted", "lottie-manifest.json"),
42564
42811
  JSON.stringify(manifest, null, 2),
42565
42812
  "utf-8"
42566
42813
  );
@@ -42622,15 +42869,15 @@ async function captureVideoManifest(page, outputDir, progress) {
42622
42869
  return true;
42623
42870
  });
42624
42871
  if (uniqueVideos.length > 0) {
42625
- const videoManifestDir = join52(outputDir, "assets", "videos");
42872
+ const videoManifestDir = join53(outputDir, "assets", "videos");
42626
42873
  mkdirSync27(videoManifestDir, { recursive: true });
42627
- const previewDir = join52(videoManifestDir, "previews");
42874
+ const previewDir = join53(videoManifestDir, "previews");
42628
42875
  mkdirSync27(previewDir, { recursive: true });
42629
42876
  const videoManifest = [];
42630
42877
  for (let vi = 0; vi < uniqueVideos.length && vi < 20; vi++) {
42631
42878
  const v = uniqueVideos[vi];
42632
42879
  const previewName = `video-${vi}-preview.png`;
42633
- const previewPath = join52(previewDir, previewName);
42880
+ const previewPath = join53(previewDir, previewName);
42634
42881
  try {
42635
42882
  await page.evaluate(`window.scrollTo(0, ${Math.max(0, v.top - 100)})`);
42636
42883
  await new Promise((r2) => setTimeout(r2, 300));
@@ -42669,7 +42916,7 @@ async function captureVideoManifest(page, outputDir, progress) {
42669
42916
  }
42670
42917
  if (videoManifest.length > 0) {
42671
42918
  writeFileSync20(
42672
- join52(outputDir, "extracted", "video-manifest.json"),
42919
+ join53(outputDir, "extracted", "video-manifest.json"),
42673
42920
  JSON.stringify(videoManifest, null, 2),
42674
42921
  "utf-8"
42675
42922
  );
@@ -49623,7 +49870,7 @@ var require_node_domexception = __commonJS({
49623
49870
  });
49624
49871
 
49625
49872
  // ../../node_modules/.bun/fetch-blob@3.2.0/node_modules/fetch-blob/from.js
49626
- import { statSync as statSync19, createReadStream as createReadStream2, promises as fs2 } from "fs";
49873
+ import { statSync as statSync21, createReadStream as createReadStream2, promises as fs2 } from "fs";
49627
49874
  import { basename as basename11 } from "path";
49628
49875
  var import_node_domexception, stat, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
49629
49876
  var init_from = __esm({
@@ -49633,10 +49880,10 @@ var init_from = __esm({
49633
49880
  init_file();
49634
49881
  init_fetch_blob();
49635
49882
  ({ stat } = fs2);
49636
- blobFromSync = (path2, type) => fromBlob(statSync19(path2), path2, type);
49883
+ blobFromSync = (path2, type) => fromBlob(statSync21(path2), path2, type);
49637
49884
  blobFrom = (path2, type) => stat(path2).then((stat3) => fromBlob(stat3, path2, type));
49638
49885
  fileFrom = (path2, type) => stat(path2).then((stat3) => fromFile(stat3, path2, type));
49639
- fileFromSync = (path2, type) => fromFile(statSync19(path2), path2, type);
49886
+ fileFromSync = (path2, type) => fromFile(statSync21(path2), path2, type);
49640
49887
  fromBlob = (stat3, path2, type = "") => new fetch_blob_default([new BlobDataItem({
49641
49888
  path: path2,
49642
49889
  size: stat3.size,
@@ -83124,8 +83371,8 @@ ${underline2}`);
83124
83371
  });
83125
83372
 
83126
83373
  // src/capture/contentExtractor.ts
83127
- import { readdirSync as readdirSync19, statSync as statSync20, readFileSync as readFileSync37 } from "fs";
83128
- import { join as join53 } from "path";
83374
+ import { readdirSync as readdirSync20, statSync as statSync22, readFileSync as readFileSync37 } from "fs";
83375
+ import { join as join54 } from "path";
83129
83376
  async function detectLibraries(page, capturedShaders) {
83130
83377
  let detectedLibraries = [];
83131
83378
  try {
@@ -83245,7 +83492,7 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
83245
83492
  try {
83246
83493
  const { GoogleGenAI: GoogleGenAI2 } = await Promise.resolve().then(() => (init_node4(), node_exports));
83247
83494
  const ai = new GoogleGenAI2({ apiKey: geminiKey });
83248
- const imageFiles = readdirSync19(join53(outputDir, "assets")).filter(
83495
+ const imageFiles = readdirSync20(join54(outputDir, "assets")).filter(
83249
83496
  (f3) => /\.(png|jpg|jpeg|webp|gif)$/i.test(f3)
83250
83497
  );
83251
83498
  const model = process.env.HYPERFRAMES_GEMINI_MODEL || "gemini-3.1-flash-lite-preview";
@@ -83254,8 +83501,8 @@ async function captionImagesWithGemini(outputDir, progress, warnings) {
83254
83501
  const batch = imageFiles.slice(i2, i2 + BATCH_SIZE);
83255
83502
  const results = await Promise.allSettled(
83256
83503
  batch.map(async (file) => {
83257
- const filePath = join53(outputDir, "assets", file);
83258
- const stat3 = statSync20(filePath);
83504
+ const filePath = join54(outputDir, "assets", file);
83505
+ const stat3 = statSync22(filePath);
83259
83506
  if (stat3.size > 4e6) return { file, caption: "" };
83260
83507
  const buffer = readFileSync37(filePath);
83261
83508
  const base64 = buffer.toString("base64");
@@ -83303,12 +83550,12 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
83303
83550
  const uncaptionedLines = [];
83304
83551
  const svgLines = [];
83305
83552
  const fontLines = [];
83306
- const assetsPath = join53(outputDir, "assets");
83553
+ const assetsPath = join54(outputDir, "assets");
83307
83554
  try {
83308
- for (const file of readdirSync19(assetsPath)) {
83555
+ for (const file of readdirSync20(assetsPath)) {
83309
83556
  if (file === "svgs" || file === "fonts" || file === "lottie" || file === "videos") continue;
83310
- const filePath = join53(assetsPath, file);
83311
- const stat3 = statSync20(filePath);
83557
+ const filePath = join54(assetsPath, file);
83558
+ const stat3 = statSync22(filePath);
83312
83559
  if (!stat3.isFile()) continue;
83313
83560
  const sizeKb = Math.round(stat3.size / 1024);
83314
83561
  const catalogMatch = catalogedAssets.find(
@@ -83336,8 +83583,8 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
83336
83583
  } catch {
83337
83584
  }
83338
83585
  try {
83339
- const svgsPath = join53(assetsPath, "svgs");
83340
- for (const file of readdirSync19(svgsPath)) {
83586
+ const svgsPath = join54(assetsPath, "svgs");
83587
+ for (const file of readdirSync20(svgsPath)) {
83341
83588
  if (!file.endsWith(".svg")) continue;
83342
83589
  const svgMatch = tokens.svgs.find(
83343
83590
  (s2) => s2.label && file.includes(
@@ -83351,8 +83598,8 @@ function generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCap
83351
83598
  } catch {
83352
83599
  }
83353
83600
  try {
83354
- const fontsPath = join53(assetsPath, "fonts");
83355
- for (const file of readdirSync19(fontsPath)) {
83601
+ const fontsPath = join54(assetsPath, "fonts");
83602
+ for (const file of readdirSync20(fontsPath)) {
83356
83603
  fontLines.push(`fonts/${file} \u2014 font file`);
83357
83604
  }
83358
83605
  } catch {
@@ -83371,12 +83618,12 @@ __export(agentPromptGenerator_exports, {
83371
83618
  generateAgentPrompt: () => generateAgentPrompt
83372
83619
  });
83373
83620
  import { writeFileSync as writeFileSync21 } from "fs";
83374
- import { join as join54 } from "path";
83621
+ import { join as join55 } from "path";
83375
83622
  function generateAgentPrompt(outputDir, url, tokens, _animations, hasScreenshot, hasLottie, hasShaders, _catalogedAssets, detectedLibraries) {
83376
83623
  const prompt = buildPrompt(url, tokens, hasScreenshot, hasLottie, hasShaders, detectedLibraries);
83377
- writeFileSync21(join54(outputDir, "AGENTS.md"), prompt, "utf-8");
83378
- writeFileSync21(join54(outputDir, "CLAUDE.md"), prompt, "utf-8");
83379
- writeFileSync21(join54(outputDir, ".cursorrules"), prompt, "utf-8");
83624
+ writeFileSync21(join55(outputDir, "AGENTS.md"), prompt, "utf-8");
83625
+ writeFileSync21(join55(outputDir, "CLAUDE.md"), prompt, "utf-8");
83626
+ writeFileSync21(join55(outputDir, ".cursorrules"), prompt, "utf-8");
83380
83627
  }
83381
83628
  function buildPrompt(url, tokens, hasScreenshot, hasLottie, hasShaders, detectedLibraries) {
83382
83629
  const title = tokens.title || new URL(url).hostname.replace(/^www\./, "");
@@ -83443,8 +83690,8 @@ var init_agentPromptGenerator = __esm({
83443
83690
  });
83444
83691
 
83445
83692
  // src/capture/scaffolding.ts
83446
- import { existsSync as existsSync51, writeFileSync as writeFileSync22, readFileSync as readFileSync38 } from "fs";
83447
- import { join as join55, resolve as resolve37 } from "path";
83693
+ import { existsSync as existsSync52, writeFileSync as writeFileSync22, readFileSync as readFileSync38 } from "fs";
83694
+ import { join as join56, resolve as resolve37 } from "path";
83448
83695
  function loadEnvFile(startDir) {
83449
83696
  try {
83450
83697
  let dir = resolve37(startDir);
@@ -83470,8 +83717,8 @@ function loadEnvFile(startDir) {
83470
83717
  }
83471
83718
  }
83472
83719
  async function generateProjectScaffold(outputDir, url, tokens, animationCatalog, hasScreenshots, hasLotties, hasShaders, catalogedAssets, progress, warnings, detectedLibraries) {
83473
- const metaPath = join55(outputDir, "meta.json");
83474
- if (!existsSync51(metaPath)) {
83720
+ const metaPath = join56(outputDir, "meta.json");
83721
+ if (!existsSync52(metaPath)) {
83475
83722
  const hostname = new URL(url).hostname.replace(/^www\./, "");
83476
83723
  writeFileSync22(
83477
83724
  metaPath,
@@ -83509,9 +83756,9 @@ __export(screenshotCapture_exports, {
83509
83756
  captureScrollScreenshots: () => captureScrollScreenshots
83510
83757
  });
83511
83758
  import { writeFileSync as writeFileSync23, mkdirSync as mkdirSync28 } from "fs";
83512
- import { join as join56 } from "path";
83759
+ import { join as join57 } from "path";
83513
83760
  async function captureScrollScreenshots(page, outputDir) {
83514
- const screenshotsDir = join56(outputDir, "screenshots");
83761
+ const screenshotsDir = join57(outputDir, "screenshots");
83515
83762
  mkdirSync28(screenshotsDir, { recursive: true });
83516
83763
  const MAX_SCREENSHOTS = 20;
83517
83764
  const filePaths = [];
@@ -83545,7 +83792,7 @@ async function captureScrollScreenshots(page, outputDir) {
83545
83792
  finalPositions[i2] / Math.max(1, scrollHeight - viewportHeight) * 100
83546
83793
  );
83547
83794
  const filename = `scroll-${String(Math.min(pct, 100)).padStart(3, "0")}.png`;
83548
- const filePath = join56(screenshotsDir, filename);
83795
+ const filePath = join57(screenshotsDir, filename);
83549
83796
  const buffer = await page.screenshot({ type: "png" });
83550
83797
  writeFileSync23(filePath, buffer);
83551
83798
  filePaths.push(`screenshots/${filename}`);
@@ -83858,8 +84105,8 @@ var capture_exports = {};
83858
84105
  __export(capture_exports, {
83859
84106
  captureWebsite: () => captureWebsite
83860
84107
  });
83861
- import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync24, existsSync as existsSync52 } from "fs";
83862
- import { join as join57 } from "path";
84108
+ import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync24, existsSync as existsSync53 } from "fs";
84109
+ import { join as join58 } from "path";
83863
84110
  async function captureWebsite(opts, onProgress) {
83864
84111
  const {
83865
84112
  url,
@@ -83876,9 +84123,9 @@ async function captureWebsite(opts, onProgress) {
83876
84123
  onProgress?.(stage, detail);
83877
84124
  };
83878
84125
  loadEnvFile(outputDir);
83879
- mkdirSync29(join57(outputDir, "extracted"), { recursive: true });
83880
- mkdirSync29(join57(outputDir, "screenshots"), { recursive: true });
83881
- mkdirSync29(join57(outputDir, "assets"), { recursive: true });
84126
+ mkdirSync29(join58(outputDir, "extracted"), { recursive: true });
84127
+ mkdirSync29(join58(outputDir, "screenshots"), { recursive: true });
84128
+ mkdirSync29(join58(outputDir, "assets"), { recursive: true });
83882
84129
  progress("browser", "Launching headless Chrome...");
83883
84130
  const { ensureBrowser: ensureBrowser2 } = await Promise.resolve().then(() => (init_manager2(), manager_exports2));
83884
84131
  const browser = await ensureBrowser2();
@@ -84034,7 +84281,7 @@ async function captureWebsite(opts, onProgress) {
84034
84281
  } catch {
84035
84282
  }
84036
84283
  if (discoveredLotties.length > 0) {
84037
- const lottieDir = join57(outputDir, "assets", "lottie");
84284
+ const lottieDir = join58(outputDir, "assets", "lottie");
84038
84285
  mkdirSync29(lottieDir, { recursive: true });
84039
84286
  const savedCount = await saveLottieAnimations(discoveredLotties, lottieDir);
84040
84287
  if (savedCount > 0) {
@@ -84054,7 +84301,7 @@ async function captureWebsite(opts, onProgress) {
84054
84301
  });
84055
84302
  capturedShaders = unique;
84056
84303
  writeFileSync24(
84057
- join57(outputDir, "extracted", "shaders.json"),
84304
+ join58(outputDir, "extracted", "shaders.json"),
84058
84305
  JSON.stringify(unique, null, 2),
84059
84306
  "utf-8"
84060
84307
  );
@@ -84065,7 +84312,7 @@ async function captureWebsite(opts, onProgress) {
84065
84312
  progress("tokens", "Extracting design tokens...");
84066
84313
  const tokens = await extractTokens(page1);
84067
84314
  writeFileSync24(
84068
- join57(outputDir, "extracted", "tokens.json"),
84315
+ join58(outputDir, "extracted", "tokens.json"),
84069
84316
  JSON.stringify(tokens, null, 2),
84070
84317
  "utf-8"
84071
84318
  );
@@ -84139,7 +84386,7 @@ async function captureWebsite(opts, onProgress) {
84139
84386
  representativeAnimations: representativeAnims
84140
84387
  };
84141
84388
  writeFileSync24(
84142
- join57(outputDir, "extracted", "animations.json"),
84389
+ join58(outputDir, "extracted", "animations.json"),
84143
84390
  JSON.stringify(leanCatalog, null, 2),
84144
84391
  "utf-8"
84145
84392
  );
@@ -84150,18 +84397,18 @@ async function captureWebsite(opts, onProgress) {
84150
84397
  assets = await downloadAssets(tokens, outputDir, catalogedAssets, faviconLinks);
84151
84398
  }
84152
84399
  if (visibleTextContent) {
84153
- writeFileSync24(join57(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
84400
+ writeFileSync24(join58(outputDir, "extracted", "visible-text.txt"), visibleTextContent, "utf-8");
84154
84401
  }
84155
84402
  if (catalogedAssets.length > 0) {
84156
84403
  writeFileSync24(
84157
- join57(outputDir, "extracted", "assets-catalog.json"),
84404
+ join58(outputDir, "extracted", "assets-catalog.json"),
84158
84405
  JSON.stringify(catalogedAssets, null, 2),
84159
84406
  "utf-8"
84160
84407
  );
84161
84408
  }
84162
84409
  if (detectedLibraries.length > 0) {
84163
84410
  writeFileSync24(
84164
- join57(outputDir, "extracted", "detected-libraries.json"),
84411
+ join58(outputDir, "extracted", "detected-libraries.json"),
84165
84412
  JSON.stringify(detectedLibraries, null, 2),
84166
84413
  "utf-8"
84167
84414
  );
@@ -84172,7 +84419,7 @@ async function captureWebsite(opts, onProgress) {
84172
84419
  const lines = generateAssetDescriptions(outputDir, tokens, catalogedAssets, geminiCaptions);
84173
84420
  if (lines.length > 0) {
84174
84421
  writeFileSync24(
84175
- join57(outputDir, "extracted", "asset-descriptions.md"),
84422
+ join58(outputDir, "extracted", "asset-descriptions.md"),
84176
84423
  "# Asset Descriptions\n\nOne line per file. Read this instead of opening every image individually.\n\n" + lines.map((l) => "- " + l).join("\n") + "\n",
84177
84424
  "utf-8"
84178
84425
  );
@@ -84188,7 +84435,7 @@ async function captureWebsite(opts, onProgress) {
84188
84435
  animationCatalog,
84189
84436
  screenshots.length > 0,
84190
84437
  discoveredLotties.length > 0,
84191
- existsSync52(join57(outputDir, "extracted", "shaders.json")),
84438
+ existsSync53(join58(outputDir, "extracted", "shaders.json")),
84192
84439
  catalogedAssets,
84193
84440
  progress,
84194
84441
  warnings,
@@ -84536,8 +84783,8 @@ __export(autoUpdate_exports, {
84536
84783
  });
84537
84784
  import { spawn as spawn12 } from "child_process";
84538
84785
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync30, openSync } from "fs";
84539
- import { homedir as homedir10 } from "os";
84540
- import { join as join58 } from "path";
84786
+ import { homedir as homedir11 } from "os";
84787
+ import { join as join59 } from "path";
84541
84788
  import { compareVersions as compareVersions2 } from "compare-versions";
84542
84789
  function isAutoInstallDisabled() {
84543
84790
  if (isDevMode()) return true;
@@ -84560,7 +84807,7 @@ function log(line) {
84560
84807
  }
84561
84808
  function launchDetachedInstall(installCommand, version) {
84562
84809
  mkdirSync30(CONFIG_DIR2, { recursive: true, mode: 448 });
84563
- const configFile = join58(CONFIG_DIR2, "config.json");
84810
+ const configFile = join59(CONFIG_DIR2, "config.json");
84564
84811
  const nodeScript = `
84565
84812
  const { exec } = require("node:child_process");
84566
84813
  const { readFileSync, renameSync, writeFileSync } = require("node:fs");
@@ -84679,8 +84926,8 @@ var init_autoUpdate = __esm({
84679
84926
  init_config();
84680
84927
  init_env();
84681
84928
  init_installerDetection();
84682
- CONFIG_DIR2 = join58(homedir10(), ".hyperframes");
84683
- LOG_FILE = join58(CONFIG_DIR2, "auto-update.log");
84929
+ CONFIG_DIR2 = join59(homedir11(), ".hyperframes");
84930
+ LOG_FILE = join59(CONFIG_DIR2, "auto-update.log");
84684
84931
  PENDING_TIMEOUT_MS = 10 * 60 * 1e3;
84685
84932
  }
84686
84933
  });