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
| Option | Default | What it does |
|---|---|---|
name | (generated) | The WGSL function name. Omit to get a generated unique name. |
curve | Gaussian | Falloff curve applied to the returned sigma (FeatherCurve.Linear for linear). |
mode | Uniform | Spatial mode applied to the returned sigma (FeatherMode.Glow, .Inner, ...). |
maxCullDistance | 16 | Outward 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. |
length | 1024 | Props collection capacity. |
When to reach for this
Most use cases are covered by the static factories in Vector Feathering:
| You want | Use |
|---|---|
| Uniform blur on a shape | Feather.blur(sigma) |
| Outer glow / inner shadow | Feather.glow(sigma) / Feather.inner(sigma) |
| Drop shadow | Feather.outer(sigma) |
| Motion blur from a velocity vector | Feather.sweep(sigma, [dx, dy]) |
| Radial blur (lens-like) | Feather.radial(sigma, [cx, cy]) |
| Sigma computed per pixel by your code | feather(...) (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.