12 KiB
Design System Introduction
How
whynot-designfits into the broaderwhynotworkflow — from atelier exploration to production deploys.Audience: anyone (human or agent) about to add
whynot-designas a dependency, or contribute changes back to it.
1. Mental model — three places, three jobs
whynot-design is one of three surfaces. Each has a different job. Don't confuse them.
| Place | Job | What lives there |
|---|---|---|
Claude atelier project (WhyNot Design System template) |
Explore, decide, mock | HTML cards, UI-kit JSX prototypes, the README that defines the rules. Source of truth for the language of the system. |
whynot-design repo (this one) |
Distribute | A versioned, publishable package: CSS tokens, components, the logo bundle. Source of truth for the artefact. |
whynot-* consuming repos (apps, prototypes, marketing sites) |
Use | pnpm add @whynot/design, import tokens + components, build the app. |
This mirrors the existing organisational logic. whynot-control is the control surface (intent, scope, decisions, governance). whynot-design is the implementation surface for the visual language. Same separation, same vocabulary.
The Claude-Design template is the atelier for the next design exploration — mocking a new screen, a beta landing page, a signal-record view. It is not what production code consumes. Production consumes this repo.
2. What this repo contains
whynot-design/
├── README.md Quick start + manifest.
├── DesignSystemIntroduction.md This file.
├── SKILL.md Agent Skill manifest — also usable by Claude Code.
├── CONTRIBUTING.md How to propose, review, and ship a change.
├── CHANGELOG.md Hand-edited, one entry per release.
├── package.json Name: @whynot/design.
│
├── tokens/ Source-of-truth design tokens (JSON).
│ ├── colors.json
│ ├── type.json
│ └── spacing.json
│
├── src/
│ ├── styles/
│ │ └── colors_and_type.css Drop-in CSS variables + semantic element styles.
│ ├── components/ JSX, consumed from source (no build step at A1).
│ └── index.js Barrel export.
│
├── assets/ Logo, favicon-ready marks, future imagery.
├── examples/
│ └── whynot-control/ Working UI-kit recreation — also the visual-regression target.
└── .gitea/workflows/
└── ci.yml Lint + Playwright screenshot diff on PR.
There is intentionally no build step. Consumers import the JSX and CSS directly. This keeps the A1 pipeline trivially debuggable. Add a build step when the system grows past ~30 components or needs to support non-React consumers.
3. Integrating with a consuming codebase
3.1 The two viable distribution channels at A1
In order of effort:
a) pnpm workspaces (recommended for now) — put whynot-design and your consuming app in the same monorepo (or use file: / link: references). Zero registry, zero auth, instant updates.
// consuming-app/package.json
{
"dependencies": {
"@whynot/design": "workspace:*"
}
}
b) Install directly from Gitea — no registry needed.
pnpm add git+ssh://git@gitea.example.com/whynot/whynot-design.git#v0.3.1
Pin to a tag, not main. Tag-pinning is the entire versioning discipline at A1.
When you outgrow either of these (a second team needs read access without repo cloning, or you want semver resolution), publish to Gitea Packages (supports npm protocol natively) or set up a private Verdaccio.
3.2 What a consumer imports
// At the root of the consuming app — once.
import "@whynot/design/styles/colors_and_type.css";
// In any component file.
import { Button, Tag, PrototypeCard, Eyebrow } from "@whynot/design";
export default function NewBetaPage() {
return (
<article>
<Eyebrow>whynot · closed beta</Eyebrow>
<h1>Concierge prototype triage</h1>
<p className="lead">Five seats. Two weeks. One learning question.</p>
<Button variant="primary">Request an invite</Button>
</article>
);
}
Three rules of consumption:
- Import the CSS exactly once, at the app's root.
- Use CSS variables for any colour, type, or spacing decision, not hex codes. If the token doesn't exist, that's a signal to extend the system — not to invent.
- Don't restyle components by overriding their CSS. If a component doesn't fit a use case, add a variant in
whynot-designitself. The discipline that makes a design system valuable is the discipline of not forking it locally.
3.3 Bootstrapping a new consuming repo
mkdir whynot-prototype-WNO-022
cd whynot-prototype-WNO-022
pnpm init
pnpm add react react-dom
pnpm add git+ssh://git@gitea.example.com/whynot/whynot-design.git#v0.1.0
echo 'import "@whynot/design/styles/colors_and_type.css"' >> src/main.jsx
That's the whole onboarding. If it takes longer than this, the design system is fighting you.
4. Propagation pipeline — five hops
The end-to-end flow for a single design change:
[Claude atelier] [whynot-design] [Consuming repo] [Deploy]
explore variants ──► PR with token / ──► Renovate / pnpm ──► staging
in the template component change up opens PR bumping
user approves + Playwright diff @whynot/design │
+ CHANGELOG entry ▼
│ │ prod
tag v0.3.1 CI runs visual
CI publishes / regression on the
attaches release consuming app
asset │
│ merge if green
└──────────────────────────────┘
Hop-by-hop
-
Atelier →
whynot-designPR. Someone (you, a designer, or an agent) takes a change agreed in the Claude project — "the prototype card's hover bar is 3px not 2px" — and opens a PR againstwhynot-design. The PR description quotes the atelier decision, e.g. "Decided in atelier 2026-04-12: thicker hover bar reads better at 14” preview sizes." -
whynot-designCI runs:- Lint + (optional) typecheck.
- Visual regression — Playwright screenshots
examples/whynot-control/index.htmland any other registered example, diffs against baselines. This is the single most valuable piece of automation; everything else is bookkeeping. - A
CHANGELOG.mdentry is required (enforce with a small CI check, or usechangesetsonce you outgrow hand-editing).
-
Merge → tag → publish. On merge to
main:- Bump
package.json(patch for token tweaks, minor for new components, major for renames/removals). - Tag
v0.3.1. - Push tag. CI uploads release notes from the CHANGELOG. (Once a registry is in use, this step also runs
npm publish.)
- Bump
-
Consumer auto-PR. Renovate or Dependabot watches
@whynot/designand opens a PR in every consuming repo bumping the version. Renovate config groups these so allwhynot-*prototypes update on the same schedule (e.g. weekly). -
Consumer CI + deploy. The consuming repo's own CI runs its visual regression — does the new token change anything in this app's screens? If not, auto-merge (Renovate can do this for patch versions with green CI). If yes, a human reviews. Merge triggers the existing deploy to staging → prod.
The whole loop, warm, takes minutes. The key insight: automation works only because every step has a deterministic check — visual regression on the design-system side, visual regression on the consumer side, semver, changelogs. Skip those and the "pipeline" is a slow manual process with extra tools.
5. Versioning discipline
Strict semver, even at A1.
| Change | Bump |
|---|---|
| Token value tweak that doesn't visibly break any existing example | patch — 0.1.0 → 0.1.1 |
| New component, new variant, new token | minor — 0.1.1 → 0.2.0 |
| Removing / renaming a component, prop, or token; changing default behaviour | major — 0.2.0 → 1.0.0 |
Stay in 0.x.x until something is in production. While in 0.x.x, minor bumps are allowed to break things — that's the convention. This gives you permission to iterate without ceremony.
Promotion past 1.0.0 should appear in whynot-control/DECISIONS.md. Same rule as promotion to Helix or Coulomb: it's a deliberate act, not a release-script side-effect.
6. Where Claude fits
Two distinct roles, both useful:
-
The Claude atelier template — used at hop 1. Designer (or you) opens a new project from the template, mocks variations, decides, hands off a PR description + diff to whoever (or whatever) writes the
whynot-designPR. The atelier never publishes anything to production directly. -
Claude Code with
SKILL.md— used at hop 1 and hop 5. The same SKILL file works in both contexts:- Pointed at
whynot-design, Claude Code knows the rules and can write component PRs. - Pointed at a consuming repo, Claude Code knows the rules and can build screens that respect them.
- Pointed at
That's why SKILL.md ships with this repo. Drop it into .claude/skills/ of any consuming repo (or copy its contents into a project-level CLAUDE.md) and any agent operating in that repo will know the visual language.
7. Pragmatic A1 staging — don't build the whole pipeline yet
Right now, whynot is at A1 Incubating with one or two prototype apps in flight. Build the smallest pipeline that still has the right shape. Promote each piece only when a real signal demands it.
| Hop | A1 version | Promote to full when… |
|---|---|---|
| Atelier | Claude template, as-is. | Never — stays here. |
whynot-design repo |
This seed. CSS + JSX consumed from source. No build step. | Second non-React consumer appears, or bundle size becomes a measurable problem. |
| Distribution | pnpm workspace, or git+ssh install from tags. |
An external collaborator needs read access without cloning. |
| Visual regression | One Playwright test screenshotting examples/whynot-control/index.html. |
The system has >20 components or >2 consuming apps. |
| Dependency updates | Manual pnpm up once a week. |
More than two consuming repos. |
| Release notes | Hand-edited CHANGELOG.md. |
More than two contributors, or releases become weekly. |
| Component-level visual coverage | One screenshot of the whole UI kit. | The system has >20 components. |
This staging is exactly the "low-cost learning first" posture in whynot-control/OPERATING_MODEL.md. A design system with one consumer and one author does not need Chromatic. A design system with five consumers and three authors absolutely does. Don't pay the cost of the second one until you're in it.
8. First-week checklist
For whoever is bootstrapping this repo right now:
- Push the seed contents to
gitea.example.com/whynot/whynot-design. - Tag
v0.1.0immediately so consumers can pin. - Add the repo as a remote dependency in one consuming app and verify imports work.
- Open one trivial PR against
whynot-design(e.g. a CHANGELOG typo) to confirm CI passes end-to-end. - Record this bootstrap in
whynot-control/DECISIONS.mdas DEC-004 or similar — "Established whynot-design as the implementation surface for the visual language." - Update
whynot-control/SCOPE.mdto mentionwhynot-designin the out-of-scope list (it's a sibling, not absorbed scope).
That's it. Anything more is over-engineering for the current stage.
A design system can be interesting and still be parked.
whynot-designexists to reduce visual uncertainty across prototypes, not to create more obligations.