Commit Graph

285 Commits

Author SHA1 Message Date
Vance Ingalls 2197f1816a fix: parser single-quote normalization breaks on apostrophes in text
The single-quote replacement regex ran after key-quoting, causing it
to match apostrophes inside already-double-quoted strings like
"didn't". Moving it before key-quoting fixes the issue since it only
matches actual single-quoted string values at that point.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:21 -07:00
Vance Ingalls b17c1ec4ca refactor: simplify review fixes
- Add change detection to 66ms overlay poll (skip setWordBoxes when unchanged)
- Add activating guard to prevent duplicate caption source fetches
- Remove applyOpacityToColor wrapper (inline hexToRgba)
- Rename rawWords back to words in normalize.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:21 -07:00
Vance Ingalls c954895c7a fix: remove non-null assertions in generator, clean dead code in property panel
- Replace filter(Boolean) + ! assertions with typed filter in generator.ts
- Hoist repeated seg.id.replace() to const segVar
- Remove unused ToggleButton, ColorInput, container/typography derived values,
  applyContainerToIframeDom, handleContainerChange, buildTextDecoration
- Remove CaptionContainerStyle import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:21 -07:00
Vance Ingalls 118747e7aa fix: code review fixes — remove non-null assertions, fix hooks ordering
- Replace doc!/win!/captionSrcPath! with guards in App.tsx async callback
- Move useCallback hooks above early return in CaptionAnimationPanel
  (React hooks must be called unconditionally in the same order)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:21 -07:00
Vance Ingalls 1c847ce697 refactor: cleanup from /simplify review
- Delete dead useCaptionDrag.ts (superseded by overlay inline drag)
- Self-cancel 200ms poll after caption activation
- Remove stale effectiveStyle deps from applyToIframeDom useCallback

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:21 -07:00
Vance Ingalls d5d22d4c0b fix: property panel transforms apply to wrapper via gsap.set
Panel rotation/scale/position changes now go through the wrapper span
using gsap.set, reading current values first to preserve other properties.
Previously set el.style.transform directly on the word span, overwriting
all existing transforms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:21 -07:00
Vance Ingalls 50afa186c5 fix: close edit panel when caption word is deselected
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:21 -07:00
Vance Ingalls 5473e496f1 fix: resolve caption source via compIdToSrc map on initial load
The runtime strips data-composition-src after loading, so the DOM query
couldn't find the captions file path. Now uses the compIdToSrc map (built
from raw index.html) as the primary lookup. Also adds compIdToSrc to
the effect dependency array so it re-runs when the map is populated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:20 -07:00
Vance Ingalls 2da95d8eec fix: caption detection on initial index.html load
- Reduce poll interval from 500ms to 200ms for faster detection
- Fall back to DOM querySelector for iframe when ref isn't set yet
- Runtime wrapper sets data-caption-wrapper for consistent detection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:20 -07:00
Vance Ingalls 3f57d4f417 fix: double-wrapper bug causing transform value drift
Runtime hook's wrapper was missing data-caption-wrapper attribute, so
the overlay created a second wrapper on top. Transforms were applied to
different wrappers causing values to compound on reload.

Also:
- Suppress auto-save during loadOverrides to prevent immediate re-write
- Only sync non-default transform values to avoid spurious overrides

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:20 -07:00
Vance Ingalls 721ac04430 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-02 00:13:20 -07:00
Vance Ingalls 793604c6a5 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-02 00:13:20 -07:00
Vance Ingalls 7777871134 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-02 00:13:20 -07:00
Vance Ingalls 74a01c2d51 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-02 00:13:20 -07:00
Vance Ingalls be953aaf99 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-02 00:13:20 -07:00
Vance Ingalls 0f171b5fb4 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-02 00:13:20 -07:00
Vance Ingalls df380d704a 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-02 00:13:20 -07:00
Vance Ingalls 82472b08a1 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-02 00:13:20 -07:00
Vance Ingalls 6367d8539e 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-02 00:13:20 -07:00
Vance Ingalls 3fd7497eda 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-02 00:13:20 -07:00
Vance Ingalls 41367b8888 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-02 00:13:20 -07:00
Vance Ingalls 33a3e080e3 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-02 00:13:20 -07:00
Vance Ingalls e4122ef56a 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-02 00:13:20 -07:00
Vance Ingalls 5a82257c24 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-02 00:13:20 -07:00
Vance Ingalls d09695014f chore: revert unrelated LintModal changes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:19 -07:00
Vance Ingalls ca49dcc439 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-02 00:13:19 -07:00
Vance Ingalls bd11f25f34 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-02 00:13:19 -07:00
Vance Ingalls 17f38239ab feat(studio): add caption module barrel export 2026-04-02 00:13:19 -07:00
Vance Ingalls bbe4f8a7c6 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-02 00:13:19 -07:00
Vance Ingalls 66f74c5e98 feat(studio): add caption animation panel with entrance/highlight/exit controls 2026-04-02 00:13:19 -07:00
Vance Ingalls 5ce8d76e88 feat(studio): wire caption property panel and parser integration 2026-04-02 00:13:19 -07:00
Vance Ingalls 1f5a7086b4 feat(studio): add caption property panel with typography, color, and transform controls
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 00:13:19 -07:00
Vance Ingalls c8652755f3 feat(studio): wire caption overlay and edit mode into Studio
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:19 -07:00
Vance Ingalls cd48e835b8 feat(studio): add drag-to-reposition for caption segments 2026-04-02 00:13:19 -07:00
Vance Ingalls 91014d0506 feat(studio): add caption overlay with segment selection boxes 2026-04-02 00:13:19 -07:00
Vance Ingalls ed2aa4a6b7 feat(studio): add caption model → HTML source sync hook 2026-04-02 00:13:19 -07:00
Vance Ingalls 9e252daaf8 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-02 00:13:19 -07:00
Vance Ingalls aebcdbecbf feat(studio): add caption editing Zustand store 2026-04-02 00:13:19 -07:00
Vance Ingalls 1f6f20968f feat(studio): parse caption styles from live iframe DOM 2026-04-02 00:13:19 -07:00
Vance Ingalls 72b870b596 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-02 00:13:19 -07:00
Vance Ingalls 5938835aa7 feat(studio): add transcript extraction from caption source
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 00:13:19 -07:00
Vance Ingalls 1597006e6b feat(studio): add caption model types 2026-04-02 00:13:18 -07:00
Vance Ingalls fbac7ab320 docs: add linting and formatting tooling instructions to CLAUDE.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:18 -07:00
Vance Ingalls feed52e7c4 fix(cli): handle unknown type in pageerror handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:18 -07:00
Vance Ingalls d3114e809a fix(cli): fix typecheck errors in validate command
- ConsoleMessage.type() returns "warn" not "warning"
- Type pageerror callback parameter as Error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:18 -07:00
Vance Ingalls b039648e1b feat(cli): add hyperframes validate command
Loads a composition in headless Chrome and reports console errors,
uncaught exceptions, and failed network requests for project assets.
Agents run this before opening the studio to catch runtime issues.

- Bundle HTML with inlined runtime (no CDN dependency)
- Minimal file server for project assets
- Captures JS errors, pageerror events, 404s on project files
- JSON output mode for programmatic consumption
- ~3s execution time, suitable as a blocking pre-preview step

Updates CLAUDE.md and compose skill to require lint + validate
before opening the studio.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:18 -07:00
Vance Ingalls ab9480fafa fix(studio): serve runtime locally instead of from CDN
The Vite dev server was loading the HyperFrames runtime IIFE from
cdn.jsdelivr.net. This caused compositions using window.__hyperframes
(e.g., fitTextFontSize) to fail when the CDN script didn't load in
the iframe context.

Add a /api/runtime.js endpoint to the Vite plugin that serves the
local built runtime, matching what studioServer.ts already does for
the CLI embedded server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:18 -07:00
Vance Ingalls fc99b407a8 chore: remove planning and spec docs from branch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:17 -07:00
Vance Ingalls 1ba503fbd1 docs: update CLAUDE.md skill install to use vercel-labs/skills
Also fix .claude/settings.json pre-commit hook to use bun instead of pnpm.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 00:13:17 -07:00
Vance Ingalls 9859693e91 docs: update CLAUDE.md skill install instructions to use vercel-labs/skills 2026-04-02 00:13:00 -07:00