Figures
A generator for little agent characters, drawn as soft 3D toys: seven bodies, seven kinds of eyes and no mouth, an antenna, ears, arms and legs, clay, vinyl or Aura's glass, and three ways to draw them.
// Each body is an implicit shape: 0 at its heart, 1 at its edge, smooth inside,
// so the surface raised from it has no creases (a distance field would have
// ridges where the corners meet).
const superellipse = (q, a, b, n) => pow(pow(abs(q.x).div(a), n).add(pow(abs(q.y).div(b), n)), float(1).div(n));
// Puffs melted with an exponential smooth minimum, smooth everywhere.
const softMin = (values, k) => log(values.reduce((sum, v) => sum.add(exp(v.mul(-k))), float(0))).div(-k);
// Raised into a surface: flat on top, falling round to the edge.
const raised = pow(clamp(float(1).sub(pow(body.value, body.flatness)), 0, 1), float(1).div(body.flatness));
// Arms, legs and antennas are tubes, round in section, joined on with a fillet.
const tube = (distance, radius) => sqrt(clamp(float(1).sub(distance.div(radius).pow(2)), 0, 1)).mul(radius);
const height = smax(raised, extras, 0.06);
// Lit like a toy from its slope: a pale lit side, its colour, a deep shadow side.
const normal = normalize(vec3(h.sub(hx).div(apart), h.sub(hy).div(apart), 1));
const wrapped = clamp(dot(normal, light).add(0.3).div(1.3), 0, 1);Shapes without creases
There's no geometry: one square fills the canvas and a TSL fragment shader works out every pixel. Each body is an implicit shape, a value that's 0 at its heart and 1 at its edge: a superellipse for the pebble, the capsule and the block, a circle whose radius drifts for the blob, three puffs on a flat base for the cloud, a dome that turns square toward a wavy hem for the ghost. That value is raised into a surface, flat on top and falling round to the edge, and lit from its slope. A distance field, the usual tool, leaves a crease wherever two corners' reach meets; this value is smooth all the way in, and the cloud's puffs are melted with an exponential smooth minimum for the same reason.
The antenna, ears, arms and legs are tubes and balls, round in section, joined to the body by the higher of the two surfaces with a fillet where they meet. Every choice is a weight the shader blends by, sprung toward 0 or 1, so a pebble melts into a ghost and legs grow out of a block with a little bounce. It breathes, blinks and follows the pointer only while it's on screen; under reduced motion each change simply appears.
Lit like a toy
The light comes from the upper left and wraps a little past the edge: a pale lit side, the body's own colour, a deep shadow shifted toward blue, all from one hue in OKLCH. Light runs round the thin edge, it darkens underneath where the ground hides it, and the highlight is broad on clay and tight on vinyl. Aura's surface swaps the paint for Aura's glass, colour flowing inside and the rainbow at the rim, halo and all. The eyes are distance fields painted under the same light, with a catchlight; glowing ones shine from a dark screen, as a robot's would. There's no mouth, as on most agents: the eyes carry the expression.
Pixel and ASCII
Both looks sample the same figure at the centre of each cell, in the shader. Pixel art gets forty cells down the frame, hard edges and the light in four flat bands; ASCII gets thirty rows of characters from a glyph atlas, denser where the figure is darker as the eye sees lightness, so the eyes come out as the densest. Save PNG draws a frame and reads it back in the same task, before the canvas lets it go.