vercel-labs / vercel-labs/native

scroll: one wheel notch flings for about forty seconds on Linux

Open
#424 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Zig
Stars
7.7k
Forks
314
Avg merge
5h
Merged PRs (30d)
13

Description

One mouse-wheel notch starts a fling that runs for roughly forty seconds. It reads as a view that cannot be stopped, only reversed, because reversing is the only thing that cancels the velocity.

All references are v0.10.1, checked against main as well.

The arithmetic

ScrollPhysics (src/primitives/canvas/tokens.zig:774) turns a wheel delta into a velocity and then decays it:

wheel_velocity_scale: f32 = 60,
deceleration_per_second: f32 = 0.86,
stop_velocity: f32 = 5,

Velocity retains 86% per second, so the time for one notch to fall under the stop threshold is ln(stop / v0) / ln(0.86).

On Linux that is much worse than it looks, because the GTK host multiplies a wheel notch by 40 before the physics ever sees it (src/platform/linux/gtk_host.c:1503-1508, converting GDK_SCROLL_UNIT_WHEEL to points):

v0 = 1 notch x 40 x 60  = 2400 points/second
stop at 5               = ln(5/2400) / ln(0.86) ~ 41 seconds

Two notches is not two flings, it is one faster one, so ordinary scrolling makes it worse rather than better.

Why it is a wheel problem specifically

These defaults are right for a trackpad, where deltas arrive small and continuous and the decay reads as momentum. A wheel notch is a discrete displacement, not a throw, and it is the same code path with a 40x multiplier in front of it.

Reproduction, headless, no compositor

The automation channel drives the canvas directly, so this needs no window manager and no real input device:

  1. Build a canvas app with -Dautomation=true, run it under Xvfb.
  2. native automate widget-wheel <view> <scroll-region-id> 5 (one command, once).
  3. Snapshot three times over the following fifteen seconds and compare widget bounds.

I measured a feed row moving 400.6 -> 57.6 -> -412.3 -> -885.4 across snapshots at +3s, +9s and +17s, from that single command with no further input. Deceleration is visible (114, then 78, then 59 points/second) which is what confirms it is the decay curve rather than repeated events.

Suggested fix

Treat a wheel notch as a displacement rather than a fling. The unit is already known at the source: gtk_event_controller_scroll_get_unit returns GDK_SCROLL_UNIT_WHEEL for a notch and GDK_SCROLL_UNIT_SURFACE for a trackpad, and the host already branches on exactly that to apply the 40x. Carrying that distinction through to the physics, so a wheel scrolls by its delta and only a surface delta contributes velocity, fixes it without changing how a trackpad feels.

Failing that, the default decay is too slow to be a fling. At 0.86 per second a throw is still moving perceptibly half a minute later. Something nearer 0.05 per second stops in about a second, which is what a fling usually means.

And the 40x and the 60x compound. Whatever else changes, wheel_velocity_scale being applied on top of the host's wheel-to-points conversion is worth a look: one of the two is enough.

The tokens are overridable, so I have set wheel_velocity_scale and deceleration_per_second in my own app to keep it usable, scoped to non-macOS. That is a workaround for one app rather than a fix, since the defaults are what every canvas app gets.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ScrollPhysics in src/primitives/canvas/tokens.zig:774 and the wheel conversion in src/platform/linux/gtk_host.c:1503-1508. Reproduce under Xvfb with -Dautomation=true using native automate widget-wheel, then compare snapshots over fifteen seconds. Done means a single Linux wheel notch no longer produces a prolonged fling while trackpad scrolling retains its momentum behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
linux, zig
Domain
desktop, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.