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/sdk is the embeddable editing engine, not a renderer. npm install @hyperframes/sdk. Open HTML with openComposition(html), mutate elements by stable HyperFrames ID, then serialize() back to HTML. Render with the CLI or @hyperframes/producer instead; 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, plus batch() 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 overrides map ("hf-title.text": "…", "hf-logo.attr.src": "…"); the SDK layers overrides on the base, accumulates further edits into that set, and getOverrides() 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 login opens 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 (mode 0600) — no per-repo .env.
  • Credential resolution is first-match-wins: HEYGEN_API_KEY env var → HYPERFRAMES_API_KEY alias → ~/.heygen/credentials. Override the config dir with HEYGEN_CONFIG_DIR and the backend with HEYGEN_API_URL (default https://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/sdk
import { 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 surfacedispatch() 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:

ImportPurpose
@hyperframes/sdkMain editing API, types, memory/headless adapters, iframe preview adapter
@hyperframes/sdk/adapters/memoryIn-memory persistence — tests, demos, ephemeral sessions
@hyperframes/sdk/adapters/fsNode.js filesystem persistence with version history
@hyperframes/sdk/adapters/headlessNo-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 delta

Preview 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 status

Credential 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:

  1. HEYGEN_API_KEY (environment variable)
  2. HYPERFRAMES_API_KEY (alias for parity with other tools)
  3. ~/.heygen/credentials (written by hyperframes auth login / heygen auth login)

Provider hierarchy by capability (first available provider wins; last is a no-key local engine):

CapabilityProvider orderKeys (first match)Local fallback dependency
Voice (TTS)HeyGen → ElevenLabs → KokoroHEYGEN_API_KEYHYPERFRAMES_API_KEY~/.heygen; then ELEVENLABS_API_KEYpip install kokoro-onnx soundfile
Music (BGM)HeyGen library → Lyria → MusicGenHeyGen credential; then GEMINI_API_KEYGOOGLE_API_KEYpip install transformers torch soundfile numpy
Sound effectsHeyGen library → bundledHeyGen credentialbundled — no deps
Capture descriptionsOpenRouter → GeminiOPENROUTER_API_KEYGEMINI_API_KEY— (optional; for website-to-video)

Environment variables:

VariableUsed for
HEYGEN_API_KEYHeyGen credential (voice + music/SFX retrieval). Highest priority.
HYPERFRAMES_API_KEYAlias for HEYGEN_API_KEY.
HEYGEN_API_URLAPI base URL (default https://api.heygen.com).
HEYGEN_CONFIG_DIRCredentials directory (default ~/.heygen).
ELEVENLABS_API_KEYElevenLabs TTS when no HeyGen credential is present.
GEMINI_API_KEY / GOOGLE_API_KEYLyria music generation (and capture descriptions).
OPENROUTER_API_KEYCapture 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 /mcp OAuth-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.mp4

Manual 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 telemetry

CLI 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

  1. Programmatic edit smoke test: npm install @hyperframes/sdk, then in a Node script openComposition(html), comp.setText(id, "..."), comp.serialize() — confirm the returned HTML reflects the edit without spinning up Studio or a browser.
  2. Check your provider tier before generating: run npx hyperframes auth status --json and read offline_engines / configured — confirms whether the next render uses HeyGen voices+music or local Kokoro+MusicGen. Then npx hyperframes doctor to see which local Python deps are installed.
  3. Sign in for premium media: npx hyperframes auth login (browser OAuth) on a dev box, or --api-key from stdin in CI — the credential lands in ~/.heygen/credentials and is reused by the heygen CLI too.
  4. Keep agent pipelines unblocked: confirm CLAUDECODE/CI is set in your render environment so the feedback prompt never blocks; submit ratings explicitly with hyperframes feedback --rating N --comment "...", or opt out entirely with DO_NOT_TRACK=1.

Open Questions

  • Does ~/.heygen/credentials store an OAuth refresh token or a long-lived API key after auth login (browser flow)? The page states the file is shared with the API-key-only heygen CLI but doesn’t specify the stored credential type.
  • How does the CLI/skills HeyGen sign-in (this page) relate to the HeyGen MCP /mcp OAuth 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 (via can() / dispatch()) but the typed-methods list omits it — is it dispatch-only, or is there a typed comp.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.