- version.ts: replace hardcoded "0.1.0" with __CLI_VERSION__ injected by
tsup at build time from package.json — fixes version mismatch where
`hyperframes --version` reported 0.1.0 while package was 0.1.4
- tsup.config.ts: add define.__CLI_VERSION__ using package.json version
- render.ts: renderDocker error handler showed "Try --docker" even when
already using --docker — changed to "Check Docker is running: docker info"
- dev.ts: add missing --port arg to embedded mode; findAvailablePort now
starts from the user-supplied port instead of hardcoded 3002
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add nullish coalescing for regex match groups that TypeScript flags as
possibly undefined.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wire up the "Export MP4" button in the studio UI. The render runs
async in the same process using @hyperframes/producer's executeRenderJob,
with SSE progress streaming and MP4 download on completion.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When installed via npx, `hyperframes dev` now starts a standalone
Hono HTTP server that serves the pre-built studio SPA and implements
the project API (file listing, read/write, preview bundling,
sub-composition rendering, runtime serving, SSE file watching).
Three modes are auto-detected:
1. Monorepo dev (running from .ts source) → spawn Vite (existing)
2. Local @hyperframes/studio installed → spawn Vite via package (new)
3. Default → embedded Hono server (new, zero extra deps needed)
Also patches the studio SPA to use EventSource SSE fallback when
Vite HMR is unavailable (production/embedded builds).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous approach called loadHyperframeRuntimeSource() to regenerate
the runtime IIFE, but its output lacked the trailing newline present in
the pre-built artifact, causing a SHA256 checksum mismatch with the
manifest. Copy the pre-built files from core/dist directly instead.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Empty src="" on <audio> elements causes the browser to fetch the
current page URL as the audio source, producing 404 errors in the
console during rendering. These are placeholder sound effect slots
whose src should be set dynamically when audio is configured.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CLI's ensureBrowser() finds Chrome via env var, cached download,
or system paths (including /Applications/Google Chrome.app on macOS).
But the result was discarded — the engine's acquireBrowser() only
checked the puppeteer cache for chrome-headless-shell, passing
undefined executablePath on macOS without headless-shell installed.
Bridge the two by setting PRODUCER_HEADLESS_SHELL_PATH from the CLI's
resolved browser path before creating the render job, so the engine's
resolveConfig() picks it up.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The hyperframeRuntimeLoader uses import.meta.url to resolve
hyperframe.manifest.json as a sibling file. When bundled into the CLI
via tsup, import.meta.url points to dist/cli.js, so the sibling lookup
checks dist/hyperframe.manifest.json — which wasn't being shipped.
Copy the manifest and the canonical-named runtime IIFE into dist/ during
the build-runtime step so the loader's sibling-path resolution works in
published npm packages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CLI bundle uses tsup to inline @hyperframes/producer, but the
deterministicFonts module used require.resolve('@fontsource/*/package.json')
at runtime to find woff2 files on disk. When installed via npx, these
@fontsource packages don't exist, causing "Cannot find module" errors.
Replace runtime filesystem lookups with a build-time generator that reads
all @fontsource woff2 files and produces a TypeScript module with base64
data URIs. The generator runs before both producer and CLI builds, making
the bundle fully self-contained with zero @fontsource runtime dependencies.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Release v0.1.3
Bumps all packages to v0.1.3.
### Changes since v0.1.2
- fix(producer): resolve manifest from sibling dist/ directory
- fix(producer): add margin reset when wrapping HTML fragments
- fix(producer): exclude test files from tsc build
- feat(cli): add opt-out anonymous telemetry via PostHog
- feat: add HyperFrames skills for AI coding tools
- fix(cli): resolve npx hyperframes from inside monorepo
- fix(ci): publish workflow fixes (remove provenance, idempotent steps, remove prepublishOnly)
After merging, the release tag is created automatically, which triggers npm publish.
* feat(cli): non-interactive by default, --human-friendly for UI
Following ElevenLabs CLI pattern: default mode is agent-friendly
(flag-driven, plain text output, fail fast on missing args).
Interactive clack UI is opt-in via --human-friendly.
Init command:
- --template required in default mode (errors with example if missing)
- --video / --audio flags for media input
- --skip-skills / --skip-transcribe to control optional steps
- --human-friendly enables the existing interactive prompts
- --help shows examples for every flag combination
- Transcription runs automatically in default mode (unless --skip-transcribe)
- Plain console.log output, process.exit(1) on errors
Skills command:
- Added --human-friendly flag
- Added examples to --help output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): improve --help documentation and add --yes/--check to upgrade
- upgrade: add --yes and --check flags to skip interactive prompt
- benchmark: clarify description — preset fps/quality/worker configs
- browser: describe each subcommand (ensure/path/clear) in help
- docs: list available topics inline in --help output
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): add whisper transcription to init flow
New modules:
- whisper/manager.ts: download/cache whisper.cpp binary + model
(~/.cache/hyperframes/whisper/)
- whisper/transcribe.ts: extract audio, run whisper, save transcript.json
Init flow changes:
- "Got a video or audio file?" now accepts audio-only files (mp3, wav, m4a)
- "Generate captions from audio?" prompt after file selection
- Transcription produces transcript.json in project root
- Graceful fallback if whisper/ffmpeg unavailable
Supports: macOS ARM64/x86, Linux x86_64. Downloads whisper.cpp v1.7.3
from GitHub releases and ggml-base.en model from Hugging Face.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): use brew/system whisper instead of downloading binaries
whisper.cpp doesn't ship pre-built macOS/Linux CLI binaries.
Use brew install whisper-cpp on macOS (auto-installs if brew available),
system PATH lookup otherwise. Model still downloaded from Hugging Face.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): simplify whisper install — detect or instruct, don't build
Remove build-from-source complexity. If whisper-cpp is found on PATH,
use it. If not, show install instructions instead of blocking:
"To generate captions, install whisper-cpp: brew install whisper-cpp"
The transcription prompt only appears when whisper is available.
When it's not, the user sees the install command and can re-run init.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): auto-install whisper via brew or build from source
ensureWhisper() now tries 4 strategies in order:
1. System PATH (whisper-cli or whisper already installed)
2. Homebrew (macOS: brew install whisper-cpp)
3. Build from source (git clone + cmake, ~30-60s)
4. Show install instructions as last resort
Init flow always asks "Generate captions?" — whisper is installed
automatically in the background if needed. No user intervention
required on macOS with Xcode CLI tools or any system with git+cmake.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): add window.__timelines guard to all templates
The studio bundler doesn't always initialize window.__timelines
before template scripts run, causing "Cannot set properties of
undefined" errors. Add defensive guard to every template.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): patch template captions with actual transcript data
After scaffolding, if transcript.json exists, replace the hardcoded
word array in the template's captions composition with the real
transcript data. The template's caption animation and styling are
preserved — only the word data changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): show install notice when whisper needs to be installed
When whisper-cpp isn't found, show an info message before the spinner:
"whisper-cpp not found — installing automatically..."
Then the spinner shows "Installing whisper-cpp (this may take a moment)..."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): add muted and playsinline to all template video elements
The framework requires video elements to have muted and playsinline
attributes. All four templates were missing these, causing video
to not play in the studio preview.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): flat asset structure + separate audio tracks in templates
Assets: video, images, fonts all go at project root (not assets/ or
fonts/ subdirectories). The studio preview can't resolve relative
paths from subdirectories due to the /preview URL suffix.
Audio: added <audio> elements alongside muted <video> in all 4
templates so the video's audio plays back. The framework requires
muted video + separate audio element.
Removed assets/ and fonts/ directory creation from scaffoldProject.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(studio): inject base tag for asset resolution in preview
The preview iframe serves bundled HTML from /api/projects/:id/preview
but relative asset paths (video.mp4, font.woff2) resolve to the wrong
URL without a <base> tag. Now injects <base href="/api/projects/:id/preview/">
so relative paths route through the static asset handler.
Also adds proper MIME types for video, audio, image, and font files
served from the preview asset route.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(studio): serve HyperFrames runtime in dev mode
The preview runtime script had an empty src — the framework never
loaded, so video playback and clip lifecycle didn't work.
Now auto-detects packages/cli/dist/hyperframe-runtime.js and serves
it at /api/runtime.js. No env var needed in dev mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): filter whisper special tokens from transcript
Use --output-json instead of --output-json-full to avoid special
tokens like [_TT_485] and [BLANK_AUDIO]. Also filter remaining
bracket tokens when building the word array for captions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): use --output-json-full for word-level timestamps
--output-json only produces segment-level timing (no tokens).
--output-json-full is required for word-level timestamps that
the captions template needs. Special tokens are filtered out
by the patchTranscript function.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): patch template durations to match uploaded video
Templates now use __VIDEO_DURATION__ placeholder that gets replaced
with the actual probed video duration. All data-duration values on
the root composition, video, audio, and caption clips are updated.
Without a video, defaults to 10 seconds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): merge punctuation tokens with preceding word
Whisper outputs punctuation (. , ! ?) as separate tokens. These
appeared as standalone words in captions, sometimes in the wrong
group. Now merged with the preceding word during transcript
normalization.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): match both TRANSCRIPT and script variable names in templates
Three templates use `const TRANSCRIPT = [...]` while warm-grain uses
`const script = [...]`. The patchTranscript function now matches both.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): security and template fixes
- Replace shell injection risk (execSync rm) with unlinkSync in transcribe.ts
- Add GIT_TERMINAL_PROMPT=0 to whisper buildFromSource git clone
- Fix hardcoded data-duration="18" in warm-grain captions template
- Add data-start="0" to root compositions in swiss-grid, vignelli, warm-grain
- Add data-start="0" to warm-grain grain-overlay composition
- Deduplicate hasFFmpeg: remove from init.ts, import from whisper/manager.ts
- Add my-video/ and packages/studio/data/ to .gitignore
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): format warm-grain captions and fix TS nullability errors
- Format warm-grain/compositions/captions.html
- Add optional chaining on token.offsets (may be undefined)
- Use intermediate variable for lastWord to satisfy TS strict checks
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): add blank template option, smart defaults for video vs audio
- Blank template: minimal scaffolding (root composition, video, audio,
GSAP timeline) with __VIDEO_SRC__ and __VIDEO_DURATION__ placeholders
- Template defaults: video uploads default to "blank" (user brings
their own content), audio-only defaults to "warm-grain" (motion
graphics template since there's no video to show)
- Audio-only projects now tracked with isAudioOnly flag
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): address whisper review feedback
- Clean stale builds: if BUILD_DIR exists but no binary, nuke and retry
- Build failures clean up BUILD_DIR so next attempt starts fresh
- patchTranscript regex scoped within <script> blocks to prevent
matching across block boundaries
- Removed hardcoded model size hint (~148MB)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): add missing rmSync import to whisper manager
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove test project and lock file
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): address review items 7-12 — execFileSync, build diagnostics, WAV verification
- manager.ts: replace all execSync with execFileSync to prevent command injection
- manager.ts: capture cmake stderr and include in build failure error message
- transcribe.ts: verify WAV is 16kHz mono via ffprobe before passing to whisper
- init.ts: replace fragile JSON formatting with JSON.stringify(words, null, 2)
- init.ts: fix default duration from "10" to "5" matching DEFAULT_META
- init.ts: add probeAudioDuration() and --audio/--skip-transcribe flags
- init.ts: extract finalizeProject() to reduce code path duplication
- init.ts: wire transcription into non-interactive path
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): publish CLI from temp copy to avoid workspace mutation
Copy packages/cli to a temp directory before renaming to "hyperframes"
for publish. Avoids corrupting the workspace if the job fails mid-way.
Addresses review feedback on #47.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): resolve leftover conflict markers in publish.yml
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): add skills install command
Adds `hyperframes skills install` to download and install HyperFrames
and GSAP skills globally to ~/.claude/skills/. Also adds
`hyperframes skills list` to show installed skills.
- HyperFrames skills: bundled in CLI dist, copied from dist/skills/
- GSAP skills: cloned from github.com/greensock/gsap-skills
- Cache: ~/.cache/hyperframes/gsap-skills/ (shallow clone, updated on install)
- Handles overwriting existing skills (removes before copy)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(cli): simplify skills to flat command
`hyperframes skills` directly installs + shows summary.
No subcommands needed — list was redundant since install
already prints all installed skills.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): scope skills summary to only HyperFrames and GSAP skills
The summary now only lists skills installed by this command, grouped
by source (HyperFrames vs GSAP), instead of listing everything in
~/.claude/skills/.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): correct dev path for bundled skills directory
Path needed 4 levels up from cli/src/commands/ to reach repo root,
not 3. Was resolving to packages/.claude/skills/ instead of
.claude/skills/.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): support multiple AI coding tools for skills install
Install to Claude Code, Gemini CLI, and Codex CLI by default.
Use flags to target specific tools:
hyperframes skills # claude + gemini + codex
hyperframes skills --cursor # cursor only (project-level)
hyperframes skills --claude # claude only
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): move skills to repo root, support multi-CLI install
- Move skills from .claude/skills/ to skills/ (tool-agnostic location)
- Install to Claude Code, Gemini CLI, Codex CLI by default
- Add --claude, --gemini, --codex, --cursor flags for targeting specific tools
- Update build script to copy from skills/ instead of .claude/skills/
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add infographics skill for data visualization compositions
Professional infographic design and animation patterns:
- Typography hierarchy (hero stat, label, context)
- Layout rules (grid-aligned, generous whitespace, 2-color max)
- 5 infographic types: single stat, comparison, bar chart, progress, steps
- Animation patterns: count-up, bar growth, entrance choreography, exits
- Narration sync (stat appears when narrator says the number)
- Design constraints (no gradients, no shadows, no clip art)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add evals for infographics skill
Three eval scenarios testing design quality and animation correctness:
1. Single stat — count-up animation synced to narration
2. Comparison — before/after reveal with visual hierarchy
3. Process steps — sequential reveal with dimming
Each eval has PASS/FAIL criteria covering: composition structure,
design rules (typography, layout, color), animation patterns
(timing, easing, choreography), and anti-patterns.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: remove infographics and transitions skills, add asset-management
Removed skills that don't add value beyond model knowledge:
- infographics: model already produces equivalent output without it
- transitions: patterns are derivable from compose-video constraints
Added:
- asset-management: organize user-uploaded files into assets/ and fonts/
- Typography section in compose-video: min font sizes, font loading
(Google Fonts + local @font-face), weight pairing, font-display:block
- Assets section in compose-video: project structure with assets/ and
fonts/ directories, path rules, CORS, "check before creating" rule
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: consolidate skills to 3, split compose-video under 500 lines
Removed skills that don't add value beyond model knowledge:
- media: duplicates compose-video
- social-media: platform safe areas are the only unique content
- infographics: model produces equivalent output without it
- transitions: patterns derivable from compose-video
Remaining skills (3):
- compose-video: core framework contract (452 lines, under 500 limit)
- patterns.md: PiP, title card, slideshow examples (loaded on demand)
- typography-and-assets.md: font loading, sizes, asset paths (on demand)
- captions: tone-adaptive caption styling from script analysis
- asset-management: organize uploaded files into project directories
Rewrote captions skill to focus on style detection from transcript
content (per-word styling, tone mapping) rather than mechanical rules.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): create assets/ and fonts/ directories on init
- scaffoldProject now creates assets/ and fonts/ directories
- Video files are placed in assets/ instead of project root
- Template __VIDEO_SRC__ placeholders resolve to assets/filename
Aligns with the compose-video skill's project structure convention
where user-provided media goes in assets/ and fonts in fonts/.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(cli): fetch skills from GitHub repos instead of bundling
Skills are now fetched directly from their source repos at runtime:
- HyperFrames skills: github.com/heygen-com/hyperframes (skills/ dir)
- GSAP skills: github.com/greensock/gsap-skills (skills/ dir)
Both cached in ~/.cache/hyperframes/ and updated on each run.
Removed skills bundling from build:copy step.
Requires the hyperframes repo to be public for HyperFrames skills
to install. GSAP skills work immediately (public repo).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): install skills automatically during init
After scaffolding a new project, `hyperframes init` now runs
`hyperframes skills` to install HyperFrames and GSAP skills.
Best-effort — if skill installation fails (no git, no network),
project creation still succeeds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): show skills install feedback during init
Added installAllSkills() export for programmatic use by init.
Init now shows a spinner and result message:
"11 AI skills installed (Claude Code, Gemini CLI, Codex CLI)"
Falls back gracefully if git or network unavailable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): let users select which AI tools to install skills for
Interactive init now shows a multi-select prompt:
"Install AI coding skills for: Claude Code, Gemini CLI, Codex CLI, Cursor"
Users can deselect tools they don't use or add Cursor (off by default).
Non-interactive mode still installs to all default targets.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): prevent git credential prompt from hanging skills install
Set GIT_TERMINAL_PROMPT=0 so git clone/pull fails immediately on
private repos instead of hanging for username/password input.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): show skipped skill sources and accurate counts
Skills install now reports which sources failed (e.g., private repo)
and only counts skills that actually installed. Prompt text simplified
to "Install skills for:".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): clean up skills command output
- Skipped sources shown as dim text, not error with full command
- Summary shows "Skipped: HyperFrames (repo not accessible)"
- Outro says "ready" not "installed"
- Shows "No skills installed" if everything failed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): clarify partial skill install in outro message
When some sources fail, the outro now says which skills are ready
and which are unavailable, instead of a misleading total count.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove planning docs and test scaffolding
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove eval projects and test examples
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove remaining test project data
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): use generic source names in skills install outro message
Replace hardcoded "GSAP skills ready. HyperFrames skills unavailable."
with a dynamic message listing which sources succeeded and which were
skipped, so the message stays correct as sources change.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): address review feedback on skills install
- Lazy process.cwd() for Cursor target (getter, not module-load)
- Track overwritten skills (logged in install output)
- Add --skip-skills flag to init for agent-friendly non-interactive use
- Guard both interactive and non-interactive paths with skipSkills
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): remove assets/ and fonts/ directories from init
Video files go to project root, not assets/. Removes assetsDir,
fonts/ directory creation, and assets/ prefix from video path.
Flat project root convention consistent with compose-video skill.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): address review items 5, 6, 13 — execFileSync, resilient cache, clear counting
- Replace all execSync with execFileSync for git commands (prevent injection)
- On git pull failure, reuse stale cache if skills dir exists instead of nuking
- Extract gitClone() helper for consistent clone calls
- Use explicit counted flag instead of confusing target === targets[0]
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): rename workspace package so npx resolves from registry
Rename packages/cli from "hyperframes" to "@hyperframes/cli" so that
npm/npx stops resolving it as a local workspace package when run from
inside the monorepo. The publish workflow sets the name back to
"hyperframes" before publishing so the npm package name is unchanged.
Root cause: npm sees workspaces in root package.json, finds packages/cli
named "hyperframes", assumes it's local, but bun manages node_modules
so there's no bin symlink — npx fails with "command not found" instead
of falling back to the registry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): update lockfile for workspace package rename
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): publish CLI from temp copy to avoid workspace mutation
Copy packages/cli to a temp directory before renaming to "hyperframes"
for publish. Avoids corrupting the workspace if the job fails mid-way.
Addresses review feedback on #47.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): resolve leftover conflict markers in publish.yml
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- flushSync: use detached spawn + unref() instead of execFileSync,
so process.exit() paths don't block up to 5s on slow networks
- showTelemetryNotice: persist notice flag BEFORE printing/tracking,
so users are never tracked without having seen the disclosure
- Config dir: set mode 0o700 on ~/.hyperframes/ directory (was umask default)
- $ip: null comment: clarify this is belt-and-suspenders with server-side discard
- shouldTrack: update comment — phc_ prefix check is a safety net, not dead code
- env.ts: add comment explaining try/catch fail-safe defaults to production
- init.ts: consistently call trackInitTemplate after scaffoldProject in both paths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Run oxfmt on cli.ts and client.ts
- Replace literal placeholder comparison with phc_ prefix check
(TS2367: comparing two different string literals has no overlap)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PostHog's $ip: null property tells the server to not associate the
request IP with the event. Combined with the "Discard client IP data"
project setting for server-side enforcement.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract shared isDevMode() to utils/env.ts (was duplicated in dev.ts and client.ts)
- Use ui/colors.ts instead of raw ANSI escapes in telemetry notice (respects NO_COLOR)
- Derive known commands from subCommands object instead of maintaining duplicate set
- Skip telemetry on --help/--version and unknown commands
- Gate incrementCommandCount() behind shouldTrack() (no disk writes in CI)
- Add flushSync() for process.exit() paths (beforeExit doesn't fire on explicit exit)
- Remove dead trackBrowserInstall(success) param (failure path never called it)
- Remove redundant isEnabled/anonymousId caching in client.ts (config.ts cache suffices)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add anonymous usage telemetry to help improve the CLI. Uses PostHog's
HTTP batch API directly (zero new dependencies) with a 5-second timeout
and fail-silent behavior — telemetry never breaks the CLI.
What's collected: command names, render performance (duration, fps,
quality), template choices, OS/arch/Node version/CLI version.
What's NOT collected: file paths, project names, video content, or
any personally identifiable information.
Telemetry is:
- Disabled in dev mode (running via tsx)
- Disabled in CI (CI=true) or via HYPERFRAMES_NO_TELEMETRY=1
- Disabled when API key is placeholder (safe to merge before key is set)
- Controllable via `hyperframes telemetry [enable|disable|status]`
- Disclosed on first run with clear opt-out instructions
Config stored at ~/.hyperframes/config.json (0600 permissions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add READMEs for all 5 packages (core, engine, producer, cli, studio)
with install, overview, basic usage, and links to full docs
- Rewrite core README from internal doc to OSS-facing format
- Polish root README: add badges, packages table, docs link, requirements
- Add AI usage policy and BDFL governance statement to CONTRIBUTING.md
- Genericize license references (pending final license decision)
- Docs URL set to hyperframes.heygen.com
Addresses VA-850.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: initial code port from hyperframes-internal
Port all OSS-ready packages from the internal monorepo:
- @hyperframes/core — shared types, HTML generation, GSAP utilities, runtime
- @hyperframes/cli — CLI for creating, previewing, and rendering compositions
- @hyperframes/engine — framework-agnostic rendering engine (BeginFrame + FFmpeg)
- @hyperframes/producer — video rendering pipeline (Puppeteer + FFmpeg)
- @hyperframes/ui-player — browser-based video player component
- @hyperframes/studio — composition editor (React frontend + Hono backend)
Includes regression test suite with Docker-based test harness.
All HeyGen-internal references, deployment infrastructure, and
proprietary assets have been removed. Package names migrated
from @app/* to @hyperframes/*.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: scrub internal codenames and stale references from OSS port
- Replace static.heygen.ai runtime URLs in test fixtures
- Remove internal CDN publish script (publish-hyperframe-runtime.ts)
- Replace sandbox-studio, sandbox-interceptor, __magicEditRuntime
with neutral names (studio, hyperframe-runtime, __hyperframeRuntime)
- Fix stale Vault API / localhost references in docs
- Remove broken deprecated_studio link
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove remaining internal codenames and stale references
- Delete stale producer README.md and PIPELINE.md (referenced nonexistent files)
- Replace "Cerberus" codename with "HyperFrames" in test design reviews
- Replace magic-edit postMessage identifiers with hf-preview/hf-parent
- Rename debug-magic-edit-timeline.ts to debug-timeline.ts
- Replace "Motion Cut" with "HyperFrames" in Timeline comments
- Fix studio/CLI references to nonexistent archive package
(use local data/projects/ dir, stub render proxy)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>