# RecordingContext2D

Import it from `@grafloria/renderer`.

A `Canvas2DLike` that records what was drawn instead of rasterising it.

The recording is the assertion surface for the canvas backend's unit tests:
"the VNode tree said `<rect fill=#fff stroke=#333 stroke-width=2>` at
(100,100)" ⇒ "the context received a fill with fillStyle #fff and a stroke
with lineWidth 2 over exactly that path, under exactly that transform".

It faithfully models the parts of the 2D state machine the painter depends on
— the save/restore stack, the current transform, the current path — so a bug
in the painter's state handling (a missing `restore`, a transform applied
twice) shows up in the recording rather than hiding behind a mock.

```ts
class RecordingContext2D implements Canvas2DLike
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `calls` | `DrawCall[]` | `[]` |  |
| `charWidthRatio` |  | `0.6` | Width of one character, used by `measureText`. Matches the SVG-side estimate. |

**Methods**

- `get fillStyle(): unknown`
- `set fillStyle(v: unknown)`
- `get strokeStyle(): unknown`
- `set strokeStyle(v: unknown)`
- `get lineWidth(): number`
- `set lineWidth(v: number)`
- `get lineJoin(): CanvasLineJoin`
- `set lineJoin(v: CanvasLineJoin)`
- `get lineCap(): CanvasLineCap`
- `set lineCap(v: CanvasLineCap)`
- `get globalAlpha(): number`
- `set globalAlpha(v: number)`
- `get font(): string`
- `set font(v: string)`
- `get textAlign(): CanvasTextAlign`
- `set textAlign(v: CanvasTextAlign)`
- `get textBaseline(): CanvasTextBaseline`
- `set textBaseline(v: CanvasTextBaseline)`
- `get filter(): string`
- `set filter(v: string)`
- `save(): void`
- `restore(): void`
- `setTransform(a: number, b: number, c: number, d: number, e: number, f: number): void`
- `beginPath(): void`
- `moveTo(x: number, y: number): void`
- `lineTo(x: number, y: number): void`
- `bezierCurveTo(x1: number, y1: number, x2: number, y2: number, x: number, y: number): void`
- `quadraticCurveTo(x1: number, y1: number, x: number, y: number): void`
- `closePath(): void`
- `fill(): void`
- `stroke(): void`
- `clip(): void`
- `clearRect(x: number, y: number, w: number, h: number): void`
- `fillRect(x: number, y: number, w: number, h: number): void`
- `setLineDash(segments: number[]): void`
- `fillText(text: string, x: number, y: number): void`
- `measureText(text: string): { width: number }` — The same average-glyph estimate the SVG text-block engine uses
(`text.length * fontSize * 0.6`), so headless measurement agrees with the
line-breaking the VNode producer already did. A real 2D context measures
glyphs properly; this is only the headless stand-in.
- `createLinearGradient(x0: number, y0: number, x1: number, y1: number): unknown`
- `createRadialGradient( x0: number, y0: number, r0: number, x1: number, y1: number, r1: number ): unknown`
- `reset(): void` — Drop the recording (keeps the current state — mirrors a fresh frame).
- `paintCalls(): DrawCall[]` — Every paint call (ignores bookkeeping ops) — the usual assertion target.
