MOTION: walk back #527, keyboard actions animate like pointer actions on every route #611

Open
opened 2026-10-01 09:39:21 +00:00 by kayg · 7 comments
Owner

Owner request (2026-10-01): walk back #527

"Can we please walk back the decision that keyboard shortcuts = no animation? It's no fun when I hit ? and it instantly appears! We will apply the no animation rule only very selectively. Make every route the same for now!"
Fix:

  • Keyboard-triggered UI animates exactly like pointer-triggered UI everywhere: the ? shortcuts card morph, ⌘K search, menus, sheets, tab switches, selection highlight moves.
  • Keep the shared modality flag/motion tokens from #527 (code reuse; the owner will name exceptions later), but make keyboard resolve to the same durations as pointer.
  • Remove the "cancel running transitions on keydown" behaviour.
  • Reduced motion still applies.
  • "Loading never waits on an animation" stays.
  • Update DESIGN §34 / the motion section and the tests: the kbd-motion e2e now asserts keyboard and pointer produce the same animation durations, and the ? card morphs in.
    Web gates; frame strips of ? opening via keyboard at 1440.
## Owner request (2026-10-01): walk back #527 "Can we please walk back the decision that keyboard shortcuts = no animation? It's no fun when I hit ? and it instantly appears! We will apply the no animation rule only very selectively. Make every route the same for now!" **Fix:** - Keyboard-triggered UI animates exactly like pointer-triggered UI everywhere: the `?` shortcuts card morph, ⌘K search, menus, sheets, tab switches, selection highlight moves. - Keep the shared modality flag/motion tokens from #527 (code reuse; the owner will name exceptions later), but make keyboard resolve to the **same** durations as pointer. - Remove the "cancel running transitions on keydown" behaviour. - Reduced motion still applies. - "Loading never waits on an animation" stays. - Update DESIGN §34 / the motion section and the tests: the kbd-motion e2e now asserts keyboard and pointer produce the same animation durations, and the `?` card morphs in. Web gates; frame strips of `?` opening via keyboard at 1440.
Author
Owner

Starting #611 on branch job/motion-611, based on 1af8ead262daf0a4ad22a60564dc75bab0005cf4 (origin/dev is currently two commits ahead). The worktree is clean. I am tracing the shared motion tokens, keyboard transition cancellation, and the kbd-motion E2E before changing behavior.

Starting #611 on branch `job/motion-611`, based on `1af8ead262daf0a4ad22a60564dc75bab0005cf4` (`origin/dev` is currently two commits ahead). The worktree is clean. I am tracing the shared motion tokens, keyboard transition cancellation, and the `kbd-motion` E2E before changing behavior.
Author
Owner

Finding: packages/ui/src/motion.ts treats html[data-input="keyboard"] as immediate, and packages/ui/src/tokens.css sets every shared duration to 0 ms and applies animation: none / transition: none to the whole tree. The latter cancels an active pointer transition when keydown updates the shared modality. The Settings shortcut also passes instantOpen into OverlaySurface (apps/web/src/routes/+layout.svelte and routes/settings/[...path]/+page.svelte). I am updating the central motion contract and removing that route exception while preserving reduced-motion handling and the focus modality flag.

Finding: `packages/ui/src/motion.ts` treats `html[data-input="keyboard"]` as immediate, and `packages/ui/src/tokens.css` sets every shared duration to 0 ms and applies `animation: none` / `transition: none` to the whole tree. The latter cancels an active pointer transition when keydown updates the shared modality. The Settings shortcut also passes `instantOpen` into `OverlaySurface` (`apps/web/src/routes/+layout.svelte` and `routes/settings/[...path]/+page.svelte`). I am updating the central motion contract and removing that route exception while preserving reduced-motion handling and the focus modality flag.
Author
Owner

Issue #611 complete

Committed on job/motion-611: 0a72fb68d6c4005febef8ccbc7a275b992ed6837 (Restore shared keyboard motion timings for #611).

Keyboard actions now use the shared pointer/touch motion durations and easing across the app. The root data-input flag remains for focus behavior; it no longer zeros duration tokens or cancels active transitions. Reduced motion remains active. Settings no longer has a keyboard-only instant-open path, and the toast timer ring uses the same motion rules. Loading still does not wait for animation.

Updated DESIGN §34 and the shared motion tests. The production E2E compares keyboard and pointer durations for Files selection, Tabs, menus, Search and Settings. It checks that keyboard input leaves an opening pointer menu animation running and that ? morphs the Tab Bar.

Screenshots

44 production screenshots are attached to this issue. They cover 390, 820 and 1440 px in light and dark themes, plus the 1440 ? morph frames:

Keyboard shortcuts card morph, 1440 px, light theme

Keyboard shortcuts card morph, 1440 px, dark theme

Gates

bun run check:

User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
svelte-check found 0 errors and 0 warnings

bun run test:

 Test Files  148 passed (148)
      Tests  1011 passed (1011)
   Start at  13:10:52
   Duration  83.78s (transform 51%, environment 18%, import 17%, tests 10%, setup 4%)

Production build completed with ✓ built in 21.05s. Its log included Vite MODULE_LEVEL_DIRECTIVE warnings for vendored use client directives.

PASS keyboard and pointer Tab, selection, and Search actions use the same durations; ? morphs in
settings-shortcut e2e passed: primary key, shared entrance timing, last section, non-toggle, Note comma guard, and host fallback; screenshots in /home/kayg/Developer/calternal-wt/motion-611/artifacts/settings-key-541

Cargo cleanup output:

/mnt/hdd/targets/jobs/motion-611
     Removed 7237 files, 4.6GiB total

Performance

The new profile ran locally with 1,000 real Files and a 100-move burst. The host load average before measurement was 16.01. Average move latency was p50 10.76 ms / p95 17.35 ms (0.38 CPU seconds; RSS 627,453,952 bytes before and 625,074,176 bytes after). Burst latency was p50 10.05 ms / p95 21.24 ms / max 233.61 ms (2.66 CPU seconds; peak RSS 638,844,928 bytes).

There is no keyboard-motion workload in docs/perf/baseline.json, so there is no baseline comparison. The profile JSON remains in ignored artifacts/kbd-motion-611/profile.json.

Decisions and gaps

No additional design decisions were needed. The implementation keeps the shared input-modality flag for focus behavior and uses reduced motion as the timing override. No Rust crate or API changed. Known gap: this workload has no recorded baseline. The production build reports the vendored directive warnings noted above.

## Issue #611 complete Committed on `job/motion-611`: `0a72fb68d6c4005febef8ccbc7a275b992ed6837` (`Restore shared keyboard motion timings for #611`). Keyboard actions now use the shared pointer/touch motion durations and easing across the app. The root `data-input` flag remains for focus behavior; it no longer zeros duration tokens or cancels active transitions. Reduced motion remains active. Settings no longer has a keyboard-only instant-open path, and the toast timer ring uses the same motion rules. Loading still does not wait for animation. Updated DESIGN §34 and the shared motion tests. The production E2E compares keyboard and pointer durations for Files selection, Tabs, menus, Search and Settings. It checks that keyboard input leaves an opening pointer menu animation running and that `?` morphs the Tab Bar. ## Screenshots 44 production screenshots are attached to this issue. They cover 390, 820 and 1440 px in light and dark themes, plus the 1440 `?` morph frames: ![Keyboard shortcuts card morph, 1440 px, light theme](https://git.kayg.org/attachments/79d531da-4b94-45aa-bfab-2dcb516cfb8a) ![Keyboard shortcuts card morph, 1440 px, dark theme](https://git.kayg.org/attachments/2fc5eaf3-db19-4fa0-ad0b-9339795f42f0) ## Gates `bun run check`: ```text User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. svelte-check found 0 errors and 0 warnings ``` `bun run test`: ```text Test Files 148 passed (148) Tests 1011 passed (1011) Start at 13:10:52 Duration 83.78s (transform 51%, environment 18%, import 17%, tests 10%, setup 4%) ``` Production build completed with `✓ built in 21.05s`. Its log included Vite `MODULE_LEVEL_DIRECTIVE` warnings for vendored `use client` directives. ```text PASS keyboard and pointer Tab, selection, and Search actions use the same durations; ? morphs in settings-shortcut e2e passed: primary key, shared entrance timing, last section, non-toggle, Note comma guard, and host fallback; screenshots in /home/kayg/Developer/calternal-wt/motion-611/artifacts/settings-key-541 ``` Cargo cleanup output: ```text /mnt/hdd/targets/jobs/motion-611 Removed 7237 files, 4.6GiB total ``` ## Performance The new profile ran locally with 1,000 real Files and a 100-move burst. The host load average before measurement was 16.01. Average move latency was p50 10.76 ms / p95 17.35 ms (0.38 CPU seconds; RSS 627,453,952 bytes before and 625,074,176 bytes after). Burst latency was p50 10.05 ms / p95 21.24 ms / max 233.61 ms (2.66 CPU seconds; peak RSS 638,844,928 bytes). There is no keyboard-motion workload in `docs/perf/baseline.json`, so there is no baseline comparison. The profile JSON remains in ignored `artifacts/kbd-motion-611/profile.json`. ## Decisions and gaps No additional design decisions were needed. The implementation keeps the shared input-modality flag for focus behavior and uses reduced motion as the timing override. No Rust crate or API changed. Known gap: this workload has no recorded baseline. The production build reports the vendored directive warnings noted above.
Author
Owner

Audit evidence for the keyboard-motion fix: packages/ui/src/components/calendar/GridColumn.svelte:974 still says that focus never inherits pointer motion and cites withdrawn issue #527. The matching focus rule at lines 986–988 sets transform: none and transition: none. Owner issue #611 says keyboard-triggered actions, including moving a selection, use the same motion as pointer actions. Please update the stale comment and check whether this focus rule suppresses keyboard-driven selection motion. Expected behavior: keyboard and pointer selection use the same shared duration; reduced motion still applies and the focus ring stays visible. Test idea: move between Calendar blocks with the keyboard and pointer and compare their transition durations.

Audit evidence for the keyboard-motion fix: `packages/ui/src/components/calendar/GridColumn.svelte:974` still says that focus never inherits pointer motion and cites withdrawn issue #527. The matching focus rule at lines 986–988 sets `transform: none` and `transition: none`. Owner issue #611 says keyboard-triggered actions, including moving a selection, use the same motion as pointer actions. Please update the stale comment and check whether this focus rule suppresses keyboard-driven selection motion. Expected behavior: keyboard and pointer selection use the same shared duration; reduced motion still applies and the focus ring stays visible. Test idea: move between Calendar blocks with the keyboard and pointer and compare their transition durations.
Author
Owner

Static audit evidence for the remaining #527 conflict:

DESIGN §34 says keyboard actions use the same motion as pointer actions, but §57 says Calendar arrow-key movement has no animation at docs/DESIGN.md:2690-2696. The same older rule remains in the closed #536 issue. This conflicts with this issue's owner request that keyboard and pointer actions use the same duration, with reduced motion still respected.

Expected: update §57 and the Calendar keyboard-nudge decision to use the shared motion duration. Regression idea: compare pointer drag and keyboard nudge transitions, and confirm both honor reduced motion.

Static audit evidence for the remaining #527 conflict: DESIGN §34 says keyboard actions use the same motion as pointer actions, but §57 says Calendar arrow-key movement has no animation at docs/DESIGN.md:2690-2696. The same older rule remains in the closed #536 issue. This conflicts with this issue's owner request that keyboard and pointer actions use the same duration, with reduced motion still respected. Expected: update §57 and the Calendar keyboard-nudge decision to use the shared motion duration. Regression idea: compare pointer drag and keyboard nudge transitions, and confirm both honor reduced motion.
Author
Owner

Design-sync #864 corrected DESIGN §57 on job/design-sync, commit d44b9a21b.

Old docs/DESIGN.md:2690-2696 made Calendar arrow-key movement an animation exception. §34:1384-1398 and owner issue #611 already require shared keyboard, pointer and touch motion. §57 now follows that rule, keeps reduced motion and states that available data and input never wait for animation.

Regression idea: compare arrow-key and pointer motion and confirm available content and input do not wait for a transition. §34 already has the current rule and was not edited. No runtime claim or test run from this LIGHT documentation job.

Design-sync #864 corrected DESIGN §57 on `job/design-sync`, commit `d44b9a21b`. Old docs/DESIGN.md:2690-2696 made Calendar arrow-key movement an animation exception. §34:1384-1398 and owner issue #611 already require shared keyboard, pointer and touch motion. §57 now follows that rule, keeps reduced motion and states that available data and input never wait for animation. Regression idea: compare arrow-key and pointer motion and confirm available content and input do not wait for a transition. §34 already has the current rule and was not edited. No runtime claim or test run from this LIGHT documentation job.
Author
Owner

Audit against origin/dev: packages/ui/src/components/calendar/GridColumn.svelte:986-989 still sets transform: none and transition: none for .block:focus-visible. Keyboard focus therefore still suppresses shared Calendar motion, contrary to this issue's all-routes rule. Leave open until this exception is removed and covered.

Audit against origin/dev: `packages/ui/src/components/calendar/GridColumn.svelte:986-989` still sets `transform: none` and `transition: none` for `.block:focus-visible`. Keyboard focus therefore still suppresses shared Calendar motion, contrary to this issue's all-routes rule. Leave open until this exception is removed and covered.
Sign in to join this conversation.
No labels
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/calternal#611
No description provided.