Source: @hyperframes/sdk, Authentication & API keys, Feedback Collection — HeyGen HyperFrames docs
Three plumbing-layer docs for driving HyperFrames programmatically rather than by hand. @hyperframes/sdk is the headless, framework-neutral editing engine an agent or custom editor embeds to open composition HTML and mutate it by stable element ID (no React, no browser, no Studio). Authentication explains that HyperFrames runs fully offline with zero keys (local Kokoro voice + MusicGen music), and that signing into a HeyGen account — via browser OAuth or an API key — only upgrades the voice/music/SFX providers; credentials resolve env-var-first, then ~/.heygen/credentials. Feedback Collection documents the anonymous post-render satisfaction prompt, its agent-runtime variant (a structured hyperframes feedback hint instead of a blocking readline prompt), and every opt-out.
Key Takeaways
@hyperframes/sdkis the embeddable editing engine, not a renderer.npm install @hyperframes/sdk. Open HTML withopenComposition(html), mutate elements by stable HyperFrames ID, thenserialize()back to HTML. Render with the CLI or@hyperframes/producerinstead; lint/parse low-level HTML with@hyperframes/core; capture frames with@hyperframes/engine.- Edits target explicit element IDs, never UI selection — which is what makes the SDK safe for headless agents and backend jobs (mutations don’t depend on mouse state). Typed convenience methods:
setText,setStyle,setAttribute,setTiming,setVariableValue,removeElement, plusbatch()to fold many mutations into one undo entry / persist write / change event. - Four package exports. Main
@hyperframes/sdk(editing API + memory/headless/iframe adapters),/adapters/memory(tests, ephemeral sessions),/adapters/fs(Node filesystem with version history),/adapters/headless(no-op preview for agents, CI, server-side). - Advanced control surface for agents:
dispatch()emits data-shaped ops;can()returns{ ok }so a host can gate a UI control or optional op before applying it;on("patch", …)mirrors edits (with inverse patches) into a host’s own history/collab/audit layer;applyPatches()replays inverse patches when the host owns undo/redo. - Embedded override mode for template products. Open a base composition with a sparse
overridesmap ("hf-title.text": "…","hf-logo.attr.src": "…"); the SDK layers overrides on the base, accumulates further edits into that set, andgetOverrides()returns only the delta to store. - Auth is optional — HyperFrames works with no key at all. No credential is a normal state, not an error: voice falls back to Kokoro-82M (54 voices, Whisper for word-level caption alignment), music to MusicGen (
facebook/musicgen-small), SFX to a bundled library. Local engines are free and offline. - Signing in uses a HeyGen credential, two ways.
npx hyperframes auth loginopens browser OAuth and captures the token on a loopback port (same step as account creation). For CI/headless,npx hyperframes auth login --api-key(hidden prompt) or pipe a key from stdin. Credential stored at~/.heygen/credentials(mode0600) — no per-repo.env. - Credential resolution is first-match-wins:
HEYGEN_API_KEYenv var →HYPERFRAMES_API_KEYalias →~/.heygen/credentials. Override the config dir withHEYGEN_CONFIG_DIRand the backend withHEYGEN_API_URL(defaulthttps://api.heygen.com). - Each capability picks the first available provider; the last is always a local engine. Voice: HeyGen → ElevenLabs → Kokoro. Music: HeyGen library → Lyria (Gemini key) → MusicGen. SFX: HeyGen library → bundled. Capture descriptions: OpenRouter → Gemini. The same HeyGen credential also renders in HeyGen’s cloud (see Cloud rendering).
- Feedback is anonymous and opt-out-able. A post-render CLI prompt appears on the first successful render then every 15th, with a 10-second auto-timeout, auto-suppressed in
--quiet, non-TTY, and CI. The Studio session bar shows from the 10th session, every 10 after. Each install has only a random UUID — no account, email, IP, file paths, or composition content is ever collected. - Agents get a non-blocking feedback path. When a known agent runtime is detected, HyperFrames skips the interactive prompt and prints a structured hint to run
hyperframes feedback --rating <1-5> --comment "…". Detected agents include Claude Code (CLAUDECODE/CLAUDE_CODE_ENTRYPOINT), Codex, Cursor, GitHub Copilot Agent, Replit, Hermes (HERMES_QUIET), openclaw, and Pi — only the presence/value of the marker var is checked, never secrets.
@hyperframes/sdk — programmatic composition editing
The SDK is the layer to embed behind your own UI or automation. The CLI and Studio are user-facing tools over the same composition format; the SDK is the engine underneath.
Install + quick start:
npm install @hyperframes/sdkimport { openComposition } from "@hyperframes/sdk";
const comp = await openComposition(html);
const [headlineId] = comp.find({ text: "Old headline" });
if (headlineId) {
comp.setText(headlineId, "New headline");
comp.setStyle(headlineId, { color: "#FFD60A", fontSize: "96px" });
}
const updatedHtml = comp.serialize();
comp.dispose();Typed editing methods (all target a stable element ID):
comp.setText("hf-title", "Launch day");
comp.setStyle("hf-title", { color: "#ffffff", transform: "translateY(24px)" });
comp.setAttribute("hf-logo", "src", "/assets/logo.png");
comp.setTiming("hf-title", { start: 0.5, duration: 2.5 });
comp.setVariableValue("brandColor", "#6C5CE7");
comp.removeElement("hf-old-caption");
// One undo entry, one persist write, one change notification:
comp.batch(() => {
comp.setText("hf-title", "Version 2");
comp.setStyle("hf-title", { color: "#22C55E" });
comp.setTiming("hf-title", { start: 1, duration: 3 });
});Iterate over elements by structure — e.g. set loading="eager" on every image:
const imageIds = comp.getElements()
.filter((el) => el.tag === "img")
.map((el) => el.id);
for (const id of imageIds) comp.setAttribute(id, "loading", "eager");Agent / automation control surface — dispatch() for data-shaped ops, can() to check feasibility first:
comp.dispatch({ type: "setStyle", target: "hf-card", styles: { borderRadius: "24px" } });
const result = comp.can({
type: "setGsapTween",
animationId: "anim-1",
properties: { ease: "power3.out" },
});
if (result.ok) comp.setGsapTween("anim-1", { ease: "power3.out" });Package exports:
| Import | Purpose |
|---|---|
@hyperframes/sdk | Main editing API, types, memory/headless adapters, iframe preview adapter |
@hyperframes/sdk/adapters/memory | In-memory persistence — tests, demos, ephemeral sessions |
@hyperframes/sdk/adapters/fs | Node.js filesystem persistence with version history |
@hyperframes/sdk/adapters/headless | No-op preview adapter for agents, CI, server-side editing |
Persistence, undo/redo, and patch mirroring
Pass a persist adapter to autosave; hosts can implement the same PersistAdapter interface for S3, HTTP, IndexedDB, etc.:
import { openComposition } from "@hyperframes/sdk";
import { createFsAdapter } from "@hyperframes/sdk/adapters/fs";
const comp = await openComposition(html, {
persist: createFsAdapter({ root: "./project" }),
persistPath: "index.html",
});
comp.setText("hf-title", "Saved title");
await comp.flush();
comp.on("persist:error", ({ error }) => console.error("Autosave failed:", error.message));Standalone sessions ship undo/redo (comp.undo() / comp.redo()). Subscribe to "patch" to mirror edits into a host’s own state/collab/audit log (the handler receives patches, inversePatches, origin); applyPatches() replays inverse patches when the host owns history. ^[inferred: the docs describe each event/method individually; the “mirror into host history/collab/audit” framing combines them]
Embedded override mode (template-driven products)
const comp = await openComposition(templateHtml, {
overrides: {
"hf-title.text": "Customer-specific title",
"hf-logo.attr.src": "/customers/acme/logo.png",
},
history: false,
});
comp.setStyle("hf-title", { color: "#0EA5E9" });
const nextOverrides = comp.getOverrides(); // store only the deltaPreview adapters
The SDK runs fully headless via createHeadlessAdapter(), or bridges to a same-origin composition iframe via createIframePreviewAdapter() so hit-testing, selection, and draft-preview updates stay outside the model-mutation path.
Authentication & API keys
HeyGen credential = upgrade, not requirement. TTS, music, and SFX retrieval all fall back to local engines when no key is present.
Sign in:
# Browser OAuth (loopback-port token capture) — same step as account creation
npx hyperframes auth login
# ✓ Signed in.
# CI / headless — long-lived API key:
npx hyperframes auth login --api-key # hidden-input prompt
echo "$HEYGEN_API_KEY" | npx hyperframes auth login --api-key # from stdin
# Verify (add --json for { configured, recommended_action, offline_engines }):
npx hyperframes auth statusCredential is stored at ~/.heygen/credentials (mode 0600). The separate heygen CLI is API-key-only (no npx heygen) but reads the same file, so signing in with one carries to the other.
Credential resolution — first match wins:
HEYGEN_API_KEY(environment variable)HYPERFRAMES_API_KEY(alias for parity with other tools)~/.heygen/credentials(written byhyperframes auth login/heygen auth login)
Provider hierarchy by capability (first available provider wins; last is a no-key local engine):
| Capability | Provider order | Keys (first match) | Local fallback dependency |
|---|---|---|---|
| Voice (TTS) | HeyGen → ElevenLabs → Kokoro | HEYGEN_API_KEY → HYPERFRAMES_API_KEY → ~/.heygen; then ELEVENLABS_API_KEY | pip install kokoro-onnx soundfile |
| Music (BGM) | HeyGen library → Lyria → MusicGen | HeyGen credential; then GEMINI_API_KEY → GOOGLE_API_KEY | pip install transformers torch soundfile numpy |
| Sound effects | HeyGen library → bundled | HeyGen credential | bundled — no deps |
| Capture descriptions | OpenRouter → Gemini | OPENROUTER_API_KEY → GEMINI_API_KEY | — (optional; for website-to-video) |
Environment variables:
| Variable | Used for |
|---|---|
HEYGEN_API_KEY | HeyGen credential (voice + music/SFX retrieval). Highest priority. |
HYPERFRAMES_API_KEY | Alias for HEYGEN_API_KEY. |
HEYGEN_API_URL | API base URL (default https://api.heygen.com). |
HEYGEN_CONFIG_DIR | Credentials directory (default ~/.heygen). |
ELEVENLABS_API_KEY | ElevenLabs TTS when no HeyGen credential is present. |
GEMINI_API_KEY / GOOGLE_API_KEY | Lyria music generation (and capture descriptions). |
OPENROUTER_API_KEY | Capture descriptions; takes priority over Gemini for that step. |
Run npx hyperframes doctor to check which local Python deps are installed. The media skills run hyperframes auth status as a preflight before generating, so you always know whether a run will use HeyGen or a local engine first.
Note: this auth flow is the CLI/skills credential model — HeyGen account via OAuth/API key, no Anthropic key involved. It is distinct from the separately documented HeyGen MCP
/mcpOAuth-into-HeyGen path used for avatar generation inside Claude Code (see hyperframes). ^[inferred — relationship between the two HeyGen sign-in surfaces is not stated on the fetched authentication page]
Feedback collection (and how to silence it)
HyperFrames sends anonymous satisfaction scores through a PostHog pipeline to catch the “render succeeded in logs but the file is broken” gap. The only identifier is a random per-install UUID (anonymousId).
CLI post-render prompt — fires on the first successful render, then every 15th (16th, 31st…), once per process, 10-second auto-timeout, auto-suppressed in --quiet, non-TTY shells, and CI:
# Change the interval (default 15):
HYPERFRAMES_FEEDBACK_INTERVAL=5 hyperframes render --output out.mp4Manual feedback (under the Settings group in --help; collects a doctor summary, flushes, exits):
hyperframes feedback --rating 5
hyperframes feedback --rating 3 --comment "render succeeded but GSAP timeline didn't animate text overlay"
# --rating 1–5 (required) --comment free-text (optional)Agent runtimes skip the readline prompt and print a structured hint instead — [hyperframes] Agent feedback: hyperframes feedback --rating <1-5> --comment "..." — same first-then-every-15th cadence. Detected via env markers: Claude Code (CLAUDECODE / CLAUDE_CODE_ENTRYPOINT), Codex (CODEX_THREAD_ID / CODEX_CI / CODEX_SANDBOX_NETWORK_DISABLED), Cursor (TERM_PROGRAM=cursor), GitHub Copilot Agent, Replit (REPL_ID / REPLIT_USER), Hermes (HERMES_QUIET), openclaw (OPENCLAW_STATE_DIR / OPENCLAW_CONFIG_PATH), Pi (PI_CODING_AGENT). Only the marker’s existence/value is read — never a key that shares a prefix.
What’s collected: survey id (render_satisfaction for CLI / studio_experience for Studio), the 1–5 rating, optional comment, render_duration_ms, and a doctor_summary env string (e.g. os=darwin/arm64 node=v22.11.0 cpu=10cores mem=32GB ffmpeg=yes). Never collected: file paths, project names, composition content/HTML/video, env var values, PII, IP, or location.
Opt out:
hyperframes telemetry disable # persisted to ~/.hyperframes/config.json
HYPERFRAMES_NO_TELEMETRY=1 hyperframes render --output o.mp4 # per-session
DO_NOT_TRACK=1 hyperframes render --output o.mp4 # global standard
hyperframes render --quiet --output o.mp4 # suppress output, keep telemetryCLI state lives in ~/.hyperframes/config.json (renderSuccessCount, lastFeedbackPromptAt, etc.). The Studio feedback bar is gated separately — disabling CLI telemetry does not silence it. Build-time controls: VITE_HYPERFRAMES_NO_FEEDBACK=1 disables the bar unconditionally; VITE_HYPERFRAMES_FEEDBACK_INTERVAL=N changes its cadence.
Try It
- Programmatic edit smoke test:
npm install @hyperframes/sdk, then in a Node scriptopenComposition(html),comp.setText(id, "..."),comp.serialize()— confirm the returned HTML reflects the edit without spinning up Studio or a browser. - Check your provider tier before generating: run
npx hyperframes auth status --jsonand readoffline_engines/configured— confirms whether the next render uses HeyGen voices+music or local Kokoro+MusicGen. Thennpx hyperframes doctorto see which local Python deps are installed. - Sign in for premium media:
npx hyperframes auth login(browser OAuth) on a dev box, or--api-keyfrom stdin in CI — the credential lands in~/.heygen/credentialsand is reused by theheygenCLI too. - Keep agent pipelines unblocked: confirm
CLAUDECODE/CIis set in your render environment so the feedback prompt never blocks; submit ratings explicitly withhyperframes feedback --rating N --comment "...", or opt out entirely withDO_NOT_TRACK=1.
Related
- hyperframes
- hyperframes-packages
- hyperframes-quickstart-cli
- hyperframes-rendering
- hyperframes-skills-catalog
Open Questions
- Does
~/.heygen/credentialsstore an OAuth refresh token or a long-lived API key afterauth login(browser flow)? The page states the file is shared with the API-key-onlyheygenCLI but doesn’t specify the stored credential type. - How does the CLI/skills HeyGen sign-in (this page) relate to the HeyGen MCP
/mcpOAuth path used for avatar generation in Claude Code — same token store, or independent? Not addressed on the fetched authentication page (noted inline as^[inferred]). - The SDK page references
setGsapTween(viacan()/dispatch()) but the typed-methods list omits it — is it dispatch-only, or is there a typedcomp.setGsapTween(...)signature? The Quick Start example calls it directly, implying a typed method, but it isn’t enumerated. - Does the PostHog feedback pipeline have a self-hostable / region-pinned endpoint for privacy-sensitive deployments, or is the destination fixed? Not stated.