A material can be made from looks instead of a shader. lighting says how its surface is lit, one look in place of the engine's light, and steps what is done to it once lit, in order: toonLighting() cuts the light into flat bands, unlitLighting() leaves it out, mangaDots() inks the shadow with dots laid out on the screen, and rim() lights the edge. The engine writes the shader in both languages.
mangaDots() after toonLighting() inks exactly where the bands went dark, which a screen effect, seeing only colours, cannot. Cast shadows count too: the floor is dotted where the shapes shade it. Every number is a knob of the material (toonShadow, mangaDotsSize…), to turn while the game runs.
The nightcrawler, the fox and the duck wear the same looks, each piece over its own picture and colour; the two with bones walk and run in them. A model takes a look when it is made with createModel({ lighting, steps }); here they change look while running, through compileShader({ lighting, steps }).
Click the preview first so it hears the keyboard. 1 to 7: as the engine draws it, toon, toon + dots, toon + dots + rim, dots on the engine's light, unlit + rim, and each surface's tangent as a colour.