PreviewAdapter interface decouples the editing model from the visual surface. For browser-based editors, createIframePreviewAdapter bridges the SDK to a same-origin <iframe> containing the composition, giving you synchronous hit-testing, 60fps drag preview, and selection management — all without touching the model until the user commits.
The iframe must be same-origin (e.g.
srcdoc or a blob: URL). Cross-origin iframe access throws a DOMException; the adapter does not guard this, so enforcing same-origin is the caller’s responsibility.Embedding the composition
Render the composition HTML into a same-origin<iframe> in your editor shell, then pass that element plus a dispatch callback to createIframePreviewAdapter:
comp before it is declared — that is intentional and safe: the arrow function captures comp by closure and is only ever invoked later (by commitPreview() on pointer-up), by which point comp is assigned. This is the standard way to break the adapter ⇄ session circular dependency.
The dispatch callback is optional. Omitting it means commitPreview() is a no-op, which is useful if you want to handle op derivation yourself.
Hit-testing: finding what the user clicked
preview.elementAtPoint(x, y) performs a synchronous hit-test at coordinates in the iframe’s own coordinate space and returns the nearest [data-hf-id] element, or null for a transparent hit.
0 (including ancestors with opacity: 0), and for <img> elements it samples the alpha at the clicked pixel using an offscreen canvas — a transparent pixel falls through to the element behind it. Cross-origin images that taint the canvas fall back to treating the pixel as opaque.
The opts.atTime parameter is accepted but does not seek the GSAP timeline. It reflects whatever frame the composition is currently paused at in the iframe. Accurate out-of-time-band opacity queries are a future capability.
Walking a click target to the nearest HF element
If you are working with events on the iframe’scontentDocument directly (e.g. via a message bridge), use the exported resolveNearestHfElement function. It walks up the DOM from any node until it finds a [data-hf-id] ancestor, skipping the root:
resolveNearestHfElement returns null when the walk exits the tree without finding a [data-hf-id] node, when the matching node carries [data-hf-root] (the root is transparent to selection), or when isVisible returns false for that node.
Draft loop: 60fps drag without model mutations
The draft loop keeps the model clean during a drag. The SDK is not in the 60fps path — you callpreview.applyDraft on every pointermove and preview.commitPreview once on pointerup. The model sees exactly one moveElement op per drag, rather than hundreds.
applyDraft writes CSS custom properties (--hf-studio-dx, --hf-studio-dy) directly onto the target element inside the iframe. The composition’s CSS uses these vars to translate the element visually. Nothing in the SDK model changes.
DraftProps accepts dx, dy, width, and height. Width and height are accepted by the interface but resize support (mapping to a setStyle op) is not yet wired — only dx/dy drive the draft CSS vars today.
Call cancelPreview() instead of commitPreview() to discard the drag without emitting any op. The model is never mutated and the CSS vars are cleared.
Selection
preview.select(ids, opts?) sets the selection state and fires the session’s selectionchange event on any listeners. Pass { additive: true } to extend the current selection rather than replace it.
comp.on("selectionchange", ...) — the adapter fires that event, not a separate event on the iframe.
Pairing with embedded override mode
For template-driven products you typically open the composition in embedded override mode and store only the sparse delta, not the full HTML. The preview adapter works identically in that mode — pass it the same way:What to build next
Once hit-testing and drag are working, you can use the affordance resolver to drive a context-aware inspector panel for whatever element is selected. See Editing Affordances for how to translate a live element into capability flags and section applicability.Adapter reference
Full
PreviewAdapter, PersistAdapter, and related type documentation.Editing Affordances
Resolve which edit controls to show for the selected element.