ascii/ui, a design system drawn in ASCII

Thirty-six shadcn-style components in an ASCII skin. Frames, fills and shadows are strings of characters. Plain HTML underneath, bad signal on top.

For designers and developers who copy a component and own the code.

0 dependencies. 36 components, 34 in the kit. 2 kit files.

Where to start

Questions

Is this accessible?

The characters are paint. Underneath are native controls with labels, focus states and keyboard support, and decorative glyphs are hidden from assistive tech. Reduced motion turns off every animation and every sound.

Does it need a framework?

No. The kit is two files, ascii-ui.css and ascii-ui.js. The components are classes and custom properties, so they drop into anything.

Why monospace only?

The grid is the design. Every width is a number of characters and every height a number of rows, which is what lets strings work as borders.

Can I turn the glitch off?

Yes. The Glitch switch kills it, the slider scales it, and the page respects reduced motion.

Who made this?

Fede Kotek designed it. Claude Code built it, in rounds: agents audit, agents fix, and a script decides what ships. The whole story is in How it was made, at the end of this page.

How it was made

A design system with one material: the character.

The kit at work: 15 seconds, 3 MB, muted. It loads when you press play.

The problem

Most component kits look like the same kit. ASCII interfaces look different, and most are screenshots or terminal toys: pure text breaks screen readers and does not reflow on a phone. The brief was a kit made of characters that still works like a kit, with a keyboard, a screen reader, a phone, and copy and paste. The person in charge is a product designer, so every rule had to be one a script can check.

By the numbers

Counted from the repo and the built site. A script recounts them before every release and fails if this page says otherwise.

What it is

  • 36 components, 34 in the kit
  • 16 blocks
  • 5 charts
  • 7 kit versions published, each still served
  • 190 kB gzip on first visit, cap 200
  • 62 kB gzip for the 2 kit files

What checks it

  • 22 checks before every release
  • 22 test scripts
  • 11 screen widths, 360 to 1920
  • 7 accessibility modes
  • 0 requests to anyone else
  • 0 animation frames at rest when the system asks for reduced motion

The bar is the weight against its cap, 6 kB a #. The seven modes: keyboard, screen reader names, reduced motion, forced colors, more contrast, print, touch.

Rules the scripts enforce

Each rule has a script, and each script is a step in the release bar. A rule no script checks is a suggestion.

Each rule, and the script in the release bar that fails the release when it is broken.
RuleScript
No em dashesfacts.py
Cyan is focus onlyfacts.py
Columns on the 1ch gridbreakpoints.py
Reduced motion means nonereduced.py
No setIntervalclock.py
Nothing from elsewherebudget.py
No tap target under 40pxaudit.py
These numbersfacts.py

Em dashes are looked for in the source, the docs, the built site and the commit log. Cyan is read from every CSS rule that paints with it: each one needs a focus state. Taps are drawn at 44px, and the script fails anything under 40.

Principles

  • Plain HTML underneath. The characters are paint. A button stays a button, so keyboards and screen readers work.
  • Every frame is a string. A border is one character repeated, so a new character reskins the part.
  • Weight is density. @ is the loudest thing on the page and . is the quietest.
  • One grid, 1ch by 21px. Widths are counts of characters, heights are counts of rows.
  • Glitch is feedback. It fires on touch and on state changes. At rest, the page reads.
  • One file, no dependencies. No framework, no bundler. The site ships as one HTML file and works from file://.

Process

One HTML file for nine versions. v10 made it a repo, with docs and Playwright scripts for QA.

  v1   HTML on a character grid
  v2   frames are strings
  v3   the ring spins
  v4   glitch, signal palette
   v5   never published
  v7   18 more parts, Code tabs
  v8   6 presets, a ramp editor
  v10  a repo, docs, QA scripts
  v11  the kit: 2 files, MIT

Each row is one step heavier on the ramp. v5 is a space because it never shipped.

From v10.8 on, the work ran in rounds. Auditors read the site in parallel, one lens each, and change nothing. Their findings are split by file, so no two builders touch the same one.

 audit   read only, in parallel

 plan    fixes split by file

 build   one worktree each

 review  reviewer and ux-critic

 release every step passes

 ship    main, Vercel, live

v10.8        8 auditors, 5 builders.
v11.0      10 auditors, 5 builders.
v11.1         7 auditors, 4 builders.
v11.2      10 auditors, 9 builders.

One # is one agent. v11.1 had seven lenses: a UI designer, legibility, copy, a frontend engineer, an interaction bug hunt, the Code tab's truth, and an LLM reading the docs cold. v11.2 went through a UX checklist: print, high contrast, touch, security, share cards, and four new overlays.

The release bar is one command. It runs 22 steps and stops at the first failure.

 clean at 2 sizes, 2 themes
 the shipped file loads clean
 the Code tab prints the kit
 11 widths, 360 to 1920
 one animation clock
 no tiny taps, no tiny text
 no surprise phone keyboard
 every kit part, pasted twice
 every Usage tab holds true
 reduced motion, both builds
 every address lands
 the docs match the code
 what ships is what builds
 every number on this page
 under the size budget

release: ok

What did not work

  • A masonry gallery. It packed the cards tight and broke the alphabetical order the index promised. It lasted 29 minutes.
  • The phone menu. The second patch made it worse, so it was rebuilt instead.
  • Three views: Play, Apps and One pager. They read as a portfolio, and this is a kit.
  • Thirty bitmap titles in a row. A wall of shouting. Now there is one per page.
  • A Try it strip on Home. It lasted nine hours.
  • A Code tab that printed the site's own engine. Now it prints the kit, and a script pastes every component twice into a blank page to prove it works.
  • Still not done: the WebGL CRT pass, Safari and Firefox on real devices, and an audit by someone who uses a screen reader.

Credits

Designed by . Built with Claude Code. This is v11.5, with kit 1.3.1.

Publish project?

Reporting redesign will be visible to anyone with the link. You can unpublish it at any time.

Filters

Search

Your signal

Generated glitch poster with your signal code

Generated from your signal code. Long-press or right-click the image to save it.