feat(studio): add animation inspector alpha#610
Open
miguel-heygen wants to merge 11 commits intonextfrom
Open
Conversation
* fix: stabilize studio preview and runtime sync * fix: pass selector through timeline thumbnails * feat: add studio timeline editing * fix: disambiguate timeline edit targets * fix: stop timeline auto-scroll in fit mode * feat: use percentage-based timeline zoom * fix: sync timeline playhead on zoom changes * fix: reset timeline scroll when returning to fit * feat(studio): add manual DOM editing inspector * docs: update studio manual dom editing guide * feat(studio): add image asset picker for fills * feat(studio): add inline image uploads for fills * fix(studio): use real file input for image fill uploads * fix(studio): restore toast plumbing after rebase * fix(studio): explain in-app upload limitation * fix(studio): reuse asset-tab upload pattern in fills * feat(studio): refine manual design inspector * fix(studio): polish manual design inspector * fix(studio): keep color picker in viewport * fix(studio): clarify color picker selection * docs: update manual DOM editing guide * fix(studio): keep gradient color picker open * fix(studio): scope text color to text layers * fix(studio): add agent fallback for immovable layers * fix(studio): address manual editing review feedback * fix(studio): make local font selection reliable
Studio manual editing and timeline editing mutate project files directly, but those edits had no reliable undo/redo path. Before releasing manual editing, users need a way to recover from visual property changes, source-editor saves, timeline moves/resizes/deletes, and timeline asset drops. The history also needs to survive a page refresh. A refresh should not erase the only way back from a bad manual edit. - Adds a persistent per-project edit-history model for file snapshots. - Stores undo/redo stacks in IndexedDB so history survives Studio refreshes. - Records source editor saves, manual DOM edits, and timeline mutations. - Adds toolbar undo/redo buttons with standard keyboard shortcuts: `Cmd/Ctrl+Z`, `Cmd/Ctrl+Shift+Z`, and `Ctrl+Y`. - Validates current file hashes before applying undo/redo so external file changes do not silently overwrite newer content. - Keeps history available in memory if IndexedDB persistence fails during a session. - Adds focused unit coverage for the pure history model, storage adapter, controller/hook behavior, and project-file save helper. Studio previously treated every editor mutation as an immediate file write. Manual DOM editing, timeline updates, and source-editor saves each had separate write paths, so there was no common transaction boundary where Studio could capture the file contents before and after an edit. Undo/redo needed to sit above those write paths as a file-level transaction system: capture changed files before saving, write the new contents, persist the history entry by project, then apply undo/redo only when the current file content still matches the expected snapshot. - `bun --filter @hyperframes/studio test src/utils/editHistory.test.ts src/utils/editHistoryStorage.test.ts src/hooks/usePersistentEditHistory.test.ts src/utils/studioFileHistory.test.ts` -> 4 files pass, 15 tests pass - `bun --filter @hyperframes/studio test` -> 26 files pass, 289 tests pass - `bun --filter @hyperframes/studio typecheck` - `bunx oxlint packages/studio/src/App.tsx packages/studio/src/icons/SystemIcons.tsx packages/studio/src/hooks/usePersistentEditHistory.ts packages/studio/src/hooks/usePersistentEditHistory.test.ts packages/studio/src/utils/editHistory.ts packages/studio/src/utils/editHistory.test.ts packages/studio/src/utils/editHistoryStorage.ts packages/studio/src/utils/editHistoryStorage.test.ts packages/studio/src/utils/studioFileHistory.ts packages/studio/src/utils/studioFileHistory.test.ts` -> 0 warnings, 0 errors - `bunx oxfmt --check packages/studio/src/App.tsx packages/studio/src/icons/SystemIcons.tsx packages/studio/src/hooks/usePersistentEditHistory.ts packages/studio/src/hooks/usePersistentEditHistory.test.ts packages/studio/src/utils/editHistory.ts packages/studio/src/utils/editHistory.test.ts packages/studio/src/utils/editHistoryStorage.ts packages/studio/src/utils/editHistoryStorage.test.ts packages/studio/src/utils/studioFileHistory.ts packages/studio/src/utils/studioFileHistory.test.ts` - `git diff --check` - `bun run --filter @hyperframes/core build:hyperframes-runtime` before commit hook, because the clean worktree needed the ignored runtime-inline artifact for typecheck - Lefthook pre-commit -> lint, format, typecheck pass - Lefthook commit-msg -> commitlint pass - Started Studio locally at `http://127.0.0.1:5190/#project/undo-redo-sample`. - Used `agent-browser` to select a preview element in the Inspector and change `#hero-card` from `left: 220px` to `left: 260px`. - Refreshed Studio and verified Undo stayed enabled. - Clicked Undo and verified the project file returned to `left: 220px`; clicked Redo and verified the inline `left: 260px` returned. - Used `agent-browser` to drag the `side-card` timeline clip, refreshed Studio, then verified Undo restored the previous timeline attributes and Redo reapplied the timeline move. - Recorded the tested undo/redo flow with `agent-browser`: `qa-artifacts/studio-undo-redo-2026-04-28/studio-undo-redo-flow.webm`. - Local screenshots and recordings are kept under `qa-artifacts/studio-undo-redo-2026-04-28/` and are intentionally not committed. - The scratch Studio project used for browser proof is local-only under `packages/studio/data/projects/undo-redo-sample/` and is intentionally not committed. - The PR intentionally excludes the earlier PRD/TDD planning notes under `docs/superpowers/`; those remain local-only per request.
8b50532 to
8beb451
Compare
8beb451 to
795f278
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Studio did not have a deterministic, source-backed way to author motion or a practical inspector workflow for manual DOM edits. Users could scrub and preview projects, but selecting real DOM layers, persisting visual edits, inspecting nested composition layers, and keeping preview/history/render behavior aligned were split across separate paths.
What this fixes
data-hf-motionruntime adapter and tests for deterministic seekable Studio-owned motion.Performance
@hyperframes/playerload path while adding a readiness probe for warm iframe loads, avoiding missed load events without reintroducing a static player import.Performance benchmark
Measured locally on
hf-manual-editing-demowith Chrome headless, 5 runs each, comparing this PR head795f278fagainstorigin/nextb07b888b. The benchmark opened the same project on isolated Studio dev servers, waited for the player/timeline to become usable, and captured CDP performance counters plus network request counts.The important win is that timeline/composition thumbnails no longer stampede hidden preview iframes and thumbnail/API requests during initial Studio load. JS heap is higher because this alpha branch adds substantial editor surface area: manual DOM selection, inspector controls, thumbnail services/caches, shared history, and motion UI.
Root cause
Studio’s existing editing model was centered on composition/timeline structure, not real DOM-layer ownership. Preview selection, source persistence, render-time runtime adapters, and history updates each had their own assumptions, so manual edits could work visually without having a deterministic owner or shared transaction model. The composition-view inspector also had to reason about iframe DOM nodes, where parent-window
HTMLElementchecks are unreliable.Verification
Local
bun run --filter @hyperframes/core test -- src/runtime/adapters/hfMotion.test.ts src/runtime/init.test.ts src/runtime/player.test.tsbun run --filter @hyperframes/studio test -- src/components/nle/NLELayout.test.ts src/components/nle/NLEPreview.test.ts src/player/components/Timeline.test.ts src/player/components/TimelineThumbnailContent.test.ts src/components/sidebar/CompositionsTab.test.ts src/utils/timelineInspector.test.ts src/utils/compositionPaths.test.ts src/thumbnails/sourceHash.test.ts src/thumbnails/thumbnailKey.test.ts src/thumbnails/thumbnailMode.test.ts src/thumbnails/memoryThumbnailCache.test.ts src/thumbnails/indexedDbThumbnailCache.test.ts src/thumbnails/studioThumbnailService.test.ts src/thumbnails/thumbnailScheduler.test.tsbun run --filter @hyperframes/studio test -- src/components/nle/NLELayout.test.ts src/components/nle/NLEPreview.test.ts src/player/components/Timeline.test.ts src/utils/timelineInspector.test.ts src/utils/compositionPaths.test.tsbun run --filter @hyperframes/core buildbun run --filter @hyperframes/studio buildbunx oxlint packages/studio/src/App.tsx packages/studio/src/components/editor/TimelineLayerPanel.tsxbunx oxfmt packages/studio/src/App.tsx packages/studio/src/components/editor/TimelineLayerPanel.tsxoxlint,oxfmt --check, andtypecheckafter the amended commit.Browser
agent-browseronhttp://127.0.0.1:5196/?v=pr-recording#project/hf-manual-editing-demo.Hooktimeline clip shows a23nested-layer button.Clip layers, selectedDI Topline, and confirmed the Design panel opens for the nested element with layout controls.agent-browseragain onhttp://127.0.0.1:5196/?v=draggable-layer-seek#project/hf-manual-editing-demo.Clip layerspanel away from the preview content and confirmed the panel stays repositioned with viewport clamping.H1 Titlefrom the nested layer list and confirmed Studio seeks from the initial frame to the first visible sampled moment before opening the Design panel for that exact title layer.qa-artifacts/pr-studio-animation-inspector/rebased-composition-layer-panel.pngqa-artifacts/pr-studio-animation-inspector/rebased-layer-flow.webmqa-artifacts/pr-studio-animation-inspector/draggable-layer-panel.pngNotes
qa-artifacts/is local-only and was not committed.