PersistAdapter and PreviewAdapter. Both ship with concrete factory functions you pass to openComposition(). You can also implement either interface directly for custom storage backends (S3, IndexedDB, HTTP) or custom preview surfaces.
PersistAdapter
Interface
Returns the stored content for
path, or undefined for a path that has never been written. Never throws for a missing path.Persists
content at path. Idempotent — a second call with the same path overwrites the prior value. Write failures must not propagate as thrown exceptions; fire persist:error instead.Forces any queued or in-flight writes to commit before resolving. Call before process exit or navigation to prevent data loss.
Returns the version history for
path ordered newest-first. Returns an empty array when no versions exist. See PersistVersionEntry below.Returns the HTML content for a specific version identified by
versionKey. Returns undefined when the key does not exist.Subscribes to write failures. Returns an unsubscribe function. Adapters must emit this event — not throw — when a write fails, so the session continues running even when storage is temporarily unavailable.
Contract summary
read()returnsundefinedfor a path that has never been written — never throws ENOENT or a 404 equivalent.write()is idempotent; a second write to the same path replaces the stored content.flush()resolves when any pending writes are committed to durable storage.listVersions()returns entries newest-first;loadFrom()uses the keys from those entries.- Write errors are emitted via
on('persist:error'), never thrown — the session keeps running.
PersistVersionEntry
key is adapter-defined and opaque to callers — pass it directly to loadFrom(). The filesystem adapter encodes milliseconds and a counter into the key; the memory adapter uses an incrementing "v1", "v2" … scheme.
PreviewAdapter
applyDraft() directly on the adapter at 60fps, and the SDK only gets involved once per gesture when commitPreview() fires to derive and dispatch the resulting op.
Interface
Synchronous hit-test at composition coordinates
(x, y). Returns the nearest [data-hf-id] element under the point, or null for a transparent hit (the composition root, an opacity-0 element, or nothing at all). Requires a same-origin iframe — cross-origin access throws a DOMException. The atTime option reflects GSAP state at the current playhead; seeking to a speculative time is not supported.Applies draft CSS markers to the preview element at 60fps during a drag. Writes CSS custom properties (
--hf-studio-dx, --hf-studio-dy) onto the element so the composition’s CSS can visually translate it without touching the model. The SDK is not called here — this is a direct write to the preview surface by your pointer-move handler.Called once on pointer-up. Reads the accumulated draft markers, derives a
moveElement op from them, dispatches it into the SDK, emits a patch event, and clears the markers. This is the only moment the SDK becomes aware of a drag.Reverts the draft CSS markers without dispatching any op. The model is never changed. Call this on
Escape keydown or when a drag is aborted.Sets the preview selection and fires
selectionchange on the session. Pass { additive: true } to merge ids into the current selection rather than replacing it.Fired when the preview host changes the selection (for example, the user clicks an element). Returns an unsubscribe function. In the current release, callers listen to the session’s own
selectionchange event instead — this hook is wired in a future stage.ElementAtPointResult
id is the element’s data-hf-id value; tag is its lowercase tag name (e.g. "div", "img").
DraftProps
dx and dy are the accumulated drag deltas in composition pixels. width and height are defined in the interface for forward compatibility but are not yet wired to any op.
ElementAtPointResult and DraftProps are the structural shapes a PreviewAdapter produces and consumes. They are not re-exported from the @hyperframes/sdk barrel — you implement against these shapes rather than importing them.Factory Functions
createMemoryAdapter
PersistAdapter backed by an in-process Map. Writes are synchronous; flush() is a no-op. Versions are keyed "v1", "v2" … and stored in memory with full content.
The returned value also exposes injectFault(message) — a test helper that causes the next write() call to fire a persist:error event with message instead of committing. Use this in unit tests to verify your error-handling code path.
createMemoryAdapter() is best suited for tests, demos, and ephemeral in-process sessions. For local development, use createFsAdapter() so edits survive restarts.createFsAdapter
PersistAdapter that reads and writes files under a root directory. Import from the @hyperframes/sdk/adapters/fs subpath — this module uses Node fs/promises and is excluded from the browser-safe main bundle.
FsAdapterOptions
Absolute or relative path to the directory where composition files are written. Created with
mkdir -p on first write.Maximum number of historical versions retained per file. Oldest versions are pruned automatically when the limit is exceeded. Defaults to
20.{root}/{path} and stores version snapshots in {root}/.hf-versions/{path}/. Version keys encode Date.now() and a monotonic counter ("1750000000000-0001"), so listVersions() returns them newest-first by lexicographic descending sort.
createHeadlessAdapter
PreviewAdapter for headless use: agents, CI pipelines, and server-side rendering. All methods are stubs — elementAtPoint always returns null, applyDraft and commitPreview are no-ops, and the "selection" event never fires.
Pass this adapter when you open a composition for programmatic editing and do not need a live preview surface.
openComposition defaults to a headless preview adapter when none is supplied, so you rarely need to pass it explicitly. The main use case is making the intent clear in code that runs in both headless and browser environments.createIframePreviewAdapter
PreviewAdapter that bridges the SDK to a same-origin <iframe> containing the composition. Provides real hit-testing via elementsFromPoint (z-stack aware), draft drag support, and selection management.
Requirements:
- The iframe must be same-origin (e.g. a
srcdocorblob:URL). Cross-origin access tocontentDocumentthrows aDOMException. - Pass your session’s
dispatchcallback to enablecommitPreview()— without it, pointer-up is a no-op on the model.
<img> elements, the adapter samples the alpha channel of the pixel under the pointer using an OffscreenCanvas. Transparent pixels fall through to the element behind. Cross-origin images that taint the canvas are treated as opaque (safe fallback, logged once per src).
Export Map
| Symbol | Imported from |
|---|---|
PersistAdapter, PreviewAdapter, PersistVersionEntry | @hyperframes/sdk (types only) |
createMemoryAdapter | @hyperframes/sdk |
createHeadlessAdapter | @hyperframes/sdk |
createIframePreviewAdapter, resolveNearestHfElement | @hyperframes/sdk |
createFsAdapter, FsAdapterOptions | @hyperframes/sdk/adapters/fs |
Persistence Guide
How to wire adapters into openComposition, handle errors, and restore versions.
Canvas Integration
Building a visual editor canvas with the iframe preview adapter and hit-testing.