initial code#2
Merged
Merged
Conversation
Port all OSS-ready packages from the internal monorepo: - @hyperframes/core — shared types, HTML generation, GSAP utilities, runtime - @hyperframes/cli — CLI for creating, previewing, and rendering compositions - @hyperframes/engine — framework-agnostic rendering engine (BeginFrame + FFmpeg) - @hyperframes/producer — video rendering pipeline (Puppeteer + FFmpeg) - @hyperframes/ui-player — browser-based video player component - @hyperframes/studio — composition editor (React frontend + Hono backend) Includes regression test suite with Docker-based test harness. All HeyGen-internal references, deployment infrastructure, and proprietary assets have been removed. Package names migrated from @app/* to @hyperframes/*. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
miguel-heygen
approved these changes
Mar 21, 2026
jrusso1020
approved these changes
Mar 21, 2026
miguel-heygen
force-pushed
the
initial-code-port
branch
from
March 21, 2026 16:41
46caf94 to
eb11071
Compare
Collaborator
This stack of pull requests is managed by Graphite. Learn more about stacking. |
This was referenced Mar 21, 2026
- Replace static.heygen.ai runtime URLs in test fixtures - Remove internal CDN publish script (publish-hyperframe-runtime.ts) - Replace sandbox-studio, sandbox-interceptor, __magicEditRuntime with neutral names (studio, hyperframe-runtime, __hyperframeRuntime) - Fix stale Vault API / localhost references in docs - Remove broken deprecated_studio link Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete stale producer README.md and PIPELINE.md (referenced nonexistent files) - Replace "Cerberus" codename with "HyperFrames" in test design reviews - Replace magic-edit postMessage identifiers with hf-preview/hf-parent - Rename debug-magic-edit-timeline.ts to debug-timeline.ts - Replace "Motion Cut" with "HyperFrames" in Timeline comments - Fix studio/CLI references to nonexistent archive package (use local data/projects/ dir, stub render proxy) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
vanceingalls
added a commit
that referenced
this pull request
Mar 22, 2026
* feat: initial code port from hyperframes-internal Port all OSS-ready packages from the internal monorepo: - @hyperframes/core — shared types, HTML generation, GSAP utilities, runtime - @hyperframes/cli — CLI for creating, previewing, and rendering compositions - @hyperframes/engine — framework-agnostic rendering engine (BeginFrame + FFmpeg) - @hyperframes/producer — video rendering pipeline (Puppeteer + FFmpeg) - @hyperframes/ui-player — browser-based video player component - @hyperframes/studio — composition editor (React frontend + Hono backend) Includes regression test suite with Docker-based test harness. All HeyGen-internal references, deployment infrastructure, and proprietary assets have been removed. Package names migrated from @app/* to @hyperframes/*. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: scrub internal codenames and stale references from OSS port - Replace static.heygen.ai runtime URLs in test fixtures - Remove internal CDN publish script (publish-hyperframe-runtime.ts) - Replace sandbox-studio, sandbox-interceptor, __magicEditRuntime with neutral names (studio, hyperframe-runtime, __hyperframeRuntime) - Fix stale Vault API / localhost references in docs - Remove broken deprecated_studio link Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: remove remaining internal codenames and stale references - Delete stale producer README.md and PIPELINE.md (referenced nonexistent files) - Replace "Cerberus" codename with "HyperFrames" in test design reviews - Replace magic-edit postMessage identifiers with hf-preview/hf-parent - Rename debug-magic-edit-timeline.ts to debug-timeline.ts - Replace "Motion Cut" with "HyperFrames" in Timeline comments - Fix studio/CLI references to nonexistent archive package (use local data/projects/ dir, stub render proxy) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6 tasks
miguel-heygen
added a commit
that referenced
this pull request
Apr 10, 2026
## Summary - Bump `@chenglou/pretext` ^0.0.3 → ^0.0.5 in `packages/core` — fixes **high-severity** algorithmic complexity DoS ([Dependabot #3](https://github.com/heygen-com/hyperframes/security/dependabot/3)) - Bump `vite` ^5.0.0 → ^6.4.2 in `packages/studio` — fixes **medium-severity** path traversal in optimized deps `.map` handling ([Dependabot #2](https://github.com/heygen-com/hyperframes/security/dependabot/2)) ## Test plan - [x] `pnpm --filter @hyperframes/core build` — passes - [x] `pnpm --filter @hyperframes/studio build` — passes (vite 6.4.2, 4631 modules, 3.85s) - [x] `@vitejs/plugin-react@^4.0.0` supports vite 6 (`peerDependencies: vite ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0`)
7 tasks
vanceingalls
added a commit
that referenced
this pull request
Apr 16, 2026
Blockers: - #2: late_init_set false positive on fractional opacity (0.5 matched as 0) Fixed: /opacity\s*:\s*0(?![.\d])/ negative lookahead - #3: scene-1 prefix skip matches scene 10+ (s1- matches s10-) Fixed: extract full number and compare exactly High severity: - #4: autoAlpha not covered by late_init_set Fixed: checks both opacity and autoAlpha - #5: al() crashes on non-hex colors (#fff shorthand, rgb(), null) Fixed: guard + shorthand expansion + NaN fallback - #6: "Full palette" with null bg crashes isDark Fixed: null guard defaults to dark - #7: template literals missed by tl_from_in_multiscene Fixed: regex includes backtick quotes Medium: - #9: no retry limit on eval failures → infinite loop Fixed: max 2 retries, then escalate to user - #10: vague ID convention Fixed: explicit s{N}- prefix rule in multi-scene.md - #11: visual-style.md backward compat Fixed: Step 0b checks both filenames - #13: preview_html script injection Fixed: documented prohibition in design-picker.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3 tasks
This was referenced Apr 18, 2026
This was referenced Apr 23, 2026
This was referenced Apr 27, 2026
4 tasks
3 tasks
7 tasks
This was referenced Jul 13, 2026
3 tasks
ukimsanov
added a commit
that referenced
this pull request
Jul 14, 2026
…floors Review findings D1 (blocker) and 4. - D1: buildChildElements assigned expanded children synthetic display rows as `host.track + index` — integers that can EQUAL a real clip's lane in another file (host on 0 with two children puts child #2 on 1). Lane grouping merges purely by track number, so the collision fused clips from different source files into one display lane, and lane-scoped actions (the gap menu) then batch-persisted a foreign file's clip. Children now take FRACTIONS strictly between the host's lane and the next integer — structurally unable to collide with any normalized lane, while still rendering as ordered rows under the host. Regression test pins the reviewer's exact two-file scenario. - Finding 4: gap math compacted toward absolute 0, but an expanded child's display time is host-anchored — close/compact could drag it before its host window and persist a wrong (even negative) local time. All gap functions now take a lane FLOOR (laneGapFloor: 0 for ordinary lanes, the children's expandedParentStart for child lanes — single-origin per lane post-D1), threaded through the menu model, hover highlights, selected-lane strips, and both commits. Close-gap shifts clamp at the gap's own left edge.
miguel-heygen
added a commit
that referenced
this pull request
Jul 14, 2026
…k order = default paint order) (#2380) * feat(studio): mirror canvas z-order actions into timeline lanes, badge z overrides Track order = default paint order; authored z = advanced override. - timelineZMirror.ts: pure resolver mapping a successful z-menu action to a timeline lane move — closest track in the action's direction that is free over the clip's whole span, else a new lane adjacent to the crossed neighbor; temporal-overlap scope (default pending product sign-off, see module doc); visual zone only; same-file reference scoping; persistTrack via the shared authored-space rules. null for non-clips (menu stays z-only) and at-extreme/no-overlap cases. - useCanvasZOrderTimelineMirror.ts: after the z commit resolves, the mirror persists the lane move through the same machinery as a timeline lane drag (optimistic store update, authoredTrack refresh, rollback); inserts reuse commitTrackInsert's renumber via a shared buildTrackInsertEdits core. Both writes share one coalesce key (zReorderCoalesceKey) and fold into ONE undo entry (test proves it over the real history reducer). The mirror never triggers the lane->z stacking sync, so it cannot fight the z values the action just set. - timelineZOverride.ts + TimelineClip badge: clips whose paint order contradicts lane order among temporally-overlapping same-context visual neighbors (laneIsAbove XOR paintsAbove, the stacking-sync predicates) show a 'z' badge — authored z overrides are surfaced instead of silently disagreeing with the timeline. - Timeline.tsx track derivations extracted to useTimelineTrackDerivations (600-line cap). * fix(studio): fold mirrored z-order gestures into one undo entry across slow persists Live verification caught the z write and the mirrored lane write splitting into two undo entries: the mirror runs after the z persist's server round trip, which exceeds editHistory's default 300ms coalesce window under real latency (the unit test's deterministic clock sat inside it). zReorderCoalesceKey now mints a per-gesture-unique key (monotonic seq, the laneChangeGestureSeq precedent) and both records carry coalesceMs Infinity — distinct gestures can never merge, and one gesture always folds regardless of write latency. coalesceMs threaded through the persist chain alongside coalesceKey. Also hardens the existing lane-drag move->z fold, which had the same latent split. Fold test now simulates a 400ms gap (failed before the fix, passes after); a two-separate-gestures test asserts two entries. * feat(studio): flashless lane mirror, z-order menu icons, close-gap track menu - Track-only batch moves (the z-mirror's lane hop and the insert renumber) skip the GSAP fallback round-trip and the preview reload entirely — the renderer never reads data-track-index, and the live DOM patch + optimistic store update cover the UI. Mixed batches keep current behavior. Kills the canvas blink on mirrored Bring/Send actions (live-verified: an iframe-scoped marker survives the whole gesture). - The four z-order menu items get 16px stroke icons (single layer diamond + directional arrow for Forward/Backward; pierced two-layer stack for Front/Back); labels unchanged — they are the industry-standard names. - New track context menu on empty lane space: 'Close gap' (shifts the next clip and every clip after it on that lane left by the clicked gap's width; leading gaps count, so a single clip with empty space before it compacts to 0) and 'Close all gaps' (whole lane contiguous from 0). Pure gap math in timelineGaps.ts; persists through the drag path's atomic batch move (one undo per action); refuses when a clip that must shift is locked; items disable when there is nothing to close. * fix(studio): rebind-only preview sync for unmutated timing edits, classical z-menu order Timing edits that rewrote NO GSAP positions (gap closes and moves of selector-addressed caption clips, zero-delta batches, comps without a rewritable script) full-reloaded the preview — and the rerun-current-scripts attempt was wrong for real compositions: re-executing init-style scripts (three.js scenes, caption engines) is exactly the unsafe case, verified live by doubled init warnings and a fallback reload anyway. The correct observation: when mutated === false the existing __timelines are still valid — only the runtime's clip visibility windows are stale, and the live DOM timing attributes were already patched. So the no-mutation path now runs applySoftReloadFinalization only (seek + __hfForceTimelineRebind + manual-edits reapply), extracted from the soft-reload machinery — zero script execution. This also un-blinks comps with no GSAP script at all, which previously always remounted. Rewritten-script soft reloads, cannot-soft-reload, otherFileChanged, and mutation failures keep their existing behavior. gsapSoftReload's undo/redo restore section moved verbatim to gsapUndoRestore.ts for the 600-line cap. Also: z-order menu items reordered to the classical arrangement (Bring to Front, Bring Forward, Send Backward, Send to Back). Live-verified on a three.js-heavy composition: Close-all-gaps shifted 4 caption clips with correct cumulative amounts, the preview iframe was never remounted (marker survived), and one undo reverted everything. * fix(studio): bound forward/backward mirror to a one-element step User-specified semantic: Bring Forward / Send Backward move the clip past EXACTLY ONE element. The mirror's lane target is now bounded by the next temporally-overlapping element beyond the crossed neighbor: a free lane strictly between the two is taken (closest to the neighbor), and when they are back-to-back a new track is inserted immediately beyond the crossed element — never past the second one. Previously the resolver took the closest free lane anywhere beyond the neighbor, which could carry the track past a second element while the z action only stepped past one — a track/paint contradiction our own zOverride badge would flag. Front/back keep whole-set semantics (past everything; back stays above the audio zone). End-to-end test pins the 3-stacked case through commitZMirrorLaneMove to the persisted renumbered tracks. * feat(studio): permanent gap-menu rows with hover and click-select gap highlights - TrackGapContextMenu always renders both rows; an inapplicable action dims with a tooltip ("No gap here" / lock reason / "No gaps on this track") instead of vanishing into a one-item menu. Width badge only when a gap exists under the pointer. - Hovering an ACTIONABLE row highlights the strip(s) it would close in the timeline: the single gap for Close gap, every current gap (leading included) for Close all gaps. New resolveAllGapIntervals in timelineGaps.ts reports present-state intervals (epsilon-tolerant, overlap-safe), distinct from resolveAllTrackGaps' post-compaction starts. - Click-selecting a single clip paints a quieter tint over its lane's gaps (suppressed for marquee multi-selection and during drags; the gap-menu hover wins on its own lane). Derivation lives in useTimelineGapHighlights with the pure buildTimelineGapStrips exported and unit-tested. - Strips render in TimelineCanvas with the drop-placeholder geometry (row top + clip inset), dashed accent for hover, faint tint for selection. - Timeline.tsx stayed under the 600-line cap by extracting the scroll-viewport plumbing (ResizeObserver width + shortcut-hint sync) into useTimelineScrollViewport, behavior unchanged. * feat(studio): stronger capcut-style timeline zoom steps One button press / pinch gesture now moves the zoom meaningfully: step factors 1.25x/0.8x -> 1.5x/(2/3) (kept reciprocal so in+out round-trips) and pinch sensitivity 0.0035 -> 0.007. Addresses "zooming several times to get anywhere" feedback; cursor anchoring unchanged. * feat(studio): three-way z sync — layers drags mirror timeline lanes, panel tracks live z edits Completes the layers/canvas/timeline sync triangle: the Layers panel was the one surface whose reorders never reached the timeline, and the one that went stale when the other two wrote z flashlessly. - Layers drag -> minimal z + equal-jump lane mirror. handleReorder now uses the canvas menu's realization core via resolveZOrderReposition (one between-z write when a strict gap exists, band-safe scoped renumber otherwise) instead of computeReorderZValues' all-sibling stamp — that helper is deleted, completing the #2347 unification follow-up. The drop then mirrors into a timeline lane move through the same machinery as the canvas menu (new resolveRepositionLaneMove: the clip lands on a free lane strictly between its NEW paint neighbors' lanes — nearest clip siblings in the desired render order, decorations skipped — else a track insert at that boundary; audio zone never crossed). Both writes share one per-gesture zReorderCoalesceKey with an unbounded fold window, so a drag is exactly ONE undo entry; useCanvasZOrderTimelineMirror's plumbing is factored into useMirrorLaneMoveCommit and reused by the new useLayerReorderTimelineMirror. A same-slot drop is a hard no-op (new order-equality guard in resolveZOrderReposition). - Panel staleness fix: flashless z commits (skipReload) reload nothing and bump no refreshKey, so the panel's z-sorted order went stale while paused. handleDomZIndexReorderCommit now bumps a store zEditVersion on apply AND rollback; the panel re-collects on it. Verified live: the panel re-sorts the instant a drag commits and again on undo. - Layer click reveal (useLayerRevealOverride): clicking a layer that stays hidden at the current frame (animation-parked opacity, non-clip display/visibility hides, hidden ancestors) temporarily forces the chain visible with live inline styles — exact priors restored on deselect, on another reveal, on play, and on unmount; never persisted (file diff == 0 verified live). Clips keep the existing seek-into-window behavior; the override applies on a short defer so a seek-revealed clip needs none. - layerOrdering's unused hasExplicitZIndex probe (zero callers) removed. Live-verified on a bed copy: a 2-position layers drag wrote exactly one element (z 6->23 + data-track-index 15->2), the timeline lane moved without a reload, and a single Cmd+Z restored the file byte-identically. * feat(studio): full-track selection highlight, borderless gap hover strips - Click-selecting a clip now lights the WHOLE lane minus its clips — leading gap, inter-clip gaps, and the open space after the last clip to the rendered end (new resolveLaneEmptyIntervals; displayDuration threaded into the strip derivation). Still click-only: any drag/resize suppresses the strips, and a marquee multi-select never shows them. - The gap-menu hover strips drop the dashed border (user feedback) — fill only, nudged to 0.18 alpha to keep the same visual weight. * feat(studio): selected layer paints on top via a reader-transparent z lift Clicking a layer in the Layers tab now shows the element as if it were at the very top of the stack while selected — whatever its authored z or panel position — extending the reveal override (which already forced hidden chains visible) with a temporary inline z lift: - liftElementToTop parks the TRUE effective z in data-hf-reveal-prior-z and writes a far-top inline z; a static element gets a layout-preserving position:relative with its prior parked in data-hf-reveal-prior-pos. Only the RENDERER sees the lift: all three studio z readers (readTimelineElementZIndex, getElementZIndex, readEffectiveZIndex) return the parked prior while the attribute is present, so the canvas z-menu, the zOverride badge, the lane mirror, the stacking sync, and the panel sort keep reasoning on the element's real z. - Strictly ephemeral: exact priors restored on deselect / another reveal / play / unmount, each property only while it still holds the value the override wrote (a later real edit is never clobbered). File diff == 0 verified live across a full lift/restore cycle. - A z-reorder commit CONSUMES an active lift (handleDomZIndexReorderCommit reads the parked position for its persist-position:relative static check, then drops the attributes) — the committed z becomes the truth and the later restore is a guarded no-op. * fix(studio): flashless undo/redo — three full-reload causes in the soft-restore path Cmd+Z blinked the canvas on essentially every undo. Three independent causes in applyUndoRestoreToPreview, each sufficient on its own: 1. Master-view path gate: activeCompPath is NULL at the master view, so the 'paths[0] === activeCompPath' eligibility check could never match the index.html restore and every default-view undo full-reloaded at the first gate. Normalized to the codebase-wide 'activeCompPath ?? "index.html"'. 2. Nested identity innerHTML check: the diff compared each identified element's innerHTML, but the composition root wraps every clip — any child change re-detected at the root rejected the restore. Change detection now compares only each element's OWN attribute surface; structure/text integrity is still guaranteed by the normalize-residual whole-doc pass (text nodes, added/removed elements, and un-identified attrs all remain after normalization and force the full reload). 3. id-only identity: elements addressed by data-hf-id / selector (no DOM id) fell outside the diff entirely. Identity is now id OR data-hf-id, with the live sync resolving either. Also stop re-running an UNCHANGED GSAP script: attribute-only restores (z, lane, timing, style — the overwhelmingly common undo) now use the rebind-only finalization (seek + __hfForceTimelineRebind + manual reapply, zero script execution — the same path as flashless timing edits), instead of tearing down and rebuilding live timelines or full-reloading when the script can't be scoped. A restore whose script text genuinely changed still re-runs it via applySoftReload, and structural restores (split/delete) still full-reload. Live-verified on the bed (iframe marker): gap-close undo AND redo both keep the iframe mounted, live DOM lands on the restored values, disk restored byte-identically. * feat(studio): left breathing pad before t=0, double zoom sensitivity again TRACKS_LEFT_PAD (48px) — the horizontal sibling of TRACKS_TOP_PAD: empty lane surface between the sticky gutter and the ruler's 00:00 / the first clips, scrolling WITH the content. - The lanes and the ruler realize it as a plain flow spacer between the sticky gutter cell and the time-mapped content div, so every content-relative computation (clip left = t*pps, beat lines, lane-menu time, clip drag deltas) is untouched by construction. - Canvas-space overlays shift by the pad: playhead (getTimelinePlayheadLeft), gap strips, drop placeholder, snap guide, range highlight, marquee clip rects, beat SVG; the insert line spans the pad. - Every pointer->time inverse subtracts it symmetrically: seekFromX, razor, range/marquee anchors, asset drops, and the zoom-anchor gutter basis; fit pps and the display width account for the consumed viewport width. - Live-verified: t=0 clip edge, the 00:00 tick, and the playhead line center all sit at GUTTER + TRACKS_LEFT_PAD, and a ruler click lands the playhead center exactly under the pointer. Also doubles the timeline zoom sensitivity again (user feedback after feel-testing the first bump): button steps 1.5x/(2/3) -> 2x/0.5, pinch 0.007 -> 0.014. * fix(studio): left pad renders as true empty space, not lane surface The pad before t=0 inherited each row's background and bottom border from the row wrapper, so it read as track lanes. Lane visuals now live on the cells: the sticky gutter keeps its own separator (header column stays delineated), the time-mapped content div carries the row background + separator, and the pad spacer stays transparent — bare shell background, no lines. The new-track insertion line also starts at the pad's end instead of crossing it. * fix(studio): no vertical line in the ruler band before 00:00 The ruler corner's right border drew the header-boundary line through the ruler strip, so the band didn't read as starting at 00:00. Dropped it — the boundary line belongs to the track rows below; the ruler stays completely clean from the panel edge to the first tick, matching the empty left pad. * refactor(studio): remove the timeline z-override badge User decision: the "z" chip on clips never earned its place — dropped entirely (timelineZOverride.ts + test deleted, TimelineClip badge rendering and the zOverrideKeys derivation/threading removed). This also eliminates the review's D2 finding at the root: the badge's cross-document comparison (stackingContextId ?? null collides across source files in the expanded view) produced false positives, and there is no longer a detector to mis-fire. overlapsInTime/paintsAbove lose their export (the badge was their only external consumer); the paint-order predicate itself is unchanged. * fix(studio): collision-free expanded child lanes and host-window gap floors Review findings D1 (blocker) and 4. - D1: buildChildElements assigned expanded children synthetic display rows as `host.track + index` — integers that can EQUAL a real clip's lane in another file (host on 0 with two children puts child #2 on 1). Lane grouping merges purely by track number, so the collision fused clips from different source files into one display lane, and lane-scoped actions (the gap menu) then batch-persisted a foreign file's clip. Children now take FRACTIONS strictly between the host's lane and the next integer — structurally unable to collide with any normalized lane, while still rendering as ordered rows under the host. Regression test pins the reviewer's exact two-file scenario. - Finding 4: gap math compacted toward absolute 0, but an expanded child's display time is host-anchored — close/compact could drag it before its host window and persist a wrong (even negative) local time. All gap functions now take a lane FLOOR (laneGapFloor: 0 for ordinary lanes, the children's expandedParentStart for child lanes — single-origin per lane post-D1), threaded through the menu model, hover highlights, selected-lane strips, and both commits. Close-gap shifts clamp at the gap's own left edge. * fix(studio): scope mirror references, insert writes, and crossed-neighbor identity Review findings 1, 2, and 3. - Finding 1: buildTrackInsertEdits normalized the FULL display set and persisted every shifted clip — writing host-lane numbers into OTHER composition files when expanded children were showing. The renumber write set is now the edited element's own source file (the sanctioned multi-write converges one FILE to lane space, never neighbors' files); foreign clips keep their authored tracks and re-derive display lanes. The locked-clip refusal scopes the same way. Expanded-origin elements refuse the insert outright (a new lane is a host-space renumber, meaningless in the child's file), and the mirrors restrict an expanded child's lane candidates to its own siblings' lanes — a sub-comp child still mirrors WITHIN its sub-comp (persisting the sibling's authored track) but can never land on a host lane with no same-file occupant. authoredTrackForLane's offset fallback rounds: fractional synthetic rows must never leak fractions into data-track-index. - Finding 2: the mirror comparison sets required only sameSourceFile, but a file can contain several CSS stacking contexts and leaf z is only comparable within one. Both resolvers now scope by samePaintScope — same source file AND same stackingContextId (the file check also stops null root contexts of different files from comparing equal in the expanded view). - Finding 3: the crossed-neighbor key was derived without selectorIndex, so duplicate class selectors (.sub) resolved to occurrence 0 — a different clip. The key now carries getSelectorIndex, matching how z-reorder entries derive theirs. * fix(studio): z-to-lane gestures are one serialized transaction gated on durable persists Review findings 5 and 7. - Finding 5: commitDomEditPatchBatches resolved successfully even when the server matched NO patch target — the z write never reached disk (the preview reloads to reconverge) yet the lane mirror still ran, desyncing track order from what actually paints. The commit now resolves a durability report ({allMatched, changed}; the save queue and commit types are generic over the result), and the mirror phase is skipped on allMatched === false. - Finding 7: the z persist rides the DOM-edit save queue while the lane move rides the timeline/SDK path — two queues, so a second rapid gesture's z write could land BETWEEN the first gesture's z and lane phases. Every z-to-lane gesture (canvas z-order menu AND Layers-panel drag) now runs through runZLaneGesture: a single module-level tail that serializes the COMPLETE two-phase transaction, with unit tests for ordering, the durability gate, and queue resilience to failed gestures. The timeline lane-drag's inverse (move-then-z-sync) shares its phases' await ordering already; cross-gesture serialization for that path is noted as follow-up. - LayersPanel's pure sort helpers moved to layersPanelSort.ts (600-line cap). * fix(studio): multi-clip GSAP batch mutations roll back on late failure Review finding 6. finishGroupTimingGsapFallback mutates files sequentially per clip; a late per-clip failure left the earlier rewrites on disk with no aggregate history entry — unreachable by undo. foldGsapMutationIntoHistory already snapshots every touched path before mutating; on a mutation failure it now restores each path whose disk content changed (all-or-nothing batch), reports restore errors without masking the original failure, and rethrows. Regression test drives a two-clip batch whose second rewrite fails and asserts the first clip's write is restored byte-identically. * fix(studio): scope mirror inserts to their lane zone * fix(studio): unify source-scoped clip identity * fix(studio): isolate track insert topology * fix(studio): harden timeline paint synchronization --------- Co-authored-by: Miguel Angel Simon Sierra <miguel.sierra@heygen.com>
This was referenced Jul 14, 2026
3 tasks
This was referenced Jul 14, 2026
3 tasks
meefs
pushed a commit
to meefs/hyperframes
that referenced
this pull request
Jul 16, 2026
…ompound Field signal ts=1784131903 (win32/x64, CLI 0.7.58, 156s UI-heavy): stable ONLY with four flags together — --workers 1 --no-browser-gpu --low-memory-mode + PRODUCER_ENABLE_STREAMING_ENCODE=false. Since --no-browser-gpu and --low-memory-mode already imply screenshot capture, three of the four flags are structurally coupled. Auto-detect the compound at resolveConfig time and disable streaming-encode on the caller's behalf; user explicit-set (PRODUCER_ENABLE_STREAMING_ENCODE or overrides.enableStreamingEncode) always wins. Composition duration is not known at the config layer, so the wire-up passes compositionDurationSec:undefined and the helper reduces to the three-condition compound (platform + softwareGpuForced + workers=1). The 4-arg helper stays exported for downstream callers that DO know duration (e.g., renderOrchestrator) and want the >120s guard. Trade-off documented in code + PR body: false positives possible for short (~<120s) Windows software-GPU single-worker renders. Mitigation is the explicit opt-in escape hatch. Emits a single [hyperframes] log line naming the trigger + how to opt back in, so operators can tell an auto-disable apart from an explicit opt-out. Adds streamingEncodeAutoDisabledOnWin32Compound internal provenance for downstream telemetry. Stack: PR heygen-com#2 of 9 (base via/protocol-timeout-discoverability). Signed-off-by: Via
vanceingalls
added a commit
that referenced
this pull request
Jul 16, 2026
…ch + preflight recompute Addresses R2 CHANGES_REQUESTED from Miga + Rames on PR #2529: 1. Sibling-surface gap (blocker): `hyperframes cloudrun render{,-batch}`, `hyperframes lambda render{,-batch}` all advertised the same tier-only aliases (`1080p` / `hd` / `4k` / `uhd`) but normalized them to `landscape` and never set `outputResolutionAspectAgnostic`. The distributed plumbing PR #2529 added received `undefined` from those callers, so portrait `1080p` still hit the original aspect-mismatch on Cloud Run / Lambda. Fix: introduce `resolveResolutionFlagPair` in `@hyperframes/parsers` (the single source of truth for the two-step normalize + aspect-agnostic detect) and route every distributed entrypoint through a shared `parseOutputResolutionFlag` CLI util so the alias signal now reaches `SerializableDistributedRenderConfig`. Studio Server keeps its canonical-only HTTP contract; that intent is now pinned in tests. 2. Preflight recompute (hardening): the earlier "downgrade aspect-mismatch" preflight cleared un-remapped mismatches, so IG 4:5 (non-preset aspect, no sibling) and portrait-4K comp + `--resolution 1080p` (remap + downsample) both slipped through to fail late in `resolveDeviceScaleFactor`. Now `checkRenderResolutionPreflight` computes the effective preset via `suggestMatchingPreset` (mirroring the compile stage's `adaptAspectAgnosticResolution`) and re-checks against that — only genuinely-fixable mismatches clear early. New tests pin both regressed input classes. 3. Docker forwarding boundary test (Miga's important #2): pinned `1080p` survives verbatim as `--resolution 1080p` in the Docker args so the in-container CLI can re-run `isAspectAgnosticResolutionAlias`. 4. Doc-nit (Miga): parsers/src/types.ts no longer references the nonexistent `resolveResolutionForComposition` — points at the actual remap helpers. Fallow: cloudrun.ts / lambda.ts share 390 lines of pre-existing structural symmetry (parallel AWS + GCP dispatchers), and lambda/render.ts + render-batch.ts declare parallel RenderArgs interfaces. Both re-flagged after threading the aspect-agnostic field through each surface; ignored with justification in .fallowrc.jsonc. lambda.ts's `run` and lambda/render.ts's `waitForCompletion` are pre-existing CRAP-score hotspots untouched by this PR — added under health.ignore. Co-Authored-By: Claude <noreply@anthropic.com> — Via
This was referenced Jul 16, 2026
This was referenced Jul 23, 2026
4 tasks
This was referenced Jul 25, 2026
This was referenced Jul 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
@hyperframes/core— shared types, HTML generation, GSAP utilities, runtime@hyperframes/cli— CLI for creating, previewing, and rendering compositions@hyperframes/engine— framework-agnostic rendering engine (BeginFrame + FFmpeg)@hyperframes/producer— video rendering pipeline (Puppeteer + FFmpeg)@hyperframes/ui-player— browser-based video player component@hyperframes/studio— composition editor (React frontend + Hono backend)