Files
whynot-design/README.md
tegwick 9419f166ce
Some checks failed
ci / check (push) Has been cancelled
ci / release (push) Has been cancelled
Seeded claude design
2026-05-23 16:34:14 +02:00

289 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# @whynot/design
The neutral, mostly-black-and-white visual language for **whynot** — Tegwick's prototype and market-signal organisation. Wireframe-leaning. Quiet. Built for artefacts that should look deliberately unfinished.
> A prototype is a question made tangible. — `whynot-control/INTENT.md`
This repository is the **implementation surface**. The *language* of the system — voice, casing, motifs, the reasoning behind each rule — lives in this README. The *artefact* — the CSS, the components, the assets — lives in `src/` and `assets/`.
If you're new here, read these in order:
1. **`DesignSystemIntroduction.md`** — how this repo relates to `whynot-control`, the Claude atelier, and consuming apps. Pipeline, versioning, propagation.
2. **`SKILL.md`** — the Agent Skill manifest. Read this if you (or an agent) will be generating new artefacts in this style.
3. **This README** — the full design language: tokens, components, content rules, iconography.
4. **`CONTRIBUTING.md`** — how to propose, review, and ship a change.
## Quick start
```sh
# in a consuming repo
pnpm add git+ssh://git@gitea.example.com/whynot/whynot-design.git#v0.1.0
```
```jsx
// at the app root, once
import "@whynot/design/styles/colors_and_type.css";
// anywhere
import { Button, Tag, Eyebrow, StageDot } from "@whynot/design";
```
## What lives where
| Path | Contents |
|---|---|
| `tokens/` | Source-of-truth design tokens as JSON. |
| `src/styles/colors_and_type.css` | All CSS variables + semantic element styles. The single file every consumer imports. |
| `src/components/` | React components (JSX, no build step). |
| `src/index.js` | Barrel export. |
| `assets/` | Logo, mark, future imagery. |
| `examples/whynot-control/` | Live click-through UI kit. Also the Playwright visual-regression target. |
---
> The remainder of this README is the full design language — colour reasoning, type stack, content rules, iconography. It is identical to the language defined in the Claude atelier project and should stay in sync. Treat it as authoritative.
## CONTENT FUNDAMENTALS
### Voice
The voice is **quiet, structured, evidence-oriented, and careful about overclaiming**. It comes directly out of the `AGENT_RULES.md` and `OPERATING_MODEL.md`:
> Agent outputs should be concise, evidence-oriented, explicit about uncertainty, and careful to separate idea, hypothesis, signal, and decision.
>
> — `whynot-control/AGENT_RULES.md`
The voice should sound like a careful field-notebook — not a startup landing page, not a product manifesto, not marketing copy.
### Casing
- **Sentence case** for headings, buttons, labels, links — *not* Title Case. ("Smallest useful test", not "Smallest Useful Test".)
- **lowercase** for the organization name in body: `whynot`, never `WhyNot` or `WHYNOT`. The logo wordmark may use `WhyWhyNot` for legacy reasons.
- **UPPERCASE** is reserved for short eyebrow labels (`PROTOTYPE`, `SIGNAL S2`, `STAGE`, `IN BETA`) — set in mono, with letterspacing.
- **`code-case`** for repo names, doc names, folder names: `whynot-control`, `INTENT.md`, `inbox/`. Always in monospace.
### Person
**Third person, with the project as subject.** Avoid "we", avoid "you", avoid "I".
- ✅ "A prototype is a question made tangible."
- ✅ "The repository helps the user capture unusual but potentially useful ideas."
- ❌ "We help you discover weird ideas."
- ❌ "You'll love how easy this is."
Direct second-person is reserved for *imperatives in a checklist* (e.g. "Read `INTENT.md`.").
### Tone
- **Curious, not enthusiastic.** "This may be worth a closer look" beats "🚀 huge if true!".
- **Hedged, not promotional.** Use *may*, *could*, *seems*, *appears to*. Avoid *will*, *guaranteed*, *the best*.
- **Distinguish idea / hypothesis / signal / decision.** Never collapse them.
- **Lack of signal is also information.** Silence is a finding, not a failure.
### Phrasing patterns to imitate
Lifted from the existing control documents:
- "A prototype is a question made tangible."
- "Signal beats enthusiasm."
- "Signals are evidence, not vibes."
- "Capture is not commitment."
- "Low-cost learning first."
- "A prototype can be interesting and still be parked."
The pattern is: **short declarative claim → small qualifier or counter-claim**. Two beats, no exclamation.
### Phrasing to avoid
- ❌ "Revolutionize…", "Reimagine…", "Unlock…", "Empower…"
- ❌ "🚀", "✨", "🔥", any other hype emoji.
- ❌ "We believe…", "We're on a mission to…"
- ❌ "Beta — sign up now!" (use "Closed beta. Invitation only.")
- ❌ Numbers without context ("10x faster"). Use signal-record format instead.
### Examples
| ❌ Avoid | ✅ Prefer |
|---|---|
| "Get started — it's free!" | "Inbox is open. Capture is not commitment." |
| "Our amazing new prototype" | "Prototype `WNO-014`. Stage: experiment." |
| "Users love it!" | "S2 — repeated interest, three concrete use-cases." |
| "Coming soon — sign up!" | "Closed beta. Five seats. Ends 2026-04-01." |
| "🎉 Launched!" | "Promoted to Helix on 2026-03-12. See `DECISIONS.md`." |
### Emoji & punctuation
- **No emoji** in body copy, headings, or UI.
- **`?` and `!`** are the brand's punctuation — they appear in the logo and may appear, sparingly, in display headlines (`try($idea) until success;`, `why? why not!`).
- **`→`** (U+2192) for "promotes to / goes to" links between stages. Not `->`.
- **`—`** (em dash) for parenthetical, not `--`.
---
## VISUAL FOUNDATIONS
### Overall posture
The system reads like **engineering graph paper** — precise hairlines, lots of whitespace, monospace labels in margins, content blocks that look like fields in a form rather than cards in a feed. The aesthetic is closer to a Bauhaus wall-chart or a `man` page than to a SaaS dashboard.
### Color
- **Mostly black on white**, with a few flat greys.
- **One accent only**: a warm yellow (`--hi: #FFE14A`) lifted from the LEGO brick in the logo. It appears as **highlighter / annotation / signal-marker** — never as a button fill, never as a hero background.
- **No gradients.** Anywhere. Including subtle ones.
- **No tinted whites** — `--paper` is a true `#FFFFFF`; `--paper-2` and `--paper-3` are barely-warm off-whites (`#FAFAF7`, `#F4F4EF`) reserved for sheets and recessed code blocks.
- Status colors (S0S4 signal strength) are **rendered as desaturated grey ramps**, not red/yellow/green. S4 ("commercial signal") is the only one that uses the yellow accent, because that's the threshold where a prototype actually matters commercially.
### Type
- **Family**: `IBM Plex Sans` for everything UI/body. `IBM Plex Mono` for labels, code, and stage markers. `IBM Plex Serif` for the occasional editorial pull-quote. (See font substitution note in *Fonts* below.)
- **Weights**: 300 (display only), 400 (body), 500 (UI / headings), 600 (occasional emphasis). Never 700+ — too marketing.
- **Tracking**: tight on display (`-0.035em`), neutral on body, **wide on uppercase labels** (`0.08em` — this is the one signature move).
- **Eyebrows everywhere**: short uppercase mono labels above titles (`STAGE`, `SIGNAL`, `PROTOTYPE`). They are the system's main rhythmic element.
### Spacing
- **4px base unit**, exposed as `--sp-1` (4) through `--sp-10` (128).
- Generous: a content block typically has `--sp-7` (48px) of internal padding. Lists separated by `--sp-5` (24px) minimum.
- **Section breaks are big** (`--sp-9`, 96px). Reads like a printed report.
### Backgrounds
- **`--paper` (#FFFFFF) by default.** Period.
- **`--paper-2`** for full-width "sheet" sections (e.g. between hero and content).
- **`--paper-3`** for recessed surfaces only — code blocks, inline pre, inset cards.
- **No images as backgrounds.** No hand-drawn illustrations. No repeating patterns. No textures. No noise. No grain. (Exception: a 1px hairline grid may be used on a literal "wireframe" mock; see `preview/grid-paper.html`.)
### Animation
- **Minimal.** This is a document system, not a product UI.
- Transitions on hover only: `120ms ease` on `text-decoration-color` for links, `border-color` for inputs.
- **No spring physics, no bounce, no fade-in-on-scroll.** Anything that draws attention is not in the spirit of "low-cost learning first".
- Exception: the cursor-blink animation on a `<TerminalLine>` is permitted because it's a literal terminal motif.
### Hover & press states
- **Links** — underline color goes from `--border-strong` to `--fg-1` on hover.
- **Buttons (primary, dark)** — `--ink``--ink-2` on hover. On press, no transform, just `--ink` (back to baseline).
- **Buttons (secondary, outline)** — border `--border``--ink`. On press, background flashes `--bg-3`.
- **Cards** — *do not have hover states.* They are documents, not interactive surfaces. Exception: prototype cards in an index list get a 1px black left border on hover.
- **No scale transforms**, no shadow lifts, no glow effects.
### Borders
- **1px solid `--border` (#E5E5E2)** is the default. Used everywhere.
- **`--border-strong` (#C9C9C5)** for section dividers and the outline of a primary block.
- **Hairline `--border-soft` (#F0F0EC)** for internal rules within a card.
- **No double borders, no inset borders, no dashed borders** except in one specific case: dashed `--border-strong` is used to indicate "placeholder / not yet defined" content (see Components / Empty State).
### Shadows
- **`--shadow-0`: none.** This is the default. Most cards and panels have no shadow.
- **`--shadow-1`: `0 1px 0 var(--line)`** — a 1px bottom-line, used in place of bottom-border on sticky headers.
- **`--shadow-2`: `0 1px 0 var(--line-strong)`** — slightly stronger version.
- **`--shadow-3`** is reserved for *floating* elements only (a popover, a focus-trapped modal). Even then it's a soft 4-12px diffuse shadow at 10% opacity — never a "card lift" shadow.
### Protection gradients vs capsules
- **No protection gradients.** Backgrounds are solid; never overlay a gradient to "rescue" text from a busy background, because backgrounds are never busy.
- **Capsules (pills with rounded ends)** are used only for `--label` and tag elements — never for buttons. Buttons are slightly rounded rectangles (`--r-2`, 4px).
### Layout rules
- **Single-column reading width** of ~640px for body, ~880px for documents with sidebars.
- **Constant page padding** of `--sp-7` (48px) on desktop, `--sp-4` (16px) on mobile.
- **Sticky element**: top navigation bar, height 56px, bottom hairline.
- **Sidebar (where used)**: 256px fixed width, `--paper-2` background, no border on right (uses whitespace to separate from main).
- **Grids** for structured data only — never as a "card wall". 12-column with 24px gutters.
### Transparency & blur
- **Almost never used.** No frosted glass. No backdrop-filter.
- One permitted use: a `rgba(255,255,255,0.92)` on the sticky top nav so that scrolled content is faintly visible behind it. No blur.
### Imagery
- **Black & white only.** All photography (when used) is rendered with `filter: grayscale(1) contrast(0.95)` — slightly low-contrast, like a Risograph print.
- **Aspect ratios**: 4:3 (preferred — feels like a document figure), 1:1 (for portraits / icons). Never 16:9 in body.
- **No people-stock-photography.** Prefer objects, diagrams, or screenshots.
- **No AI-generated imagery** unless explicitly labelled as such with a `[generated]` caption.
### Corner radii
- **`--r-1` (2px)** for inputs and tags.
- **`--r-2` (4px)** for buttons and small cards.
- **`--r-3` (8px)** for large cards and modals.
- **`--r-pill` (999px)** for label capsules only.
- **`--r-0` (0px / square)** is the default for documents, sheets, and any element wider than ~600px. Big things are square.
### Cards
A "card" in this system is **a bordered rectangle**, not a shadowed object floating off the page.
- 1px `--border` outline.
- `--paper` background.
- 4px or 8px radius depending on size.
- **No shadow.**
- Internal padding `--sp-5` (24px) minimum.
- A monospace eyebrow at top-left + a stage label at top-right is the canonical card header.
- On hover (when interactive): the top-left eyebrow tints to `--fg-1`, and a 2px black bar appears flush against the left edge. Nothing else moves.
---
## ICONOGRAPHY
The codebase did **not** ship an icon font, an icon sprite, or any SVG icons — `whynot-control` is a documents-only repo. The only visual asset is the LEGO-brick logo.
### Approach
- **Lucide icons via CDN** is the chosen icon set. It matches the system's stroke weight (1.5px), neutral geometry, and "wireframe artefact" feel better than Material, Heroicons, or Phosphor. Load with `<script src="https://unpkg.com/lucide@latest"></script>` and call `lucide.createIcons()`.
- **Stroke weight is always 1.5px.** Override Lucide's default 2px via `stroke-width="1.5"` on each `<svg>` or via CSS.
- **Color**: `currentColor`. Icons inherit from text. No two-tone, no fills.
- **Size**: 16px (inline), 20px (button), 24px (heading-adjacent), 32px (feature). Never larger — large icons read as decoration, and decoration is not in the spirit.
### When to use icons
- In navigation labels, button labels, and inline status — **only when the icon adds parsing speed**. If the word reads faster than the icon, skip the icon.
- In document margins to mark stage transitions (e.g. `→ Helix`).
- **Not** as decorative chrome on cards.
- **Not** as "feature icons" in a 3-up grid on a marketing page (this system has no marketing pages).
### Emoji
- **Never.** Emoji are not used anywhere — in copy, labels, alt text, or as fallback for missing icons.
### Unicode characters used as icons
These are allowed and preferred over raster icons in some contexts:
| Char | Used for |
|---|---|
| `→` | "promotes to" / pipeline arrow |
| `←` | back / previous |
| `·` | inline bullet separator (in nav, in meta lines) |
| `—` | em dash, in metadata |
| `?` `!` | the brand's signature punctuation, in display headlines only |
| `§` | section marker, in long documents |
### The logo
- The primary mark is **the LEGO brick with `?` and `!` underneath**, in pure black & white. `assets/whynot-logo.png` (300×300 raster, transparent background).
- For very small uses (favicon, footer mark), a **simplified mark** is recommended: just the `?!` pair in `IBM Plex Sans 600`, with the brick implied by a 2×4 dot grid above. See `preview/logo.html`.
- The brick should **never be coloured** (no LEGO-red, LEGO-blue, etc). It is always black-outlined on white, or white-outlined on black.
- Minimum size: 32px square. Below that, fall back to the `?!` wordmark.
---
## A note on font substitution
The control repo did not ship font files. **IBM Plex Sans / Mono / Serif** were chosen as a fresh pairing because:
- The "Plex" family was designed by IBM as an explicitly *neutral, technical-document* family — the same use-case as this system.
- All three (sans, mono, serif) share metrics, so they mix cleanly in templates and tables.
- They are openly licensed (SIL OFL) and available on Google Fonts.
Plex is currently loaded from Google Fonts (see top of `colors_and_type.css`). For offline use, drop the `.woff2` files into `fonts/` and swap the `@import` for a local `@font-face` block.
> **🟨 Substitution flagged**: there was no specified brand font; IBM Plex is a choice made here. If `whynot` later adopts a different brand font, replace `--ff-sans` / `--ff-mono` / `--ff-serif` in `colors_and_type.css` and everything downstream will follow.