Commit Graph
214 Commits
Author SHA1 Message Date
Miguel Ángel adc8ffed7d test: update missing-host-comp-id baseline after runtime body margin normalization
The body margin:0 fix shifts all content by 8px (removing the browser
default margin). The new render is correct — update the baseline.
2026-03-30 23:25:59 +02:00
Miguel Ángel 7bd8086387 fix(runtime): normalize html/body margin in runtime to eliminate white bars in renders
The browser's default 8px body margin was causing white bars at the top
and left edges of rendered videos. Previously normalizePreviewViewport
(a React call on the studio iframe) handled this for preview, but the
render pipeline never called it — creating a preview/render parity gap.

Fix: apply margin:0 / padding:0 / overflow:hidden on documentElement and
body at the start of initSandboxRuntimeModular, so both preview and render
contexts get identical normalization from the same code path.
2026-03-30 23:04:56 +02:00
Miguel Ángel f2ae1f592a fix(studio): remove debug outline from preview iframe; add sub-composition video regression test
Removes outline: '1px solid black' from the preview iframe in Player.tsx —
a leftover debug style that drew a visible rectangular border around every
composition preview.

Adds regression test 'sub-composition-video' to prevent recurrence of
the bug where video elements inside sub-compositions (lacking explicit
id attributes) rendered as black frames. Covers the three-part fix:
union selector in parseVideoElements, Infinity end fallback, and
auto-assigned id persistence into compiled HTML.
2026-03-30 22:56:15 +02:00
Miguel Ángel 5d88240b04 chore: add pre-commit Claude Code hook for build + lint + typecheck
Blocks git commit via Claude Code if pnpm build, pnpm run -w lint,
or per-package typecheck fails, catching issues like the TS2345
error that slipped through to CI.
2026-03-30 22:40:33 +02:00
Miguel Ángel 69bf6a3ad2 fix(cli): pass required width/height to buildChromeArgs 2026-03-30 22:34:53 +02:00
Miguel Ángel 3fa61e11c2 fix(cli): fix thumbnail generation — engine import, singleton browser, seek time
Root cause: buildChromeArgs/acquireBrowser imported from
@hyperframes/producer which does not re-export them; only
@hyperframes/engine does. All requests silently returned null.

Also: singleton shared browser (was spawning per request),
domcontentloaded instead of networkidle2, seek time 0.5→2s.
2026-03-30 22:24:43 +02:00
Miguel Ángel a182ffdb0c fix(studio): object-contain on inline hover-autoplay video and image assets 2026-03-30 22:24:43 +02:00
Miguel Ángel b1d5c0aaee fix(studio): use object-contain for thumbnails so portrait videos display correctly
object-cover was cropping 9:16 portrait videos to a narrow slice inside
the fixed landscape 80x45px thumbnail cells. object-contain shows the
full frame with neutral-background letterboxing. Applies to Renders tab,
Compositions tab, Assets tab, and timeline clip strip thumbnails.
2026-03-30 22:24:43 +02:00
Miguel Ángel f705402c6d fix(engine,studio): persist auto-assigned video IDs into compiled HTML; shared VideoFrameThumbnail
Render fix: parseVideoElements assigned IDs in JSDOM memory but the
compiled HTML written to disk had no id on id-less video elements, so
injectVideoFramesBatch's getElementById returned null. Now does a second
DOM pass to inject IDs into the HTML string before returning it.

Studio thumbnails: extracted VideoFrameThumbnail into a shared ui/
component. AssetsTab now uses canvas frame extraction (seeks to 10%
duration) instead of <video preload=metadata> which shows a black t=0
frame. RenderQueueItem imports from the same shared component.
2026-03-30 22:24:43 +02:00
Miguel Ángel 42de3086d9 fix(engine): resolve video end time from data-duration; probe file when end is unspecified
The runtime uses data-start + data-duration (not data-end) to bound
media clips. parseVideoElements was only reading data-end, so videos
with only data-start (no data-end, no data-duration) got end=0 and zero
frames were extracted.

Two-part fix:
1. parseVideoElements now derives end from data-end → data-start+data-duration
   → Infinity (meaning 'play for natural duration').
2. The frame extractor fallback that probes the actual file now triggers
   for both end<=0 and !isFinite(end), so Infinity correctly causes
   the video file to be probed for its real duration.
2026-03-30 22:22:35 +02:00
Miguel Ángel 18e1a76f11 feat(lint): add external_script_dependency rule for CDN scripts in sub-compositions
Added info-level lint rule that flags compositions loading external CDN
libraries via <script src>. The bundler auto-hoists these into the
parent document and the runtime re-injects them in unbundled mode, but
the rule surfaces the dependency so developers know it exists if using
a custom pipeline.

Also added tests for the htmlBundler fix (external CDN scripts from
sub-compositions are preserved and deduped in the bundle output).
2026-03-30 22:22:35 +02:00
Miguel Ángel 385cd19901 refactor(cli): use producer acquireBrowser/releaseBrowser for thumbnails
Replaced direct puppeteer.launch() call with the same acquireBrowser /
releaseBrowser / buildChromeArgs infrastructure the render pipeline
already uses. No new dependency is introduced (puppeteer-core is already
a transitive dep through @hyperframes/producer).
2026-03-30 22:22:35 +02:00
Miguel Ángel 30962b9ac7 fix(runtime): extend GSAP timeline in-place instead of creating composite
createDurationFloorTimeline appended a tween AFTER the existing
timeline, making it originalDuration + declaredDuration (e.g. 4.6+5.6=
10.2s) instead of just declaredDuration (5.6s). This caused regression
tests to render the wrong number of frames.

Now extends the original timeline in-place by placing a zero-duration
no-op tween at the declared end position — GSAP then reports the correct
duration with no composite overhead. Also adds a 0.5s minimum gap guard
to avoid floating-point false positives on compositions where the GSAP
timeline is already close to data-duration.
2026-03-30 22:22:35 +02:00
Miguel Ángel a63f644002 feat(studio): inline autoplay on render thumbnail hover (no expand)
On hover the thumbnail slot swaps from the static extracted frame to a
live muted looping video in the same w-20 h-[45px] cell — no overlay,
no expansion. Static frame fades out (150ms opacity) as the video takes
over; video is only mounted while hovered so it doesn't run in the
background.
2026-03-30 22:22:35 +02:00
Miguel Ángel 2e60005137 feat(studio): hover-to-autoplay on render rows using shared ExpandedVideoPreview
Extracted shared ExpandedVideoPreview component (src/components/ui/)
used by both AssetsTab (video assets) and RenderQueueItem (rendered
videos). Wraps completed render rows in ExpandOnHover with the same
spring-expand + video autoplay pattern as the Compositions and Assets
tabs. No code duplication: AssetsTab video case delegates to the shared
component, RenderQueueItem reuses it with an Open action button.
2026-03-30 22:22:35 +02:00
Miguel Ángel 781bae2a44 feat(studio): show video frame thumbnail on render rows
Extracts a first-representative-frame from the rendered MP4 using a
hidden video + canvas (same technique as VideoThumbnail). The thumbnail
cell matches CompCard's w-20 h-[45px] sizing so Renders, Compositions,
and Assets tabs all share the same visual language. Rendering/failed/
cancelled rows show a status indicator in the thumbnail slot instead.
2026-03-30 22:22:34 +02:00
Miguel Ángel 4d5b4976ef fix(engine): union video selectors to restore backward compat with regression tests
The video[src][data-start] selector excluded production compositions
whose video elements have id+src but no data-start, breaking all visual
frames while audio passed. Now unions both selectors so videos are
discovered if they match either video[id][src] (original) or
video[src][data-start] (sub-composition without explicit id).
2026-03-30 22:22:34 +02:00
Miguel Ángel 7bc8d3ff66 feat(studio): open rendered video in new tab on row click
Clicking a completed render row now opens the video inline in the
browser instead of forcing a download. Added /render/:jobId/view
endpoint with Content-Disposition: inline so the browser plays the
video natively. Download button is preserved on hover for explicit
saves. stopPropagation on action buttons prevents row click conflicts.
2026-03-30 22:22:34 +02:00
Miguel Ángel 04cf7b2eb6 fix(studio): raise Shift+drag hint above timeline clips with z-20 2026-03-30 22:22:34 +02:00
Miguel Ángel c41e9bf6cd fix(cli): replace deprecated page.waitForTimeout with setTimeout
page.waitForTimeout was removed in Puppeteer v22+.
2026-03-30 22:22:34 +02:00
Miguel ÁngelandClaude Sonnet 4.6 81e6ff6e73 fix(compiler): preserve external CDN scripts from sub-compositions in bundle
When bundleToSingleHtml inlined sub-compositions, external <script src>
tags were silently dropped because $content(s).html() returns "" for
external scripts. This caused CDN libraries like lottie-web loaded only
in a sub-composition to be missing from the bundle, breaking animations.

Now external script URLs are collected and deduped into the bundle,
preserving CDN dependencies from any sub-composition.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:22:34 +02:00
Miguel ÁngelandClaude Sonnet 4.6 2bd516044e fix(engine): render videos inside sub-compositions that lack an explicit id
parseVideoElements used "video[id][src]" which silently excluded video
elements without an id attribute — common in sub-compositions. Changed
selector to "video[src][data-start]" and auto-assign stable ids for
any video that lacks one, so the frame injection pipeline processes all
timed video clips.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:22:34 +02:00
Miguel Ángel 20f1a167fa fix(cli): implement generateThumbnail in studio adapter
The CLI adapter was missing generateThumbnail, so the thumbnail route
always returned 501 and composition thumbnails showed as blank black
rectangles in both the Compositions sidebar and the Timeline.
2026-03-30 22:22:34 +02:00
Miguel Ángel 90f2eb7a73 fix(studio): surface render error messages in the renders panel
The SSE progress stream already sent error details on failure but
the client never stored or displayed them. Failed renders now show
the error message below the status indicator, matching the detail
level of the CLI render command.
2026-03-30 22:22:34 +02:00
Miguel ÁngelandClaude Sonnet 4.6 3db7870d6d fix(runtime): fix Lottie adapter conflicting with GSAP-driven animations
Two issues caused GSAP-controlled Lottie animations to display at the
wrong frame or not at all:

1. Adapter order: Lottie ran after GSAP, overriding the correct frame
   from GSAP's onUpdate with wrong absolute-time ms.
   Fix: move Lottie before GSAP so GSAP's onUpdate fires last and wins.

2. play() conflict: adapter called anim.play() causing Lottie to
   advance independently, fighting GSAP's goToAndStop scrubbing.
   Fix: remove play() from the Lottie adapter (it is optional).

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:22:33 +02:00
Miguel ÁngelandClaude Sonnet 4.6 4f0cb3f789 fix(runtime): pad GSAP timeline to data-duration when composition declares longer duration
When a root composition declares data-duration="5" but the captured
GSAP timeline only has 3s of content, playback stopped at 3s.
resolveRootTimelineFromDocument now pads the timeline with a duration
floor tween to match the declared data-duration, so the composition
plays for its full declared length.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:22:33 +02:00
Miguel ÁngelandClaude Sonnet 4.6 9d1652ccd7 fix(studio): add range request support for audio/video seeking in preview
The static asset server was responding 200 OK with the full file for
all requests, including browser Range requests. Browsers send Range
requests when seeking audio/video elements; without 206 Partial
Content responses the seek fails silently and audio goes silent.
Now responds with 206 + Content-Range for byte-range requests and
always includes Accept-Ranges + Content-Length headers.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:22:33 +02:00
Miguel ÁngelandClaude Sonnet 4.6 6b33baa205 fix(studio): make previously-completed renders downloadable after restart
The download endpoint only checked the in-memory renderJobs map, which
is empty after a server restart. The list endpoint now registers on-disk
renders into the map when it serves them, so subsequent download
requests find the correct output file.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:22:33 +02:00
Miguel ÁngelandClaude Sonnet 4.6 9422acf9c2 fix(studio): store render job reference instead of snapshot copy
The spread operator created a shallow copy of jobState at call time.
Async mutations to the original state (progress, status) were never
reflected in the copy stored in renderJobs, so the SSE stream always
emitted progress:0.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:22:33 +02:00
Vance Ingalls 229538c622 fix: add media rendering guardrails to prevent silent failures (#112)
## Summary

- **Lint rules** catch media elements missing `id` (renderer silently skips them), missing `src`, `preload="none"` (blocks renderer), and video nested in timed divs (freezes playback). Upgraded `video_nested_in_timed_element` from warning to error.
- **Compiler** strips `preload="none"` from media during compilation. Runs parallel, cached keyframe interval analysis via ffprobe — warns on sparse keyframes (>2s) that cause seek failures and audio/video desync. Suggested ffmpeg command preserves audio (`-c:a copy`).
- **Pre-render lint** lints `index.html` + all `compositions/*.html` sub-compositions before render via shared `lintProject()` helper. Warns by default; `--strict` blocks on errors, `--strict-all` blocks on errors + warnings.
- **Render orchestrator** logs a hint to retry with `--workers 1` when parallel capture times out on video-heavy compositions.
- **Refactor**: extracted `runFfprobe()` + `parseProbeJson()` helpers to deduplicate ~80 lines of spawn boilerplate across 3 ffprobe functions. Extracted `shouldBlockRender()` so strict flag tests exercise production code. Shared `lintProject()` used by both `lint` and `render` commands.

## Context

Discovered during a real composition build session where:
1. `<audio>` without `id` rendered silently (preview worked fine because runtime queries `[data-start]`, but renderer queries `[id][src]`)
2. `<video>` inside timed `<div>` froze on first frame
3. `preload="none"` caused 45s renderer timeout
4. YouTube clips with sparse keyframes from `yt-dlp --download-sections` caused audio/video desync
5. Parallel workers timed out on video-heavy compositions

## Test plan

- [x] Core: 365/365 tests passing (5 new lint tests)
- [x] Engine: 24/24 tests passing
- [x] CLI: 14/14 tests passing (7 lintProject + 7 shouldBlockRender)
- [x] Lint + format hooks pass
- [ ] Manual: create a composition with `<audio data-start="0" src="test.wav">` (no id) — verify `npx hyperframes lint` catches it
- [ ] Manual: run `npx hyperframes render --strict` with lint errors — verify it blocks
- [ ] Manual: run `npx hyperframes render --strict-all` with lint warnings — verify it blocks
2026-03-30 11:07:19 -07:00
Miguel ÁngelandClaude Opus 4.6 808d196fe0 chore: bump to v0.1.12
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.1.12
2026-03-29 10:10:03 +00:00
Miguel Ángel 4d659064ef fix(studio): show clear error when render server is unreachable (#116)
## Summary

- Surfaces error message when render fails due to producer server not running
- Two cases covered: initial POST failure and SSE connection drop
- Failed jobs now show the error reason in red text in the Renders panel

## Test plan

- [x] Start studio without producer server
- [x] Click render → should show "Could not reach render server" in red
- [x] Start render then kill producer → should show "Connection lost"

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-29 08:16:05 +02:00
Miguel Ángel 05f28d9ba4 feat(cli): lint all HTML files and add --json for agents (#118)
## Summary
- `hyperframes lint` now scans ALL HTML files in the project (not just index.html)
- Includes composition files in `compositions/` directory
- `--json` output includes `file` field and `filesScanned` count
- Exit code 1 on errors for CI integration

## Examples
```bash
# Human-friendly output
hyperframes lint

# Agent/CI-friendly JSON
hyperframes lint --json
```

## Test plan
- [ ] `hyperframes lint` on a project with compositions → shows findings from all files
- [ ] `hyperframes lint --json` → outputs valid JSON with all findings
- [ ] Exit code 1 when errors found, 0 when clean
2026-03-29 08:15:31 +02:00
Miguel Ángel 54020d41ce fix(cli): use correct project name for symlinked directories (#117)
## Summary
- When running `hyperframes dev .` inside a symlinked directory, the project name showed the resolved target name instead of the visible directory name
- Now uses `$PWD` to preserve the user-facing name
- Added `projectName` option to `StudioServerOptions` for explicit override

## Test plan
- [ ] `ln -s /path/to/project my-project && cd my-project && hyperframes dev .` → should show "my-project"
- [ ] `hyperframes dev /path/to/project` → should show "project" (basename of path)
2026-03-29 08:15:01 +02:00
Miguel ÁngelandClaude Sonnet 4.6 6d105a3e64 chore: bump to v0.1.11
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
v0.1.11
2026-03-28 19:39:38 -04:00
Miguel Ángel b11edbf800 refactor(studio): wire vite.config.ts to shared studio API module (#115)
## Summary

- Replaces ~850 lines of inline route handlers in `vite.config.ts` with the shared `createStudioApi(adapter)` module
- Implements `StudioApiAdapter` for the Vite dev server context (SSR-loaded bundler/linter, producer HTTP proxy, Puppeteer thumbnails)
- Bridges Hono `fetch()` to Vite's Connect middleware with streaming support for SSE

Now **both** consumers (CLI + studio) use the same shared API module, ensuring feature parity.

## Test plan

- [x] `pnpm --filter @hyperframes/studio dev` starts correctly
- [x] Home page shows project grid with thumbnails
- [x] Preview plays with correct fonts/animations
- [x] Sub-composition drill-down works
- [x] Lint modal shows findings
- [x] File read/write works in code editor
- [x] Render queue works (requires producer server)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 22:30:44 +01:00
Miguel Ángel bd175b64a6 refactor(core): extract shared studio API module (#113)
## Summary
Extracts all studio API routes into a shared Hono-based module at `@hyperframes/core/studio-api`.

### Architecture
- **`StudioApiAdapter` interface** — consumers inject host-specific behavior (project resolution, bundling, rendering, thumbnails)
- **Shared route modules**: projects, files, preview, lint, render, thumbnail
- **Shared helpers**: `isSafePath`, `walkDir`, `getMimeType`, `buildSubCompositionHtml`

### What this PR does
- Creates the shared module with all API routes extracted from both `vite.config.ts` and `studioServer.ts`
- Both consumers will be refactored in follow-up commits to mount this module with their own adapter

### What stays in each consumer
- **Vite**: SSR module loading, Puppeteer thumbnails, file watcher + HMR, producer HTTP proxy, multi-project scanning
- **CLI**: in-process `executeRenderJob`, local runtime serving, browser management, SPA static file serving

### Follow-up needed
- [ ] Refactor `packages/studio/vite.config.ts` to use `createStudioApi(adapter)` via `@hono/node-server`'s `getRequestListener`
- [ ] Refactor `packages/cli/src/server/studioServer.ts` to use `createStudioApi(adapter)`
- [ ] Add `./studio-api` export path to `packages/core/package.json`
- [ ] Add `hono` as peer dependency of `@hyperframes/core`

## Test plan
- [ ] Verify shared module compiles without type errors
- [ ] After consumer refactoring: all studio features work identically via both vite dev and CLI embedded servers

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 22:28:12 +01:00
Miguel Ángel fecd4c8485 fix(core): strip template wrapper before linting composition files (#111)
## Summary
- Composition HTML files are always wrapped in `<template id="...">` tags
- The linter was checking the raw HTML including the template wrapper, causing false positives:
  - `missing-composition-id` on files that have it inside `<template>`
  - `missing-dimensions` on files that have `data-width`/`data-height` inside `<template>`
- Fix: strip `<template>` wrapper before linting, matching how the runtime and preview server handle these files

## Test plan
- [x] Added test: `strips <template> wrapper before linting composition files`
- [x] All 345 existing tests pass
- [ ] Verify lint panel no longer shows false positives for composition files

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 22:08:35 +01:00
Miguel Ángel 95d7dc0623 fix(cli): align render output naming and add WebM support to studioServer (#109)
## Summary

- CLI render: use timestamped filenames (`project_date_time.ext`) matching the studio's naming convention, preventing overwrites of previous renders
- studioServer: read `fps`/`quality`/`format` from POST body instead of hardcoding `fps:30`/`quality:standard`/`mp4`
- studioServer: use timestamped job IDs matching the studio pattern
- studioServer: fix download endpoint to serve correct content-type for WebM

## Test plan

- [x] `hyperframes render --format webm` outputs timestamped WebM file
- [x] `hyperframes render` outputs timestamped MP4 (no overwrite)
- [x] Studio embedded server (`hyperframes dev`) renders with correct format when selected in UI
- [x] Download endpoint serves correct MIME type for WebM renders
2026-03-28 21:49:10 +01:00
Miguel Ángel 40bd159103 feat(studio): render queue, layout restructure, home page, hover preview (#95)
## Summary
- Add render queue panel with progress tracking, download, and delete actions
- Restructure App layout: home page with project picker, session-based routing
- Add ExpandOnHover component for preview-on-hover interactions (uses motion/react)
- CompositionsTab now supports hover preview with expanded iframe view
- Vite config: guard setInterval cleanup to dev-only (fixes CI build timeout)
- Add favicon and update studio package deps

## Test plan
- [x] Render queue shows progress, completes, and allows download
- [x] Home page lists projects and navigates to session view
- [x] ExpandOnHover shows expanded preview on mouse hover with spring animation
- [x] `vite build` exits cleanly (no hanging process from setInterval)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 21:28:43 +01:00
Miguel Ángel 9ae239d177 feat(studio): add left sidebar with Compositions and Assets tabs (#94)
## Summary
- Add collapsible left sidebar with Compositions and Assets tabs
- Compositions tab lists all sub-compositions with thumbnail previews and navigation
- Clicking a composition opens it in the code editor AND navigates the preview to show that composition
- Assets tab categorizes project files by type (images, fonts, media)
- Race condition guard on composition fetch with functional state update
- Thumbnail error fallback shows name initial instead of empty box

## Test plan
- [x] Sidebar opens/closes with smooth transition
- [x] Compositions tab lists files from project API
- [x] Clicking a composition changes the preview iframe to that composition
- [x] Assets tab categorizes files by type

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 20:55:15 +01:00
Miguel Ángel 0167e69374 feat(studio): add Edit Range toolbar with Copy to Agent (#65)
## Summary
- Replace Split/Delete buttons with Edit Range toolbar
- Edit button opens a time-range selection on the timeline
- "Copy to Agent" exports the selected range as a prompt-ready description
- Range selection shows start/end times with drag handles

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 20:50:34 +01:00
Miguel Ángel 8c1ae77697 refactor(studio): update layout, config, and remove agent activity tracking (#64)
## Summary
- **NLELayout**: Add toolbar slot, composition breadcrumb navigation, improved responsive layout
- **Vite config**: Add full project API (preview, thumbnail, render, file CRUD) for standalone dev mode
- Remove AgentActivityTrack component (replaced by timeline clips)
- Add HTML editor utilities for composition source editing
- Guard setInterval cleanup to dev-only to prevent `vite build` from hanging in CI

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 20:45:00 +01:00
Miguel Ángel 0769678f46 refactor(studio): improve Timeline, PlayerControls, and player hook (#63)
## Summary
- **Timeline**: Refactored track rendering with zoom support, drag/resize interactions, and playhead scrubbing
- **PlayerControls**: Redesigned with seek bar, time display, playback rate selector
- **useTimelinePlayer**: Enhanced with iframe bridge communication, timeline message parsing, and deterministic seek
- Add Timeline unit tests (109 lines)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 20:39:35 +01:00
Miguel Ángel 625b5131bd refactor(studio): improve player store with zoom and element updates (#61)
## Summary
- Add zoom state (zoomMode, pixelsPerSecond) to player store
- Add timeline element updates (setElements, clearElements)
- Remove unused/duplicate exports from player barrel file

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-28 08:59:33 +01:00
James 7d7af7902b chore: release v0.1.10 v0.1.10 2026-03-28 03:59:00 +00:00
James RussoandClaude Opus 4.6 865843ba9a feat(cli): add system metrics to telemetry and expand doctor command (#110)
* feat(cli): add system metrics to telemetry and expand doctor command

Enrich render telemetry with device/environment metadata (CPU, memory,
OS, Docker/CI/WSL detection) following patterns from Next.js and
Turborepo. Add speed_ratio (render time / composition duration),
per-frame capture timing, and resource usage to render events.

Expand the doctor command with CPU, memory, disk, /dev/shm, and
environment checks to help debug rendering issues on user machines.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): invert speed_ratio to match experiment-framework convention

composition_duration / render_time — higher is better, >1 means faster
than realtime. Matches magic_edit.render.speed_ratio in experiment-framework.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): wire errorMessage into render error telemetry

Address review feedback — the errorMessage field was declared in the
trackRenderError interface but never populated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(cli): add render telemetry to embedded studio server

Track render_complete and render_error from the studio's render API
endpoint (hyperframes dev). Uses dynamic imports so telemetry is
resolved at call time within the CLI package — no telemetry coupling
added to @hyperframes/studio or @hyperframes/producer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:53:06 -07:00
James Russo ce63160907 Merge pull request #108 from heygen-com/chore/rename-skills-namespace
chore(skills): rename compose-video/captions to hyperframes-compose/hyperframes-captions
2026-03-27 18:42:10 -07:00
JamesandClaude Opus 4.6 b8149abef5 chore(skills): rename compose-video → hyperframes-compose, captions → hyperframes-captions
Namespace skill names with `hyperframes-` prefix for clearer identity in
OSS contexts where users may have other skills installed.

Updates skill directories, SKILL.md frontmatter, CLAUDE.md, README.md,
CLI build script, init command, and project template.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 01:26:13 +00:00
Miguel Ángel d781398813 feat(lint): add gsap_css_transform_conflict (#106)
## Changes

Added a new lint rule `gsap_css_transform_conflict` that detects when GSAP animations will silently overwrite CSS transforms.

**`gsap_css_transform_conflict` (error)** — fires when an element has `transform: translateX(-50%)` or `transform: scale()` in CSS and a GSAP `tl.to/from` tween animates `x`, `y`, `xPercent`, `yPercent`, or `scale`. GSAP silently overwrites the full CSS transform, discarding centering tricks like `translateX(-50%)`. Fix hint guides authors to the safe `fromTo` + `xPercent` pattern.

## Root cause

This bug surfaced while building compositions where title reveals were placed off-center because `tl.to("#title", { x: 0 })` stripped the `translateX(-50%)` centering from CSS.

## Test coverage

- [x] `gsap_css_transform_conflict` — `tl.to` with `x` on CSS `translateX` element → error
- [x] `gsap_css_transform_conflict` — `tl.to` with `scale` on CSS `scale()` element → error  
- [x] `gsap_css_transform_conflict` — `tl.fromTo` without CSS transform → no finding
2026-03-28 01:44:52 +01:00