Skip to content

fix: stabilize studio preview and runtime sync#389

Merged
miguel-heygen merged 6 commits intomainfrom
fix/studio-preview-runtime-foundation
Apr 21, 2026
Merged

fix: stabilize studio preview and runtime sync#389
miguel-heygen merged 6 commits intomainfrom
fix/studio-preview-runtime-foundation

Conversation

@miguel-heygen
Copy link
Copy Markdown
Collaborator

Summary

Stabilize the Studio preview/runtime path so timeline data, preview rendering, and thumbnails stay in sync.

This PR includes:

  • preview hot-refresh without remounting the iframe
  • runtime duration/timeline fixes so Studio stops drifting from playback state
  • thumbnail and selector-based preview fixes
  • local Studio runtime serving and player-resolution fixes so dev/CI do not depend on prebuilt player artifacts
  • tests around preview identity and thumbnail/runtime behavior

Why This PR Exists

This is the foundation layer for timeline editing. Without it, the editor was prone to:

  • iframe remount flashes after saves
  • duration mismatches between preview and timeline
  • stale or incorrect thumbnails
  • CI/test failures when @hyperframes/player artifacts were not prebuilt

Verification

  • bun run --filter @hyperframes/studio test
  • bun run --filter @hyperframes/studio typecheck
  • bun run --filter @hyperframes/core typecheck
  • bunx oxlint packages/cli/src/server/studioServer.ts packages/core/src/runtime/timeline.ts packages/core/src/runtime/timeline.test.ts packages/core/src/studio-api/routes/thumbnail.ts packages/core/src/studio-api/routes/thumbnail.test.ts packages/core/src/studio-api/types.ts packages/studio/src/components/nle/NLELayout.tsx packages/studio/src/components/nle/NLEPreview.tsx packages/studio/src/components/nle/NLEPreview.test.ts packages/studio/src/player/components/CompositionThumbnail.tsx packages/studio/src/player/components/Player.tsx packages/studio/src/player/hooks/useTimelinePlayer.ts packages/studio/src/player/store/playerStore.ts packages/studio/vite.config.ts
  • bunx oxfmt --check packages/cli/src/server/studioServer.ts packages/core/src/runtime/timeline.ts packages/core/src/runtime/timeline.test.ts packages/core/src/studio-api/routes/thumbnail.ts packages/core/src/studio-api/routes/thumbnail.test.ts packages/core/src/studio-api/types.ts packages/studio/src/components/nle/NLELayout.tsx packages/studio/src/components/nle/NLEPreview.tsx packages/studio/src/components/nle/NLEPreview.test.ts packages/studio/src/player/components/CompositionThumbnail.tsx packages/studio/src/player/components/Player.tsx packages/studio/src/player/hooks/useTimelinePlayer.ts packages/studio/src/player/store/playerStore.ts packages/studio/vite.config.ts

Stack

  • base of stack
  • followed by feat: add studio timeline editing
  • followed by fix: smooth scrubber end seeking

Copy link
Copy Markdown
Collaborator Author

miguel-heygen commented Apr 21, 2026

@miguel-heygen miguel-heygen marked this pull request as ready for review April 21, 2026 20:02
Comment thread packages/cli/src/server/studioServer.ts Outdated
Comment thread packages/studio/src/player/hooks/useTimelinePlayer.ts Outdated
@jrusso1020
Copy link
Copy Markdown
Collaborator

One additional gap I noticed that I could not attach inline because the file is outside the PR diff: the selector-aware thumbnail path looks only partially wired through. useTimelinePlayer now captures selector metadata and CompositionThumbnail accepts it, but the timeline rendering call sites in packages/studio/src/App.tsx still instantiate CompositionThumbnail without passing el.selector. So the new server-side selector clipping path does not appear to be exercised by the main timeline UI yet.

@miguel-heygen
Copy link
Copy Markdown
Collaborator Author

Addressed the selector thumbnail gap in 51135377.

What changed:

  • packages/studio/src/App.tsx now passes selector={el.selector} through all three CompositionThumbnail timeline render paths
  • this wires the selector-aware server thumbnail clipping path into the main timeline UI, not just the data pipeline

Verification:

  • bunx oxlint packages/studio/src/App.tsx
  • bunx oxfmt --check packages/studio/src/App.tsx
  • bun run --filter @hyperframes/studio typecheck

Copy link
Copy Markdown
Collaborator

@jrusso1020 jrusso1020 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Foundation looks solid. Good test coverage on the new pure helpers (mergeTimelineElementsPreservingDowngrades, getPreviewPlayerKey, thumbnail selector plumbing). The runtime-source fallback making dev/CI independent of a prebuilt @hyperframes/core artifact is a nice ergonomic win.

Two things worth calling out — neither blocking:

  1. Soft breaking change in timeline.ts: persistent overlays now require data-timeline-role="overlay" (or "persistent-overlay") to appear in Studio. Existing compositions with auto-showing <div id="grid-overlay"> style decorations will silently disappear from the timeline UI. Playback isn't affected, but the in-Studio tracklist will look different. Worth a one-line mention in the alpha release notes so authors know about the opt-in attribute.

  2. Duration no longer "don't-downgrade": previous guard on handleMessage was if (dur > currentDur) setDuration(dur); this PR removes that and accepts any 0 < dur < 7200. Reasoning is clear (stop drifting from runtime), and mergeTimelineElementsPreservingDowngrades handles the element side. Just noting: if an intermediate manifest during generation reports a shorter duration, the timeline controls will now flap with it. Likely fine, but keep an eye on it once timeline editing lands on top.

  3. opts.selectorpage.evaluate(selector => document.querySelector(selector)): safe functionally (querySelector doesn't execute), but a crafted selector like *:has(*:has(...)) could be arbitrarily expensive to evaluate and the cache-key sanitizer creates distinct keys per input, so every variation bypasses the cache. Post-alpha, worth a selector length/complexity guard on the route handler.

Approved for alpha.

Rames Jusso

@miguel-heygen miguel-heygen merged commit 1582043 into main Apr 21, 2026
26 checks passed
Copy link
Copy Markdown
Collaborator Author

Merge activity

miguel-heygen added a commit that referenced this pull request Apr 21, 2026
## Summary

Add the actual Studio timeline editing layer on top of the preview/runtime foundation.

This PR includes:

- drag-to-move clips across time and tracks
- left/right resize handles with media-aware trim persistence
- edge auto-scroll and edge track creation while dragging
- selector-based source patching for `data-start`, `data-duration`, `data-track-index`, `z-index`, and media trim attributes
- timeline UI cleanup, theming, hover/drag states, and the `Copy Prompt` action

## Why This PR Is Separate

This is the user-facing editing behavior. It depends on the preview/runtime fixes in the base PR, but it is much easier to review once that plumbing is isolated.

## Verification

- `bun run --filter @hyperframes/studio test`
- `bun run --filter @hyperframes/studio typecheck`
- `bunx oxlint packages/studio/src/App.tsx packages/studio/src/components/nle/NLELayout.tsx packages/studio/src/player/components/EditModal.tsx packages/studio/src/player/components/Timeline.tsx packages/studio/src/player/components/TimelineClip.tsx packages/studio/src/player/components/timelineEditing.ts packages/studio/src/player/components/timelineEditing.test.ts packages/studio/src/player/components/timelineTheme.ts packages/studio/src/player/components/timelineTheme.test.ts packages/studio/src/utils/sourcePatcher.ts packages/studio/src/utils/sourcePatcher.test.ts`
- `bunx oxfmt --check packages/studio/src/App.tsx packages/studio/src/components/nle/NLELayout.tsx packages/studio/src/player/components/EditModal.tsx packages/studio/src/player/components/Timeline.tsx packages/studio/src/player/components/TimelineClip.tsx packages/studio/src/player/components/timelineEditing.ts packages/studio/src/player/components/timelineEditing.test.ts packages/studio/src/player/components/timelineTheme.ts packages/studio/src/player/components/timelineTheme.test.ts packages/studio/src/utils/sourcePatcher.ts packages/studio/src/utils/sourcePatcher.test.ts`

## Browser Proof

- verified timeline drag / resize / trim flows in Studio with `agent-browser`
- verified preview hot-refresh behavior without iframe remount flashes

## Stack

- depends on #389
- followed by `fix: smooth scrubber end seeking`

[result.mp4 <span class="graphite__hidden">(uploaded via Graphite)</span> <img class="graphite__hidden" src="https://app.graphite.com/user-attachments/thumbnails/ca71c177-5042-468d-906f-b353938f40f8.mp4" />](https://app.graphite.com/user-attachments/video/ca71c177-5042-468d-906f-b353938f40f8.mp4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants