Veris
scroll
Figma plugin · design audit engine

Veris

It reads a screen the way a senior designer would — and shows its work.

6 evaluators 90 catalogued rules WCAG 2.2 · Nielsen · Laws of UX optional multi-AI

Scroll to watch one audit travel the whole pipeline — from the frame you select, across the runtime boundary, through six evaluators running at once, to the graded report you read.

The idea

One frame in.
A graded critique out.

You select a frame. Veris extracts every node, works out what kind of screen it is, then measures it against contrast, layout, typography, colour, interaction heuristics and your design library — all at once. Nothing leaves your machine unless you turn on AI. Here is exactly how a single run unfolds.

Stage 01 · Source

You choose
a frame.

The run begins with your selection — a single frame or the whole page. On mount the UI and the sandbox shake hands (UI_READY → INIT) so the first message is never missed, and the Run button stays in sync with what's selected.

  • selection audits just the chosen frame(s)
  • page audits every root frame on the current page
figma.currentPage · selection
Stage 02 · Controller · sandbox

Read the canvas.

0
nodes flattened into plain SerializedNodes
walk the tree · documentAccess: dynamic-pagegetNodeByIdAsync
serialize fills · strokes · per-segment text · autoLayout · hierarchy
skip invisible children · cap 10,000 nodes · emit EXTRACTION_PROGRESS
2nd async pass · getMainComponentAsync() resolves every instance
crosses the postMessage boundary — two isolated runtimes, one channel · EXTRACTION_COMPLETE { SerializedPage }
Stage 03 · Context engine

Understand
the screen.

Before a single rule runs, inferScreenContext() decides what this screen is — so rules know whether they even apply. Touch-target rules skip desktop; "no empty state" only fires where a list is expected; a component sheet skips palette and hierarchy checks.

context/inferScreenContext
inferred context
devicemobile
screen typelogin
form fields2
navigationnone
taxonomy slotauth · 1 / 56
Stage 04 · The core

The evaluator engine.

0rules across 6 pure functions — fired in parallel, each error-isolated, every finding traced to the catalog
Promise.all( safeEvaluate ×6 ) · assertCatalog()
ContrastWCAG 2.2 AA / AAA12 rules
Layouttargets · spacing · grid13 rules
Typographyscale · hierarchy17 rules
Colorpalette · colour-blind4 rules
HeuristicsNielsen · Laws of UX40 rules
Design Libraryinstance drift4 rules
01
Evaluator 01 / 06

Contrast

WCAG 2.2 · 1.4.3 / 1.4.6 / 1.4.11 / 2.4.11 / 2.5.8
  • Reads every text layer and resolves its true, alpha-composited backdrop through ancestors
  • Checks AA and AAA, non-text control contrast, and text sitting on images without a scrim
  • Flags gradients & image fills for manual review instead of guessing
12 rules can fire here
produces →
errorwcag-aa-normal
Body text sits at 3.1:1 — below the AA floor of 4.5:1
#8A8A8A on #FFFFFF · ratio 3.1 : 1
↳ Darken the text to #595959 (4.6:1) or move it onto a solid surface.
02
Evaluator 02 / 06

Layout

WCAG 2.5.8 · Apple HIG 2024 · Material Design 3
  • Measures touch targets, tap spacing, input heights and safe-area collisions
  • Detects off-grid spacing, asymmetric padding and stray corner-radius tokens
  • Knows the device — skips desktop for touch rules, watches the keyboard zone on mobile
13 rules can fire here
produces →
errortouch-target-small
Icon button is 32×32 — under the 44px touch-comfort size
32 × 32 px · comfort min 44 × 44 (WCAG floor 24)
↳ Grow to 44×44, or expand the hit area with invisible padding.
03
Evaluator 03 / 06

Typography

WCAG 1.4.12 · Modular Scale · Apple HIG 2024
  • Judges size, line-height, tracking and real hierarchy — not just how many sizes exist
  • Enforces the 16px mobile baseline for body and input text (iOS focus-zoom)
  • Catches long measures, mixed families and text frames that will clip real content
17 rules can fire here
produces →
warningmobile-body-text-small
Body copy is 13px on a mobile screen — below the 16px baseline
font-size 13px · body ≥ 50 chars · device: mobile
↳ Set body copy to 16px+; reserve 14px for captions and secondary text.
04
Evaluator 04 / 06

Color

WCAG 1.4.1 · Viénot / Brettel dichromacy simulation
  • Counts the working palette and folds near-duplicate tokens together
  • Re-simulates each pair under deuteranopia, protanopia & tritanopia
  • Notices a near-grayscale palette that may have lost its hierarchy cues
4 rules can fire here
produces →
warningcolorblind-risk
Passes normal contrast, fails under deuteranopia simulation
normal 4.7:1 → deuteranopia 2.6:1 · affects ~8% of men
↳ Don't lean on hue alone — add contrast, a label, or an icon.
05
Evaluator 05 / 06 · the big one

Heuristics

Nielsen 2020 · Laws of UX · deceptive patterns · UX-writing
  • System status, user control, consistency, error prevention & recovery — the 10 heuristics
  • Mental models: Hick, Miller, Fitts, Jakob, Von Restorff, goal-gradient, peak-end
  • Deceptive patterns (confirmshaming, false urgency) and microcopy lint
40 rules can fire here — nearly half the catalog
placeholder-as-label hicks-law-choice-overload von-restorff-cta-blends-in ux-writing-vague-label
produces →
warningdark-pattern-confirmshaming
Confirmshaming decline copy: “No thanks, I hate saving money”
deceptive.design · FTC 2022 · EU DSA Art. 25
↳ Use neutral copy — “No thanks” — and sell the offer on its value, not shame.
06
Evaluator 06 / 06

Design Library

Your registered libraries · matched by name & canonical size
  • Matches every instance against the components you've imported
  • Spots detached instances, unregistered components and ±2px size drift
  • Reports overall library coverage — how system-built the screen really is
4 rules · only when a library is active
produces →
errorlibrary-detached-instance
A frame matches “Card / Default” but is no longer an instance
name match · not linked · won't receive library updates
↳ Restore the component so it tracks the system, or document the detach.
Stage 05 · Optional

A second
opinion.

When you enable it, multiple AI providers analyse the same screenshot in parallel via Promise.allSettled. interpretAIResults clusters their findings, dedupes across providers, and blends them in consensus-weighted and capped — AI nudges the score, it never dominates it.

  • One screenshot, shared across every provider
  • Keys live in clientStorage — they never leave your machine
  • A provider error never aborts the audit — rule results still stand
providers · parallel
Anthropicvision
OpenAIvision
interpretAIResults() → 6 raw → 3 merged · deduped
Stage 06 · runAudit()

Score & grade.

0
GRADE —

Each category gets a damped-sigmoid penalty — errors weigh more than warnings, warnings more than infos — then the overall score is a weighted blend, and a letter grade.

  • Contrast30%
  • Layout20%
  • Typography20%
  • Heuristics20%
  • Color10%
scoring/score.ts · a library shifts these ×0.9 + 10%
Stage 07 · The deliverable

What you get back.

The finished AuditResult renders as a dashboard — a score ring and grade, a card per principle, the top priorities, the inferred-context chip, and a score delta versus the last run of the same target.

Contrast72
2 errors2 warn
Layout80
1 error2 warn
Typography85
2 warn1 info
Heuristics74
1 error4 warn
Color90
1 warn
Library88
1 error1 info
per-principle issues with one-click fixes export JSON / PDF Add to Figma → numbered annotations history & score trend
Finale · Attention Engine v2

Where the eye goes.

  • 1
    Capture & tile the frame
    Screenshot the frame and slice it into device-sized tiles — the raw pixels the model reads.
    engine/capture.ts
  • 2
    Neural saliency model
    A saliency net (WebGL, WASM fallback) predicts each tile, stitched into one bottom-up "where the eye lands" grid.
    engine/model.ts
  • 3
    Semantic channels + priors
    Faces & text pull gaze on their own; reading follows an F-pattern with above-the-fold decay. Each becomes a grid.
    semantic.ts · priors.ts
  • 4
    Fuse the channels
    Normalized, blended with screen-family weights, fovea-blurred and percentile-normalized so no magnet flattens the map.
    engine/fusion.ts
  • 5
    Build outputs
    A heat grid, ranked areas of interest, a deterministic scanpath, and a focus score fall out of the fused grid.
    engine/outputs.ts
  • 6
    Render on canvas
    Underlay, colour-ramped heat, AOI boxes, numbered scanpath and the top attention magnets — deterministic, same frame → same map.
    ui · AttentionView
0/100
Focus score
0%
First-fold share
That's Veris.

One frame, read end to end — extracted, contextualised, measured by six evaluators and 90 rules at once, optionally weighed against AI, scored, graded, and handed back as something you can act on. And when you want to know where attention actually lands, the engine draws that too.

WCAG 2.2 Nielsen · Laws of UX deterministic & self-contained your keys, your machine