Skip to content

feat(studio): flat inspector — Layout + Motion groups#2122

Open
vanceingalls wants to merge 11 commits into
studio-flat-02-stylefrom
studio-flat-03-layout-motion
Open

feat(studio): flat inspector — Layout + Motion groups#2122
vanceingalls wants to merge 11 commits into
studio-flat-02-stylefrom
studio-flat-03-layout-motion

Conversation

@vanceingalls

@vanceingalls vanceingalls commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

What

Third PR in a 6-PR stack for the flat inspector redesign (see #2120 for the foundation and full stack list). Adds the flat Layout group (X/Y/W/H/Angle geometry rows with keyframe gutters, Z-index, Flex, a wrapped 3D transform sub-view) and the flat Motion group (Timing row, effect-card list), each wired into the accordion, plus a cross-group fix reconciling their timing basis.

Stack: #2120 (Foundation+Text) → #2121 (Style) → #2122 (this) → #2123 (Media) → #2124 (Grade) → #2125 (Pinning + multi-field Text).

Why

Layout and Motion are the two groups most entangled with GSAP keyframe state — an element's timing (start/duration) has to agree between Layout's keyframe-seek gutter and Motion's Timing row, or keyframe diamonds and prev/next-arrow navigation land in the wrong place.

How

  • FlatLayoutSection composes geometry/Z-index/Flex/3D-transform sub-blocks; the 3D transform view is the existing component nested in a new flat wrapper, not rebuilt.
  • FlatMotionSection composes a new FlatTimingRow with the existing effect-card list (given a new flat collapsed-header variant).
  • Cross-group fix included in this PR: a coherence review across Layout+Motion found their keyframe-seek bases disagreed for elements with animations but no explicit data-duration (Layout used a naive duration ?? 1, Motion correctly inferred from the GSAP tween). Fixed via a new shared deriveElementTiming helper both groups now read from, plus a follow-up fix threading the corrected basis into the keyframe diamond active-state/arrow-navigation calculation.
  • Still behind STUDIO_FLAT_INSPECTOR_ENABLED (default off).

Test plan

  • Every row/primitive has a real DOM-event test with exact assertions.
  • The timing-basis fix was caught by a whole-plan coherence review (not per-task review) and independently verified against both groups' keyframe rendering before and after.
  • Full monorepo suite green; oxlint/oxfmt/fallow clean.
  • Unit tests added/updated
  • Manual testing performed
  • Documentation updated (not applicable — internal Studio UI behind an off-by-default flag)

vanceingalls and others added 11 commits July 9, 2026 11:52
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Thread the Layout-group values through PropertyPanel -> PropertyPanelFlat
and add the third FlatGroup to the one-open/pin accordion (unconditional,
matching legacy Layout). Default-open Layout when neither Text nor Style
applies.

Fix the Flex double-render: the legacy StyleSections still renders its own
Flex Section, and the new flat Layout group renders its own LayoutFlexBlock.
Add an additive optional hideFlex prop to StyleSections and pass it on the
flat path so Flex renders exactly once (from the flat Layout group). Non-flat
callers omit it and are unchanged.

Extract the shared onLivePreviewProps closure into gsapLivePreview.ts (it was
duplicated inline in the legacy path) so PropertyPanel.tsx stays within the
600-LOC studio gate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… and Motion groups

Whole-plan coherence review (Plan 3a Layout + Plan 3b Motion) found that
Layout's keyframe gutter and Motion's Timing row independently derived an
element's start/duration and disagreed whenever an element had animations
but no explicit data-duration: Motion correctly inferred the range from the
element's GSAP tweens, while Layout's keyframe gutter fell back to a naive
`duration ?? 1`, so clicking a keyframe percentage in Layout could seek to a
different absolute time than what Motion's Timing row displayed.

Extract deriveElementTiming (propertyPanelFlatTimingDerivation.ts) as the
single shared basis both paths now consume: FlatTimingRow (Motion) and
PropertyPanelFlat's own elStart/elDuration (Layout's keyframe gutter and 3D
Transform block). PropertyPanelFlat now recomputes this basis itself from
its own element/gsapAnimations props instead of trusting the parent's naive
value, so PropertyPanel.tsx (and its legacy non-flat panel) is untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…basis in the flat Layout group

Follow-up to 684ec4e: that fix corrected the seek target for Layout's
keyframe gutter via deriveElementTiming, but currentPct — which drives
KeyframeNavigation's diamond active/inactive state and prev/next arrow
targeting — still used PropertyPanel's naive elStart=0/elDuration=1
basis. For an element with animations but no explicit data-duration,
seeking to a keyframe's real absolute time no longer lit that
keyframe's diamond as active, and the prev/next arrows targeted the
wrong keyframes.

Thread currentTime into PropertyPanelFlat (swapping the now-redundant
currentPct prop 1-for-1, so PropertyPanel.tsx's line count is
unchanged) and recompute currentPct there from the same
deriveElementTiming basis already used for the seek fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

vanceingalls commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

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.

1 participant