Skip to main content
Technical preview

Redraw is currently in technical preview, available to start-react-native.dev subscribers. API is unstable.

Stroke Width Presets

Three ready-made width functions for the most common animated stroke patterns. Pass any of them to brush.addStroke(color, widthPreset):

import { SingleStrokeBrush, TaperedTip } from "redraw";

const stroke = new TaperedTip({ baseWidth: 25, headRatio: 2, progress: 0 });
const brush = new SingleStrokeBrush();
brush.addStroke(color, stroke);

// Animate every frame:
stroke.props.progress = animation(ctx, { duration: 12, boomerang: true });

The presets are RenderFunction subclasses, built from hand-written WGSL, no unplugin-typegpu required. They live in packages/redraw/src/nodes/brushes/StrokeWidthPresets.ts.

TaperedTip

A fat leading "head" that tapers behind itself, retracting to the base width as progress reaches 1. Pairs naturally with path.segment(0, progress) for a stylus-like draw-on stroke.

new TaperedTip({
baseWidth: 25, // resting stroke width (px)
headRatio: 2, // head is 2× the base when fully extended
taperStart: 0.5, // taper begins halfway along the path
progress: 1, // 0..1; 0 = no head, 1 = head retracted
});

Props (default in parens):

PropDefaultEffect
baseWidth25Width when no head is present.
headRatio2Multiplier for the head width.
taperStart0.5Fraction of ctx.t where the taper begins.
progress1Drives the head: 0 = full head, 1 = retracted.
TaperedTip animated alongside path.segment(0, progress)Open in editor →

CalligraphyWidth

Width modulates with the angle between the path tangent and a fixed pen orientation. Mimics a flat nib: thick on the broadside, thin along the pen's axis.

new CalligraphyWidth({
minWidth: 5,
maxWidth: 30,
penAngle: 0.7, // radians
});

Props:

PropDefaultEffect
minWidth5Width when path runs along the pen axis.
maxWidth30Width when path runs perpendicular to the pen.
penAngle0.7Pen orientation in radians. Animate for variation.
CalligraphyWidth with an oscillating pen angleOpen in editor →

PulseWidth

Single-frequency sine modulation along the path. Animate phase to make it travel; raise frequency for tighter ripples.

new PulseWidth({
baseWidth: 25,
amplitude: 6,
frequency: 6,
phase: 0, // animate this each frame: ctx.time * speed
});

Props:

PropDefaultEffect
baseWidth25Resting width.
amplitude6Peak deviation above and below baseWidth.
frequency6Cycles across the path's arc length.
phase0Phase offset; animate to make ripples travel.
const pulse = new PulseWidth({});
brush.addStroke(color, pulse);

// every frame:
pulse.props.phase = ctx.time * 4;

The renderer holds a regression snapshot for PulseWidth; the gallery doesn't have a live demo yet, but the test snapshot illustrates the look:

PulseWidth

When to write your own

The three presets cover the common cases. If you need:

  • Width that responds to ctx.sdf (radial taper, distance-from-edge)
  • Combined modulation (taper + pulse + calligraphy)
  • Width as a function of ctx.pos (spatial effects)

…write your own. See Custom Effects: Stroke.