cellshade
cellshade · effects · schema v1Cel-shader (toon / retro-video-game) video PROCESSOR. Takes a video input and emits a cel-shaded version: the colour is QUANTIZED to a retro N-bit palette and the salient CONTOURS are inked in as BLACK outline strokes (a reused EDGES Sobel pass). STATELESS per frame — the look moves/transforms live with the source. Pipeline: (1) quantize the colour to the chosen bit depth; (2) run a 3×3 Sobel on the input's Rec. 601 LUMINANCE (the exact EDGES algorithm — same normalisation, THRESHOLD gate, THICKNESS dilation) to get a 0/1 edge mask; (3) ink the mask as black lines over the quantized colour: color = mix(quantizedColor, vec3(0.0), edge). BITS is a 5-step DISCRETE knob (the param is the step INDEX 0..4; the card shows the bit value + colour count, and the matching CV input uses a discrete cvScale so it snaps to the 5 steps) mapping to RETRO TOTAL COLOR-DEPTH: 1-bit=2 colours, 2-bit=4, 4-bit=16 (default), 8-bit=256, 16-bit=65536. The quantization is done WELL, per-depth: the LOW depths (1/2/4-bit = 2/4/16 colours) use LUMA-BAND quantization — convert RGB→HSV, keep HUE + SATURATION (gently posterized for the 16-colour budget), quantize only BRIGHTNESS (V) into a few bands, reconstruct RGB — so the result reads as hand-painted flat tonal bands (the cel look) rather than the channel-clipped rainbow a naive per-channel RGB floor produces; 8-bit uses the authentic console RGB 3-3-2 allocation (8 R / 8 G / 4 B levels = 256) and 16-bit the RGB 5-6-5 allocation (32 R / 64 G / 32 B = 65536). THRESHOLD (0..1, default 0.2) gates which contours get inked — raise it to ink only the strongest edges, lower it for more outline. THICKNESS (1..8 px, default 2) dilates the ink stroke wider (morphological MAX, same as EDGES). THRESHOLD / THICKNESS / BITS each have a matching CV input (port id == param id). IN takes RGB; OUT is video — patch a source (CAMERA / VIDEOBOX / SHAPES / a generator) → IN, OUT → OUTPUT or a video mixer; sweep BITS for the colour-depth retro step, THRESHOLD/THICKNESS to tune the ink.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
in | video | The RGB video source to cel-shade. Its colour is quantized and its luminance contours are inked as black outlines; with no input the output is solid black. RGB video stream |
threshold | cv | CV input that modulates Thresh, sweeping the edge gate linearly over its full 0..1 range — higher CV inks fewer, stronger contours. control voltage (CV); modulates threshold (additive offset — ±1 CV sweeps the full range, centered on the knob) |
thickness | cv | CV input that modulates Thick, sweeping the ink stroke width linearly over its 1..max px range — higher CV makes the black outlines wider. control voltage (CV); modulates thickness (additive offset — ±1 CV sweeps the full range, centered on the knob) |
bits | cv | CV input that modulates Bits using a discrete cvScale, so the CV snaps to the 5 colour-depth steps (1/2/4/8/16-bit) rather than sweeping continuously. control voltage (CV); modulates bits (integer buckets — CV selects a discrete step) |
outputs
| id | cable | what it does |
|---|---|---|
out | video | The cel-shaded video frame: the quantized retro-palette colour with black ink strokes drawn over the detected contours. RGB video stream |
params
| id | label | range | default | curve |
|---|---|---|---|---|
threshold | Thresh | 0..1 | — | linear |
thickness | Thick | 1..?px | — | linear |
bits | Bits | 0..? | — | discrete |
controls
| control | what it does |
|---|---|
| Bits | Bits — a 5-step discrete control selecting colour depth: 1-bit (2 colours), 2-bit (4), 4-bit (16), 8-bit (256, RGB 3-3-2), 16-bit (65536, RGB 5-6-5). Default is 4-bit/16 colours; the card shows the current bit value and colour count. Low steps give a flat luma-band cel look, high steps the hi-colour console look. |
| Thick | Thick — ink stroke width in pixels (1..max, default 2, shared with EDGES). It dilates the edge mask, so higher values make the black outlines wider; 1 is a thin single-pixel line. |
| Thresh | Thresh — the edge gate (normalized Sobel gradient magnitude, 0..1, default 0.2, shared with EDGES). Lower inks more/weaker contours; higher inks only the strongest edges, fewer lines. |
source
cellshade.ts on GitHub.