Commit Graph
52 Commits
Author SHA1 Message Date
Vance IngallsandClaude Opus 4.6 614a67dfd3 fix: caption init race condition, auto-save, and panel auto-open
- Remove store reset from useEffect cleanup — was wiping state on dep changes
  and breaking auto-save subscription
- Move panel auto-open into useEffect instead of during render
- Add fallback 500ms poll alongside postMessage listener for initial load

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:13 -07:00
Vance IngallsandClaude Opus 4.6 f2718783c2 fix: use runtime postMessage events to detect caption composition loading
Replace polling with a message listener for hf-preview state/timeline
events. These fire after loadExternalCompositions completes, guaranteeing
.caption-group elements exist in the DOM. Eliminates the race condition
on initial page load.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:13 -07:00
Vance IngallsandClaude Opus 4.6 96866cddf6 feat: auto-detect captions from any composition, edit from master view
Caption edit mode now activates automatically when .caption-group elements
are found in the iframe DOM. Works from index.html (master) without
requiring drill-down into the captions sub-composition. Finds the captions
source file via data-composition-src attribute.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:12 -07:00
Vance IngallsandClaude Opus 4.6 76a667c281 feat: auto-activate caption editor when viewing captions composition
- Caption overlay and hover states always active on captions compositions
- Clicking a word auto-opens the property panel
- Remove Edit Captions button — edit mode activates automatically
- Reset edit mode when navigating away from captions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:12 -07:00
Vance IngallsandClaude Opus 4.6 0e1148556f feat: arrow key nudge for selected caption words
1px per press, 10px with Shift held. Syncs to store and auto-saves.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:12 -07:00
Vance IngallsandClaude Opus 4.6 f321269a65 refactor: strip property panel to position, scale, rotation only
Remove typography, color, opacity, stroke, and background controls.
Keep only Position (X/Y) and Transform (Scale/Rotation) — the controls
that work reliably with the wrapper-based override system.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:12 -07:00
Vance IngallsandClaude Opus 4.6 9dd394eb70 feat: active/dim color states for caption word overrides
Replace single "color" with activeColor (spoken) and dimColor (inactive).
Runtime hook modifies existing GSAP color tweens by detecting dim vs active
states via opacity heuristic. Property panel shows both color pickers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:12 -07:00
Vance IngallsandClaude Opus 4.6 613ed774ae refactor: remove preview refresh suppression during caption edit mode
No longer needed — caption overrides are a JSON data file, not HTML patches.
The runtime hook re-applies overrides on every reload, so preview refresh
during editing is safe and ensures the preview stays in sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:12 -07:00
Vance IngallsandClaude Opus 4.6 933b72b633 feat: auto-save caption overrides on model change
Replace manual Save button with 800ms debounced auto-save. Writing to
caption-overrides.json is safe because preview refresh is suppressed
during caption edit mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:12 -07:00
Vance IngallsandClaude Opus 4.6 b7d7a1c2b0 fix: wrapper-aware element resolution for caption overlay
- getWordEl skips wrapper spans and finds actual word elements inside them
- readWordBoxes handles wrapped words in position calculations
- getOrCreateWrapper detects if element IS a wrapper to prevent double-wrapping
- Remove debug logging from save

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:11 -07:00
Vance IngallsandClaude Opus 4.6 bf27578755 fix: caption overrides runtime hook — run in both load paths, write to project root
- applyCaptionOverrides() now runs both when compositions load async AND when
  already ready (standalone composition view)
- Overrides file written to project root (not compositions/) to match <base href>
- Remove debug logging

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:11 -07:00
Vance IngallsandClaude Opus 4.6 b6bdce065e feat: wrapper-based caption overrides — preserve all GSAP animations
Instead of killing transform tweens, wrap each overridden word span in an
inline-block wrapper span. Editor transforms (position, scale, rotation)
are applied to the wrapper while the inner span keeps all GSAP entrance,
exit, and karaoke animations intact.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:11 -07:00
Vance IngallsandClaude Opus 4.6 7c0f825d72 feat: caption overrides with stable word IDs and killTweensOf
- Add optional `id` field to transcript Word interface, assigned as `w{index}` during normalization
- caption-overrides.json uses `wordId` (preferred) with `wordIndex` fallback
- Runtime hook calls gsap.killTweensOf for overridden transform properties before applying
- Studio parser carries wordId through from transcript to segments
- Add typecheck to lefthook pre-commit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:11 -07:00
Vance IngallsandClaude Opus 4.6 5d2efb24c1 feat: replace HTML patching with caption-overrides.json data file
- New caption-overrides.json format: [{wordIndex, x, y, scale, rotation, color, ...}]
- Runtime hook in packages/core applies overrides via gsap.set() after compositions load
- Studio writes/reads caption-overrides.json instead of injecting code into HTML
- Original composition source is never modified
- Remove old parseExistingOverrides and source patching code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:11 -07:00
Vance IngallsandClaude Opus 4.6 b00f062bdf chore: revert unrelated LintModal changes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:10 -07:00
Vance IngallsandClaude Opus 4.6 7c07d09cf3 chore: add typecheck to lefthook pre-commit and fix container type
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:10 -07:00
Vance IngallsandClaude Opus 4.6 cb335ba2a7 feat(studio): caption designer canvas controls, real-time editing, and save-as-patch
- Canvas: move (translate), scale, and rotate handles on selected words via gsap.set()
- Property panel: real-time style updates applied directly to iframe DOM
- Save: patches original source with gsap.killTweensOf + gsap.set per edited word
- Parser: reads existing editor overrides on re-entry to preserve prior edits
- Suppress preview refresh during caption edit mode to prevent reload cycle

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:10 -07:00
Vance Ingalls 9f73dae176 feat(studio): add caption module barrel export 2026-04-01 23:37:10 -07:00
Vance IngallsandClaude Sonnet 4.6 2e850cb360 feat(studio): add caption timeline track with word-level blocks and drag-to-retime
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:37:10 -07:00
Vance Ingalls 876a053b90 feat(studio): add caption animation panel with entrance/highlight/exit controls 2026-04-01 23:37:10 -07:00
Vance Ingalls 0233ae2361 feat(studio): wire caption property panel and parser integration 2026-04-01 23:37:10 -07:00
Vance IngallsandClaude Sonnet 4.6 97b88d86fc feat(studio): add caption property panel with typography, color, and transform controls
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:37:09 -07:00
Vance IngallsandClaude Opus 4.6 9370e4fb7b feat(studio): wire caption overlay and edit mode into Studio
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 23:37:09 -07:00
Vance Ingalls fce9268304 feat(studio): add drag-to-reposition for caption segments 2026-04-01 23:37:09 -07:00
Vance Ingalls 9128524cf4 feat(studio): add caption overlay with segment selection boxes 2026-04-01 23:37:09 -07:00
Vance Ingalls 486a018dc9 feat(studio): add caption model → HTML source sync hook 2026-04-01 23:37:09 -07:00
Vance IngallsandClaude Sonnet 4.6 980ca1f750 feat(studio): add caption HTML generator
Implements generateCaptionHtml(model) which serializes a CaptionModel
into a complete captions.html HyperFrames composition with template
wrapper, CSS per-group classes, TRANSCRIPT array, and GSAP timeline
registration via window.__timelines["captions"].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:37:09 -07:00
Vance Ingalls 39712ba6e7 feat(studio): add caption editing Zustand store 2026-04-01 23:37:09 -07:00
Vance Ingalls be97bfadd6 feat(studio): parse caption styles from live iframe DOM 2026-04-01 23:37:08 -07:00
Vance IngallsandClaude Sonnet 4.6 7b5cfea5e8 feat(studio): build caption model from transcript words
Adds `buildCaptionModel` to the caption parser — groups TranscriptWord
arrays into CaptionGroups (default 5 words each), creates CaptionSegments
with correct timing and groupIndex, and wires in DEFAULT_STYLE,
DEFAULT_CONTAINER, and DEFAULT_ANIMATION_SET. Covers 23 tests (13 new).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:37:08 -07:00
Vance IngallsandClaude Sonnet 4.6 012d1afbf3 feat(studio): add transcript extraction from caption source
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 23:37:08 -07:00
Vance Ingalls 0d310fc05d feat(studio): add caption model types 2026-04-01 23:37:08 -07:00
Miguel Ángel 5f3488e996 feat(studio): drag-drop assetfile/folder and asset import anywhere in the studio (#155)
## Summary

- Add `/api/projects/:id/upload` endpoint for multipart file uploads with automatic dedup naming
- Wire `onImportFiles` from Assets tab "Import media" button through to the upload API
- Add global drag-drop overlay — drop media files **anywhere** in the studio, not just the Assets panel
- Files that already exist get `(2)`, `(3)` suffixes instead of overwriting
- Support uploading into subdirectories via `?dir=` param — dropping on a folder imports there
- Make folders draggable in the file tree + support drop-to-root
- Add `bodyLimit` middleware for early rejection of oversized payloads
- Surface skipped/failed uploads via toast notification instead of console-only

Addresses feedback: _"Wish I could upload/drag-drop assets directly in the Studio (music, images, video) like a CapCut media panel"_

## Test plan

- [x] Open studio, drag an image/video/audio file onto any part of the UI
- [x] Verify the drop overlay appears with "Drop files to import" message
- [x] Drop the file — verify it appears in the Assets tab and file tree
- [x] Drop a file with the same name — verify it gets a `(2)` suffix
- [x] Click "Import media" button in Assets tab — verify file picker works
- [x] Import multiple files at once via drag-drop
- [x] Drop a file onto a nested folder in the file tree — verify it lands in that folder
- [x] Drag a folder in the file tree and drop it on another folder or root — verify it moves
- [x] Drop a file >500MB — verify toast notification appears
- [x] Verify drag overlay doesn't get stuck when dragging over nested UI elements
2026-04-01 00:21:34 +02:00
Miguel Ángel ecb590d444 feat(studio): full IDE-like file management (#147)
## Summary

- **API**: POST (create), DELETE (delete), PATCH (rename/move), POST duplicate endpoints with null-byte sanitization
- **FileTree**: right-click context menu with New File, New Folder, Rename, Duplicate, Delete
- **Drag-and-drop**: move files between folders with visual feedback and subtree guard
- **Inline editing**: rename/create inputs with filename validation
- **Header actions**: quick New File / New Folder buttons in the FILES header

Stacks on top of `feat/studio-code-quality`.

## Test plan

- [x] Right-click file → Rename, Delete, Duplicate all work
- [x] Right-click folder → New File, New Folder, Delete work
- [x] Drag file from one folder to another
- [x] Create file with invalid name (`../foo`, `a/b`) → rejected client-side
- [x] Delete currently-edited file → editor clears
- [x] Studio build succeeds
2026-03-31 20:03:05 +02:00
Miguel Ángel dac304ed9f refactor(studio): code quality — 22 findings, dead code removal, App.tsx split (#144)
## Summary

Full code quality review of the studio package, fixing 22 of 25 findings. Removes dead code, extracts modules from App.tsx, fixes accessibility and performance issues.

## Critical fixes (3)

- **`aria-valuenow`** on seek bar now updates imperatively via `liveTime.subscribe` — screen readers previously always reported position 0
- **Speed menu** closes on outside click (was permanently stuck open)
- **RenderQueue auto-scroll** moved from render phase to `useEffect` (was violating React render purity via `queueMicrotask` during render)

## Dead code removed (-331 lines)

| File | Lines | Why dead |
|---|---|---|
| `PreviewPanel.tsx` | 180 | Replaced by NLELayout + NLEPreview |
| `useCodeEditor.ts` | 80 | Exported but never imported |
| `formatTick` alias | 2 | Deprecated, unused |
| `onClipChange` prop | 5 | Declared, never used |
| `trackH` prop | 5 | Declared, never used |
| `editRange*` + updaters in store | 60 | Never read or written |

## App.tsx extraction

| Extracted to | Lines | What |
|---|---|---|
| `components/LintModal.tsx` | 130 | Lint results modal + LintFinding type |
| `components/MediaPreview.tsx` | 75 | Image/video/audio/font file previewer |
| `utils/mediaTypes.ts` | 15 | Shared regex constants (App.tsx and AssetsTab.tsx had diverged copies) |

## Performance fixes

- `useMemo` for `compositions`/`assets` derivation from `fileTree`
- `useMemo` for `buildTree(files)` in FileTree
- Debounced `handleContentChange` PUT (600ms — was firing on every keystroke)
- CompositionsTab iframe hover debounced (300ms — was mounting immediately)
- `VideoFrameThumbnail` re-extracts frame when `src` prop changes

## Not addressed (3 — low priority)

- #6: SystemIcons consolidation (large refactor across many files)
- #16-17: Overlay dismiss pattern standardization
- #18: Inline SVG → Phosphor replacement (gradual, per-PR)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-31 04:21:12 +02:00
Miguel Ángel 1bc83c62a5 feat(studio): timeline hidden by default with toggle in header + player (#142)
## Summary

The timeline is now hidden by default. A toggle button appears in both the header (alongside panel toggles) and the player controls bar. Both sync the same state and turn teal when the timeline is visible.

## Changes

- **`timelineVisible` state** in `App.tsx`, defaults to `false`
- **Header toggle**: icon button between sidebar toggle and Renders button
- **Player controls toggle**: icon button at the right end of the controls bar
- **NLELayout**: `timelineVisible` and `onToggleTimeline` props gate the timeline + resize divider
- **Player controls stay visible**: moved from inside the timeline section to inside the preview area, so hiding the timeline doesn't hide play/seek/timecode

## Behavior

| State | Preview | Player controls | Timeline |
|---|---|---|---|
| Timeline hidden (default) | Full height | ✅ Visible | Hidden |
| Timeline visible | Shorter | ✅ Visible | Shown with resize handle |

Both toggle buttons show identical teal active state (`#3CE6AC/10` bg + `#3CE6AC/30` border).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-31 04:01:01 +02:00
Miguel Ángel 7b18c0352e feat(studio): redesign left panel — Code tab, Renders header, Lint bottom (#141)
## Summary

Major layout redesign matching the Paper mockup. The Code editor moves to the left panel, Renders moves to the header, and interactions are simplified.

## Layout changes

| Before | After |
|---|---|
| Left: Compositions \| Assets | Left: **Code** \| Compositions \| Assets |
| Right: Code \| Renders tabs | Right: Renders-only (hidden by default) |
| Header: Projects ← / Lint / panel toggles | Header: title / sidebar toggle / **Renders button** |
| Lint: header button | Lint: **pinned to bottom** of left panel |

## Interaction changes

- **Renders panel** opens via a dedicated header button (teal when active), hidden by default
- **ExpandOnHover removed** — replaced with inline autoplay on thumbnails:
  - Compositions: hover shows a tiny iframe (1920px scaled to 80px, 300ms debounce)
  - Assets: hover shows `<video autoPlay muted loop>` in the thumbnail cell
- **Deleted** `ExpandOnHover.tsx` (194 lines) and `ExpandedVideoPreview.tsx` (35 lines)
- **Left panel max width**: 50% viewport, auto-expands to 50% when opening a file in Code tab

## Visual polish

- Equal-width tabs (Code \| Compositions \| Assets)
- Sidebar toggle button highlighted when panel is open
- Phosphor duotone file-type icons (`FileHtml`, `FileCss`, `FileJs`, `FileTs`, etc.)
- "FILES" header removed from file tree
- Redundant "RENDERS (N)" title removed from renders panel

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-31 03:57:32 +02:00
Miguel Ángel 05a7b03841 feat(studio): remove home page, auto-select project (#145)
## Summary

Removes the `ProjectPicker` home screen entirely. The studio now boots directly into the editor by auto-selecting the first available project from `/api/projects`.

## Changes

- **Auto-select on load**: When no `#project/` hash is present, fetches the project list and navigates to the first one
- **Type narrowing**: Added `if (resolving || !projectId)` early return so TypeScript narrows `projectId` to `string` for all downstream props
- **Removed**: `ProjectPicker`, `ProjectCard`, `ExpandedPreviewIframe` components (~280 lines), `handleSelectProject` callback, `ProjectEntry` interface

## Why

The CLI studio always has exactly one project. The home page was an extra click with no value.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-03-31 03:51:55 +02:00
Miguel Ángel 1230657ed0 fix(studio,runtime,engine,compiler): 8 bug fixes — audio, render, timeline, Lottie, thumbnails, video render (#133)
## Summary

**Original 5 bugs fixed:**

- **Bug 1 — Audio silent after seek**: Added `Accept-Ranges` / `Content-Length` + `206 Partial Content` to the static asset server for byte-range seeking.
- **Bug 2 — Download 404 after restart**: Render list endpoint now registers on-disk renders into the in-memory job map.
- **Bug 3 — Timeline stops at GSAP end**: `resolveRootTimelineFromDocument` pads the GSAP timeline to match `data-duration` when the composition declares longer.
- **Bug 4 — Render stuck at 0%**: Store `jobState` reference (not spread copy) so async progress mutations reach the SSE stream.
- **Bug 5 — Lottie missing in preview/render**: Two fixes — (a) moved Lottie adapter before GSAP so `onUpdate` wins; (b) fixed bundler silently dropping external CDN `\<script src>` tags from sub-compositions (root cause: `$content(s).html()` returns `""` for external scripts).

**3 additional bugs fixed:**

- **Bug 6 — Blank thumbnails outside monorepo**: Implemented `generateThumbnail` in the CLI adapter using Puppeteer.
- **Bug 7 — Video empty in rendered sub-compositions**: Fixed `parseVideoElements` selector from `video[id][src]` to `video[src][data-start]` + auto-assign IDs.
- **Render errors**: Failed renders now show their error message in the renders panel.

## Commits

| Commit | Description |
| --- | --- |
| `3951c6f` | fix(studio): store render job reference instead of snapshot copy |
| `f331c30` | fix(studio): make previously-completed renders downloadable after restart |
| `a5e2d04` | fix(studio): add range request support for audio/video seeking in preview |
| `f24317a` | fix(runtime): pad GSAP timeline to data-duration when composition declares longer duration |
| `7cf38ca` | fix(runtime): fix Lottie adapter conflicting with GSAP-driven animations |
| `bc99209` | fix(studio): surface render error messages in the renders panel |
| `8fc9e8b` | fix(cli): implement generateThumbnail in studio adapter |
| `90277ea` | fix(engine): render videos inside sub-compositions that lack an explicit id |
| `f5bb579` | fix(compiler): preserve external CDN scripts from sub-compositions in bundle |

## Test plan

- [x] `golden-lyric-video`: seek → audio plays from seeked position
- [x] Any project: render → progress advances past 0%, reaches 100%
- [x] Any project: complete render, restart `hyperframes dev`, Download → works
- [x] `intro-vid`: play → runs full 5s (not stopping at 3s)
- [x] `hyperframe-build-up-demo`: play → rocket Lottie visible during 0-2s ✅ verified
- [x] Outside monorepo: Compositions sidebar shows thumbnail images (not blank)
- [x] `bug.zip` project: render → video in polaroid sub-composition appears in output
- [x] Trigger a failed render → error message shown
2026-03-30 23:58:08 +02: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 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
Miguel ÁngelandClaude Opus 4.6 d52ea88df5 fix(cli): make blank template a full HTML document
The blank template was a bare `<div>` fragment without `<!DOCTYPE>`,
`<head>`, or `<body>`. This caused:
- Blank preview (bundler/runtime can't initialize from a fragment)
- "Failed to run lint" (parsing errors on the malformed document)

All other templates (swiss-grid, vignelli, warm-grain, play-mode) are
proper HTML documents — blank was the only outlier.

Also improves lint error reporting to show the actual error message
instead of the generic "Failed to run lint."

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 02:50:53 -04:00
JamesandClaude Opus 4.6 5ace89d634 feat(cli): implement embedded dev server for hyperframes dev
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>
2026-03-26 23:34:00 +00:00
Vance Ingalls 20be2ea1c2 style: apply oxfmt baseline formatting across all source files (#25)
## Summary
- Run `oxfmt .` across the entire codebase to establish formatted baseline
- 299 files changed — mechanical formatting only, no logic changes
- Double quotes, semicolons, 2-space indent, trailing commas, 100 print width

Part 3/4 of [VA-851](https://linear.app/heygen/issue/VA-851/pre-migration-configure-eslint-prettier-and-conventional-commits)

## Test plan
- [x] `pnpm format:check` — all 426 files pass
- [x] `pnpm -r typecheck` — all packages pass
- [x] `pnpm build` — all packages build
- [x] All 348 tests pass
2026-03-23 17:15:14 -07:00