Redraw is currently in technical preview, available to start-react-native.dev subscribers. API is unstable.
Vector Feathering
Most 2D pipelines blur things in raster: sample neighboring pixels, weight them, sum. That's an expensive operation, and quality degrades at small radii.
Redraw blurs analytically. The feathering pass modulates the alpha coverage we apply to a shape. That's what makes a few effects raster pipelines reach to post-process for practical at interactive frame rates: motion blur from a velocity vector, backdrop filters that compose, glow that scales without artifacting.
import { Feather, FeatherCurve } from "redraw";
brush.addFill("#3FCEBC", Feather.blur(20));
brush.addStroke("#fff", 8, Feather.glow(50));
A feather is a curve that represent the shape of the falloff (gaussian or linear) combined with a mode (where the falloff is applied around the edge).
There are two kinds for curves:
enum FeatherCurve {
Gaussian, // erf-based bell, most natural
Linear, // simple linear falloff
}
Default is Gaussian. Every factory below accepts a FeatherCurve as its
last argument: Feather.glow(50, FeatherCurve.Linear).
And we support eight modes
| Factory | Mode | What it produces |
|---|---|---|
Feather.blur(sigma, curve?) | Uniform | Symmetric blur on both sides of the edge. |
Feather.glow(sigma, curve?) | Glow | Sharp inside, soft outward (outer halo). |
Feather.inner(sigma, curve?) | Inner | Sharp outside, soft inward (inner shadow). |
Feather.outer(sigma, curve?) | Outer | Transparent inside, soft outside (drop-shadow shape). |
Feather.inset(sigma, curve?) | Inset | Soft outward, clipped to the original boundary (inset highlight). |
Feather.radial(sigma, [cx, cy], curve?) | Radial | Blur radius grows with distance from a center point. |
Feather.sweep(sigma, [dx, dy], curve?) | Sweep | Sigma varies along a direction vector (motion blur, glass). |
Feather.fromContext(curve?) | Variable | Reads sigma per-pixel from canvas.field set by your TypeGPU callback. |
Feather instances are handles: feather.sigma = newSigma can be used at animation time.
Analytical motion blur
Motion blur is normally a post-processing pass. In redraw, it's a property of the brush: set the direction to your velocity vector and sigma to its magnitude, and the renderer produces motion blur at the correct intensity per pixel:
const feather = Feather.sweep(0, [0, 0]);
const brush = new Brush();
brush.addFill("#0a0a1a", feather);
const circle = new Circle([cx, cy], 120);
canvas.draw(circle, brush);
// every frame:
const speed = Math.sqrt(vx * vx + vy * vy);
feather.sigma = Math.min(speed * 0.25, 50); // scale by velocity
feather.direction = [-vx / speed, -vy / speed]; // trail behind motion
The "sweep" demo below pushes this further: each color channel gets its own brush with a per-channel, and the channel offsets produce chromatic aberration that intensifies with velocity.
Fused Backdrop Filters
canvas.pushLayer({ clip, feather, tint }) opens a layer whose boundary
is feathered: the feather applies to the layer's clip, and contents drawn
inside compose against the soft edge.
canvas.pushLayer({
clip: card,
feather: 25,
tint: ["rgba(255, 255, 255, 0.2)", new Grain(0.2)],
});
// ... draw the content this layer feathers ...
canvas.popLayer(); // applies the tint and pops
The LayerDescriptor:
| Field | Type | What it does |
|---|---|---|
clip | RenderNode (a shape, path, …) | The region the layer affects. |
feather | number | Soft-edge radius in pixels. |
tint | string | (string | RenderNode)[] | Optional color or layered effects (Gradient, Grain, …). |
Variable Feather
For sigma that varies pixel-by-pixel (depth-of-field along a curve, a
moving focus, sigma that ramps with arc length), write a fn that emits
sigma into canvas.field and wrap it with ApplyFeather:
brush.addStroke(color, strokeWidth, new ApplyFeather(yourSigmaFn));
That's its own page: Custom Effects: Feather.