feat(studio): runtime-synced design panel + 3D props + split polish#1188
Conversation
82a5989 to
9a94cd9
Compare
82a5989 to
6c8acf6
Compare
0f7b0eb to
80f8959
Compare
790ef3f to
99fc9ee
Compare
8699a60 to
8b58fb0
Compare
1937dd3 to
c048e70
Compare
ec0c763 to
69354c0
Compare
jrusso1020
left a comment
There was a problem hiding this comment.
Top-of-stack polish + 3D props. +362/-58. The 3D property additions are the most interesting cross-stack change — they extend the keyframeable surface from 2D transforms into 3D space.
3D transform properties — z, rotationX/Y/Z, perspective, transformOrigin
Two cross-browser concerns:
1. perspective placement matters
perspective set on an element creates 3D context for its children, not itself. If a user sets perspective: 800 on an element and expects that element's own 3D rotation to depth-render, they'll see a flat result. The Studio UI should either:
- Auto-apply perspective to the parent when a 3D property is set on a child.
- OR document the rule clearly in the property-panel UI (e.g., "set perspective on the parent of this element").
Without one of these, users will silently get flat-looking 3D and not understand why.
2. transformOrigin interaction with GSAP xPercent / yPercent
GSAP's xPercent: -50 / yPercent: -50 (centering pattern) interacts with transformOrigin. If the SUPPORTED_PROPS set now includes both transformOrigin and the existing transform props, verify the property panel doesn't allow conflicting combinations (e.g., setting xPercent: -50 and transformOrigin: "top left" simultaneously without a warning).
gsap.getProperty() at current seek time — design panel sync
Reading interpolated values from the live runtime is the right approach. Two questions:
- Cost:
getProperty()is cheap for a single element but called for every visible field on every scrub. With Layout (5 fields × multiple selected clips), this could be 20+ calls per scrub frame. Worth a memo with the scrub time as the dep so it batches per-frame. - Stale during transition: between
seek()and the next runtime sync,getProperty()returns pre-seek values. Verify the design panel reads happen after the runtime has applied the seek (likely via the runtime bridge from #1169's optimistic-update pipeline).
Clip selection border (full accent + glow shadow) + 0.5% diamond tolerance
Both are UX-polish tunings. The 0.5% diamond tolerance (vs the prior 0.05%) is a 10× widening — confirm this matches user-tested expectations and doesn't make adjacent diamonds in dense timelines confusable.
DOM selection syncs to timeline selectedElementId on cold-load URL restore
Important for shareable Studio URLs. Verify the sync handles the case where selectedElementId references a stale element (no longer in the DOM after a script edit). Silent no-select or fallback to first element is fine; uncaught error is not.
Phosphor Scissors icon — duplicates #1189
Both #1189 and this PR mention the Phosphor Scissors icon. Once the stack merges in order, the second one is a no-op. Just flagging that the icon import lives in two PRs of the same stack.
Review by Jerrai (hyperframes specialist)
c048e70 to
aae066c
Compare
c12e51d to
437b02d
Compare
0845d38 to
7b29dd3
Compare
437b02d to
2a074bc
Compare
Revert totalTime nudge that caused black first frames in from() tweens. Keep stale CSS offset cleanup. Regenerate baselines for offset cleanup.
Revert totalTime nudge that caused black first frames in from() tweens. Keep stale CSS offset cleanup. Regenerate baselines for offset cleanup.
…ation U1: stripGsapTranslateFromTransform now rotates the offset vector by the element's CSS rotation angle before subtracting from m41/m42. Fixes elements drifting from cursor during drag when rotated. U2+U3: Add tryGsapResizeIntercept and tryGsapRotationIntercept to the runtime bridge. Resize and rotation handle changes now create keyframes via the same async pipeline as position drag. CSS path guards prevent double-persistence for GSAP-animated elements.
…yBoxSizes guard - Fix overlay bounding box jump: reapplyBoxSizes now skips elements whose width/height are animated by GSAP (gsapAnimatesProperty check prevents studio CSS from overwriting GSAP interpolated values) - Delete All Keyframes removes entire animation (handleGsapDeleteAnimation) with fallback to first animation when no keyframed anim exists - Wire split clip through App → StudioPreviewArea → NLELayout → Timeline (onSplitElement prop, toolbar button, S hotkey, clip context menu) - Add onContextMenu to TimelineClip for right-click clip context menu
Sub-compositions (data-composition-src) cannot be meaningfully split — the clone would load the same source and fight for the same timeline. Block with a specific toast message and disable in the context menu.
…rties The Layout section (X, Y, W, H, R) now reads GSAP-interpolated values from the runtime via gsap.getProperty() at the current seek time. When an element has GSAP animations, the fields reflect the actual interpolated position/size/rotation instead of the CSS defaults. Also adds 3D transform properties to SUPPORTED_PROPS: z, rotationX, rotationY, rotationZ, perspective, transformOrigin.
… tolerance - Selected clip: full accent border (was 38% opacity), subtle glow shadow - Keyframe diamond at playhead: tolerance 0.5% (was 0.05% — too tight at high zoom levels, causing diamonds to never highlight)
Extract useAnimatedPropertyCommit hook that handles the three-case commit logic: keyframed → add-keyframe, flat → convert + add, no animation → create + convert + add. Wire Z, Scale, RotX, RotY design panel fields and 2D Layout fields through this unified pipeline. Export readAllAnimatedProperties and readGsapProperty from the runtime bridge so the commit helper can read all animated props for backfill.
These design plans were accidentally committed and should not be in the PR.
06325c3 to
eb8f448
Compare

Summary
gsap.getProperty()at the current seek time — values update live when scrubbingz,rotationX,rotationY,rotationZ,perspective,transformOriginselectedElementIdon cold-load URL restoreStacked on #1172.