canvaskit-wasm 0.39 build 2026-04-29

Path

A Path is geometry — a sequence of moves, line segments, quadratic and cubic Bezier curves, and closures. It carries no color, no fill style, no stroke; you hand a Path plus a Paint to canvas.drawPath, and the Paint decides what to do with it.

Paths are the cheapest way to describe complex 2D shapes Skia can render: stars, glyphs, vector-network output, the result of boolean operations between two other paths. A circle drawn with path.addCircle is internally four cubic Bezier segments; the same Path can later be filled, stroked, dashed, hit-tested, transformed, or boolean'd against another path.

Path is a WASM object — call path.delete() when you're done with it.

Building a path manually

moveTo plants a starting point; lineTo, quadTo, and cubicTo extend the current subpath. close connects the current point back to the most recent moveTo. Each method returns the path so you can chain.

const p = new CK.Path(); p.moveTo(80, 200); p.lineTo(340, 200); p.lineTo(210, 60); p.close(); const fill = new CK.Paint(); fill.setColor(CK.Color(70, 120, 200, 1)); fill.setAntiAlias(true); canvas.drawPath(p, fill); surface.flush(); p.delete(); fill.delete();

Curves and the cubic-bezier cubicTo

Cubic Beziers take two control points plus an end. The control points decide how aggressively the curve pulls toward them. Move the cursor — the second control point follows it.

const p = new CK.Path(); const stroke = new CK.Paint(); stroke.setStyle(CK.PaintStyle.Stroke); stroke.setStrokeWidth(3); stroke.setColor(CK.Color(70, 120, 200, 1)); stroke.setAntiAlias(true); loop(() => { p.reset(); p.moveTo(60, 130); p.cubicTo(150, 30, mouse.x || 280, mouse.y || 230, 360, 130); canvas.clear(CK.WHITE); canvas.drawPath(p, stroke); canvas.drawAnchors(p); canvas.drawTangents(p); surface.flush(); });

Convenience constructors

addCircle, addOval, addRect, addRRect, addPoly, addArc build common shapes in one call. addCircle is internally four cubics — Skia's standard quarter-circle approximation.

const p = new CK.Path(); p.addRect(CK.LTRBRect(40, 40, 160, 160)); p.addOval(CK.LTRBRect(180, 40, 300, 160)); p.addCircle(370, 100, 50); const stroke = new CK.Paint(); stroke.setStyle(CK.PaintStyle.Stroke); stroke.setStrokeWidth(2); stroke.setAntiAlias(true); stroke.setColor(CK.Color(70, 120, 200, 1)); canvas.clear(CK.WHITE); canvas.drawPath(p, stroke); surface.flush(); p.delete(); stroke.delete();

A single Path can hold multiple disjoint subpaths. They render as one shape but each add* call starts a new subpath.

Parsing SVG path data

CK.Path.MakeFromSVGString accepts the same d="" string SVG <path> elements use. It returns a fresh Path you must .delete().

const p = CK.Path.MakeFromSVGString( "M 100 60 L 220 60 L 220 200 L 100 200 Z " + "M 250 130 m -50 0 a 50 50 0 1 0 100 0 a 50 50 0 1 0 -100 0 Z" ); const fill = new CK.Paint(); fill.setColor(CK.Color(220, 60, 60, 0.4)); fill.setAntiAlias(true); const edge = new CK.Paint(); edge.setStyle(CK.PaintStyle.Stroke); edge.setStrokeWidth(2); edge.setColor(CK.Color(180, 30, 30, 1)); edge.setAntiAlias(true); canvas.clear(CK.WHITE); canvas.drawPath(p, fill); canvas.drawPath(p, edge); surface.flush(); p.delete(); fill.delete(); edge.delete();

MakeFromSVGString covers everything in the SVG path mini-language: M m L l H h V v C c S s Q q T t A a Z z. Round-trip via path.toSVGString() gives back a deterministic string that may not match the input character-for-character but draws the same shape.

Transforming a path

offset(dx, dy) translates in place. transform(matrix) accepts a 6- or 9-element affine matrix and bakes the transform into the path's points — the Path itself moves; subsequent draws don't re-transform.

const star = new CK.Path(); for (let i = 0; i < 10; i++) { const a = -PI / 2 + i * PI / 5; const r = i % 2 === 0 ? 70 : 30; if (i === 0) star.moveTo(cos(a) * r, sin(a) * r); else star.lineTo(cos(a) * r, sin(a) * r); } star.close(); const drawn = new CK.Path(); const stroke = new CK.Paint(); stroke.setStyle(CK.PaintStyle.Stroke); stroke.setStrokeWidth(2); stroke.setAntiAlias(true); stroke.setColor(CK.Color(60, 160, 90, 1)); loop(() => { drawn.reset(); drawn.addPath(star); const angle = (mouse.x || 200) / 200; const k = cos(angle), s = sin(angle); drawn.transform([k, -s, mouse.x || 200, s, k, mouse.y || 130]); canvas.clear(CK.WHITE); canvas.drawPath(drawn, stroke); surface.flush(); });

Inspecting a path

countPoints, getPoint(i), countVerbs, getVerb(i) walk the path point-by-point. toCmds() returns a flat Float32Array of [verb, …coords, verb, …coords] (verbs: 0=move, 1=line, 2=quad, 3=conic, 4=cubic, 5=close). The runtime helpers canvas.drawAnchors(path) and canvas.drawTangents(path) use exactly this for the dot/handle visualizations.

Common methods

Hover any non-primitive type to see its description. Most builders return this so calls chain.

MemberArgsReturnsNotes
addCirclecx, cy, r: numberthisAppend a circle as four cubic Beziers.
addOvalrect: RectthisAppend an oval inscribed in rect.
addPathother: Path, matrix?: MatrixthisCopy other's geometry into this path, optionally transformed.
addPolypoints: Float32Array | number[], close: booleanthisAppend a polyline from a flat [x0, y0, x1, y1, …] array.
addRectrect: RectthisAppend an axis-aligned rectangle.
addRRectrrect: RRectthisAppend a rounded rectangle. Per-corner radii via RRect.
arcToTangentx1, y1, x2, y2, r: numberthisArc that tangents the lines from current → (x1, y1)(x2, y2).
closethisConnect back to the latest moveTo.
computeTightBoundsRectExact bounds (slower, samples the curves).
containsx, y: numberbooleanHit-test using the current fill rule.
copyPathIndependent copy. The copy must be .delete()'d separately.
countPointsnumberNumber of anchor + control points.
countVerbsnumberNumber of verbs (move / line / quad / cubic / close).
cubicToc1x, c1y, c2x, c2y, x, y: numberthisAppend a cubic Bezier with two controls and end.
deletevoidFree the WASM memory. Required.
getBoundsRectLoose bounds (cheap, ignores curve control points).
getPointi: numberPointRead a single point by index.
getVerbi: numbernumberRead a single verb by index.
lineTox: number, y: numberthisAppend a line segment to (x, y).
moveTox: number, y: numberthisStart a new subpath at (x, y).
offsetdx, dy: numberthisTranslate the path in place.
quadTocx, cy, x, y: numberthisAppend a quadratic Bezier with control (cx, cy), end (x, y).
resetthisEmpty the path so it can be reused. Cheaper than new CK.Path().
toCmdsFloat32ArrayFlat array of all verbs + coords.
toSVGStringstringSerialize as SVG d attribute.
transformmatrix: MatrixthisApply a 6- or 9-element affine matrix in place.

Static factories

FactoryArgsReturnsNotes
CK.Path.MakeFromCmdscmds: Float32ArrayPathRound-trip from toCmds() output.
CK.Path.MakeFromOpa: Path, b: Path, op: PathOpPath | nullBoolean op between two paths.
CK.Path.MakeFromPathInterpolationstart: Path, end: Path, t: numberPathMorph between two compatible paths.
CK.Path.MakeFromSVGStringd: stringPath | nullParse an SVG d attribute.
CK.Path.MakeFromVerbsPointsWeightsverbs: Uint8Array, points: Float32Array, weights?: Float32ArrayPathDirect construction from typed arrays.

See also