Skip to content

📝 Scroll specification (RFC)#25

Open
cowboyd wants to merge 1 commit intomainfrom
scroll
Open

📝 Scroll specification (RFC)#25
cowboyd wants to merge 1 commit intomainfrom
scroll

Conversation

@cowboyd
Copy link
Copy Markdown
Member

@cowboyd cowboyd commented Apr 20, 2026

Motivation

Clayterm's renderer spec lists scroll containers as a deferred area, but the underlying layout engine (Clay) already supports clipping, child offsets, and scroll hit testing. Before fully implementing scroll support, we need agreement on the API surface.

View Rendered Spec

specs/scroll-spec.md

Approach

The clip property on open() changes from { horizontal?, vertical? } to { x?: number; y?: number }, where each axis is a numeric offset the caller provides each frame. The caller always owns the scroll position — there is no renderer-managed scroll state.

Wheel scrolling works through a delta reporting mechanism on RenderInfo. When a WheelEvent is passed via the new RenderOptions.event field, the renderer performs hit testing to find the targeted scroll container and reports the resulting delta on ElementInfo.scrollDelta. The caller reads the delta and applies it to their own position:

let result = term.render(ops, { event });
let info = result.info.get("viewport");
if (info) {
  scrollY += info.scrollDelta.y;
}

scrollDelta is always defined on ElementInfo{ x: 0, y: 0 } when no wheel event targeted the element — so the caller can unconditionally read it without null checks.

RenderOptions.event accepts a single InputEvent per render call. The renderer extracts pointer state from mouse events and scroll deltas from wheel events, deprecating the manual pointer: { x, y, down } option. When multiple events are available from a single input.scan() call, the caller renders once per event — the diff engine ensures unchanged frames emit zero bytes.

Drag scrolling and momentum are out of scope but not precluded — they would produce additional deltas through the same scrollDelta mechanism.

TODOs and Open Questions

Sign convention for manual offsets (scroll spec Section 10.1): Should clip: { y: 20 } mean "scroll to position 20" (positive, matching browser scrollTop) or should the caller pass clip: { y: -20 } as a raw offset matching Clay's childOffset? The spec lays out pros and cons for both — would love community input.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 20, 2026

Open in StackBlitz

npm i https://pkg.pr.new/clayterm@25

commit: ae6bfcf

@cowboyd cowboyd force-pushed the scroll branch 7 times, most recently from b2c1856 to 2d44ee2 Compare April 21, 2026 18:23
@cowboyd cowboyd requested review from rauhryan and taras April 21, 2026 18:25
@cowboyd cowboyd force-pushed the scroll branch 4 times, most recently from 4802219 to e030433 Compare April 21, 2026 20:59
Introduces specs/scroll-spec.md (v0.2) with caller-owned scroll model.
Clip API changes from { horizontal, vertical } to { x?, y? } with
numeric offsets. Adds scrollDelta on ElementInfo for wheel delta
reporting. Adds RenderOptions.event for input event integration.
Includes scroll demo with ~10k lines of lorem markdown.
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.

1 participant