ux-skill 4.0, Foundations: one brand color in, a design system out.
Give it your brand color and a short brief. ux-skill 4.0 works out a whole design system from them, measures every color pairing against WCAG in light, dark and high contrast, and writes the files only when every pairing passes. If you already have a system, it reads that one in its own names and extends it instead.
What 4.0 is
Earlier releases handed an AI coding tool a recommendation: a style, a palette, a type pair, the rules to hold. 4.0 hands it a system: the tokens, the roles that bind them, the contracts components and sections follow, and a report that says in plain words what was built and why. One command does it:
# one brand color in, a checked design system out
pip install --upgrade uxskill
uxskill system build --brand '#0E7490' --out design-system
On that exact command the build prints WCAG gate passed: 1308 checks, 0 failing, and the report notes that the button keeps the brand color exactly, with white text at 5.35:1. Add --brief with the file /ux-discover writes and the look follows the brief as well as the color. The same inputs give the same bytes; no model is called.
A build writes six things: tokens.css to link from your pages, tokens.json in the W3C design tokens format (DTCG), fonts.css with metric-matched fallbacks, fonts-self-host.css for faces served from your own files, decorative brand art in art/, and system-report.md.
Nine foundations
Each foundation runs from primitives (a scale, a ramp) to semantic roles your markup uses, such as --color-action-primary, --space-control-gap or --motion-state-duration:
- Color. Scales and roles from your brand color, including six category colors for nominal data, each with a soft fill, a strong tone, text, and text on the strong tone.
- Type. Display, text and mono faces plus an Arabic face with its own sizes and line height.
- Space. One scale for gaps and padding, in comfortable and compact density.
- Layout. Container, margins, reading width and the gap between sections.
- Radius. One value per kind of part, from sharp to round.
- Border. Line widths, control edges and a focus ring.
- Elevation. Shadows and surfaces that keep depth readable in dark mode.
- Motion. Timing and curves for state changes, presses and arrivals, still under reduced motion.
- Imagery. A photo direction every picture on the page shares: light, temperature, grain and framing, locked to one grade.
Seven axes shape the look (warmth, contrast, density, geometry, formality, motion and type personality), each a value from 0 to 1. Every look is a continuous function of the axes, the brand and the brief; no industry or keyword picks one.
Five mode axes, one set of roles
Every role carries a value for each mode, so a page switches with one attribute on <html> instead of a second stylesheet:
- light and dark
- standard and high contrast
- comfortable and compact spacing
- left to right and right to left
- full and reduced motion
Under dir="rtl" text switches to the Arabic face and its type scale, spacing follows logical properties and motion mirrors. There is no second system to keep in step. --latin-only leaves the Arabic face out.
Checked before it is written
The gate measures every text, control and focus color pairing in light and dark, at standard and high contrast. At standard contrast it holds text to 4.5:1, the level WCAG 1.4.3 (Contrast, Minimum) sets for text that is not large-scale, and control edges, focus rings and other parts you need to see to 3:1, the level WCAG 1.4.11 (Non-text Contrast) sets for user interface components and graphical objects. In high contrast it raises text to 7:1, the level WCAG 1.4.6 (Contrast, Enhanced) sets for text that is not large-scale. WCAG sets no enhanced level for non-text parts, so the 4.5:1 floor the gate holds them to in high contrast is ux-skill's own.
If one pairing falls short in any mode, nothing is written. The message names the pairing, the mode and what to change.
Reading and extending the system you have
Most teams are not starting from nothing. 4.0 reads an existing system in its own names: DTCG tokens, CSS custom properties, a Tailwind 4 theme or a resolved Tailwind 3 config, Markdown rule files, and Figma variables exports. An importer never guesses. It reads a value, or lists the entry under Not read with how to write it.
# what is there, and what it lacks uxskill system detect uxskill system import --from tokens.css uxskill system enhance --from DESIGN.md --out design-system # add what is missing, beside the source, never over it uxskill system extend --from tokens.css --add motion
enhance measures the system through the same gate, and with --scan the code that uses it; it changes nothing. extend adds foundations, roles or contracts in an extension file next to the source and never overwrites a token you have.
Exports
uxskill system export writes a system as tokens.css, a Tailwind 4 theme, Figma variables (with the script that applies them in a Figma file) or tokens.json, into the folder you name and never over its source. Every write goes through an intake step that backs up your files byte for byte.
uxskill system export --from design-system/tokens.json --to tailwind --out exports
Contracts for components and sections
23 component contracts say which role each part of a control binds in every state and how each state moves: a change of state transitions on motion.state, a press scales on motion.press.scale and holds still under reduced motion, and tabs, menus and segmented controls slide one indicator. 14 section contracts (hero, pricing, FAQ, footer and the rest) name each section's job, the components its slots take, the proof it needs and how it recomposes on a phone. Pages built from them use photographs; interface fragments are extra imagery, never a replacement.
The linter reads the page
The linter ships 171 rules, and in 4.0 it reads the page's own system: a weight, size or duration your tokens define passes, motion is timed from its declared curve, and a display line height is held to the engine's floor. uxskill lint --render opens each page in headless Chromium at desktop and phone width and drives it: focus rings that do not show or are clipped, hover and press that answer late, focus lost after Escape, a press that still moves under reduced motion, the color budget and the photo grade lock.
uxskill lint index.html --render
Fewer commands
25 slash commands become 18, and each merged command keeps every step and flag of the ones it absorbed: /ux-discover takes --frame and --recommend, /ux-design takes --component, --dashboard and --from-image, /ux-polish loops lint, fix and re-lint until the score reaches 90 or three rounds pass, and /ux-init takes --stats. The seven old names still run as aliases that say where they moved; they are removed in 4.1.
What it took, and what came back
None of this was tracked as it happened, so these are estimates, and the method behind each one is written down.
- Time: about 600 hours, somewhere between 400 and 800, from the first release on 22 May to 4.0 on 1 November. Git shows only the part after June, because the early history was squashed; the rest is counted from the release log, 44 changelog entries in five months, which cover about a hundred builds in the last week of May.
- Money: about $1,400 over six months: two AI coding subscriptions, a self-hosted model router, a small server and the domain. The site, the package registries and the CI run free.
- What it is now: 17 tagged releases, 13,101 passing tests, 171 lint rules and 25 MCP tools, MIT licensed and free.
- What came back so far: 537 installs from npm between 27 May and 29 October, and 230 from PyPI in the last month alone. And a working design engine that builds the pages it was made to judge, this site included.
How to upgrade
4.0 needs Python 3.10 or newer. Then:
pip install --upgrade uxskill # for the MCP server pip install --upgrade 'uxskill[mcp]' # or, with Node npx uxskill@latest
With pipx over an installed 3.x, run pipx upgrade uxskill. To stay on 3.x on purpose, pin pip install 'uxskill<4'; on Python 3.9, pip keeps installing 3.2.x, which still works.
The 3.x outputs (the tokens.css that ux generate wrote, and the DESIGN.md and tokens.css of a system pack) are replaced by the files above. Nothing is rewritten for you. The guide to moving from 3.x to 4.0 gives two paths:
- Build a new system and move the page onto its roles. Link
fonts.cssand thentokens.csswhere the 3.xtokens.csswas linked, and replace each 3.x custom property with its role:--color-canvasis--color-surface-page,--color-primaryis--color-action-primary,--space-mdis--space-4,--motion-baseis--motion-state-duration. The guide has the full table. Then runuxskill lintwith--renderand fix what it reports. - Keep your 3.x system and extend it.
uxskill system import --from DESIGN.mdreads it as it is,system enhancereports what it lacks and how to add it, andsystem extendadds the missing foundations, roles or contracts beside it.
The engine sets the rails; your AI tool still writes the markup.
A vague brief still gives a neutral system: with no brief or axes every axis sits at 0.5, and the report says so. The gate measures contrast, sizes, widths and durations; it does not judge whether a layout is good. That is what the render checks, the contracts and your own eye are for.
The full list of what changed is in the changelog.