Canvas
A Canvas records draw operations against a backing surface. You don't create one directly — surface.getCanvas() hands you the canvas tied to that surface, and every draw* you call paints into the surface's pixels. Calling surface.flush() pushes the recorded operations to the GPU (or onto a 2D context for software-backed surfaces).
Canvas is not a WASM object you delete(); its lifetime is tied to its parent Surface. When the surface goes away, the canvas does too.
The state model is a stack: save() pushes the current transform/clip/layer state, restore() pops it. saveLayer() additionally pushes an offscreen buffer that gets composited back when popped — that's how blur backdrops, blend-mode-scoped draws, and opacity groups work.
A first draw
The simplest possible canvas program: clear, set up a paint, draw a shape, flush.
const paint = new CK.Paint();
paint.setColor(CK.Color(40, 90, 180, 1));
paint.setAntiAlias(true);
canvas.clear(CK.WHITE);
canvas.drawCircle(210, 128, 80, paint);
surface.flush();
paint.delete();
Save / restore
save() pushes the current transform + clip + layer state. restore() pops it. They nest. Use them whenever a transform or clip should affect a region of your draws and not leak outward.
const paint = new CK.Paint();
paint.setColor(CK.Color(40, 90, 180, 1));
paint.setAntiAlias(true);
canvas.clear(CK.WHITE);
canvas.drawCircle(80, 128, 40, paint);
canvas.save();
canvas.translate(180, 0);
canvas.rotate(15, 0, 128);
canvas.drawCircle(80, 128, 40, paint);
canvas.restore();
canvas.drawCircle(340, 128, 40, paint);
surface.flush();
paint.delete();
The middle circle inherits the rotated frame; the outer two stay axis-aligned because restore() brought the original transform back.
saveLayer with a backdrop filter
saveLayer(paint?, bounds?, backdrop?, flags?) pushes an offscreen buffer. When restore() runs, the buffer composites back into the parent layer through the layer's paint (which can carry blend modes, color filters, image filters). The optional backdrop filter samples the parent layer's pixels through that filter as the offscreen buffer is initialized — that's how frosted-glass blur works.
Error: Line 1: Unexpected identifier
Clipping
clipRect, clipRRect, clipPath intersect (or replace) the current clip region. Anything you draw afterward is masked to that region until the next restore().
const paint = new CK.Paint();
paint.setColor(CK.Color(220, 60, 60, 1));
paint.setAntiAlias(true);
const rrect = CK.RRectXY(CK.LTRBRect(120, 50, 300, 200), 30, 30);
loop(() => {
canvas.clear(CK.WHITE);
canvas.save();
canvas.clipRRect(rrect, CK.ClipOp.Intersect, true);
for (let i = 0; i < 12; i++) {
canvas.save();
canvas.translate(mouse.x || 210, mouse.y || 130);
canvas.rotate(i * 30, 0, 0);
canvas.drawRect(CK.LTRBRect(-200, -6, 200, 6), paint);
canvas.restore();
}
canvas.restore();
surface.flush();
});
Transformations
translate, scale, rotate, skew, concat left-multiply onto the current matrix. Reading: each call is "apply this transform to whatever was there before". The matrix is Matrix3x3 in 2D.
const paint = new CK.Paint();
paint.setStyle(CK.PaintStyle.Stroke);
paint.setStrokeWidth(2);
paint.setColor(CK.Color(40, 90, 180, 1));
paint.setAntiAlias(true);
const tile = CK.LTRBRect(-30, -30, 30, 30);
loop(() => {
canvas.clear(CK.WHITE);
for (let i = 0; i < 8; i++) {
canvas.save();
canvas.translate(60 + i * 45, 130);
canvas.scale(1 - i * 0.06, 1 - i * 0.06);
canvas.rotate(i * 12 + (mouse.x || 0) * 0.2, 0, 0);
canvas.drawRect(tile, paint);
canvas.restore();
}
surface.flush();
});
Common methods
| Member | Args | Returns | Notes |
|---|---|---|---|
clear | color: Color | void | Fill the entire canvas with a single color. |
clipPath | path: Path, op: ClipOp, antiAlias: boolean | void | Intersect or replace the clip region with a path. |
clipRect | rect: Rect, op: ClipOp, antiAlias: boolean | void | Clip to a rectangle. |
clipRRect | rrect: RRect, op: ClipOp, antiAlias: boolean | void | Clip to a rounded rectangle. |
concat | matrix: Matrix | void | Left-multiply the given matrix onto the current transform. |
drawArc | oval: Rect, startAngle, sweepAngle: number, useCenter: boolean, paint: Paint | void | Draw an arc bounded by oval. |
drawAtlas | atlas: Image, srcRects, dstXforms, colors?, blendMode?: BlendMode, paint?: Paint | void | Batch-draw sprites from a single atlas image. |
drawCircle | cx, cy, r: number, paint: Paint | void | Fill or stroke a circle. |
drawColor | color: Color, blendMode?: BlendMode | void | Flood-fill the canvas with a color, blended. |
drawImage | img: Image, x, y: number, paint?: Paint | void | Draw an image at (x, y) at its native size. |
drawImageRect | img: Image, src: Rect, dst: Rect, paint: Paint | null | void | Draw a sub-rect of an image scaled into a destination rect. Used for sprite atlases. |
drawLine | x0, y0, x1, y1: number, paint: Paint | void | Stroke a line segment. |
drawOval | rect: Rect, paint: Paint | void | Fill or stroke an oval inscribed in rect. |
drawDRRect | outer: RRect, inner: RRect, paint: Paint | void | Fill the area between outer and inner — donut shape with rounded corners. |
drawPaint | paint: Paint | void | Fill the entire canvas with the paint (color, shader, image filter). |
drawPatch | cubics: Float32Array | number[24], colors?: Color[4] | null, textureCoords?: Float32Array | number[8] | null, blendMode: BlendMode, paint: Paint | void | Coons-patch — a 4-side bicubic mesh. cubics is 12 control points (24 floats). Per-corner colors blend bilinearly across the patch. |
drawPath | path: Path, paint: Paint | void | Fill or stroke a path. |
drawPicture | picture: Picture | void | Replay a recorded picture into this canvas. |
drawPoints | mode: PointMode, points: Float32Array | number[], paint: Paint | void | Draw a flat [x0, y0, x1, y1, …] array as points / lines / a polyline depending on mode. Stroke cap controls the dot shape. |
drawRect | rect: Rect, paint: Paint | void | Fill or stroke a rectangle. |
drawRRect | rrect: RRect, paint: Paint | void | Fill or stroke a rounded rectangle. |
drawShadow | path: Path, zPlaneParams, lightPos, lightRadius: number, ambientColor, spotColor: Color, flags: number | void | Draw a soft shadow under path as if lit from lightPos. |
drawVertices | vertices: Vertices, blendMode: BlendMode, paint: Paint | void | Draw a triangle mesh with optional per-vertex colors and texture coords. |
getDeviceClipBounds | — | IRect | Bounds of the current clip in device pixels. |
getLocalToDevice | — | Matrix | The 4x4 matrix from local space to device space. |
getTotalMatrix | — | Matrix | The current 3x3 transform matrix. |
readPixels | x, y: number, info: ImageInfo, dst?: MallocObj, bytesPerRow?: number | Uint8Array | Float32Array | null | Read pixels from the canvas back to JS. |
restore | — | void | Pop one save / saveLayer level. |
rotate | degrees, cx, cy: number | void | Rotate the current transform around (cx, cy). |
save | — | number | Push current transform + clip. Returns the save count. |
saveLayer | paint?: Paint, bounds?: Rect, backdrop?: ImageFilter, flags?: number | number | Push an offscreen layer. Composited via paint on restore. backdrop filters the underlying layer. |
scale | sx, sy: number | void | Scale the current transform. |
skew | sx, sy: number | void | Skew the current transform. |
translate | dx, dy: number | void | Translate the current transform. |
writePixels | pixels: Uint8Array | number[], srcWidth, srcHeight, x, y: number | boolean | Blit a pixel buffer onto the canvas at (x, y). |
Runtime extensions (this site only)
Canvas instances on the doc-page bundle carry two extra helpers, defined client-side:
| Member | Args | Returns | Notes |
|---|---|---|---|
drawAnchors | path: Path | void | Draws a small dot at every move/line/quad/cubic endpoint. |
drawTangents | path: Path | void | Draws each cubic's two tangent handles in red, with dots on anchors and controls. |
These are not part of CanvasKit — they're implemented in the doc runtime so examples can visualize the curves without each demo redefining the helper.
See also
Surface— owns the canvas;flush()pushes pixels.Paint— color, style, blend, filters consumed bydrawXcalls.Path— geometry passed todrawPath/clipPath.BlendMode— composite ops fordrawColor/ viaPaint.setBlendMode.ClipOp— Intersect or Replace.- Memory management — Canvas is not
deleted directly; the surface owns it.