Skip to main content
Technical preview

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

FactoryModeWhat it produces
Feather.blur(sigma, curve?)UniformSymmetric blur on both sides of the edge.
Feather.glow(sigma, curve?)GlowSharp inside, soft outward (outer halo).
Feather.inner(sigma, curve?)InnerSharp outside, soft inward (inner shadow).
Feather.outer(sigma, curve?)OuterTransparent inside, soft outside (drop-shadow shape).
Feather.inset(sigma, curve?)InsetSoft outward, clipped to the original boundary (inset highlight).
Feather.radial(sigma, [cx, cy], curve?)RadialBlur radius grows with distance from a center point.
Feather.sweep(sigma, [dx, dy], curve?)SweepSigma varies along a direction vector (motion blur, glass).
Feather.fromContext(curve?)VariableReads 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.

Motion blur derived from velocity; per-channel offsets give chromatic aberrationOpen in editor →

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:

FieldTypeWhat it does
clipRenderNode (a shape, path, …)The region the layer affects.
feathernumberSoft-edge radius in pixels.
tintstring | (string | RenderNode)[]Optional color or layered effects (Gradient, Grain, …).
Frosted glass: feathered layer + tint + grain over a colorful backdropOpen in editor →

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.