hyperframes 0.8.36 → 0.8.38

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.
Files changed (33) hide show
  1. package/dist/cli.js +287 -251
  2. package/dist/docs/examples.md +1 -1
  3. package/dist/fontLocalizeCli.js +49 -108
  4. package/dist/hyperframe-runtime.js +24 -24
  5. package/dist/hyperframe.manifest.json +1 -1
  6. package/dist/hyperframe.runtime.iife.js +24 -24
  7. package/dist/hyperframes-player.global.js +1 -1
  8. package/dist/skills/hyperframes/SKILL.md +1 -1
  9. package/dist/skills/hyperframes/references/brief-contract.md +108 -0
  10. package/dist/skills/hyperframes/references/brief-format.md +72 -0
  11. package/dist/skills/hyperframes/references/capability-menu.md +1 -1
  12. package/dist/skills/hyperframes/references/frame-worker-core.md +80 -0
  13. package/dist/skills/hyperframes/references/intent-interview.md +8 -8
  14. package/dist/skills/hyperframes/references/production-loop.md +26 -0
  15. package/dist/skills/hyperframes/references/review-loop.md +41 -0
  16. package/dist/skills/hyperframes/references/route-briefs.md +1 -1
  17. package/dist/skills/hyperframes/references/script-format.md +52 -0
  18. package/dist/skills/hyperframes/references/storyboard-format.md +130 -0
  19. package/dist/skills/hyperframes/references/subagent-dispatch.md +35 -0
  20. package/dist/skills/hyperframes/scripts/lib/frame-packets-core.mjs +212 -0
  21. package/dist/skills/hyperframes-cli/SKILL.md +9 -8
  22. package/dist/skills/hyperframes-cli/references/init-and-scaffold.md +6 -6
  23. package/dist/skills/hyperframes-cli/references/preview-render.md +6 -3
  24. package/dist/studio/assets/{hyperframes-player-BIpJmC69.js → hyperframes-player-otov4oIw.js} +1 -1
  25. package/dist/studio/assets/{index-z2_QKypm.js → index-B-FzDhAR.js} +1 -1
  26. package/dist/studio/assets/{index-Df3VgdgL.js → index-Bw6cyxOm.js} +1 -1
  27. package/dist/studio/assets/{index-BmPeyP0k.js → index-DWFEyVJZ.js} +4 -4
  28. package/dist/studio/index.html +1 -1
  29. package/dist/studio/index.js +1 -1
  30. package/dist/studio/index.js.map +1 -1
  31. package/dist/templates/blank/index.html +17 -37
  32. package/dist/templates/from-file/index.html +74 -0
  33. package/package.json +1 -1
@@ -4,7 +4,7 @@ Built-in templates available via `npx hyperframes init --example <name>`.
4
4
 
5
5
  ## blank
6
6
 
7
- Empty 1920x1080 composition with GSAP timeline wired up. Start from scratch.
7
+ Centered Inter stage, paused GSAP timeline. Default `hyperframes init` scaffold.
8
8
 
9
9
  ## title-card
10
10
 
@@ -55006,7 +55006,6 @@ async function syncVideoFrameVisibility(page, activeVideoIds) {
55006
55006
  img.style.visibility = "visible";
55007
55007
  }
55008
55008
  } else {
55009
- video.style.removeProperty("display");
55010
55009
  video.style.setProperty("visibility", "hidden", "important");
55011
55010
  video.style.setProperty("pointer-events", "none", "important");
55012
55011
  if (hasImg) {
@@ -69964,10 +69963,6 @@ function targetHasNoStableIdentity(selector, identity) {
69964
69963
  if (identity) return false;
69965
69964
  return selector === UNRESOLVED_TARGET || selector === "dwell/hold" || selector.startsWith("proxy \u2192 ");
69966
69965
  }
69967
- function readRegisteredTimelineCompositionId(script) {
69968
- const match = script.match(WINDOW_TIMELINE_ASSIGN_PATTERN);
69969
- return match?.[1] || match?.[2] || null;
69970
- }
69971
69966
  function unwrapRaw(value) {
69972
69967
  if (typeof value === "number") return value;
69973
69968
  if (typeof value !== "string") return void 0;
@@ -70134,21 +70129,6 @@ function makesOverlayVisible(win) {
70134
70129
  if (win.method === "from" && isHiddenGsapState(win.propertyValues)) return true;
70135
70130
  return isVisibleGsapState(win.propertyValues);
70136
70131
  }
70137
- function isSceneBoundaryExit(win) {
70138
- if (win.end <= win.position) return false;
70139
- if (win.method !== "to" && win.method !== "fromTo") return false;
70140
- return isHiddenGsapState(win.propertyValues);
70141
- }
70142
- function isHardKillSet(win, selector, boundary) {
70143
- return win.method === "set" && win.targetSelector === selector && Math.abs(win.position - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS && isHiddenGsapState(win.propertyValues);
70144
- }
70145
- function hiddenStateLiteral(values) {
70146
- if (zeroValue(values.autoAlpha)) return "{ autoAlpha: 0 }";
70147
- if (zeroValue(values.opacity)) return "{ opacity: 0 }";
70148
- if (stringValue(values.visibility)?.toLowerCase() === "hidden") return '{ visibility: "hidden" }';
70149
- if (stringValue(values.display)?.toLowerCase() === "none") return '{ display: "none" }';
70150
- return "{ opacity: 0 }";
70151
- }
70152
70132
  function findTagEnd2(source, tag) {
70153
70133
  const escapedTagName = tag.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
70154
70134
  const pattern = new RegExp(`<\\/?${escapedTagName}\\b[^>]*>`, "gi");
@@ -70165,56 +70145,11 @@ function findTagEnd2(source, tag) {
70165
70145
  }
70166
70146
  return source.length;
70167
70147
  }
70168
- function collectCompositionRanges(source, tags) {
70169
- return tags.map((tag) => {
70170
- const id = readDecodedAttr(tag.raw, "data-composition-id");
70171
- if (!id) return null;
70172
- return {
70173
- id,
70174
- start: tag.index,
70175
- end: findTagEnd2(source, tag)
70176
- };
70177
- }).filter((range) => range !== null);
70178
- }
70179
- function findContainingCompositionId(tag, ranges) {
70180
- let match = null;
70181
- for (const range of ranges) {
70182
- if (tag.index < range.start || tag.index >= range.end) continue;
70183
- if (!match || range.start >= match.start) match = range;
70184
- }
70185
- return match?.id || null;
70186
- }
70187
70148
  function getClipTagClasses(tag) {
70188
70149
  const classAttr = readAttr(tag.raw, "class") || "";
70189
70150
  const classes = classAttr.split(/\s+/).filter(Boolean);
70190
70151
  return classes.includes("clip") ? { classAttr, classes } : null;
70191
70152
  }
70192
- function collectClipStartBoundariesByComposition(source, tags) {
70193
- const ranges = collectCompositionRanges(source, tags);
70194
- const boundaries = /* @__PURE__ */ new Map();
70195
- for (const tag of tags) {
70196
- if (!getClipTagClasses(tag)) continue;
70197
- const compositionId = findContainingCompositionId(tag, ranges);
70198
- if (!compositionId) continue;
70199
- const start = numberValue(readAttr(tag.raw, "data-start") ?? void 0);
70200
- if (start == null || start <= 0) continue;
70201
- const compositionBoundaries = boundaries.get(compositionId) ?? /* @__PURE__ */ new Set();
70202
- compositionBoundaries.add(start);
70203
- boundaries.set(compositionId, compositionBoundaries);
70204
- }
70205
- return new Map(
70206
- [...boundaries.entries()].map(([compositionId, values]) => [
70207
- compositionId,
70208
- [...values].sort((a, b) => a - b)
70209
- ])
70210
- );
70211
- }
70212
- function findMatchingSceneBoundary(time, boundaries) {
70213
- for (const boundary of boundaries) {
70214
- if (Math.abs(time - boundary) <= SCENE_BOUNDARY_EPSILON_SECONDS) return boundary;
70215
- }
70216
- return null;
70217
- }
70218
70153
  function readStyleProperty(style, property) {
70219
70154
  const escapedProperty = property.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
70220
70155
  const match = style.match(new RegExp(`(?:^|;)\\s*${escapedProperty}\\s*:\\s*([^;]+)`, "i"));
@@ -72549,7 +72484,7 @@ ${allInlineStyles}`.replace(/\/\*[\s\S]*?\*\//g, "");
72549
72484
  },
72550
72485
  // overlapping_gsap_tweens + gsap_animates_clip_element
72551
72486
  // fallow-ignore-next-line complexity
72552
- async ({ source, tags, scripts, styles, rootCompositionId }) => {
72487
+ async ({ tags, scripts, styles }) => {
72553
72488
  const findings = [];
72554
72489
  const authoredHiddenSelectors = new Set(
72555
72490
  scripts.flatMap((script) => [...extractStandaloneHiddenSelectors(script.content)])
@@ -72570,13 +72505,10 @@ ${allInlineStyles}`.replace(/\/\*[\s\S]*?\*\//g, "");
72570
72505
  if (cls !== "clip") clipClasses.set(`.${cls}`, info);
72571
72506
  }
72572
72507
  }
72573
- const clipStartBoundariesByComposition = collectClipStartBoundariesByComposition(source, tags);
72574
72508
  const styleRules = collectSimpleStyleRules(styles);
72575
72509
  const reportedVisibleOverlayKeys = /* @__PURE__ */ new Set();
72576
72510
  for (const script of scripts) {
72577
- const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);
72578
72511
  const gsapWindows = await cachedExtractGsapWindows(script.content);
72579
- const clipStartBoundaries = clipStartBoundariesByComposition.get(localTimelineCompId || rootCompositionId || "") ?? [];
72580
72512
  for (let i = 0; i < gsapWindows.length; i++) {
72581
72513
  const left = gsapWindows[i];
72582
72514
  if (!left) continue;
@@ -72638,28 +72570,6 @@ ${right.raw}`)
72638
72570
  snippet: truncateSnippet(fromToWindows.map((win) => win.raw).join("\n"))
72639
72571
  });
72640
72572
  }
72641
- if (clipStartBoundaries.length > 0) {
72642
- for (const win of gsapWindows) {
72643
- if (win.targetSelector === UNRESOLVED_TARGET) continue;
72644
- if (!isSceneBoundaryExit(win)) continue;
72645
- const boundary = findMatchingSceneBoundary(win.end, clipStartBoundaries);
72646
- if (boundary == null) continue;
72647
- const hasHardKill = gsapWindows.some(
72648
- (candidate) => isHardKillSet(candidate, win.targetSelector, boundary)
72649
- );
72650
- if (hasHardKill) continue;
72651
- const exitClipInfo = clipIds.get(win.targetSelector) || clipClasses.get(win.targetSelector);
72652
- const fixHint = exitClipInfo ? `"${win.targetSelector}" is a clip element \u2014 the framework already manages its visibility. Wrap the scene's content in an inner non-clip <div>, move the exit tween and the hard kill (\`tl.set("<inner-selector>", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\`) onto that wrapper instead.` : `Add \`tl.set("${win.targetSelector}", ${hiddenStateLiteral(win.propertyValues)}, ${boundary.toFixed(2)})\` after the exit tween.`;
72653
- findings.push({
72654
- code: "gsap_exit_missing_hard_kill",
72655
- severity: "error",
72656
- message: `GSAP exit on "${win.targetSelector}" ends at the ${boundary.toFixed(2)}s clip start boundary without a matching tl.set hard kill. Non-linear seeking can land after the fade and leave stale visibility state.`,
72657
- selector: win.targetSelector,
72658
- fixHint,
72659
- snippet: truncateSnippet(win.raw)
72660
- });
72661
- }
72662
- }
72663
72573
  for (const tag of tags) {
72664
72574
  const selectors = tagSimpleSelectors(tag);
72665
72575
  if (selectors.length === 0) continue;
@@ -74471,6 +74381,7 @@ function declarerVariableRules(document2, layerFor) {
74471
74381
  }
74472
74382
  return rules;
74473
74383
  }
74384
+ var MAX_INLINE_ASSET_BYTES;
74474
74385
  var init_htmlBundler = __esm({
74475
74386
  "../core/dist/compiler/htmlBundler.js"() {
74476
74387
  "use strict";
@@ -74491,6 +74402,7 @@ var init_htmlBundler = __esm({
74491
74402
  init_cssSelector();
74492
74403
  init_safePath();
74493
74404
  init_colorGrading();
74405
+ MAX_INLINE_ASSET_BYTES = 2 * 1024 * 1024;
74494
74406
  }
74495
74407
  });
74496
74408
 
@@ -86803,6 +86715,17 @@ var ArtifactTransaction = class {
86803
86715
  };
86804
86716
 
86805
86717
  // ../producer/src/services/render/capturePlan.ts
86718
+ function drawElementVerificationFailure(plan2, hasDiskFallbackHeadroom) {
86719
+ const { routing } = plan2;
86720
+ const needsHeadroom = routing.kind !== "default" && routing.fallback.kind === "sdr_disk" && routing.memoryExhaustionFallback.kind === "sdr_streaming";
86721
+ return {
86722
+ kind: "draw_element_verification",
86723
+ diskFallbackAvailable: needsHeadroom ? hasDiskFallbackHeadroom() : void 0
86724
+ };
86725
+ }
86726
+ function streamingCaptureFailure(plan2, classification, hasDiskFallbackHeadroom) {
86727
+ return classification.isVerifyError ? drawElementVerificationFailure(plan2, hasDiskFallbackHeadroom) : { kind: "capture_failure", memoryExhaustion: classification.isMemoryExhaustion };
86728
+ }
86806
86729
  function assertWorkerCount(workerCount) {
86807
86730
  if (!Number.isInteger(workerCount) || workerCount < 1) {
86808
86731
  throw new Error(`CapturePlan workerCount must be a positive integer; got ${workerCount}`);
@@ -86873,11 +86796,12 @@ function replanAfterFailure(plan2, failure) {
86873
86796
  });
86874
86797
  }
86875
86798
  const isMemoryExhaustion = failure.kind === "capture_failure" && failure.memoryExhaustion;
86799
+ const diskFallbackUnavailable = failure.kind === "draw_element_verification" && failure.diskFallbackAvailable === false;
86876
86800
  const fallback = plan2.routing.kind === "default" ? {
86877
86801
  kind: plan2.kind,
86878
86802
  workerCount: isMemoryExhaustion ? 1 : plan2.workerCount,
86879
86803
  forceParallelStream: false
86880
- } : isMemoryExhaustion ? plan2.routing.memoryExhaustionFallback : plan2.routing.fallback;
86804
+ } : isMemoryExhaustion || diskFallbackUnavailable ? plan2.routing.memoryExhaustionFallback : plan2.routing.fallback;
86881
86805
  return createCapturePlan({
86882
86806
  ...plan2,
86883
86807
  workerCount: fallback.workerCount,
@@ -92793,7 +92717,7 @@ function estimateDiskCaptureBytes(totalFrames, captureOptions) {
92793
92717
  const outputHeight = Math.ceil(captureOptions.height * scale);
92794
92718
  return Math.ceil(totalFrames) * outputWidth * outputHeight * 4;
92795
92719
  }
92796
- function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeDiskBytes = (path) => {
92720
+ function inspectDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeDiskBytes = (path) => {
92797
92721
  try {
92798
92722
  const stat = statfsSync(path);
92799
92723
  return stat.bavail * stat.bsize;
@@ -92802,11 +92726,22 @@ function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeD
92802
92726
  }
92803
92727
  }) {
92804
92728
  const freeBytes = freeDiskBytes(framesDir);
92805
- if (freeBytes === null) return;
92806
92729
  const estimatedBytes = estimateDiskCaptureBytes(totalFrames, captureOptions);
92807
- if (estimatedBytes <= freeBytes * 0.9) return;
92730
+ if (freeBytes === null || estimatedBytes <= freeBytes * 0.9) {
92731
+ return { available: true, estimatedBytes, freeBytes };
92732
+ }
92733
+ return { available: false, estimatedBytes, freeBytes };
92734
+ }
92735
+ function assertDiskCaptureHeadroom(framesDir, totalFrames, captureOptions, freeDiskBytes) {
92736
+ const headroom = inspectDiskCaptureHeadroom(
92737
+ framesDir,
92738
+ totalFrames,
92739
+ captureOptions,
92740
+ freeDiskBytes
92741
+ );
92742
+ if (headroom.available) return;
92808
92743
  throw new Error(
92809
- `Disk capture may need ~${(estimatedBytes / 1e6).toFixed(1)} MB of temporary frame storage, but only ${(freeBytes / 1e6).toFixed(1)} MB is free at ${framesDir}. Re-run with --low-memory-mode to stream frames, raise PRODUCER_STREAMING_ENCODE_MAX_DURATION_SECONDS if streaming is supported, or free up disk space.`
92744
+ `Disk capture may need ~${(headroom.estimatedBytes / 1e6).toFixed(1)} MB of temporary frame storage, but only ${(headroom.freeBytes / 1e6).toFixed(1)} MB is free at ${framesDir}. Re-run with --low-memory-mode to stream frames, raise PRODUCER_STREAMING_ENCODE_MAX_DURATION_SECONDS if streaming is supported, or free up disk space.`
92810
92745
  );
92811
92746
  }
92812
92747
  async function runCaptureStage(input) {
@@ -95780,6 +95715,7 @@ import { mkdtempSync as mkdtempSync10, renameSync as renameSync6, rmSync as rmSy
95780
95715
  import { dirname as dirname17, join as join42 } from "path";
95781
95716
  var AUDIO_DURATION_TOLERANCE_SECONDS = 1e-3;
95782
95717
  var AAC_DELIVERY_TRUE_PEAK_DBFS = -1;
95718
+ var AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB = 0.5;
95783
95719
  var MAX_TRUE_PEAK_CORRECTION_PASSES = 3;
95784
95720
  function buildAacTruePeakCorrectionArgs(inputPath, outputPath, targetDurationSeconds, attenuationDb) {
95785
95721
  return [
@@ -95979,10 +95915,15 @@ async function enforceAacTruePeak(input) {
95979
95915
  try {
95980
95916
  scratchDir = mkdtempSync10(join42(dirname17(input.audioPath), ".true-peak-"));
95981
95917
  const correctedPath = join42(scratchDir, "audio.m4a");
95918
+ const correctionTargetDbfs = AAC_DELIVERY_TRUE_PEAK_DBFS - AAC_TRUE_PEAK_CORRECTION_HEADROOM_DB;
95919
+ const measurements = [];
95982
95920
  let attenuationDb = 0;
95983
95921
  let measuredPath = input.audioPath;
95984
95922
  for (let pass = 0; pass <= MAX_TRUE_PEAK_CORRECTION_PASSES; pass += 1) {
95985
95923
  const truePeakDbfs = await input.probeTruePeak(measuredPath, input.signal);
95924
+ measurements.push(
95925
+ `pass ${pass}: ${truePeakDbfs.toFixed(3)} dBFS at ${attenuationDb.toFixed(3)} dB attenuation`
95926
+ );
95986
95927
  if (Number.isNaN(truePeakDbfs) || truePeakDbfs === Number.POSITIVE_INFINITY) {
95987
95928
  return { success: false, error: "audioPadTrim: FFmpeg reported an invalid true peak" };
95988
95929
  }
@@ -95991,7 +95932,7 @@ async function enforceAacTruePeak(input) {
95991
95932
  return { success: true };
95992
95933
  }
95993
95934
  if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
95994
- attenuationDb += AAC_DELIVERY_TRUE_PEAK_DBFS - truePeakDbfs;
95935
+ attenuationDb += correctionTargetDbfs - truePeakDbfs;
95995
95936
  const result = await input.runner(
95996
95937
  buildAacTruePeakCorrectionArgs(
95997
95938
  input.audioPath,
@@ -96014,7 +95955,7 @@ async function enforceAacTruePeak(input) {
96014
95955
  }
96015
95956
  return {
96016
95957
  success: false,
96017
- error: `audioPadTrim: AAC true peak remained above ${AAC_DELIVERY_TRUE_PEAK_DBFS} dBFS after ${MAX_TRUE_PEAK_CORRECTION_PASSES} correction passes`
95958
+ error: `audioPadTrim: AAC true peak remained above ${AAC_DELIVERY_TRUE_PEAK_DBFS} dBFS after ${MAX_TRUE_PEAK_CORRECTION_PASSES} correction passes; ${measurements.join("; ")}`
96018
95959
  };
96019
95960
  } catch (err) {
96020
95961
  return {
@@ -97923,10 +97864,12 @@ async function executeRenderPipeline(input) {
97923
97864
  isVerifyError ? "drawElement self-verify failed; retrying with forceScreenshot" : isDeStall ? "drawElement renderer stalled; retrying with forceScreenshot" : isSequentialStall ? "sequential capture stalled; retrying with a fresh screenshot session" : "capture failed; retrying with a fresh screenshot session"
97924
97865
  );
97925
97866
  const failedRouting = capturePlan.routing.kind;
97926
- capturePlan = replanAfterFailure(
97867
+ const failure = streamingCaptureFailure(
97927
97868
  capturePlan,
97928
- isVerifyError ? { kind: "draw_element_verification" } : { kind: "capture_failure", memoryExhaustion: isMemoryExhaustion }
97869
+ { isVerifyError, isMemoryExhaustion },
97870
+ () => inspectDiskCaptureHeadroom(framesDir, totalFrames, buildCaptureOptions()).available
97929
97871
  );
97872
+ capturePlan = replanAfterFailure(capturePlan, failure);
97930
97873
  syncCapturePlan();
97931
97874
  updateCaptureObservability({
97932
97875
  forceScreenshot: capturePlan.forceScreenshot,
@@ -97946,13 +97889,11 @@ async function executeRenderPipeline(input) {
97946
97889
  probeSession = null;
97947
97890
  await closeOrphanedProbeForRetry(orphaned, closeCaptureSession, log, "streaming");
97948
97891
  }
97949
- if (failedRouting === "worker_inversion") {
97950
- log.info(
97951
- `[Render] Reverting worker inversion for the retry: ${capturePlan.workerCount} workers, plan=${capturePlan.kind}.`
97952
- );
97953
- } else if (failedRouting === "parallel_router") {
97892
+ if (failedRouting !== "default") {
97893
+ const route = failedRouting === "worker_inversion" ? "worker inversion" : "parallel router";
97894
+ const diskFallbackLacksHeadroom = failure.kind === "draw_element_verification" && failure.diskFallbackAvailable === false;
97954
97895
  log.info(
97955
- `[Render] Reverting parallel router for the retry: ${capturePlan.workerCount} workers, plan=${capturePlan.kind}.`
97896
+ diskFallbackLacksHeadroom ? `[Render] ${route} disk fallback lacks headroom; retrying with ${capturePlan.workerCount}-worker screenshot streaming.` : `[Render] Reverting ${route} for the retry: ${capturePlan.workerCount} workers, plan=${capturePlan.kind}.`
97956
97897
  );
97957
97898
  }
97958
97899
  if (capturePlan.kind === "sdr_streaming") {
@@ -99626,8 +99567,8 @@ async function runFontLocalize(io, localize) {
99626
99567
  }
99627
99568
 
99628
99569
  // src/version.ts
99629
- var VERSION = true ? "0.8.36" : "0.0.0-dev";
99630
- var PRODUCER_VERSION = true ? "0.8.36" : "0.0.0-dev";
99570
+ var VERSION = true ? "0.8.38" : "0.0.0-dev";
99571
+ var PRODUCER_VERSION = true ? "0.8.38" : "0.0.0-dev";
99631
99572
 
99632
99573
  // src/fontLocalizeCli.ts
99633
99574
  async function readStdin() {