Add fast, interruptible native motion throughout the app #9

Open
opened 2026-08-21 08:34:37 +00:00 by kayg · 1 comment
Owner

Goal

Add broad but disciplined motion polish throughout Hermternal: lots of feedback, all fast, interruptible, native, and performant.

Candidate surfaces

  • Chat selection and cache-first transcript transition.
  • New message insertion and streaming-start handoff.
  • Composer send ↔ stop state, attachment/model controls when they ship.
  • Notice banners, empty states, settings tab/state changes, search palette, and cache progress.
  • Sidebar selection/hover and window materialization.

Motion rules

  • Immediate feedback; no animation may delay input or network work.
  • Prefer native SwiftUI/AppKit springs and compositor-friendly transform/opacity. Avoid animating layout on large transcript trees.
  • Critically damped, short responses by default; bounce only when momentum caused it.
  • Every transition is interruptible and starts from the current presentation value.
  • Respect Reduce Motion with short cross-fades/static state changes and Reduce Transparency with solid alternatives.
  • Do not animate every streamed token or auto-scroll with a long catch-up animation.

Acceptance

Instrument representative interactions: no dropped frames on the current 500+ row transcript, no additional Markdown parsing during streaming, and no input lockout while motion is active.

## Goal Add broad but disciplined motion polish throughout Hermternal: lots of feedback, all fast, interruptible, native, and performant. ## Candidate surfaces - Chat selection and cache-first transcript transition. - New message insertion and streaming-start handoff. - Composer send ↔ stop state, attachment/model controls when they ship. - Notice banners, empty states, settings tab/state changes, search palette, and cache progress. - Sidebar selection/hover and window materialization. ## Motion rules - Immediate feedback; no animation may delay input or network work. - Prefer native SwiftUI/AppKit springs and compositor-friendly transform/opacity. Avoid animating layout on large transcript trees. - Critically damped, short responses by default; bounce only when momentum caused it. - Every transition is interruptible and starts from the current presentation value. - Respect Reduce Motion with short cross-fades/static state changes and Reduce Transparency with solid alternatives. - Do not animate every streamed token or auto-scroll with a long catch-up animation. ## Acceptance Instrument representative interactions: no dropped frames on the current 500+ row transcript, no additional Markdown parsing during streaming, and no input lockout while motion is active.
Author
Owner

Concrete search-palette animation requirements (the ⌘K palette planned as an .overlay on ChatWindow):

  • Entrance: the panel must fade in gradually and smoothly rather than appear instantly. The underlying view must fade to maximum frost with it, regardless of the user's frost-slider setting.
  • Dismissal: fade out symmetrically for both Escape and clicking outside the panel frame. The overlay needs a hit-testable backdrop so outside-click dismissal is structural, not merely visual.
  • Couple panel opacity/scale and backdrop frost to one state change so they animate together and cannot desynchronize; do not use two independent animations. Motion must be interruptible: rapid ⌘K → Escape → ⌘K must start from current presentation values without queuing or fighting.
  • Respect accessibilityReduceMotion: replace scale/spring motion with a plain cross-fade, while retaining feedback.
  • #8 requires the palette to accept input within one frame. Entrance animation must not delay focus or keystroke handling; the field must be live while the panel is animating in.
Concrete search-palette animation requirements (the ⌘K palette planned as an `.overlay` on `ChatWindow`): - Entrance: the panel must fade in gradually and smoothly rather than appear instantly. The underlying view must fade to maximum frost with it, regardless of the user's frost-slider setting. - Dismissal: fade out symmetrically for both Escape and clicking outside the panel frame. The overlay needs a hit-testable backdrop so outside-click dismissal is structural, not merely visual. - Couple panel opacity/scale and backdrop frost to one state change so they animate together and cannot desynchronize; do not use two independent animations. Motion must be interruptible: rapid ⌘K → Escape → ⌘K must start from current presentation values without queuing or fighting. - Respect `accessibilityReduceMotion`: replace scale/spring motion with a plain cross-fade, while retaining feedback. - #8 requires the palette to accept input within one frame. Entrance animation must not delay focus or keystroke handling; the field must be live while the panel is animating in.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/hermternal-apple#9
No description provided.