live artifacts, not a demoOpen the workspace →

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

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
10/10
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

see it work

Ten pages, audited live

Not mockups. Real pages, written the way product pages get written — a dashboard, a SaaS landing page, a settings form, a coffee roastery, an investment platform, a training studio, a gallery archive, an API reference, a vegetable box and a long-read journal. Each is audited at desktop and mobile by the same headless browser this product uses on your code.

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.

The Analytics dashboard sample page at the desktop viewport

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
The Product landing page sample page at the desktop viewport

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
The Account settings sample page at the desktop viewport

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
The Coffee roastery sample page at the desktop viewport

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
The Investment platform sample page at the desktop viewport

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
The Training studio sample page at the desktop viewport

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
The Gallery archive sample page at the desktop viewport

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
The API reference sample page at the desktop viewport

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
The Vegetable box sample page at the desktop viewport

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
The Long read sample page at the desktop viewport

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

What the “before” figures are. Frozen from the versions UXAI fixed autonomously — sample 1 at 0% accessibility with eight critical contrast failures, sample 2 at 26% and scrolling sideways on a phone. All six have since been redesigned by hand on a generated design system, so the right-hand number is a later page than the left-hand one. The baseline column is written once and never updated: a baseline that drifts with each re-audit erases the result it exists to record.

This page runs on the engine

Move a dial. Everything re-derives.

258°
0.016
0.15
0.55×
1.280
Ink on the field
9.48:1 AA
Field on the ink
9.48:1 AA

This page is two colours: a field and an ink, both taken from the generated ramp. Swept across 4,320 positions these sliders can reach, the lowest either pairing ever falls to is 8.65:1 — so you cannot drag this page into something unreadable.

the load-bearing idea

Measured and estimated are never mixed

A vision model reading a screenshot produces estimates. It identifies a layout, a metric grid, a chart and a table reliably. It does not measure.

So UXAI never asks a model for a number it can obtain itself. It runs the page and reads the DOM. That is why one side of every comparison in this product is exact, and why the other side is labelled.

The same rule decides what gets scored at all. Accessibility, layout and style consistency are computed from a live DOM and need no target. A per-pixel match against a screenshot is not scored — the target side is an estimate, and a precise-looking number built on an estimate gets believed.

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 on this project’s own dashboard.
Measured element geometry
selectorsizefontcolour
#page-title342 × 2420pxrgb(17, 17, 17)
.card133 × 7816pxrgb(17, 17, 17)
.card-label99 × 1614pxrgb(107, 114, 128)

Real getBoundingClientRect output, through the DevTools protocol.

the part most tools skip

It refuses to score what it cannot measure

This is a failing page, kept on purpose. A real evaluation taken Wed, 26 Aug 2026 15:26:59 GMT at the desktop viewport. The page it came from scored 0% and has since been fixed — autonomously, and the result is in the gallery above. It stays here because a scoring system that only ever reports success is not a measurement.

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

  • structureestimated

    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

There is no headline number either. Averaging a measured contrast ratio with an estimated structural match produces a figure that inherits the precision of the first and the reliability of the second — and people quote it.

The 12 findings behind those scores
  • critical contrast-insufficienttext contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • serious contrast-insufficienttext contrast is 3.44:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • critical contrast-insufficienttext contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • serious contrast-insufficienttext contrast is 3.44:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • critical contrast-insufficienttext contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • critical contrast-insufficienttext contrast is 2.57:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • serious contrast-insufficienttext contrast is 3.44:1 against its background, below the WCAG AA minimum of 4.5:1 for this size (13px)
  • critical contrast-insufficienttext 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

20 tools

Across 7 categories. Every one carries a permission, a risk level and both schemas — defined once, in a registry the CLI dispatch table and the wire protocol are both derived from.

Inspect every tool

A design system that generates

A mode and three hues produce eleven-step OKLCH ramps, type, spacing, elevation and motion. Every colour role is the first ramp step that measurably clears its contrast target — or a refusal, never a near miss.

Move the dials

External servers, untrusted

MCP servers are capability providers, reached through one tool that cannot register new wire actions. Their tool descriptions reach a planner's prompt, so they are bounded and flagged before they get there.

See the integrations

the autonomous part

It iterates, then stops on its own

Autonomy is a spendable budget, not a mode. Your terminal is asked once — up to N changes, for M minutes, on a branch you can throw away — and each automatic change is printed as it happens.

The loop optimises only the measured objective, and every exit is named. Spent, timed out, patch too large, wrong branch, or converged: each returns to asking you, and none of them is an infinite loop.

Both fixed samples stopped on converged, not on the iteration limit — it ran out of measurable problems before it ran out of turns.

convergedafter 1 iteration59%100%

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

on branch uxai/fix-sample1 · 3 files changed

  1. iteration 180 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 general command executionIt can run a named script your package.json already defines. The backend cannot supply a command, arguments, environment or working directory.
  • The browser cannot be pointed anywhereCaptures take a path on the dev server the CLI started. There is no URL field in the schema — visible in the tool inspector, not just in a comment.
  • Nothing pushes, resets or force-anythingNot gated behind a flag. Not implemented, so no bug and no prompt injection can reach it.
  • Secrets are unreadablePath containment is enforced by realpath, and the deny-list is applied to the resolved path, so a symlink pointing at your .env is refused too.
  • Approval happens on your machineThe backend can ask; it cannot approve. Without a terminal to ask on, the answer is no, and no flag changes that.
  • External tools inherit nothingAn MCP server cannot register a wire action, cannot hold a UXAI permission, and cannot reach the filesystem.