Decide whether windows slide with a spring that keeps its speed when you press another key mid-slide#278

opened7d agobySSamanyu Das

Question

Should strip motion use a spring that keeps its speed when you press another key mid-slide, or keep the engine's current ease-out?

The documents and the code disagree:

  • decisions/features and shortcuts.md:84 says "Use a spring animation for strip motion that starts as soon as a navigation key is pressed", and line 85 says "Synchronize animation with the display refresh rate". The same document says that its features "do not establish a complete v1 commitment".
  • decisions/configuration.md:143-152 defers spring duration and damping options to v2.
  • decisions/release-scope.md does not mention a spring.
  • The engine at af52f84 uses an exponential ease-out (ease_out_factor and ease_step in src/ecs/systems.rs:715-761). Each frame covers a fixed share of the remaining distance, set by animation_speed, and it steps by elapsed time.

From the code, not from an observation: with an ease-out, a new target mid-slide sets the speed from the new distance at once, so a second key press makes the window jump to a higher speed. A spring would carry its current speed into the new slide. Nobody has compared the two on the Mac.

Options

  1. Keep the ease-out and change the features document to describe it. No engine change. The pacing and edge fixes, such as #163, stay as they were tested.
  2. Replace the ease-out with a critically damped spring that keeps its speed across new targets. This is an engine change. It needs every slide, swipe, and shared-edge check to run again.
  3. Defer the spring to v2, together with the duration and damping options, and record the ease-out as the v1 behavior.

Acceptance criteria

  • Sam records the choice in decisions/features and shortcuts.md, and in decisions/release-scope.md if it changes v1.
  • If Sam picks option 2, a separate enhancement issue holds the engine work and its checks.

Recommendation

Option 3. It keeps the tested v1 motion and makes the documents match the code. Before Sam decides, a recording of repeated Control-Option-Right presses mid-slide can show whether the speed jump is visible.

Note

🤖 grok-4.7-build-fast responding on behalf of samanyudas

This was generated by AI during triage.

This stays a decision for Sam. No document edit, no engine change, and no pull request until he records the choice.

The engine at 481d52ff (engine af52f84) slides windows with an exponential ease-out. ease_out_factor turns animation_speed (14) and the frame time into a fraction of the remaining distance. ease_step moves from the current point toward RepositionMarker, which stores only the target. A new key mid-slide sets the next frame's speed from the new distance. Scrolling.velocity is the trackpad swipe, not this slide.

decisions/features and shortcuts.md says to use a spring, and the same file says those features do not establish a complete v1 commitment. decisions/configuration.md defers spring duration and damping to v2. decisions/release-scope.md does not require a spring for keyboard slides. Its "springs back" line is the overscroll of a strip that already fits. Release scope also defers animation tuning to v2.

#280 already measured this on a main build, verify-miri run 20261103-210038. A 673 point swap jumped 251 points in the first visible frame. That is 37% of the move, and 1 - e^(-14/30) is 0.373. A reversing key changed speed by a median of 6,360 points per second in one frame.

Triage outcome: keep the decision label, remove needs-triage, add ready-for-human. The acceptance criteria require Sam to record the choice. An agent cannot tick them. The criteria are plain bullets, not checkboxes.

make verify-engine-lifecycle does not apply. Its model covers start, stop, restart, and quit, not window frames or strip motion, so it cannot show this choice as fixed. There is no after build for verify-miri until a choice lands. The before measurement is the #280 run.

A draft of option 2 already exists and was not adopted. Engine branch miri/spring-key-motion at 61f131d in /Users/sam/.t3/worktrees/miri/spring-motion adds a critically damped spring and says it refs #280. Uncommitted src/ecs/spring.rs is part of that draft. It assumes the spring.

Recommendation: option 3. Record the ease-out as the v1 behavior and defer the spring with the duration and damping options. The first-frame jump in #280 is a separate defect in the ease-out's idle-sleep step. It can be fixed without a spring. #280's expected result currently treats the features-document spring sentence as the v1 contract, so that issue should wait on this choice.

Note

🤖 grok-4.7-build-fast responding on behalf of samanyudas

Sam chose option 3 on 4 November 2026. Both acceptance criteria hold on the branch. The issue stays open until the pull request is on main, because main still tells agents to use a spring.

Verified artifact: commit 04485d4 on fix/issue-278. No engine pin change. The bundled engine stays af52f84.

  1. decisions/features and shortcuts.md and decisions/release-scope.md both say a keyboard slide in v1 is an exponential ease-out, and that a spring that keeps its speed across a new keyboard target is deferred to v2. python3 scripts/check-docs.py reported 0 problems. make pre-push passed on the push.
  2. Option 2 was not chosen, so no enhancement issue is required. The spring draft on engine branch miri/spring-key-motion stays unmerged.

make verify-engine-lifecycle does not apply. Its model covers start, stop, restart, and quit, not keyboard slides. verify-miri has no after build. This change does not alter the running app. The before measurement remains #280 run 20261103-210038 on main at 481d52ff.

Swipe settling is outside this choice. settle_strip already moves a swipe on a critically damped spring.