16 of 16 pages clean, audited on every deploy

It measures what it built, and says what it cannot.

UXAI reads your interface and your code, makes the change you approve, then measures what actually rendered.

16/16
sample pages with zero findings
20
tools, each with a permission and a risk level
15
real page captures
12
evaluations run
4
autonomous runs

watch it measure

Measured boxes, labelled guesses

Outlined boxes were measured by the browser, to the pixel. What the model only guessed is listed beside them, never drawn.

what the model thinks is there

The Analytics dashboard sample page, captured at 1440 by 900
sample11440×90053 nodes inferred · 0 measured

Inferred

53 nodes, no geometry

A vision model names regions reliably and sizes them badly. Measured over four runs on one image it read a 240px sidebar as 250px twice, and omitted it twice — so it is never asked for a number.

  • text ×29
  • link ×5
  • heading ×4
  • metric_card ×3
  • card ×2
  • page
  • sidebar
  • nav
  • header
  • input
  • avatar
  • main
  • metric_grid
  • chart
  • table

see it work

Sixteen pages, audited live

Real pages, each audited on desktop and phone by the same browser UXAI runs on your code.

How sixteen pages ended up looking nothing alike

They are also not one page recoloured six times, though the first version was. Each carries its own scale: type ratio, grid unit, corner softness, shadow depth, duration. Those are the dials the design agent moves, and the figures under each card are read off the running theme rather than typed beside it.

A scale was not enough either. Probing them with this product’s own browser found every one of them rendering in ui-sans-serif — no typeface at all — five of them declaring the same fallback stack character for character, at five weights each. So each now carries its own typeface and exactly two weights, and asking for a third does not compile.

UXAI fixed the first two by itself — planned the change, edited the code, re-rendered and re-measured, stopping when nothing measurable was left. Both arrows below are real before-and-after measurements.

  • 0% → 100% accessibility, fixed autonomously

    Dense: a tight ratio and a 4px rhythm, because the job is scanning numbers. Inter Tight with tabular JetBrains Mono figures — the number is the headline, so the number is the display type.

    face Inter Tight + JetBrains Monobase 15pxgrid 4pxradius 13pxmotion 136ms
  • 26% → 100% accessibility, fixed autonomously

    Generous: a wide ratio and a 5px rhythm, so the headline carries the page. Instrument Serif over Inter — one serif cut at display size, and nothing else on the page competing with it.

    face Instrument Serif + Interbase 17pxgrid 5pxradius 21pxmotion 184ms
  • Quiet: shallow elevation and a modest ratio, because a settings page is read, not admired. IBM Plex Sans, two weights, nothing at poster size — a form should not have opinions about itself.

    face IBM Plex Sansbase 16pxgrid 4pxradius 16pxmotion 160ms
  • Editorial: the widest rhythm here, near-square corners, print proportions. Fraunces at optical display size over Work Sans — a face drawn for the size it is set at, not scaled to it.

    face Fraunces + Work Sansbase 17pxgrid 6pxradius 6pxmotion 200ms
  • Precise: small base, shallow shadows, corners just off square. A table is the hero. Space Grotesk with Space Mono figures — one drawing in two widths, so the fund codes belong to the prose.

    face Space Grotesk + Space Monobase 15pxgrid 4pxradius 6pxmotion 128ms
  • Loud: square corners, the deepest shadows, the fastest motion. Nothing decorative. Anton uppercase over Barlow — the poster idiom, with tracking at normal because that is what a condensed face wants.

    face Anton + Barlowbase 17pxgrid 6pxradius 2pxmotion 112ms
  • Airy: the widest rhythm and no corners at all, because the work is the subject. Bodoni Moda over Outfit - a didone set large, with a neutral grotesque kept deliberately silent underneath.

    face Bodoni Moda + Outfitbase 18pxgrid 6pxradius 0pxmotion 224ms
  • Technical: a 4px grid, square corners, almost no elevation. Rules do the work shadows would. DM Mono as the body face, not just for figures - an API reference is scanned like code, and a proportional face fights that.

    face Sora + DM Monobase 15pxgrid 4pxradius 0pxmotion 96ms
  • Soft: the largest radii the dials allow, a 6px rhythm, and real shadow depth. Bricolage Grotesque throughout, one variable file with an optical-size axis doing display and text.

    face Bricolage Grotesquebase 17pxgrid 6pxradius 38pxmotion 216ms
  • Editorial reading: an 18px base, a measured column, and corners you have to look for. Newsreader at optical size for both display and text - a serif drawn to be read at length, not admired at 96px.

    face Newsreaderbase 18pxgrid 5pxradius 2pxmotion 176ms
  • Slow: the widest type ratio allowed, deep air, and a real sea moving behind the headline. Cormorant Garamond with italic emphasis over plain Manrope - the change of voice is the luxury, not the weight.

    face Cormorant Garamond + Manropebase 18pxgrid 6pxradius 8pxmotion 256ms
  • Loud in the other direction: an extended face, zero elevation, the fastest motion, pill-shaped tickets. Unbounded uppercase over Archivo - an extended face where the training studio uses a condensed one.

    face Unbounded + Archivobase 17pxgrid 5pxradius 29pxmotion 80ms
  • Compact: the smallest type ratio the dials allow, because an app screen is scanned, not read. Plus Jakarta Sans alone at 15px - hierarchy by weight, since the sizes barely differ.

    face Plus Jakarta Sansbase 15pxgrid 4pxradius 19pxmotion 144ms
  • Made by hand: nearly flat, soft corners, and the photographs doing the talking. Syne over Karla - a display face that looks cut rather than drawn, for things that were thrown rather than made.

    face Syne + Karlabase 16pxgrid 5pxradius 10pxmotion 192ms
  • Accessible first: an 18px base, a 6px grid for large targets, and the least motion of any sample. Atkinson Hyperlegible throughout - drawn for low vision, so I, l and 1 cannot be mistaken for each other.

    face Atkinson Hyperlegiblebase 18pxgrid 6pxradius 26pxmotion 80ms
  • Tidal: the slowest motion allowed, a generated sea behind the numbers, tabular figures to compare hours. Red Hat Display with Red Hat Mono figures - a forecast is a column of numbers read against each other.

    face Red Hat Display + Red Hat Monobase 16pxgrid 4pxradius 16pxmotion 320ms

The “before” scores are frozen from the versions UXAI fixed on its own, and are never updated: a baseline that moves erases the result it records.

This page runs on the engine

Move a dial. Everything re-derives.

258°
0.016
0.15
0.55×
1.280
Muted text
7.14:1 AA
Accent text
9.48:1 AA

Every colour here comes from one generated ramp, and every dial position is tested: you cannot drag this page into something unreadable.

the load-bearing idea

Measured and estimated are never mixed

A vision model can name a layout but cannot measure one, so UXAI never asks it for a number the page itself can give.

Asked four times about one screenshot, the vision model reported a 240px sidebar as “250px twice, and omitted it twice” — while naming the layout, the cards, the chart and the table correctly every time.
Semantics reliable, geometry not.
Measured element geometry
selectorsizefontcolour
#page-title342 × 2420pxrgb(17, 17, 17)
.card133 × 7816pxrgb(17, 17, 17)
.card-label99 × 1614pxrgb(107, 114, 128)

The table is real getBoundingClientRect output from the browser.

the part most tools skip

It refuses to score what it cannot measure

What it can measure gets a score. What it can only guess is named and left unscored, with the reason.

A real failing evaluation, kept on purpose. Taken Wed, 26 Aug 2026 15:26:59 GMT; the page has since been fixed. A scorer that only ever reports success is not measuring.

Scored, and how

  • accessibility0%measured

    computed from 12 finding(s) in the live DOM (8 critical, 4 serious), weighted critical:5 serious:3 moderate:1 minor:0.25 against a budget of 38 for 76 visible elements

  • layout100%measured

    the document fits the 1440px viewport with no horizontal scroll

  • consistency100%measured

    7 font sizes, 3 families, 6 text colours, 10 spacing values and 2 radii across 76 elements

  • structure—estimated

    no target design was supplied, so there is nothing to compare the rendered page against

Deliberately not scored

  • visualSimilaritytypographyVsTargetspacingVsTargetcolourVsTarget

    the target side of this comparison is a vision model reading a screenshot. Measured over four runs on one image, that model reported a 240px sidebar as 250px twice and omitted it twice. A per-pixel score built on those numbers would look precise and would not be.

  • structure

    no target design was supplied for this evaluation

And no single headline score: averaging a measurement with a guess makes the guess look measured.

The 12 findings behind those scores
  • critical contrast-insufficient — text contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • serious contrast-insufficient — text contrast is 3.44:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • critical contrast-insufficient — text contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • serious contrast-insufficient — text contrast is 3.44:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • critical contrast-insufficient — text contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • critical contrast-insufficient — text contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • serious contrast-insufficient — text contrast is 3.44:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • critical contrast-insufficient — text contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)

what it can reach

A capability platform, not a prompt with a screenshot

Real tools with real permissions, a design system that generates itself, and every change checked against your actual code.

A design system that generates

Three hues become ramps, type, spacing and motion, with every colour checked for contrast.

Move the dials →

the autonomous part

It iterates, then stops on its own

You grant a budget: so many changes, so many minutes, on a branch you can throw away. It stops when nothing measurable is left, and says why.

convergedafter 1 iteration59% → 100%

no moderate-or-worse findings remain after 1 iteration(s)

on branch uxai/fix-sample1 · 3 files changed

  1. iteration 18 → 0 findings+54 −20 across 3 files

    targeted horizontal-overflow, overflow-culprits, tap-target-small

what it will not do

Absent by decision, not by omission

  • No arbitrary commandsOnly scripts your package.json already defines.
  • No browsing anywhereOnly paths on the dev server your CLI started.
  • No push, reset or forceNot switched off. Never built.
  • No reading secretsNot even through a symlink to your .env.
  • No approval from afarThe server can ask. Only your terminal can say yes.
  • No inherited powerExternal tools get no permissions, files or new actions.
Figures on this page are read live from artifacts UXAI produced while building itself, generated Mon, 28 Sep 2026 18:00:50 GMT.
Built by Daniel Shammah. Back to danielshammah.com