Skip to content

perf(studio): centralize timeline viewport geometry - #2700

Open
miguel-heygen wants to merge 1 commit into
codex/studio-timeline-d-render-contracts-v2from
codex/studio-timeline-d-viewport-geometry-v2
Open

perf(studio): centralize timeline viewport geometry#2700
miguel-heygen wants to merge 1 commit into
codex/studio-timeline-d-render-contracts-v2from
codex/studio-timeline-d-viewport-geometry-v2

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

What

Centralize the stable, layout-owned timeline viewport geometry used by row layout, visible-range derivation, scrolling snapshots, indexes, and playback consumers.

Scope boundary

This PR does not migrate every coordinate read to the cached geometry model. Gesture-time code in range selection, playhead interaction, reveal, editing, and drag preview intentionally keeps direct getBoundingClientRect() / scrollLeft reads where pointer freshness matters. The shared model owns stable layout geometry; live pointer handlers own live DOM coordinates.

How

  • Add immutable TimelineRowGeometry snapshots with identity-based caching.
  • Centralize viewport snapshots and time/content conversion.
  • Reuse the existing canonical timeline element identity helper in the new element index.
  • Keep project-reset state owned by the D1 helper while adding D5 session-boundary behavior.

Test plan

  • Geometry, viewport, track-layout, element-index, player-store, and Timeline tests
  • Full Studio suite
  • Studio typecheck, oxfmt, and oxlint

Review fixes are included at head b15627d5e.

@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from 73d1bb5 to ecf76d7 Compare July 27, 2026 20:51
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from af82757 to 13367e5 Compare July 27, 2026 20:51
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from ecf76d7 to a69af1c Compare July 28, 2026 20:42
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from 13367e5 to 9a2c975 Compare July 28, 2026 20:43
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from a69af1c to 832f7b3 Compare July 28, 2026 22:09
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from 9a2c975 to d9c532f Compare July 28, 2026 22:09
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from 832f7b3 to 57aa9f0 Compare July 28, 2026 22:35
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from d9c532f to eb24bd5 Compare July 28, 2026 22:35
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from 57aa9f0 to 6f4ff16 Compare July 28, 2026 23:03
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from eb24bd5 to 684ce21 Compare July 28, 2026 23:03
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from 6f4ff16 to c41fac2 Compare July 28, 2026 23:23
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from 684ce21 to 030583a Compare July 28, 2026 23:23
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from c41fac2 to 42579a9 Compare July 28, 2026 23:54
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from 030583a to 028174c Compare July 28, 2026 23:54
@miguel-heygen
miguel-heygen changed the base branch from codex/studio-timeline-d-render-contracts-v2 to main July 29, 2026 02:06
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from 028174c to f43747b Compare July 29, 2026 02:28
@github-actions

Copy link
Copy Markdown

Fallow audit report

Found 5 findings.

Duplication (4)
Severity Rule Location Description
minor fallow/code-duplication packages/studio/src/player/components/timelineClipDragGestureLifecycle.ts:56 Code clone group 1 (25 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/player/components/useTimelineClipDrag.ts:359 Code clone group 1 (25 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/player/components/useTimelineTrackLayout.test.ts:26 Code clone group 2 (25 lines, 2 instances)
minor fallow/code-duplication packages/studio/src/player/components/useTimelineTrackLayout.test.ts:73 Code clone group 2 (25 lines, 2 instances)
Health (1)
Severity Rule Location Description
minor fallow/high-crap-score packages/studio/src/player/hooks/useTimelinePlayer.ts:69 'syncTimelineElements' has CRAP score 31.6 (threshold: 30.0, cyclomatic 10)

Generated by fallow.

@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from f43747b to eab22e6 Compare July 29, 2026 14:46
@miguel-heygen
miguel-heygen changed the base branch from main to codex/studio-timeline-d-render-contracts-v2 July 29, 2026 15:03
@miguel-heygen
miguel-heygen marked this pull request as ready for review July 29, 2026 15:06
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from eab22e6 to 9e92dbc Compare July 29, 2026 23:35
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from 29b22a9 to 4edbc70 Compare July 29, 2026 23:35

@vanceingalls vanceingalls left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verdict: APPROVE — grade B — rubric PARTIAL

Role in stack: D5 refactor — viewport geometry centralization (SSOT for scroll/zoom/time-to-x + row-index-to-y across drag, marquee, layout, active clips, scrub).

Root-cause fit: Good. New timelineViewportGeometry.ts owns time-range + row anchoring; useTimelineScrollViewport owns DOM reads (scrollLeft/Top/clientW/H + isScrolling + RO wiring + settled-timer). timelineLayout.ts owns row geometry as a frozen TimelineRowGeometry (binary-search y↔row over cumulative offsets, WeakMap-cached per height-array), consumed by drag/marquee/drop through rowGeometryRef.

Claims verified (file:line at HEAD 9e92dbc9):

  • New module timelineViewportGeometry.ts:1-31getTimelineVisibleTimeRange + getTimelineScrollTopForGeometryChange.
  • Snapshot hook useTimelineScrollViewport.ts:47-155 — rAF-throttled viewport publish + settled timer + RO + shortcut-hint sync.
  • Row geometry SSOT timelineLayout.ts:78-172 — immutable TimelineRowGeometry, WeakMap cache, binary search in getRowFromY.
  • Element indexes timelineElementIndexes.ts:1-43 — one scan per snapshot, WeakMap-cached; consumed by Timeline.tsx:118, useTimelineClipDrag.ts:761, playbackScrub.ts:6.
  • Test coverage Timeline.test.ts:47-66, useTimelineScrollViewport.test.tsx, timelineElementIndexes.test.ts.

Adversarial findings:

  • P2 — Callsite migration is partial. PR body claims "one geometry model owns scroll, drag, selection, layout, playback". useTimelineRangeSelection.ts:1155-1339 still does its own scrollRef.current?.getBoundingClientRect() / .scrollLeft / .scrollTop reads for pointer→content mapping; useTimelinePlayhead.ts (16 refs), useTimelineRevealClip.ts (10 refs), timelineEditing.ts (9 refs), timelineClipDragPreview.ts also bypass the snapshot. Defensible for pointer-freshness (state snapshot lags by rAF + settled timeout), but the body language is stronger than what shipped — worth naming the exceptions.
  • P3 — setTimelineScale writer with no reader. playerStore.ts:480-486 adds non-reactive timelinePps/timelineFitPps, published from useTimelineGeometry.ts:465-467. No consumer exists. useTimelineEditPinning.ts:41 still pins via ppsRef.current / fitPpsRef.current. Docstring names pinTimelineZoomToCurrent, absent. Prep for D6 — call it out or drop it.
  • P3 — In-place mutation on Zustand state. state.timelinePps = pps sidesteps set() — silent hazard if anyone selects this field via usePlayerStore(s => s.timelinePps). Comment warns "never read as render input", but the type is public. A Symbol-keyed scratch or plain module-level ref would advertise the contract more loudly.
  • Nit — getTimelineVisibleTimeRange ships zero overscan; callers should know. end clamps to duration (comp), not displayDuration (extent) — semantically "visible clip time," which the name doesn't disclose.
  • Nit — Reference stability: TimelineScrollViewportSnapshot is a fresh object every rAF while scrolling; downstream useMemo([viewport]) will re-run each frame. Consumers should destructure fields.

Standards: No new any, empty catch, TODO, disabled test. oxfmt/oxlint/typecheck pass. useEffect uses are external-system sync — permitted.

CI state: All 8 required checks pass. Graphite mergeability_check pending (transient).

Suggested next step: Land as-is (awaits Family D landing order). Follow-up: either delete the unused setTimelineScale/timelinePps writer or ship its consumer in D6, and document the pointer-freshness carve-out in the geometry module header.

Review by Via

@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from 9e92dbc to b15627d Compare July 30, 2026 00:23
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from 4edbc70 to 2b89498 Compare July 30, 2026 00:23
@miguel-heygen

Copy link
Copy Markdown
Collaborator Author

Addressed at b15627d5e.

  • The PR body now explicitly limits the shared geometry claim to stable/layout-owned snapshots and documents the live DOM reads retained for pointer freshness.
  • The new element index reuses the canonical timeline identity helper.
  • The project reset snapshot now has one owner in D1; D5 only adds its session-boundary behavior.
  • setTimelineScale and its non-reactive Zustand scratch fields predate Family D (introduced in feat(studio): revamps Studio + improves code quality #2291 / df29fa7a5) and are not changed by this PR, so that cleanup remains outside D5’s patch scope.

@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from 2b89498 to f5cd679 Compare July 30, 2026 01:31
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from b15627d to 02ca243 Compare July 30, 2026 01:31

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Exact-delta review at 02ca243f1a (additive to the existing review).

I audited all 29 changed files: the row-geometry/store/index production paths, every migrated caller, focused tests, and the Chromium harness. I am not treating the rest of the stack as evidence for this PR.

No new actionable finding. The geometry conversion remains symmetric at the boundaries; row snapshots are rebuilt from immutable array identities; session changes reset scroll ownership once; and the resource audit is clean (ResizeObserver, rAF, scroll-settle timer, PerformanceObserver, probe page, and browser are all released on their terminal paths). The PR body now accurately limits the SSOT claim to stable layout geometry and leaves gesture-time DOM reads explicitly live.

The exact functional CI is green. Graphite's remaining state is a stack/dependency gate, not a failing check in this delta.

Verdict: APPROVE
Reasoning: The exact delta preserves behavior while centralizing the stable geometry contract, and I found no additional correctness, lifecycle, or cleanup defect beyond feedback already recorded on the PR.

— Magi

@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from 02ca243 to eef5fb4 Compare July 30, 2026 03:15
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch 2 times, most recently from 60e3c4f to 3f74418 Compare July 30, 2026 03:47
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from eef5fb4 to 0546ad3 Compare July 30, 2026 03:47
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-render-contracts-v2 branch from 3f74418 to f8cd5e9 Compare July 30, 2026 04:05
@miguel-heygen
miguel-heygen force-pushed the codex/studio-timeline-d-viewport-geometry-v2 branch from 0546ad3 to 3702ced Compare July 30, 2026 04:05
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