Drawn UI
A drawn screen shows a product the way a designer would sketch it for a case study: the real interface, simplified until only its structure is left, tinted in the product's own colour. It reads as design work where a screenshot reads as pasted, and it never shows private data, because all text is bars.
The look stays calm because the rules are few and strict. Every project still looks like itself, because the tint, the screens and the one lifted part come from the project. Where the drawings go (a hero, a grid, a feature list, a slide) is up to whoever uses them.
Work in this order
- Read the real product. Its current screens, from the code, the app or the design file. Every drawing traces to a real screen or component. Never invent a metaphor (floating scales, doors, arrows between cards): if the product does not have it, the drawing does not show it.
- Pick the moments. What each drawing is for: one screen, one component, one state. A set shows different components, not one component with more detail each time.
- Take the accent. The product's own tint or brand colour.
scripts/tint.py "#hex"shows the tones it gives. More accents only when they mean something in the product (status colours, a brand pair). - Write the spec.
drawings.json, format inreferences/spec.md(read its sections on sizes, lifting and tones before drawing), with the example inexamples/ledger/drawings.jsonbeside it. Size each drawing for the space it will fill. - Draw and check.
python3 scripts/draw.py drawings.json --shots(the screenshot needs Playwright with Chromium). Fix every problem it prints, then openout/shots/sheet.pngand look. Numbers flag, eyes decide: empty corners inside a card, a drawing that leans to one side, a pile that reads as pills. Repeat until it passes and looks calm.
The rules
- A drawing has no words in it. All text becomes bars: heights 12, 8, 6 or 4, widths in steps of 4, fully rounded.
- White cards, one radius per role (cards 12, inner boxes 8, rows 4, phones 32), one card shadow, one lift shadow.
- One part per drawing may lift out of its card: it leaves on one side only, by 16 to 72 (24 to 40 reads best), never past the card's top or bottom, with 8 or more around it. A drawing 600 or wider may lift two. The lifted part replaces what it lifts, it does not half cover it.
- One accent per drawing, used on the thing that matters in that screen.
- At most one line glyph per drawing, drawn at 1.5 with round ends.
- No background by default: the drawing comes with just room for its shadows and sits on whatever page it is placed on. With
"ground": trueit gets a tinted ground, which it fills 65 to 75 percent of in width and height, centred. - Everything at 1:1 on a 4 grid. Drawings in one set that sit side by side share a scale: draw them at the size they are shown, and match heights when they sit in a row.
- Phones are 1 to 2.05.
Using the output
out/<id>.svg files are self-contained, carry their own width and height, and adjust to the page: light on white, dark on black. They follow the viewer's system setting, and a dark or light class (or data-theme) on any parent forces one. They are aria-hidden, with ids namespaced per drawing, so several can sit inline on one page. Shapes carry role classes (p-ground, p-card, p-bar, p-dot, p-glyph, p-hi for the lifted part) for hover motion; out/index.html shows a calm one with a Reduce Motion answer. A drawing too wide for a phone gets a narrower second drawing; never squeeze it.
Designing in Figma instead: the same rules apply, and the spec values map one to one to frames (auto layout for cards, absolute position only for the lifted part). Export each ground as SVG.
When the rules fight the product
A product with no single accent can use its darkest neutral. A screen that only makes sense with two highlights can be two drawings. Bend one rule at a time and say which.