canvaskit-wasm 0.39 build 2026-04-29

saveLayer vs clip

Two different mechanisms answer questions that look similar:

  • clipRect / clipRRect / clipPathmasks the destination. Subsequent draws are intersected with the clip region. Cheap. The clip stacks with save / restore.
  • saveLayercreates an offscreen layer. Subsequent draws go into a fresh buffer. When restore() runs, that buffer composites back into the parent layer through the layer's paint (which can carry blend modes, color filters, image filters). Expensive — Skia allocates an offscreen GPU texture.

Picking the wrong one is one of the most common CanvasKit performance traps.

Use a clip when …

You want to bound where future draws land. The classic "rounded card with content inside" pattern:

const card = CK.RRectXY(CK.LTRBRect(60, 30, 360, 220), 18, 18); const fill = new CK.Paint(); fill.setColor(CK.Color(220, 60, 60, 1)); const stripe = new CK.Paint(); stripe.setColor(CK.Color(40, 90, 180, 1)); loop(() => { canvas.clear(CK.WHITE); canvas.save(); canvas.clipRRect(card, CK.ClipOp.Intersect, true); canvas.drawRect(CK.LTRBRect(0, 0, 420, 256), fill); for (let i = 0; i < 10; i++) { canvas.drawRect(CK.LTRBRect(40 + i * 40, 0, 60 + i * 40, 256), stripe); } canvas.restore(); surface.flush(); });

The stripes draw straight across, but the clip masks them to the card's rounded shape. Draws outside the rounded rect simply don't land. No offscreen buffer.

Use saveLayer when …

You want to apply an effect or blend to a group of draws, treated as one composite. Or you want a backdrop filter (frosted glass).

Group blend mode

Error: Line 1: Unexpected identifier

The two circles are drawn into an offscreen layer. When restore() runs, the composite (red ∪ blue) gets multiplied against the chess background — not each circle individually. Without saveLayer, the second circle would multiply against the first circle instead of against the background.

Backdrop blur (frosted glass)

Error: Line 1: Unexpected identifier

The saveLayer(null, null, blur, 0) followed by an immediate restore does no new drawing — but the backdrop filter samples the underlying chess pattern through the blur as the layer initializes. The clip first bounds the region.

The performance picture

clipRect etc. — pure scissor test. Free.

saveLayer — Skia must allocate an offscreen texture the size of the bounds (or the canvas if bounds = null), redirect rasterization there, then composite the texture back. On large canvases this is a significant cost. Use it when the effect actually requires it; reach for clip first if the goal is just "bound the area".

When in doubt

  • "I want shapes I'm about to draw to be masked into a region" → clip.
  • "I want a single blend / opacity / filter to apply to a group of draws as one composite" → saveLayer.
  • "I want what's behind to be blurred / transformed / colored through a shape" → saveLayer with backdrop.

See also