Skip to content
STUFFY

One hundred figures · one style

Waiting,fauxhawk

Ink-silhouette illustrations for the moments your interface has nothing to show yet — loading, empty, missing. Same face, same desk. Hair, drink, and prop change.

Illustration: faux hawk · iced · camera
Plain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne stylePlain SVGNo dependencies~2 KB eachReduced-motion safe100 figuresOne style

The cast

Seventeen haircuts, six drinks, thirty-three desk objects. One hundred combinations, still one set.

Open the playground

Three rules

Everything in Stuffy follows them. Break one and it reads as a different drawing.

Mass, not outline

The body is one filled shape with no neck and no contour line. The white face simply sits on top of it — that overlap is the chin. Outlining the figure is what collapses this style into clip art.

The line boil

Every edge runs through a noise filter whose seed flips eight times a second, so it wobbles the way hand-redrawn frames do. One SVG filter, no frames to draw.

Two features, no more

A nose and a mouth. No eyes at all — the gaze is down at the cup, so they simply are not drawn. Adding them back flattens the whole thing.

Use it

Plain SVG. No runtime, no dependency, roughly two kilobytes each.

loading-curtain.jsxDocs
// the pile of notes is the progress bar — one per 20%
<LoadingCurtain progress={pct} character="curls" />

// hold it a beat so a warm cache doesn't flash it
await Promise.all([
  document.fonts.ready,
  new Promise((r) => addEventListener("load", r, { once: true })),
]);
setTimeout(() => setDone(true), Math.max(0, 1400 - elapsed));