Skip to content

The caret's glide is a setting, not a hard-coded on - #712

Merged
PathGao merged 1 commit into
masterfrom
feat/cursor-animation-setting
Aug 23, 2026
Merged

The caret's glide is a setting, not a hard-coded on#712
PathGao merged 1 commit into
masterfrom
feat/cursor-animation-setting

Conversation

@PathGao

@PathGao PathGao commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

What this is

Adds Animate Cursor Movement to Settings → Appearance, directly under
Animate Scrolling on Jump. Closes #710, reported by @eli-yip, who found
cursorSmoothCaretAnimation hard-coded and asked for the same treatment the
scroll animation already gets.

Defaults to on, so nothing about an existing install changes.

Mechanism

cursorSmoothCaretAnimation: 'on' was a literal in the monaco.editor.create()
call in Editor.svelte. That made the caret's slide between positions the only
motion in the app with no switch: animateJumpScroll already answers for the
animated jump in both panes, and the glide answered to nothing.

It is its own preference rather than a second reader of animateJumpScroll. A
jump is the app moving the view on the user's behalf, a few times a session;
the glide is drawn under every arrow key. Someone who finds the glide smeary
has no reason to lose the animated jump along with it. The alternative —
folding both into one "reduce animation" switch — was rejected for that reason,
and because the issue asks for a switch similar to the existing one, not a
change to what the existing one covers.

The option moves out of the creation literal and into
editorOptionsFromSettings, for the reason smoothScrolling moved there
earlier: the set updateOptions re-applies is what makes a toggle reach the
editor that is already open. Left where it was, the switch would have taken
effect only on the next editor — the toggle would look inert to anyone who
flipped it and went back to typing.

Both preferences resolve through one predicate in utils/motion.ts, so
prefers-reduced-motion cannot end up honoured by one and not the other. That
is the same expression-written-twice shape the module's existing comment was
written about.

Scope

Only the main editor. The other Monaco instance, the diff view in
DiffOverlay.svelte, is readOnly: true and never set the option, so it has
no caret to animate. The preview pane is rendered output with no editable
surface, and the app's <input> fields use the native caret, which Monaco does
not reach.

No version bump, no changes to the jump-scroll preference or its call sites.

Tests

Four assertions in editorOptionWiring.test.ts, all behavioural — they call
editorOptionsFromSettings rather than matching source text:

  • the default resolves to 'on'
  • the setting off resolves to 'off'
  • systemReducedMotion alone resolves to 'off', with the app setting still on
  • animateJumpScroll: false leaves the caret at 'on' — the two are independent

Revert check: restoring the hard-coded 'on' in editorOptionsFromSettings
and keeping the tests turns the new test red and leaves the other 971 green.

The existing assertion that pins the exact set of options both call sites share
gains cursorSmoothCaretAnimation. That is the assertion doing its job: it is
there so an option cannot quietly enter or leave the shared set, and this change
deliberately puts one in.

Verification

npm audit          0 vulnerabilities
npm run check      816 files, 0 errors, 0 warnings
npm test           972 pass, 0 fail
npm run test:vitest 398 pass, 0 fail
cargo test         164 pass, 0 fail

Manually verified on macOS 15 in a release build: the toggle changes the caret
in the open editor with no restart, survives a relaunch, leaves the animated
jump working when it is off, and both animations stop when the system's Reduce
Motion is on while both switches stay on in the UI.

Not verified: Windows and Linux. The change is one Monaco option and a
localStorage key, with no platform-conditional path, so I reasoned about
those rather than running them.

`cursorSmoothCaretAnimation: 'on'` sat in the `monaco.editor.create()`
literal, so the caret's slide between positions was the only motion in
the app with no way to turn it off — `animateJumpScroll` already answers
for the animated jump in both panes.

Its own preference rather than a second reader of `animateJumpScroll`: a
jump is the app moving the view on the user's behalf a few times a
session, and the glide is drawn under every arrow key. Someone who finds
the glide smeary has no reason to lose the animated jump with it.

The option moves into `editorOptionsFromSettings` for the reason
`smoothScrolling` moved there — the set `updateOptions` re-applies is
what makes a toggle reach the editor that is already open. Left in the
creation literal it would have taken effect only on the next one.

Defaults to on, so nothing about an existing install changes, and it
answers `prefers-reduced-motion` through the same predicate the jump
preference does: either voice asking for less motion is enough.
@PathGao
PathGao merged commit aa0bf4c into master Aug 23, 2026
4 checks passed
@PathGao
PathGao deleted the feat/cursor-animation-setting branch August 23, 2026 19:03
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.

Add an option to disable cursor animation

1 participant