feat(studio): keyframes flag, gesture recording + timeline/selection refinements#1561
Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
b46e2b6 to
a96a6cf
Compare
d9d0a45 to
ba99ae0
Compare
a96a6cf to
b56fbc8
Compare
terencecho
left a comment
There was a problem hiding this comment.
Stack-wide process note (Rames covered structure / 2 concerns on this PR)
Endorsing @rames-jusso's #1561 take in full — playerStore.ts:374-379 exposing the full Zustand store via window.__playerStore in prod is a real footgun (anyone with devtools access can call __playerStore.setState({...}) to mutate selection/elements/playing); and the clipToTweenPercentage 1-keyframe edge using a clipPct fallback IS the same pattern this PR fixes elsewhere. Both should land before merge.
Stack-wide process observation (non-blocking, easy fix for next stack)
All 9 PR descriptions across this stack are the unfilled PR template. For a stack with several PRs north of +500 LOC (and the +651/-4 core-mutations PR #1554 being load-bearing), the empty bodies mean reviewers (human and bot) and future archaeologists have nothing to anchor to — no "what / why / how / test plan" content. Commit messages cover the what well, but PR-body framing of why doesn't survive a bisect via the GitHub UI.
This stack is heavily test-backed and Graphite-anchored, so structural intent is recoverable from diff + commit messages. Not blocking — just a process nudge for the next stack.
Test-coverage map across the 9-PR stack (from my axis pass)
| PR | Files | Test files | Notes |
|---|---|---|---|
| #1553 | 2 | 0 | banner shim, n/a |
| #1554 | 5 | 2 | strong (parity + parser units) |
| #1555 | 4 | 1 | adequate |
| #1556 | 3 | 0 | CLI surface, typical no-unit |
| #1557 | 7 | 3 | strong |
| #1558 | 8 | 3 | strong on new infra |
| #1559 | 6 | 2 | strong on pure-logic helpers |
| #1560 | 5 | 0 | UI overlay, typical no-unit |
| #1561 | 19 | 5 | very strong |
— Review by tai (pr-review)
ba99ae0 to
676ba06
Compare
b56fbc8 to
878d25a
Compare
676ba06 to
f9e5f4f
Compare
878d25a to
bcdfd8e
Compare
vanceingalls
left a comment
There was a problem hiding this comment.
Concurring with the consolidated review's two author-response gates at HEAD 878d25a2 (both verified still open):
packages/studio/src/player/store/playerStore.ts:377-379—window.__playerStoreships unguarded in prod. Verified at HEAD: only the SSRtypeof window !== "undefined"guard wraps it; there is noimport.meta.env.DEVorprocess.env.NODE_ENV === "development"gate. Production users get the full Zustand mutating surface via__playerStore.setState({...}).packages/studio/src/components/editor/KeyframeNavigation.tsx:32-46—clipToTweenPercentage1-anchor edge. Verified at HEAD:if (mapped.length < 2) return clipPct;returns clip-relativeclipPctwhen only one keyframe has atweenPercentage, which is exactly the off-by-tween-offset silent no-op the PR's own comment block (:115-126) calls out as the bug pattern this PR is fixing. Identity-slope at one anchor (mapped[0].tweenPercentage! + (clipPct - mapped[0].percentage)) is the right fallback.
Two depth additions from my pass:
-
useEnableKeyframesbehavioural change is migration-safe. The diff narrows scope to the "no existing animation" branch only — thekfAnimbranch atuseEnableKeyframes.ts:126-137and the flat-anim branch are untouched. New behaviour: a single keyframe at the playhead viaresolveNewTweenRange-clamped start, matching the stated intent ("creating 0%+100% up front showed two diamonds for a single add keyframe"). Existing compositions with keyframes already enabled take the unchangedkfAnimbranch — they are not migrated.resolveNewTweenRangeships with regression coverage inuseEnableKeyframes.test.tsincluding the auto-stampdata-start="0"/data-duration=14scenario. Ungating is appropriate here because the regression risk is one-way (better, not worse) for a brand-new gesture. -
Drive-by behavioural changes verified non-regressive. (a) Timeline-element key-form fix —
buildTimelineElementKeyrecomputed withdomId/selectorto match the store's hash form; backed byuseExpandedTimelineElements.test.ts(+34) andstudioHelpers.test.ts(+32); a pure fix to a selection-highlight bug. (b)setSelectedElementIdclearingactiveKeyframePct— comment explains the diamond-click ordering invariant; sensible and contained. (c)findTimelineIdByAncestor— additive, tried only whenfindMatchingTimelineElementIdreturns null; tested. (d)StudioHeaderno longer clears DOM selection on inspector-panel collapse — strictly less destructive than before; the orphanedclearDomSelectionimport is correctly removed. None of (a-d) is a regression for prior muscle memory.
Title note stands: STUDIO_KEYFRAMES_ENABLED is pre-existing on main at manualEditingAvailability.ts:73; this PR adds use sites, not the flag itself.
Review by Via
f9e5f4f to
789f860
Compare
bcdfd8e to
cd69359
Compare
…refinements Enable-keyframes gate, recorded-gesture-stays-in-place, clipToTweenPercentage keyframe-nav, inline-expand timeline elements, and minor header/layout/store touches.
789f860 to
80f1a0f
Compare
cd69359 to
be3c288
Compare

Stack: GSAP keyframe + motion-path editing — feature flag, gesture recording, timeline polish (top of #1553 → #1561).
What
Ties the feature together and adds the remaining tooling:
useEnableKeyframes).Why
The keyframe/motion-path surface ships behind a flag; gesture recording gives a fast way to author motion; the navigation + razor tooling rounds out the timeline editing experience.
How
useEnableKeyframes.ts: flag + enablement gate.useGestureRecording.ts: samples pointer position over the timeline, simplifies (RDP), and commits keyframes (merge into an overlapping tween, else add a new range).KeyframeNavigation.tsx: per-property diamond (add / remove / convert) + prev/next seek.useRazorSplit.ts: split a clip at the playhead.useDomSelection.ts/useStudioContextValue.ts/StudioHeader.tsx/NLELayout.tsx/RenderQueue.tsx: selection + timeline refinements (selection survives inspector collapse, etc.).Test plan