04 · Craft: 12 brand-agnostic rules
A design system decides what it looks like. Craft decides what counts as acceptable.
Those are two different things, and OpenDesign separating them is right: changing brands shouldn't move the accessibility floor, and choosing a striking visual style shouldn't cost the button its disabled state.
How it works
A skill declares which craft rules it needs in its frontmatter. Loading the skill loads those rule files into the system prompt.
Quality constraints therefore travel with capability, and you don't restate them per prompt. You write "a landing page" and accessibility, state coverage, and typographic hierarchy come along.
The twelve
| # | Name | What it governs |
|---|---|---|
| 01 | Accessibility baseline | The legal floor, plus the craft commitments beyond it |
| 02 | Animation discipline | Whether motion earns its place, and the numbers that bound it |
| 03 | Anti-AI-slop rules | Concrete rules separating "shipped by a human" from "default LLM output" |
| 04 | Color | How to use the palette the design system supplies |
| 05 | Editorial typography hierarchy | Hierarchy for long-form articles, magazine layouts, editorial pages |
| 06 | Form validation | Validation lifecycle, error wiring for assistive tech, where the rule lives |
| 07 | Future Craft Sections | A register of slugs skills already reference before the rule files ship |
| 08 | Laws of UX | Research-grounded cognitive and behavioural heuristics that decide composition |
| 09 | RTL and bidirectional | Right-to-left layout, and mixed direction within a line |
| 10 | State coverage | Which states every interactive surface must render |
| 11 | Typography | Universal type rules on top of any design system |
| 12 | Typography hierarchy | How hierarchy is established, broken, and when breaking is allowed |
Number 07 isn't a rule
"Future Craft Sections" is a register: skills already declare dependencies on rules whose files don't exist yet. pnpm lint:craft treats those as planned forward references while still failing on unregistered typos. It's in the catalog so the arrangement stays visible rather than implicit.
The three that bite most often
State coverage
The official phrasing is worth keeping: the single most reliable AI-design failure is shipping only the populated state.
Generate a list view and you get a handsome list full of data. What about empty? Loading? Errored? One item? A thousand?
This rule requires the states to be written. Use it as your acceptance list too:
- [ ] Empty (with a way forward)
- [ ] Loading
- [ ] Error (saying how to recover)
- [ ] Minimal data (one item)
- [ ] Heavy data (pagination or virtualisation?)
- [ ] Unauthorised
Anti-AI-slop
This one is unusual: some of its rules are auto-enforced by the daemon's lint-artifact linter. Failing an enforced rule is a regression, not a style preference.
The rest are guidance for agents and reviewers, and the file marks them inline as "(guidance, not auto-checked)". Stating the boundary out loud is more useful than claiming everything is checked — you know what to rely on and what to inspect.
See 05 · Anti-slop.
Animation discipline
The design system decides motion's personality; this rule decides whether motion runs at all, plus duration, easing, and the accessibility floor.
The floor is the part most often forgotten: prefers-reduced-motion must be honoured. If a user has turned motion off at the OS level, your page doesn't move. That isn't a preference.
Declaring craft in your skills
In SKILL.md frontmatter:
---
name: your-skill
craft: [accessibility-baseline, state-coverage, typography-hierarchy, color]
---Which ones depends on what the skill produces:
| Producing | Declare |
|---|---|
| Interactive interfaces | accessibility-baseline, state-coverage, form-validation, laws-of-ux |
| Landing pages | accessibility-baseline, typography-hierarchy, color, animation-discipline |
| Long-form / editorial | typography, typography-hierarchy-editorial, color |
| Decks | typography-hierarchy, color, animation-discipline |
| Anything international | add rtl-and-bidi |
Invoking it by hand
Without a skill, reference it in the prompt:
Bring this version up to state coverage: empty, loading, error, single
item, and heavy data — each with its own rendering. Don't ship only the
populated state.
Then self-check against the anti-AI-slop rules, list what you hit, and
fix it.Useful at acceptance time. Running it after generation surfaces a set of problems you've already stopped seeing.
Related
- 05 · Anti-slop — how the three gates fit together
- 01 · Skills — where the craft declaration goes
- The official catalog: open-design.ai/craft