ADR-0005 — Canvas 2D kit: functional core, optional facade
Status: Accepted (documents the existing decision)
Context
Canvas 2D is the workhorse medium for artifacts (weaver today; several roadmap candidates). Every canvas piece needs the same plumbing: DPR-correct sizing, resize handling, a delta-clamped rAF loop with cleanup, and basic draw calls.
Problem
Provide shared canvas plumbing that speeds up artifact authoring without becoming a framework that artifacts must fight.
Decision
src/utils/canvas/ exposes a functional core — plain functions over a Canvas2D
struct (createCanvas2D, resizeToViewport, clearCanvas, startLoop,
onWindowResize, draw helpers) — plus an optional chainable Sketch facade over
the same core. Artifacts may also ignore all of it and touch the raw context; the kit
is a convenience, not a contract.
Alternatives considered
- p5.js / processing-style dependency: huge surface, global-mode footguns, ~1 MB; the kit covers the needed 5% in ~180 lines.
- Class-based mini-engine (scene graph, entities): premature; artifacts differ too much (IK spider vs. logic puzzle) for a shared object model.
- Nothing (copy-paste per artifact): where the project started; DPR and loop-cleanup bugs are exactly the kind that copy-paste multiplies.
Tradeoffs
- (+) Small, tree-shakeable, fully typed; the loop’s delta clamping
(
MAX_DELTA = 1/60) prevents tab-switch physics explosions by default. - (+) Functional core is trivially testable and framework-agnostic.
- (−) Two APIs for one capability (core +
Sketch) is a documentation cost;Sketchcurrently has zero adopters — it’s speculative (code-quality delete list: adopt in the next artifact or delete). - (−)
elapsedin the loop is computed fromframeIndex * MAX_DELTA(fixed-step assumption) — drifts from wall-clock time under throttling; fine for art, worth a comment.
Consequences
- The scaffold (artifacts.md R2) stamps canvas-kit boilerplate, making the kit the default authoring path.
- The lifecycle composable (artifacts.md R3) will wrap
startLoopwith visibility/intersection pausing — extend the kit, don’t fork it.
Future evolution
- Decide
Sketch’s fate with the next canvas artifact (adopt or delete; don’t carry). - Open-source extraction is parked in future-ideas.md behind the “two strangers asked” trigger.