Malevich v1.0 — Master Diff-Merge Document
Status: Architectural decisions finalized, implementation pending. Date: 2026-05-18 Source documents: ai-native-design-system.mdx (architectural spec), v0.1.0 implementation (10 components shipped).
This document is the single source of truth for the architectural transition from v0.1.0 to v1.0. It records every adopted decision, every rejected alternative, and every modification we made to the source spec.
Quick orientation
- v0.1.0: 10 components shipped (Button, Input, Badge, Avatar, Checkbox, Card, Alert, Tabs, Dialog, Tooltip). 109 component tests passing. Phase 2 closed with tag v0.1.0.
- v1.0 target: 53 components across 4 layers + 6 overlays. 42 architectural principles documented.
- Source spec: The architecture document describes ~50-60 components. Most adopted; some rejected, some modified.
- Brand identity: Malevich (Suprematist heritage, Ukrainian cultural anchor, manifesto voice) remains. The architecture beneath it is generic.
1. Architectural framing
1.1 What stays from the source spec
Adopted with minimal changes:
- Four-layer component classification by functional role (Foundations, Elements, Blocks, Sections)
- Three-tier token system (foundations → semantic → component-specific)
- Modifiers as cross-cutting layer with category axes
- Variants vs Modifiers distinction (variants = what it is, modifiers = how it appears)
- Native-first approach (
<dialog>,<select>,<details>) - Container queries for blocks/elements, viewport queries for layouts
- Component-as-layer principle (Avatar in Foundations, not Elements)
1.2 What we changed from the source spec
| Source spec | Malevich v1.0 | Why |
|---|---|---|
| Card variants per content type (BlogCard, ProductCard, CartCard) | One Card with named slots + data-pattern hints |
Composability > component multiplication for our open-source audience |
| React + Tailwind + CVA stack | Vanilla CSS + optional JS enhancement | Framework-agnostic, broader audience, CSS-first principle |
Field-group only as composite |
Field-group + Label + Input + HelperText + Error as full family | Form is its own subsystem |
| Overlays as presentation mode | Overlays as their own layer | Developer mental model preserved |
| Surface options: ghost, island, elevated, primary | Surface options: flat, elevated, float | "Primary" is a variant axis, not a surface axis. Three elevation tiers cover full range. |
| Category name "treatment" | Category name "effect" | More universally understood; treatment ambiguous |
| Charts as a Block | Charts out of scope | Data viz is its own domain; we delegate to Recharts/Visx/D3 |
Form-button as Button with type=submit |
Form-button as separate component | Form-context buttons have distinct states (submitting, validation-error, success-confirmed); separation keeps generic Button aesthetically free |
| Abstract typography sizes (xl, l, m, s) | Semantic typography roles (hero, statement, title, lead, regular, support) | Names describe role, not size — better for AI, decoupled from values |
| Single icon library bundled | Pluggable icon packs with canonical name registry | Documentation focuses on icon selection principles; default pack = Phosphor |
| No mention of shader/WebGL | @malevich/shaders as separate v2.0 package |
Progressive enhancement; CSS-first base stays lightweight |
| Static treatments only | CSS effects (core) + interactive shaders (opt-in via @malevich/shaders) | Both worlds supported |
1.3 What we added beyond the source spec
behaviormodifier category — sticky, dismissible, collapsible (runtime behaviors)- State block with 4 variants — empty, loading, error, success
- Inline-form-group composite — for inline searches, filters, subscriptions (v2.0)
- Sheet component as Section-in-overlay-mode, four sides (top/right/bottom/left)
- Popover component with Floating UI positioning
- Toast + Notifications system inspired by Sonner (credit author)
- Site-header with shape/surface/background/behavior modifiers — Apple-pill, Stripe-flat, Linear-gradient all from one component
- Pluggable icon packs — adapter API for Phosphor, Lucide, Tabler, etc.
- Display typography fluid scaling (clamp), body typography fixed
- Token-to-component mapping in component AGENTS.md
1.4 What we deferred
- Bento layout (v1.1)
- Masonry layout (v1.1 native CSS if stable, v2.0 JS fallback)
- Multiselect, Slider, Pagination (v1.1)
- Input-OTP (v2.0)
- Carousel auto-play/loop/fade (v1.1)
- Testimonials, Pricing, FAQ, Newsletter ready sections (v2.0)
- Inline-form-group composite (v2.0)
- Cookie banner (v2.0)
- Popup, Context menu (v1.1)
- W3C Design Tokens spec compliance (v1.1)
- High contrast theme variant (v1.1)
- Multi-brand support (v2.0)
- Custom DevTools extension (v1.1)
1.5 What we explicitly rejected
- Charts as in-scope components — delegated to external libraries
- Auto-fallback for shader modifier — explicit fallback required for predictability
- Cookie banner with consent logic — UI primitive only if shipped; consent is legal domain
- Bento layout in v1.0 — Grid + Split cover the gap; Bento adds complexity without urgent need
- Single Cards with content-typed variants (god-component) — content is in slots, semantic intent in tag + data-pattern
- Style Dictionary integration — our pipeline sufficient, adds dependency weight
- Sprite-based icons — HTTP/2 + per-file with mask-image is simpler
2. Component layer architecture
2.1 Final v1.0 component inventory
Layer: Foundations (8)
- Avatar (moved from Elements)
- Icon (pluggable packs)
- Typography (CSS classes + adjacent-selector behavior rules)
- Divider (horizontal/vertical, CSS-only)
- Spinner
- Skeleton
- Dots
- Image (with
<picture>support)
Layer: Elements
Interactive (6):
- Button (5 variants: primary/secondary/ghost/danger/success)
- Button-group
- Tabs (migrated from Blocks)
- Switch
- Toggle
- Kbd
Form (12):
- Field-group (composite)
- Label
- Input
- Textarea
- HelperText
- Error
- Select (native styled)
- Radio-group
- Checkbox (existing)
- Checkbox-group
- Form-button
- Form-divider (with separation text)
Display (6):
- Badge (existing)
- Tag
- Tags-group
- Avatar-group
- Code (inline)
- Alert (migrated from Blocks)
Layer: Blocks (7)
- Card (one component, semantic tags, data-pattern hints, slots)
- Accordion (built on
<details>) - Carousel (minimal scope: scroll-snap, pagination, prev/next)
- Breadcrumb
- Code block (multi-line, with Shiki integration on docs)
- Quote block
- State (variants: empty/loading/error/success)
Layer: Sections
Layout (4):
- Block layout
- Split layout
- Grid layout
- Stack layout
Ready (4):
- Hero (with patterns)
- CTA
- Site-header (shape/surface/background/behavior modifiers)
- Site-footer
Layer: Overlays (6)
- Dialog (existing, native
<dialog>) - Sheet (new, 4 sides, native
<dialog>) - Tooltip (existing, Floating UI)
- Popover (new, click-triggered, Floating UI)
- Toast (new, individual notification)
- Notifications (new, stack manager, inspired by Sonner)
Total v1.0: 53 components
2.2 Component layer rules
A component belongs to a layer based on what it does, not how complex it looks:
| Layer | Test |
|---|---|
| Foundation | No slots, no logic, called from many components, no own semantics |
| Element | Fixed structure, takes props, doesn't accept arbitrary content |
| Block | Slots for elements, structural brick for sections |
| Section | Slots for blocks, organizes a page region |
| Overlay | Same component identity, but rendered in portal/top-layer |
2.3 Tabs migration
Was: packages/components/src/blocks/tabs/
Becomes: packages/components/src/elements/interactive/tabs/
Rationale: Tabs has fixed structure (tab list + panels), doesn't accept arbitrary content, fits Element criteria better than Block.
2.4 Alert migration
Was: packages/components/src/blocks/alert/
Becomes: packages/components/src/elements/display/alert/
Rationale: Alert has fixed structure (icon + title + message + up to 2 buttons), doesn't accept arbitrary content. Inline alert is a Display Element. Overlay-style notifications are Toast/Notifications (separate components in Overlays layer).
2.5 Avatar migration
Was: packages/components/src/elements/avatar/
Becomes: packages/components/src/foundations/avatar/
Rationale: Avatar is called from many components (Card, Header, Comment lists), has no inherent semantics beyond display, no slots, no logic. Foundation case.
3. Token system architecture
3.1 Three-tier structure
┌─────────────────────────────────────────────────┐
│ Tier 3 — Component-specific │
│ Flat naming: button.background, card.padding │
│ Sparse, used only when semantic insufficient │
│ References semantic │
├─────────────────────────────────────────────────┤
│ Tier 2 — Semantic │
│ Nested in JSON: color.text.primary, etc. │
│ Flat in CSS: --color-text-primary │
│ Theme-aware (light/dark vary HERE) │
│ Primary consumption layer │
│ References foundations │
├─────────────────────────────────────────────────┤
│ Tier 1 — Foundations (PRIVATE) │
│ Nested in JSON: color.neutral.900, space.4 │
│ Flat in CSS: --color-neutral-900 │
│ Raw values, narrow set, never read by component │
│ Theme-invariant │
└─────────────────────────────────────────────────┘
3.2 Strict tier separation rule
Components NEVER reference foundations directly. Only semantic or component-specific tokens.
Enforced via @malevich/lint rule no-foundation-direct-reference.
Example:
/* ❌ FORBIDDEN — component references foundation directly */
.card {
background: var(--color-neutral-50);
}
/* ✅ CORRECT — component references semantic */
.card {
background: var(--color-surface-raised);
}
/* ✅ CORRECT — component references its own tier */
.card {
background: var(--card-background);
}
3.3 Foundation tier inventory
color (palette only):
neutral.0, neutral.50, neutral.100, neutral.200, neutral.400,
neutral.600, neutral.700, neutral.800, neutral.900, neutral.950
accent.subtle, accent.muted, accent.base, accent.hover, accent.pressed
danger.subtle, danger.500
warning.subtle, warning.500
success.subtle, success.500
info.subtle, info.500
bone.base
space (4px-based):
0, 1 (4px), 2 (8px), 3 (12px), 4 (16px), 6 (24px), 8 (32px),
12 (48px), 16 (64px), 24 (96px)
radius:
none (0), small (4px), field (6px), medium (8px), card (12px),
large (16px), full (9999px)
shadow:
1 (0 1px 2px rgba(0,0,0,0.04))
2 (0 4px 12px rgba(0,0,0,0.08))
3 (0 12px 32px rgba(0,0,0,0.12))
4 (0 24px 64px rgba(0,0,0,0.16))
font:
family.display (NAMU 1930)
family.text (NAMU Pro)
family.mono (JuliaMono)
weight.regular (400), weight.medium (500), weight.bold (700)
line-height.tight (1.15), line-height.regular (1.5),
line-height.loose (1.7)
letter-spacing.tight (-0.02em), letter-spacing.regular (0),
letter-spacing.wide (0.04em), letter-spacing.overline (0.1em)
duration:
instant (0ms), fast (150ms), standard (250ms),
slow (400ms), deliberate (600ms)
easing:
standard (cubic-bezier(0.2, 0, 0, 1))
accelerate (cubic-bezier(0.3, 0, 1, 1))
decelerate (cubic-bezier(0, 0, 0.2, 1))
emphasized (cubic-bezier(0.2, 0, 0, 1.2))
3.4 Semantic tier inventory
color.text:
primary, secondary, muted, disabled
on-accent, on-inverse
link, link.hover, link.visited
code
color.surface:
canvas, raised, float
inverse, accent, accent.subtle
bone, scrim
color.border:
subtle, default, strong
accent, focus
on-inverse
color.status:
danger, danger.subtle, danger.on
warning, warning.subtle, warning.on
success, success.subtle, success.on
info, info.subtle, info.on
color.accent:
default (= base), hover, pressed, subtle
color.focus-ring:
default
typography sizes:
display.hero (clamp(2.5rem, 1.5rem + 5vw, 5rem)) — landing hero, max impact
display.statement (clamp(2rem, 1.5rem + 3vw, 3.5rem)) — section-level statement
display.title (clamp(1.75rem, 1.25rem + 2vw, 2.5rem)) — page title emphasis
heading.title (1.875rem / 30px) — main heading (h1)
heading.section (1.5rem / 24px) — section heading (h2)
heading.subsection (1.25rem / 20px) — subsection heading (h3)
heading.group (1.125rem / 18px) — group heading (h4)
body.lead (1.125rem / 18px) — lead paragraph
body.regular (1rem / 16px) — standard body
body.support (0.875rem / 14px) — supporting text
caption (0.75rem / 12px)
overline (0.6875rem / 11px, uppercase, wide spacing)
eyebrow (0.75rem / 12px, mixed case)
code (0.875rem / 14px, monospace)
mono.l (1rem / 16px, monospace)
mono.m (0.875rem / 14px, monospace)
mono.s (0.75rem / 12px, monospace)
radius (semantic):
control → foundation.radius.field
card → foundation.radius.card
surface → foundation.radius.large
pill → foundation.radius.full
shadow (semantic):
raised → foundation.shadow.2
overlay → foundation.shadow.3
popover → foundation.shadow.4
motion (semantic):
duration.enter, duration.exit, duration.emphasis, duration.deliberate
easing.enter, easing.exit, easing.emphasis, easing.standard
distance.subtle (4px), distance.moderate (12px), distance.expressive (24px)
preset.none, preset.subtle, preset.standard, preset.expressive
size-control (semantic, for interactive elements):
size-control.s, size-control.m, size-control.l, size-control.xl
border-width (semantic):
border-width.hairline (0.5px), border-width.regular (1px),
border-width.focus (2px), border-width.emphasis (3px)
3.5 Component-tier convention
Component tokens are flat in both JSON and CSS:
{
"button": {
"background": "{color.accent}",
"text": "{color.text.on-accent}",
"border": "transparent",
"padding-block": "{space.3}",
"padding-inline": "{space.4}",
"radius": "{radius.control}"
}
}
--button-background: var(--color-accent);
--button-text: var(--color-text-on-accent);
--button-padding-block: var(--space-3);
--button-padding-inline: var(--space-4);
--button-radius: var(--radius-control);
Variants override via cascade, not via multiplied tokens:
.button {
background: var(--button-background);
color: var(--button-text);
}
.button.-secondary {
--button-background: var(--color-surface-raised);
--button-text: var(--color-text-primary);
}
.button.-danger {
--button-background: var(--color-status-danger);
--button-text: var(--color-status-danger-on);
}
3.6 Token-to-component mapping (per-component documentation)
Each component's AGENTS.md documents which tokens it consumes. Example for Card:
## Tokens consumed
### From semantic tier
- color.surface.raised — default background
- color.surface.float — for surface=float variant
- color.border.subtle — for default border
- radius.card — corner radius
- shadow.raised — for surface=elevated
- shadow.overlay — for surface=float
### From component tier (Card-specific)
- card.padding-block — vertical inner padding
- card.padding-inline — horizontal inner padding
- card.gap — gap between slots
- card.background — final background (resolved from surface)
- card.border — final border (resolved from surface)
- card.shadow — final shadow (resolved from surface)
### Typography classes used in slots
- card__header text typically uses: eyebrow, body.support
- card__body text typically uses: heading.subsection, body.regular
- card__footer text typically uses: body.support, caption
This mapping is mandatory in every component AGENTS.md for v1.0.
4. Modifier system architecture
4.1 Seven modifier categories
Modifiers system
├── background — what's behind the surface (CSS static)
├── surface — how the surface sits (flat / elevated / float)
├── effect — decorative overlays (grain / glow / noise / ring / blur)
├── shader — interactive WebGL backgrounds (opt-in via @malevich/shaders)
├── rhythm — internal breathing (compact / regular / spacious)
├── motion — animation character (none / subtle / standard / expressive)
└── behavior — runtime behaviors (sticky / dismissible / collapsible / copyable)
4.2 Modifier syntax
- Variants (what the component is): BEM short modifiers →
.button.-primary,.alert.-danger - Modifiers (how it appears): data-attributes →
data-surface="elevated",data-effect="glow"
Syntactic split signals architectural axis to readers and AI agents.
4.3 Namespace separation rule
Each modifier owns a variable namespace:
- Surface →
--{component}-surface-* - Effect →
--{component}-effect-* - Background →
--{component}-background-* - etc.
Components compose final styles from multiple namespaces:
.card {
box-shadow:
var(--card-surface-shadow, none),
var(--card-effect-shadow, none);
}
This makes modifiers stack without conflict.
4.4 Selective inheritance
- Rhythm inherits via CSS custom property cascade (environmental)
- Motion inherits via cascade (environmental)
- Surface, effect, background, shader, behavior do NOT inherit (component-specific)
4.5 Applicability matrix
Single source of truth: modifiers/applicability.json
{
"components": {
"card": {
"surface": ["flat", "elevated", "float"],
"effect": ["grain", "glow", "noise", "ring", "blur"],
"background": ["solid", "gradient", "image"],
"shader": "all",
"rhythm": ["compact", "regular", "spacious"],
"motion": "all",
"behavior": []
},
"button": {
"surface": ["flat"],
"effect": ["glow", "ring"],
"background": [],
"shader": [],
"rhythm": ["compact", "regular"],
"motion": "all",
"behavior": []
}
}
}
Build pipeline generates from this:
- TypeScript types for IDE autocomplete
- AGENTS.md sections per component
- Validation logic for lint rules
4.6 Custom modifier extension
Public extension API documented in /playbook/extending-modifiers. No plugin system — just data-attribute + CSS convention:
<article class="card" data-corporate="enterprise">
[data-corporate="enterprise"] {
--card-border: 2px solid var(--color-corporate-accent);
--card-radius: 0;
}
4.7 Behavior modifier auto-init
init() from @malevich/components runtime discovers and wires up behavior modifiers automatically:
import { init } from '@malevich/components';
init();
// Now [data-sticky="true"] elements have sticky behavior
// [data-dismissible="true"] have dismiss handlers, etc.
4.8 Built-in behaviors per component
Some components have specific behavior modifiers enabled by default, because the behavior is core to the component's identity:
- Code (inline) —
data-copyable="true"default (copy button visible on hover) - Code block —
data-copyable="true"default (copy button in chrome) - Kbd —
data-copyable="false"default (opt-in, since copying a keyboard shortcut name is rare)
For all other components, behavior modifiers are opt-in via explicit
data-{behavior}="true" declaration. This pattern lets common cases
work automatically while keeping the API explicit for edge cases.
The copy behavior implementation:
- Renders a small copy button overlaid (CSS) on the component
- On click: copies the element's textContent to clipboard via Clipboard API
- Provides visual feedback: button morphs from copy icon to check icon for 1.5 seconds (uses @malevich/morph-icons copy↔done pair)
- Falls back gracefully when clipboard API unavailable
- Respects reduced motion preferences for the morph animation
5. Presentation modes architecture
5.1 Two modes
- Inline — default, in document flow
- Overlay — rendered in portal or top-layer
5.2 Why overlays are their own layer (not a mode)
Conceptually, overlays are a presentation mode applied to existing components. Practically, developers reach for "Dialog" or "Sheet" as a category, not as a modifier. We organize file structure and documentation as a discoverable layer; we preserve the mode concept in our architectural discussions and AGENTS.md.
5.3 Overlay technical implementation
- Modal overlays (Dialog, Sheet) — native
<dialog>element withshowModal()(top-layer, native focus trap, escape handling,inertbackground) - Non-modal overlays (Tooltip, Popover, Toast, Notifications) —
@malevich/componentsruntimeoverlay-stackmodule manages z-index, escape handling, focus restoration - Positioning (Tooltip, Popover) —
@floating-ui/dom(10KB dependency, industry standard)
5.4 Focus management defaults
| Overlay type | Focus behavior |
|---|---|
| Modal (Dialog, Sheet) | Focus trapped, initial focus configurable, restored on close |
| Popover | Focus moves into overlay, tab cycles within, restored on close |
| Tooltip | Focus stays on trigger, tooltip non-focusable |
| Toast/Notifications | Focus untouched, content announced via aria-live |
Overrides available via data-attributes (data-focus-trap, data-focus-restore).
6. Responsive architecture
6.1 Three-tier responsive ownership
| Layer | Responsive tool |
|---|---|
| Layout sections | Viewport queries (@media) — own breakpoints |
| Blocks, Elements | Container queries (@container) — adapt to slot |
| Foundations | Intrinsic (clamp(), min(), max(), percentages) — natural scaling |
This makes responsive logic predictable per layer. An agent writing Card CSS never writes a media query. An agent writing Layout never writes a container query.
6.2 Display typography fluid scaling
Display sizes (hero, statement, title) use clamp():
.display-hero {
font-size: clamp(2.5rem, 1.5rem + 5vw, 5rem);
}
Heading, body, caption, code — fixed sizes. Hierarchy preserved across viewports.
7. Theming architecture
7.1 Theme variants in v1.0
- Light (default)
- Dark (auto via
prefers-color-scheme: dark)
Detection and persistence: localStorage + matchMedia + pre-paint inline script (no FOUC).
7.2 Theme tier rule
Themes change semantic tier only. Foundations stay theme-invariant. Brand red is brand red whether on light or dark canvas.
:root {
/* foundations — same in all themes */
--color-neutral-0: #ffffff;
--color-neutral-900: #171717;
/* semantic — light theme defaults */
--color-surface-canvas: var(--color-neutral-0);
--color-text-primary: var(--color-neutral-900);
}
[data-theme="dark"] {
/* semantic only — foundations untouched */
--color-surface-canvas: var(--color-neutral-900);
--color-text-primary: var(--color-neutral-0);
}
7.3 Theme roadmap
- v1.1 — High contrast variant (a11y feature)
- v2.0 — Multi-brand support (one app, multiple brand themes)
- v2.0 — Named theme packs (sepia, blueprint, etc. as community contributions)
8. Iconography architecture
8.1 Pluggable icon packs
Malevich does not ship its own icon library. It ships:
- Canonical name registry (~100 standard icon names)
- Adapter API for icon packs
- Default pack:
@malevich/icons-defaultwrapping Phosphor (MIT, 1500+ icons) - Alternative packs: Lucide, Tabler, Heroicons, Iconoir adapters
8.2 Implementation
CSS mask-image for icon rendering. currentColor inheritance via mask background.
<span class="icon" data-icon="check"></span>
.icon {
display: inline-block;
inline-size: var(--icon-size, 1em);
block-size: var(--icon-size, 1em);
background: currentColor;
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
}
[data-icon="check"] { mask-image: url("/icons/check.svg"); }
One SVG file per icon, served over HTTP/2 + CDN for parallel loading.
8.3 Pack switching
Global override via root data-attribute:
<html data-icon-pack="lucide">
Pack adapters map canonical names → pack-specific names internally.
8.4 Documentation focus
The Icon documentation page focuses on principles of icon selection (when to use delete vs trash vs x), not on an icon catalog. AGENTS.md per category guides AI agents on icon-to-intent mapping.
9. Effect (formerly "treatment") category
Renamed from "treatment" to "effect" for universal clarity.
9.1 v1.0 effect values
grain— noise overlay textureglow— soft accent glow around elementnoise— pixel noise texturering— accent ring around elementblur— frosted glass back
All implemented as CSS-only overlays. No JS, no WebGL.
9.2 Shader category (separate)
Interactive WebGL backgrounds (mesh-gradient, fluid, particle-flow) ship in @malevich/shaders (v2.0). Without the package, data-shader is ignored. Explicit fallback via data-background="gradient" is recommended pattern.
10. Brand vs architecture separation
10.1 What Malevich brand carries
- Name (Suprematist heritage)
- Manifesto voice (editorial, confident, cultural anchor)
- Typography defaults (NAMU 1930 display, NAMU Pro text, JuliaMono mono)
- Default palette (ink, canvas, accent #D32F1E Suprematist Red, bone)
- Cultural specificity (Ukrainian, Kyiv-anchored examples)
10.2 What the architecture is
- Generic and brand-agnostic
- Could ship under any name
- Component classification, modifier system, token tiers — all reusable
10.3 Why separation matters
This split lets the brand evolve (new palette, refreshed voice, expanded cultural references) without rewriting the system. A future "Malevich Industrial" or "Malevich Editorial" theme pack changes only semantic tokens and typography classes — the architecture stays untouched.
11. Implementation enforcement
11.1 Lint rules (@malevich/lint)
| Rule | What it enforces |
|---|---|
no-raw-values (existing) |
No hardcoded colors, sizes, durations in CSS |
bem-short-modifier (existing) |
Variants use .-modifier syntax |
custom-element-prefix (existing) |
Reserved m- prefix |
no-foundation-direct-reference (new) |
Components can't read foundation tokens directly |
modifier-namespace-check (new) |
Modifiers write to their own variable namespace only |
tier-respect (v1.1) |
Token reference order: component → semantic → foundation |
11.2 Type generation
@malevich/core build pipeline generates:
- CSS variables (flat)
- TypeScript exports for IDE autocomplete
- AGENTS.md sections per component (from applicability matrix)
11.3 Documentation discipline
Every component MUST ship with:
<name>.css— styles<name>.docs.md— long-form human docsindex.ts(orexport {}) — runtime exports<name>.agents.md— AI agent guidance (400-800 words)_visual-reference.html— handcrafted variant + state showcase- Token-to-component mapping section in agents.md
12. Migration path from v0.1.0
See 04-migration-plan.md for step-by-step execution.
Summary:
- Breaking changes: Avatar/Tabs/Alert move between layers, treatment→effect rename, token naming convention restructure
- Migration scripts: codemods for token renames + file moves
- Compatibility: no backwards compat — we have no external users yet, breaking change OK
- New work: 43 net-new components (53 v1.0 target - 10 v0.1.0 existing)