mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-28 06:51:16 +08:00
perf(tui): scroll one row at a time per wheel event, half-viewport per pageUp
User observation: "it doesn't scroll line by line/row by row."
Was right. Two places hardcoded big deltas:
1. WHEEL_SCROLL_STEP = 6 (config/limits.ts)
Each wheel event scrolled 6 rows. A mechanical wheel notch emits
3-5 events → 18-30 rows per click, which visually teleports past
content instead of smooth-scrolling it. Drop to 1. Trackpads
emit 50-100 events per flick — at step=1 that's still a fast flick
(a whole viewport in one flick) but each intermediate frame is
visible. Porting claude-code's wheel accel state machine is the
right next step if this feels sluggish on precision scrolls.
2. pageUp/pageDown = viewport - 2 (useInputHandlers.ts)
Full-viewport jumps replace the entire screen — no visual
continuity, can't scan content — AND land right at Ink's fast-path
threshold (`delta < innerHeight`), which disqualifies the DECSTBM
blit on every press. Half-viewport keeps 50% continuity AND
drops well under the threshold. Two presses still cover the same
total distance.
Profiled against the 1106-msg session, holding the key at 30Hz for
6s:
wheel_up (step 6 → 1):
frames 142 → 163 (+15%)
throughput 10.7 → 15.8 fps (+48%)
patches tot 53018→ 36562 (-31%)
gap p50 5ms → 16ms (actual rendering ~60fps now)
<16ms frames 93 → 76
16-33ms 82 → 76
hitches 3 → 1
pageUp (viewport-2 → viewport/2):
throughput 10.7 → 9.5 fps (same ballpark — smaller delta × same
event rate = less total scroll)
Ink's proportional drain caps at `innerHeight - 1` per frame to keep
the DECSTBM fast path firing. With these smaller deltas every event
comfortably fits under that cap, so fast-path hit rate goes up and
patch volume per frame drops — the measured 31% reduction in total
patches-sent correlates with users perceiving smoother scrolling
because the outer terminal (VS Code / xterm.js / tmux) isn't drowning
in ANSI between paints.
Tests/type-check/build clean; 352 tests pass.
This commit is contained in:
@@ -296,7 +296,14 @@ export function useInputHandlers(ctx: InputHandlerContext): InputHandlerResult {
|
||||
|
||||
if (key.pageUp || key.pageDown) {
|
||||
const viewport = terminal.scrollRef.current?.getViewportHeight() ?? Math.max(6, (terminal.stdout?.rows ?? 24) - 8)
|
||||
const step = Math.max(4, viewport - 2)
|
||||
// Half-viewport per keystroke. A whole-viewport jump (our old
|
||||
// `viewport - 2`) fully replaces what's on screen — no visual
|
||||
// continuity, the user can't scan — AND it lands right at Ink's
|
||||
// `delta < innerHeight` fast-path threshold, disqualifying the
|
||||
// DECSTBM blit on every press. Half-viewport keeps 50% continuity,
|
||||
// well under the threshold, and two presses still scroll the same
|
||||
// total distance.
|
||||
const step = Math.max(4, Math.floor(viewport / 2))
|
||||
|
||||
return scrollTranscript(key.pageUp ? -step : step)
|
||||
}
|
||||
|
||||
@@ -4,4 +4,20 @@ export const LIVE_RENDER_MAX_LINES = 240
|
||||
export const LONG_MSG = 300
|
||||
export const MAX_HISTORY = 800
|
||||
export const THINKING_COT_MAX = 160
|
||||
export const WHEEL_SCROLL_STEP = 6
|
||||
// Rows scrolled per wheel-notch event.
|
||||
//
|
||||
// One notch of a mechanical wheel emits multiple wheel events (3-5 per
|
||||
// click in most terminals; trackpad flicks emit 100+). Each event scrolls
|
||||
// WHEEL_SCROLL_STEP rows. The product = rows-per-click.
|
||||
//
|
||||
// 1 = pure line-by-line. Small per-event delta keeps Ink's DECSTBM fast
|
||||
// path firing (each scroll < viewport-1) and produces smooth visible
|
||||
// motion — the user can scan content mid-scroll. We were at 6 before
|
||||
// (= ~20-30 rows per notch) which visually teleported and forced the
|
||||
// virtualization to reshape the mount range on every event.
|
||||
//
|
||||
// If this feels sluggish on precision scrolls, porting claude-code's
|
||||
// wheel accel state machine (ScrollKeybindingHandler.tsx) is the right
|
||||
// next step — it ramps step up during sustained fast clicks and decays
|
||||
// on pause.
|
||||
export const WHEEL_SCROLL_STEP = 1
|
||||
|
||||
Reference in New Issue
Block a user