Skip to main content
Technical preview

Redraw is currently in technical preview, available to wcandillon.dev subscribers. API is unstable.

Custom Feathers

A feather function computes the blur sigma per pixel instead of a color or a stroke width. The pipeline applies the falloff itself (you never author the falloff math): your callback just returns the sigma for the current pixel, which gives analytical blur with a different radius at every fragment.

This page is for the write your own sigma case. For ready-made feather modes (uniform, glow, sweep, radial, and the rest) see Vector Feathering.

Anatomy

import { feather, FeatherCurve, FeatherMode } from "redraw";
import { std } from "typegpu";

const VariableFeather = feather(
(ctx, tctx, props) => {
"use gpu";
const topY = props.centerY - props.radius;
const bottomY = props.centerY + props.radius;
const t = std.clamp((tctx.pos.y - topY) / (bottomY - topY), 0, 1);
return std.mix(props.minSigma, props.maxSigma, t); // sigma for this pixel
},
{ centerY: 0, radius: 0, minSigma: 0, maxSigma: 0 },
{ maxCullDistance: 3 * 66 },
);

Attach it like any feather, and declare it in the Library:

const paint = new Paint()
.setColor("#3FCEBC")
.setFeather(VariableFeather, {
centerY: cy,
radius: 120,
minSigma: 2,
maxSigma: 40,
});
canvas.draw(new Circle([cx, cy], 120), paint);

The callback reads the same contexts as the other helpers: ctx.t for the arc-length position along a path, ctx.sdf for the distance to the edge, tctx.pos for the position. To animate (a focus pull, a moving blur front), pass different props on the next frame.

Options

OptionDefaultWhat it does
name(generated)The WGSL function name. Omit to get a generated unique name.
curveGaussianFalloff curve applied to the returned sigma (FeatherCurve.Linear for linear).
modeUniformSpatial mode applied to the returned sigma (FeatherMode.Glow, .Inner, ...).
maxCullDistance16Outward reach for bounding-box padding. Unlike the built-in Feather factories, the sigma is computed per pixel, so the reach can't be derived up front: set it to about 3 * maxSigma for a gaussian curve, or the tail gets tile-culled.
length1024Props collection capacity.

When to reach for this

Most use cases are covered by the static factories in Vector Feathering:

You wantUse
Uniform blur on a shapeFeather.blur(sigma)
Outer glow / inner shadowFeather.glow(sigma) / Feather.inner(sigma)
Drop shadowFeather.outer(sigma)
Motion blur from a velocity vectorFeather.sweep(sigma, [dx, dy])
Radial blur (lens-like)Feather.radial(sigma, [cx, cy])
Sigma computed per pixel by your codefeather(...) (this page)

If your sigma can be expressed as a function of ctx.t, ctx.sdf, or tctx.pos, a custom feather gives you per-pixel control. Common recipes: depth-of-field along a curve, focus-pull animations, sigma that ramps with arc length.