Skip to content

feat(app): add a "James" option for sidebar motion - #57901

Merged
jlongster merged 11 commits into
betafrom
low-movement-sidebars
Oct 21, 2026
Merged

jlongster merged 11 commits into
betafrom
low-movement-sidebars

Conversation

@jlongster

@jlongster jlongster commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Issue for this PR

Closes #

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Builds on Kit's #57692. It adds James as an entry in the Knobs preset strip (dev tools → Knobs → Sidebars), next to Shipped / Snappy / Smooth / Calm.

  • Internal knob ids keep the sidebars.low.* prefix, so tuned Knobs values survive the rename.
  • Choosing it swaps the section's knobs for James's: Movement, Fade, Fade duration, Layout, Layout open, Layout close.
  • Choosing any other preset brings back Kit's knobs (Spring, and Motion with Spring / Instant), exactly as before, and applies that preset.
  • James is the shipped default: a client with no saved Knobs settings gets it. Kit's Spring presets and Instant stay selectable in Knobs, and the replay buttons are unchanged. This replaces feat(app): open sidebars with a short fade, close them instantly #57880, which rewrote Kit's motion instead of adding to it.

What James does, for both the left sidebar and the side panel:

  • Open: layout changes in one frame (Kit's paint snapped to open). Then only the panel moves: it shifts in from 30px (side panel; "Panel shift" knob, 0–48) or 10px (left sidebar), mirrored in RTL, on a 240ms spring with bounce 0, while it fades from opacity 0.15 to 1 on cubic-bezier(0.44, 0.75, 0.63, 1.03) over 180ms.
  • Close: instant. The panel hides at once and the layout closes in one frame; only the neighbours glide (below). Closing during an opening cancels it.
  • Layout glide (on by default): when the layout changes, on open and close, the neighbours glide from their old box to the new one: the session column, plus the side panel when the left sidebar toggles.
    • "Glide (FLIP)" translates them on the compositor, anchored on the session column's centre and the side panel's start edge.
    • "Width" animates the resized box's real width instead.
    • Default: a 160ms spring with bounce 0, separate for open and close.
    • Old and new boxes are measured on either side of the layout change, and the glide starts in the same frame.
  • Keyboard toggles animate like clicks. Reduced motion is instant.
  • Both animations are Web Animations on transform and opacity: no per-frame layout, and the compositor plays them through main-thread work. The spring is sampled once into a CSS linear() easing.

Changes:

  • ui/src/motion-tuning.ts and motion-tuning-panel.ts (a mode can ship on with value: true, and shows in the strip only on its own section's tab):
    • an optional when on any knob. The panel shows only knobs whose when holds, and rebuilds when that changes.
    • a mode knob kind. It shows as a preset-strip entry rather than a row, is on while chosen, and is off once another preset is chosen; that other preset is then re-applied after the rebuild so it reaches the knobs that came back.
    • easing editors open inline.
    • a new easing knob kind (a cubic-bezier, saved as four numbers). The panel renders it with knobs' own easing() editor.
  • app/src/shell/panel-motion.ts:
    • the sidebars.low mode. Kit's Motion choice is back to Spring / Instant only;
    • the James knobs:
      • Movement (spring, 240ms, bounce 0);
      • Fade (easing; knobs' own bezier editor, since the panel had no bezier control yet);
      • Fade duration (0.18s);
      • Layout (Glide / Width / Off);
      • Layout open and Layout close (springs, 160ms, bounce 0).
      • The time-based ones are scaled by the global Speed and Slow-motion knobs.
    • a fade() branch in createPanelMotion, used when element and offset are passed.
    • whenSettled, sync and panelsMoving cover both kinds of flight.
    • The 0.15 starting opacity is hard-wired.
  • shell.tsx and session/screen.tsx: pass the panel layer (element) and its offset. Kit's paint is unchanged.

How did you verify your code works?

  • bun typecheck in packages/app and packages/ui.

  • bun test --conditions=browser --isolate --preload ./happydom.ts ./test-browser/panel-motion.test.ts: 14 pass (including which controls show for each Motion choice). Kit's tests are unchanged; there are new James cases for:

    • open: layout first, then the keyframes, the spring samples and the bezier;
    • close in reverse, keeping the layout until the fade ends;
    • mid-flight reversal;
    • reduced motion.
  • ui motion-tuning.test.ts and app motion-tuning-panel.test.ts pass. bun run lint:changed origin/beta is clean.

  • James is trying it in the web app.

  • e2e/regression/panel-edges.spec.ts now seeds Kit's spring ("sidebars.low": 0), because that spec covers Kit's spring and James is now the default. Not run locally.

Screenshots / recordings

None. James is checking it live.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@jlongster
jlongster force-pushed the low-movement-sidebars branch 4 times, most recently from 9eaeebe to 41f3517 Compare October 21, 2026 20:54
@jlongster jlongster changed the title feat(app): add a Low movement option for sidebar motion feat(app): add a "James" option for sidebar motion Oct 21, 2026
@jlongster
jlongster force-pushed the low-movement-sidebars branch from b255909 to 5c211ea Compare October 21, 2026 21:22
@jlongster
jlongster force-pushed the low-movement-sidebars branch from a3480ed to 01ae89f Compare October 21, 2026 21:32
@jlongster
jlongster merged commit a900537 into beta Oct 21, 2026
9 of 17 checks passed
@jlongster
jlongster deleted the low-movement-sidebars branch October 21, 2026 22:42
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