Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/shopify/react-native-skia/llms.txt

Use this file to discover all available pages before exploring further.

Paths are the foundation for creating complex shapes in Skia. They can contain lines, curves, and multiple contours.

Creating Paths

Using Skia.Path

import { Skia } from "@shopify/react-native-skia";

const path = Skia.Path.Make();
path.moveTo(10, 10);
path.lineTo(100, 10);
path.lineTo(100, 100);
path.lineTo(10, 100);
path.close();

From SVG String

const path = Skia.Path.MakeFromSVGString(
  "M 10 10 L 100 10 L 100 100 L 10 100 Z"
);

Path Methods

Movement Commands

moveTo
(x: number, y: number) => SkPath
Starts a new contour at the specified point
path.moveTo(50, 50);
lineTo
(x: number, y: number) => SkPath
Draws a straight line to the specified point
path.lineTo(100, 100);
rMoveTo
(dx: number, dy: number) => SkPath
Relative move (offset from current position)
path.rMoveTo(20, 20);
rLineTo
(dx: number, dy: number) => SkPath
Relative line (offset from current position)
path.rLineTo(50, 0);

Curves

quadTo
(x1: number, y1: number, x2: number, y2: number) => SkPath
Draws a quadratic Bezier curve
path.moveTo(0, 100);
path.quadTo(50, 0, 100, 100); // control point, end point
cubicTo
(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number) => SkPath
Draws a cubic Bezier curve
path.moveTo(0, 100);
path.cubicTo(25, 0, 75, 0, 100, 100);
conicTo
(x1: number, y1: number, x2: number, y2: number, w: number) => SkPath
Draws a conic curve with weight
path.conicTo(50, 0, 100, 100, 0.5);

Arcs

arcToOval
(oval: SkRect, startAngle: number, sweepAngle: number, forceMoveTo: boolean) => SkPath
Draws an arc within an oval
const oval = rect(0, 0, 100, 100);
path.arcToOval(oval, 0, 180, false);
arcToRotated
(rx: number, ry: number, xAxisRotate: number, useSmallArc: boolean, isCCW: boolean, x: number, y: number) => SkPath
Draws an SVG-style arc
path.moveTo(10, 50);
path.arcToRotated(40, 40, 0, false, true, 90, 50);

Shapes

addRect
(rect: SkRect, isCCW?: boolean) => SkPath
Adds a rectangle to the path
path.addRect(rect(10, 10, 100, 100));
addRRect
(rrect: SkRRect, isCCW?: boolean) => SkPath
Adds a rounded rectangle
path.addRRect(rrect(rect(10, 10, 100, 100), 10, 10));
addCircle
(x: number, y: number, r: number) => SkPath
Adds a circle
path.addCircle(50, 50, 40);
addOval
(oval: SkRect, isCCW?: boolean, startIndex?: number) => SkPath
Adds an ellipse
path.addOval(rect(0, 0, 100, 50));
addPoly
(points: SkPoint[], close: boolean) => SkPath
Adds a polygon from points
path.addPoly([
  { x: 50, y: 0 },
  { x: 100, y: 50 },
  { x: 50, y: 100 },
  { x: 0, y: 50 },
], true);

Path Operations

close
() => SkPath
Closes the current contour with a line to the start point
path.close();
reset
() => SkPath
Clears the path and releases memory
path.reset();
rewind
() => SkPath
Clears the path but keeps allocated memory
path.rewind(); // Faster for reuse
copy
() => SkPath
Creates a copy of the path
const pathCopy = path.copy();

Transformations

transform
(matrix: InputMatrix) => SkPath
Transforms the path by a matrix
const matrix = Skia.Matrix();
matrix.translate(50, 50);
matrix.rotate(Math.PI / 4);
const transformed = path.transform(matrix);
offset
(dx: number, dy: number) => SkPath
Translates the path
const moved = path.offset(20, 30);

Boolean Operations

op
(path: SkPath, op: PathOp) => boolean
Performs boolean operations on paths
import { PathOp } from "@shopify/react-native-skia";

const result = path1.op(path2, PathOp.Union);
Operations:
  • PathOp.Difference: Subtract path2 from path1
  • PathOp.Intersect: Intersection of both paths
  • PathOp.Union: Combination of both paths
  • PathOp.XOR: Exclusive OR
  • PathOp.ReverseDifference: Subtract path1 from path2
simplify
() => boolean
Simplifies overlapping contours
path.simplify();

Stroking

stroke
(opts?: StrokeOpts) => SkPath | null
Converts path to its stroked equivalent
const stroked = path.stroke({
  width: 5,
  join: StrokeJoin.Round,
  cap: StrokeCap.Round,
});
dash
(on: number, off: number, phase: number) => boolean
Applies dash pattern to path
path.dash(10, 5, 0);

Measurement

getBounds
() => SkRect
Gets the bounding box
const bounds = path.getBounds();
console.log(bounds); // { x, y, width, height }
computeTightBounds
() => SkRect
Gets tight bounds (more accurate but slower)
const tightBounds = path.computeTightBounds();
contains
(x: number, y: number) => boolean
Tests if a point is inside the path
const isInside = path.contains(50, 50);
isEmpty
() => boolean
Checks if path has no verbs
if (path.isEmpty()) {
  console.log("Path is empty");
}

Path Interpolation

interpolate
(end: SkPath, weight: number, output?: SkPath) => SkPath | null
Interpolates between two paths
const morphed = path1.interpolate(path2, 0.5);
isInterpolatable
(path: SkPath) => boolean
Checks if paths can be interpolated
if (path1.isInterpolatable(path2)) {
  const morphed = path1.interpolate(path2, 0.5);
}

Path Trimming

trim
(start: number, end: number, isComplement: boolean) => SkPath | null
Trims path to a segment (0-1)
const segment = path.trim(0.25, 0.75, false);

Fill Types

import { FillType } from "@shopify/react-native-skia";

path.setFillType(FillType.Winding); // Default
path.setFillType(FillType.EvenOdd);
path.setFillType(FillType.InverseWinding);
path.setFillType(FillType.InverseEvenOdd);

Path Component

import { Canvas, Path } from "@shopify/react-native-skia";

const path = Skia.Path.Make();
path.moveTo(50, 50);
path.lineTo(150, 50);
path.lineTo(100, 150);
path.close();

<Canvas style={{ flex: 1 }}>
  <Path path={path} color="blue" />
</Canvas>

Examples

Rounded Path

const path = Skia.Path.Make();
path.moveTo(50, 100);
path.lineTo(150, 100);
path.arcToRotated(25, 25, 0, false, true, 150, 150);
path.lineTo(50, 150);
path.arcToRotated(25, 25, 0, false, true, 50, 100);
path.close();

Star Shape

const star = () => {
  const path = Skia.Path.Make();
  const points = 5;
  const outerRadius = 50;
  const innerRadius = 20;
  
  for (let i = 0; i < points * 2; i++) {
    const angle = (i * Math.PI) / points - Math.PI / 2;
    const radius = i % 2 === 0 ? outerRadius : innerRadius;
    const x = 100 + Math.cos(angle) * radius;
    const y = 100 + Math.sin(angle) * radius;
    
    if (i === 0) {
      path.moveTo(x, y);
    } else {
      path.lineTo(x, y);
    }
  }
  
  path.close();
  return path;
};

Animated Path

import { useSharedValue, withRepeat, withTiming } from "react-native-reanimated";
import { Canvas, Path, Skia } from "@shopify/react-native-skia";

const path1 = Skia.Path.MakeFromSVGString("M 50 50 L 150 50 L 100 150 Z");
const path2 = Skia.Path.MakeFromSVGString("M 50 150 L 150 150 L 100 50 Z");

export default function MorphingPath() {
  const progress = useSharedValue(0);
  
  useEffect(() => {
    progress.value = withRepeat(
      withTiming(1, { duration: 2000 }),
      -1,
      true
    );
  }, []);
  
  return (
    <Canvas style={{ flex: 1 }}>
      <Path
        path={() => path1.interpolate(path2, progress.value)}
        color="purple"
      />
    </Canvas>
  );
}