mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-11-07 15:27:14 +00:00
sync/hyperframes-codegen-856bcbbf
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
73dfe35e46 |
fix(preview): show the correct scene instead of every scene at once on some loads (#3848)
* fix(runtime): show the right scene when the preview DOM comes from another window The Studio preview sometimes builds the composition body in the editor window and adopts it into the preview frame's document. Adopted nodes keep the prototypes of the realm that created them, so `node instanceof HTMLElement` is false for every element in the composition even though the elements are ordinary HTML sitting in that document. Every guard in the runtime written as `if (!(node instanceof HTMLElement))` then skipped the whole document, silently: nothing threw, nothing logged, and readiness still reported success. The timed-element visibility pass wrote no inline visibility at all, so on those loads the preview painted every scene on top of every other and the editor drew off-canvas markers for elements the user could not see. The auto-stamp pass stopped stamping too, which is why the composition came up one timeline clip short. Replace every realm-sensitive element check in the runtime with structural predicates that ask what a node IS (node type, namespace, tag name) rather than which window's constructor made it. Two local `doc.defaultView.HTMLElement` workarounds are deleted with it: they fix only the case where the nodes belong to the document's own realm, and adoption is exactly what breaks that. * fix(studio): scrub the music track the timeline named, not the first audio `resolveScrubAudioEl` tested `byId instanceof HTMLAudioElement` on a node from the preview iframe's document. That node is an instance of the IFRAME's `HTMLAudioElement`, never this module's, so the check was false on every load and the `musicId` hint was dead. Scrub fell through to the first `<audio>` in the document, which the comment right above it warns can be the voiceover, so dragging the playhead could preview the wrong track. Ask what the node is instead. Also close the gaps an independent review found in the runtime fix: - the cross-realm predicate test had no `<audio>` and no `<img>`, so reverting `isAudioElement` or `isImageElement` to `instanceof` left it green. It no longer does, and the audio case also pins `isMediaElement`, which composes from it and gates the media sync path. - nothing stopped the runtime regressing. `lint-runtime-preview-guards.ts` gains a second check kind: patterns that must be ABSENT under a directory, seeded with DOM-typed `instanceof` under `src/runtime`, pointing at domRealm.ts. Comment lines and tests are exempt, both on purpose. - domRealm.ts stated the adoption mechanism as settled fact. The mixed prototypes are measured; how the nodes get into the frame is not identified, and the docstring now says which is which. Its ownership claim is scoped to the runtime, since packages/studio still hand-rolls its own checks. |
||
|
|
634df5a5af |
fix(producer): give inlined media a document-unique render id (#3342)
* fix(producer): give inlined media a document-unique render id
Element ids are unique per composition file, but the render document is
the inlined union of every file. The producer merged the per-file media
lists and deduplicated by id, so clips that shared an id collapsed into a
single entry, and every id-keyed stage (extract, inject, visibility,
bounds) resolved to whichever element came first in the document. The
surviving clip's frames landed on the wrong element and the visible scene
rendered without footage.
Two shapes hit this, and neither is author error:
- Two scenes that each declare `<video id="clip">`. Legal per file, and
unavoidable when a scene is duplicated into a copy with inner ids
kept, or when one file is mounted twice.
- Two scenes that each declare a bare `<video>`. The timing compiler
numbers auto-ids per file, so both arrive as `hf-video-0` with no
authored id involved at all.
Stamp a document-unique `data-hf-render-id` while inlining, and read the
media list off the inlined document instead of merging per-file lists.
The render id equals the element id whenever that id is already unique,
so documents without a collision keep identical pipeline keys.
Author `id` attributes are left alone: 158 of the 161 registry blocks
reference their own ids from `#id` CSS or getElementById, so renaming
would trade broken footage for broken styling. The engine resolves media
elements through the render id instead, falling back to getElementById
for documents the producer never compiled.
Collecting from the inlined document also retires the per-file media
extraction in parseSubCompositions along with its offset bookkeeping;
host offsets are recovered from the composition hosts the clip sits in.
* fix(core): resolve render-frame siblings by render id in the runtime
The injector creates each `__render_frame_<id>__` sibling from the media
element's render id, but four runtime readers still built that id from the
plain `el.id`. On a document where two compositions share a media id, all
of them resolved the first collider's frame.
colorGrading is the one that changes pixels: findRenderFrameImage returns
the image the grading pass samples, with no class check to catch the
mismatch, so the second video was graded from the first one's frame.
media, mediaProxy and video-texture-compat use it as a render-mode or
substitute-source signal, where both colliders happen to agree during
render, but none of them should rest on that.
Add renderFrameSibling as the single owner of "which frame belongs to
this element" and route all four through it. It reads the stamped render
id and falls back to the author id, so a collision-free document resolves
exactly as before and an uncompiled one (preview, snapshot, check) is
unchanged.
The engine's in-page bridge keeps its own copy of the rule because code
serialized into page.evaluate cannot import; it now names core as the
definition, and a test pins the sibling-id format both sides build so
they cannot drift apart silently.
* refactor(engine): build render-frame sibling ids from core's definition
The drift guard named both sides but pinned one. renderFrameSibling.test
asserts core's format, while the engine rebuilt the same id from a literal
template at six independent sites. Changing the format on either side left
the test green and every runtime reader silently unable to find its frame —
this PR's own failure mode, one level up.
Export the affixes and renderFrameIdForRenderId from core, and take the id
from there at all six. Four sites resolve it on the Node side, where the
engine can import; the two that iterate the DOM in-page receive the affixes
as evaluate arguments, which avoids depending on bridge install order.
Also switch two `__hfMediaId?.(el) ?? el.id` reads to `||`. The bridge
returns "" for an element with neither id, so `??` kept the empty string
and built `__render_frame___`, which no reader looks for. Inert today
because the compiler assigns positional ids to id-less timed media, but it
made the two sides disagree in the one case they could.
|
||
|
|
e64a22893a |
fix(studio): preserve alpha proxy playback (#2625)
* fix(studio): preserve alpha proxy playback * test(cli): pin VP8 alpha proxy pre-resolution * fix(studio): emit textarea field-sizing CSS * test(studio): verify textarea CSS generation |
||
|
|
e8371a7acc |
feat(media): alpha-capable authoring proxies (#2598)
* feat(media): alpha-capable authoring proxies Alpha sources were refused a proxy before the codec map ever asked whether the browser could decode them, so a ProRes 4444 alpha file (which no browser previews at all) rendered black forever, while an alpha WebM (which previews fine) was already covered by the browser-safe check on the next line. The alpha veto earned nothing and cost the one case that needed help. Alpha is now a target-codec choice rather than a veto: alpha sources transcode to VP9 + yuva420p in WebM, everything else keeps the existing H.264/MP4 path byte for byte. Only files no browser can preview are proxied, which is the rule the runtime already followed everywhere else. WebM cannot carry AAC, so the VP9 path uses Opus and drops the MP4-only faststart flag. PROXY_PARAMS_VERSION moves to v3 so clients stop serving the previously cached proxies. Safari does not decode VP9 alpha and still shows black for alpha sources, as it does today: this is better on Chromium and Firefox and no worse anywhere. * fix(media): infer proxy variant for rescue * fix(media): preserve alpha proxy hardening after restack |
||
|
|
39b588cbd0 |
feat(core): swap undecodable video to its proxy at runtime (#2592)
* feat(studio-server): serve H.264 proxies from the preview route Wires the codec manifest and the transcoder into the preview surface: the route negotiates a proxy via a query param and serves it through the existing range and ETag machinery, composition HTML carries a codec map for the runtime, and hostile assets pre-warm so a first play does not wait on a cold transcode. Exposes the three subpath exports the CLI surfaces consume upstack. Drops the TEMP fallow entry added with the transcoder: it has real importers now. * fix(studio-server): publish media proxy exports * fix(parsers): scan HTML comments linearly * feat(cli): let projects opt out of automatic proxying Adds media.autoProxy to hyperframes.json plus --proxy/--no-proxy flags, and forwards the resolved value into the studio and preview servers and the vite adapter. Lands before the runtime slice that turns auto-proxying on, so the switch exists before there is any behavior to switch off. * fix(cli): align media config schema * feat(core): swap undecodable video to its proxy at runtime Adds the browser-side half: before first load the runtime consults the injected codec map and swaps a hostile source to its proxy, and if a video still reports zero decodable width it rescues it reactively. An HEVC file carrying AAC fires no error event, so zero videoWidth, not the error event, is the reliable signal. Audio elements and alpha sources are never proxied, render mode never proxies, and each swap evicts the element's stale sync state and reports once. This completes the loop: auto-proxying is live for preview and studio from here. The opt-out (media.autoProxy, --no-proxy) shipped in the previous slice. |