/ordinary-interfaces
An agent skill for building and auditing UI. Every rule states a value, cites where that value came from, and says where it stops applying.
Ordinary is the goal, and it is not the same as generic. An ordinary interface is unremarkable in use. It behaves the way people already expect, its hit areas are where fingers go, its errors appear where the user is looking. Generic is the other failure: the same cream-and-terracotta palette on every brief, because nothing was decided.
In Claude Code: /plugin marketplace add Board-ly/ordinary-interfaces
Commands
The skill loads itself when a task calls for it. These run one part of it on demand, so a contrast check does not pull in 180 rules. None of them auto-load.
read-project[path]
Reads what your codebase already decided about tokens, scales, colour notation and motion, so a review adopts your system instead of overwriting it.
accessibility[file or path]
The seven floors only: contrast, colour, hit areas, alt text, focus, motion, reflow. Pass, fail or unverified, and one verdict.
review[file, component, screenshot]
The full review, ordered critical to low. Every finding carries a rule id, the measured value and the fix.
new-screen[what you are building]
The workflow for building. Adopt the system, let the floors constrain the space, greyscale first, hardest state first.
contrast<fg> <bg> [--fix]
Measures a pair against WCAG and reports the ratio. --fix returns the nearest passing foreground, hue kept.
find-rule[rule-id or topic]
One rule by id or topic: the value, its evidence grade, and where it stops applying.
Evidence
Design advice stops being trustworthy the moment a convention gets repeated as a law. So each value is graded, and the grade travels with it into whatever the skill tells you.
Normative. WCAG 2.2, ISO, OpenType. Stated as required, never hedged.25 rules
From a study, carrying its sample size where that matters, cited to the primary source rather than to someone's summary of it.40 rules
Industry practice with no primary source. The 8pt grid lives here. Useful, well reasoned, and not a fact.36 rules
Gates
Accessibility floors with legal weight in most jurisdictions. They constrain the solution space before anything gets drawn.
wcag-contrast Contrast Ratiored-green-color-blindness Never Color Alonetouch-target Size the Hit Area, Not the Glyphwcag-images Equivalent Purpose, Not Descriptionwcag-motion Flashing and Vestibular Safetyreduced-motion Gentler, Not Absentnative-elements-first Don't Rebuild What Shipsfocus-visible Style the Right Pseudo-Classkeyboard-patterns Follow the APGalt-by-purpose Describe the Job, Not the PictureShape of a rule
One schema throughout: what to do, the values, why it holds and who established it, where it stops applying, and the code.
concentric-radiusOuter Equals Inner Plus PaddingouterRadius = innerRadius + paddingempty-statesEmpty Is Three StatesAll three render zero rows, which is why they get one screen. That screen is wrong for two of them.
animation-necessityAsk Whether, Before Asking WhichFrequency decides. The first question is never the easing curve.
padding-gap-ratioPadding Exceeds the GapContainer padding ≥ 1.5× the gap to its siblings, at every nesting level.
default-effectPreselection PersistsDefaults are a design decision with a legal boundary.
Before and after
Live, not screenshots. Every pane below is the rule applied to real markup, so it renders in your theme and cannot drift from what the rule says.
concentric-radiusOuter Equals Inner Plus PaddingouterRadius = innerRadius + padding
outer 12px · inner 12 + padding 8 = 20breaks the rule
padding-gap-ratioPadding Exceeds the GapContainer padding ≥ 1.5× the gap to its siblings, at every nesting level.
padding 16px · gap 16px · 1× the gapbreaks the rule
icon-optical-balanceCentre by Mass, Not by BoxOffset 1–3px toward the lighter side. No formula covers every shape.
translateX(0) · centred on the box, not on the massbreaks the rule
icon-stroke-weightMatch the Adjacent TextIcon weight is a function of the label beside it, not an independent choice.
1.5px stroke beside a 700 labelbreaks the rule
wcag-contrastContrast RatioBody text clears 4.5:1 against what it actually renders on. Large text and any control that carries meaning clear 3:1.
#777777 on #ffffff · 4.48:1breaks the rule
touch-targetSize the Hit Area, Not the Glyph24×24 is the floor. 44×44 on touch and 40×40 on desktop is the target. Padding counts.
28×28px around a 16px glyphbreaks the rule
default-tellsRecognise Your Own DefaultsOrdinary is decided. Generic is undecided. They look different.
Invoice
Sent 12 March. Due 26 March. Studio Sphere has opened it twice.
Send a reminderordinary · this project's own tokenssatisfies the rule
dark-mode-color-adaptationThree Axes, Three JobsHold hue, cut chroma, raise tone until it measures. Never invert lightness and call it done.
hue held, tone moved until it measuressatisfies the rule
error-copySay How to Fix It, Where It BrokeAn error is an instruction, and it belongs beside the field that failed.
beside the field, stays, says what to dosatisfies the rule
never-scale-zeroNothing Appears From NothingStart at scale(0.95) with opacity: 0.
from 0.95 and opacity 0, 180ms ease-outsatisfies the rule
Step 0
A 7px radius in a system built on 7px is correct, and "should be 8px per the grid" is noise. So the skill looks first. A finding is this breaks the project's own system before it is this differs from the reference.
$ python3 scripts/project-system.py . Tokens (159 custom properties across 6 files) families: color (37×), ink (5×), font (5×), radius (5×), ease (4×) Scales radius: 999px (13×), 7px (10×), 10px (8×), 6px (6×), 4px (6×) spacing: 10px (10×), 6px (10×), 4px (10×), 7px (7×), 14px (6×) breakpoints: 720px (2×), 880px, 1160px, 900px, 560px, 40rem, 48rem Colour notation hex 343 (72%) oklch 130 (27%) → Mixed notation. Match the dominant one (hex). Flags ✓ :focus-visible ✓ prefers-reduced-motion ✓ tabular-nums 67× fixed height on text 1× outline: none
Contents
Routed, not dumped. The skill loads only the file the task touches. A fifteenth file below sits outside the UI focus and is kept as an appendix.
Contrast, ramps, tokens, dark mode, gradient interpolation.
wcag-contrastred-green-color-blindnessdark-mode-color-adaptationluminance-vs-lightnesscielab-color-spaceramp-structureramp-constructioncolor-namingtoken-role-disciplineone-color-one-meaningfill-one-actioncolor-scalegreyscale60-30-10color-temperature-dominancesaturation-controlsimultaneous-contrastcolor-constancycolor-psychologygradient-interpolationrgb-vs-cmykScale, measure, leading, weight floors, wrapping, web font delivery.
type-hierarchyline-lengthline-heightthree-line-leadingtext-alignmentfont-weight-contrastweight-size-floorx-heightfont-pairingwcag-typographytext-wrapletter-spacing-by-sizeall-caps-fatigueios-input-zoomvariable-fontstypeface-vs-fontfont-synthesiscss-properties-over-tagssmart-punctuationunderline-metricssmall-capsligaturesfont-smoothingProximity, the padding-to-gap rule, grids, breakpoints, translation growth.
proximitypadding-gap-ratiogroup-with-space8pt-grid4pt-systembaseline-gridactive-white-spacecontrols-distinctalign-to-shared-edgesprogressive-disclosure-cuecontent-breakpointstranslation-growthcontent-bleeds-controls-floatmanuscript-gridtwelve-column-gridmodular-gridwcag-layoutHit areas, the six button states, links, form and navigation criteria.
touch-targetbutton-designbutton-paddinglink-designwcag-formswcag-navigationwcag-imageswcag-motionConcentric radius, shadow-as-border, image outlines, press feedback.
concentric-radiusshadow-as-borderimage-outlinespress-scaletheme-switch-suppressionElevation, borders, depth strategy, tokens, recognising your own defaults.
surface-elevationborder-disciplinedepth-strategytoken-architectureinteractive-statestabular-numeralsicon-restraintdefault-tellsLight direction, elevation scale, stroke matching, optical centring, RTL.
shadow-fundamentalselevation-systemraised-vs-inseticon-stroke-weighticon-bounding-boxicon-optical-balanceicon-alignmenticon-color-statesicon-render-sizeicons-rtlWhether to animate at all, duration, easing, springs, gestures, reduced motion.
animation-necessityanimation-durationeasing-curvesenter-exit-asymmetrysubtle-exitnever-scale-zerotransform-originstaggerstaged-entericon-transitionsspring-physicsgesture-physicsanimation-performancetransition-specificitywill-change-disciplinehover-gatingmotion-restraintreduced-motionseam-principlereveal-choreographystate-transition-timingnumbers-in-motionThe ledger, three empty states, loading guards, error taxonomy, rollback.
state-ledgerempty-statesloading-strategypartial-dataerror-taxonomyoptimistic-rollbackoverflow-pressureoffline-stalepermission-statesend-of-listNative elements, focus-visible, keyboard patterns, live regions, alt text.
native-elements-firstfocus-visiblekeyboard-patternsfocus-traphit-area-extensionform-controlserror-announcementlive-regionsalt-by-purposeVoice, vocabulary, button labels, errors, empty states, capitalisation.
voice-and-toneconsistent-vocabularyverb-first-buttonslink-texterror-copyempty-state-copytoggle-labelscapitalization-policyno-string-concatenationEmphasis, visual weight, framing heuristics, chart encoding.
emphasisvisual-weighthierarchy-channelsrule-of-thirdsgolden-ratiorule-of-oddscorner-radius-tonepie-chart-problemhandmade-vs-polishedChoice cost, memory, attention, defaults, and the numbers people quote wrong.
jakobs-lawmillers-lawchunkinghicks-lawsubitizingvon-restorff-effectbanner-blindnessinattentional-blindnessdefault-effectdecoy-effectpeak-end-rulepicture-superioritystroop-effectreward-anticipationebbinghaus-illusionoptical-centercenter-biasmuller-lyer-illusionirradiation-illusionbouba-kiki-effectBrand assets, photography, physical scale, print. Outside the UI focus.
viewing-distancevisual-angle-arcminutesaspect-ratioslogo-clearspacelogo-variationsjoint-croppingdieline-bleedcmyk-vs-pantoneiso-216