Skip to content

Class: PencilSurface

Defined in: surface.ts:90

Constructors

Constructor

new PencilSurface(opts): PencilSurface

Defined in: surface.ts:124

Parameters

opts

PencilSurfaceOptions

Returns

PencilSurface

Properties

canvas

readonly canvas: HTMLCanvasElement

Defined in: surface.ts:91

Methods

clear()

clear(auto?): void

Defined in: surface.ts:295

Parameters

auto?

boolean = false

Returns

void


clearAnimated()

clearAnimated(durationSec?): void

Defined in: surface.ts:369

Clear, but let the ink go the way vanishing ink goes: every stroke jumps to the charge-and-pop tail of the fade curve — it thickens, heats, and pops, over durationSec — and then the surface is really cleared. The same curve a fading stroke rides; an animated clear is just all of them riding it at once.

This is also D4's retire mechanism: an overlay whose viewport scrolled or reflowed calls this, and the disappearance reads as intentional rather than as a glitch. Strokes already flattened past the horizon have no dabs left to warp, so settled alpha-fades as a layer on the same clock — an honest degradation, and one the overlay never sees (with fade active nothing ever reaches settled).

Parameters

durationSec?

number = 0.5

Returns

void


dispose()

dispose(): void

Defined in: surface.ts:434

Returns

void


hasInk()

hasInk(): boolean

Defined in: surface.ts:194

Returns

boolean


ink()

ink(): InkState

Defined in: surface.ts:250

The drawing, as data: committed strokes (including those flattened past the undo horizon — still part of the picture) plus the strokes in flight with every point captured so far. Fresh arrays each call, so reference equality means "actually changed"; committed point arrays are shared (they never mutate), live ones are copied (they do).

Returns

InkState


inkBounds()

inkBounds(): Rect | undefined

Defined in: surface.ts:203

Returns

Rect | undefined


params()

params(): PencilParams

Defined in: surface.ts:275

The instrument as currently configured — so a downstream consumer can run the widget's own pipeline (planStroke(stroke.points, surface.params())) or substitute parameters of its own. The math itself is exported from the package root: planStroke, densify, detectCusps, PointFilter.

Returns

PencilParams


popCompleted()

popCompleted(): void

Defined in: surface.ts:327

Send every COMPLETED stroke into the TAIL of the vanishing curve — the charge-and-pop — so previous marks animate OUT rather than snapping off, while leaving the stroke still under the pen untouched.

This is the "one mark at a time" primitive. PencilSurfaceOptions.onStrokeStart fires from inside beginStroke, after the new stroke has joined the live set, so — like a plain clearAnimated — touching live here would wipe the mark just begun; this re-times only the completed strokes. Each is advanced to the hold→pop boundary of the AMBIENT fade window (fadeSec) and left to pop on the normal per-frame fade, so starting a new stroke triggers the previous one's dissolve exactly as if its clock had run out. A stroke already in its tail is not re-charged (min keeps the earlier clock). With no fade window (fadeSec 0) there is nothing to animate against, so the completed strokes are dropped at once.

Returns

void


remoteBegin()

remoteBegin(id, init): void

Defined in: surface.ts:404

Parameters

id

string

init
params

PencilParams

point

PenSample

tool

Tool

Returns

void


remoteCancel()

remoteCancel(id): void

Defined in: surface.ts:428

Parameters

id

string

Returns

void


remoteEnd()

remoteEnd(id, point?): void

Defined in: surface.ts:417

Parameters

id

string

point?

PenSample

Returns

void


remotePoint()

remotePoint(id, point): void

Defined in: surface.ts:408

Parameters

id

string

point

PenSample

Returns

void


repaint()

repaint(): void

Defined in: surface.ts:228

Force the next frame to redraw, even though nothing changed.

Exists for one consumer: a captureStream() of this canvas. The stream emits a frame only when the canvas REPAINTS, and this surface deliberately paints nothing when still ("free battery on an iPad") — so a viewer joining a quiet host would stare at a stream that has never produced a frame. The host keeps the stream warm by calling this on a slow tick while anyone is watching; the cost is a few drawImage calls per tick.

Returns

void


restartFade()

restartFade(): void

Defined in: surface.ts:394

Restart every stroke's fade clock. Turning vanishing ink ON is why this exists: bornAt is pen-up time, so ink that sat on a permanent canvas for minutes is already older than any fade window, and flipping the switch would blink the whole drawing out in a single frame.

Returns

void


setActive()

setActive(on): void

Defined in: surface.ts:177

Parameters

on

boolean

Returns

void


size()

size(): object

Defined in: surface.ts:190

Returns

object

height

height: number

width

width: number


strokeCount()

strokeCount(): number

Defined in: surface.ts:199

Completed strokes still individually addressable (i.e. still undoable).

Returns

number


subscribe()

subscribe(listener): () => void

Defined in: surface.ts:238

Watch the drawing change. "strokes" fires at human rate (commit, undo, clear, fade-out); "live" fires per pointer batch — 60–120 Hz while the pen moves. The events carry nothing: read ink when you care, so a throttled subscriber pays for snapshots at ITS rate, not the pen's.

Parameters

listener

(event) => void

Returns

() => void


translate()

translate(dx, dy): void

Defined in: surface.ts:736

Translate every stroke by (dx, dy) CSS px — the document-anchored overlay's REBASE (owner, 2026-07-17). Stroke tiles are bounds-local, so ink translated past the canvas edge keeps its points AND its pixels and re-bakes back into view on a later translate: the overlay's window slides over an unbounded drawing, viewport-sized memory for the visible raster. settled (raster past the points horizon) cannot move and is dropped — rescale's same honest degradation; fade-active surfaces never grow one. Fade clocks are PRESERVED (a rebase is bookkeeping, not new ink).

Parameters

dx

number

dy

number

Returns

void


undo()

undo(): boolean

Defined in: surface.ts:285

Undo the most recent retained stroke. Returns false when there is nothing left to undo — because the horizon has been crossed and the stroke is now part of settled, which is exactly what flattening MEANS. Undo depth and the retention horizon are the same number by construction, not by coincidence.

Returns

boolean