Every effect has a set of dials from 0 to 1, named for what you see: how far a glow reaches, how torn an edge is, how worn the press. Turn a dial and the effect’s numbers follow. Leave it alone and the effect looks exactly as it always has.
import { composeEffects, fill } from "shodo";
import { effectFeel, getEffect } from "shodo/registry";
const glow = getEffect("glow")!;
const shader = composeEffects(fill(), glow.create(effectFeel(glow, { reach: 0.8, brightness: 0.3 })));
That is a wide, faint glow. effectFeel returns plain uniform values, so they go wherever values go: create(), a setter, a preset.
The dials
Each dial rests where the effect’s defaults put it: a glow’s reach rests at 0.5, its brightness at a third.
fill1 dial
presenceghostsolidHow solid the letters are.
wipe1 dial
softnesshard cutslow fadeHow soft the edge of the reveal is.
outline1 dial
weighthairlineheavyHow heavy the line around each letter is.
glow2 dials
reachtightwideHow far the light spreads from the letters.
1 more dial
brightnessfaintblazingHow strong the light is.
scramble1 dial
paceslowfranticHow fast the letters flicker through other characters.
grain3 dials
gritcleangrittyHow much noise sits over the letters.
2 more dials
coarsenessfinecoarseHow big each speck of grain is.
lifestillboilingHow fast the grain moves.
wake3 dials
pulllightheavyHow hard the letters are dragged behind the pointer.
2 more dials
reachclosefarHow far from the pointer letters still feel it.
lingersnaps backlingersHow long the letters take to settle back.
rough3 dials
roughnessclean cuttornHow torn the letters’ edges are.
2 more dials
scalefinecoarseHow big the bumps along the edge are.
detailsmoothbusyHow much small wobble rides on the big bumps.
dotgain2 dials
swellstarvedswollenHow much the letters fatten as ink spreads into the paper.
1 more dial
bleedcrispbleedingHow soft the spread ink’s edge is.
inkpool3 dials
poolingdrypooledHow dark the ink gathers at the letters’ edges.
2 more dials
spreadtightwideHow far in from the edge the pooled ink reaches.
starveevenstarvedHow much the middle of each letter runs out of ink.
press2 dials
wearfreshwornHow uneven the ink lies, like a worn printing plate.
1 more dial
voidssolidpatchyHow many bare patches the press leaves.
liquid1 dial
swellthinnedswollenHow much the letters thin or swell, like ink on wet paper.
dither2 dials
strengthofffullHow much of the dither shows.
1 more dial
chunkfinechunkyHow big each dither pixel is.
halftone3 dials
screenfine screencoarse screenHow big the halftone dots are.
2 more dials
inklightheavyHow much ink each dot carries.
softnesscrispsoftHow soft each dot’s edge is.
Each definition carries its own in definition.feel: the title, the sentence, the two end words, the uniforms it moves and where it rests. A panel can be built from that alone.
Giving your own effect dials
Add feel to the spec. A dial names the uniforms it moves and their values at 0 and at 1:
defineEffect({
id: "pulse",
// ...
uniforms: { beat: { type: "float", value: 1, min: 0, max: 8, unit: "per second", description: "Beats per second." } },
feel: {
tempo: { title: "Tempo", summary: "How fast it beats.", ends: ["slow", "fast"], drives: { beat: [0, 4] } },
},
});
You don’t say where the dial rests: defineEffect works it out from the default (beat 1 between 0 and 4 rests at 0.25). It refuses a dial that names a uniform the effect lacks, that moves anything but a single float, that reaches outside a uniform’s range, whose default lies outside its ends, or whose uniforms would rest at different points. A dial moves in a straight line between its ends; anything subtler belongs in the uniforms themselves.
Dials are optional and add nothing to the shader: an effect without them works as before, under contract version 1. See writing-effects.md for the rest of a spec.