Architecture
How KDS is organised and how the pieces fit together at runtime.
How KDS is organised, why it's organised that way, and how the pieces fit together at runtime.
Repository structure
KDS lives in the bridge monorepo, in packages/kds/. The
monorepo also hosts apps/docs (this site), apps/storybook (the
internal lab) and apps/control (an internal Unraid-inspired
dashboard).
bridge/
├── apps/
│ ├── docs/ # this site (Fumadocs)
│ ├── storybook/ # internal Storybook lab
│ └── control/ # internal dashboard (Phase 6)
├── packages/
│ ├── kds/ # @kalvner/kds — the DS package
│ ├── eslint-config/ # @kalvner/eslint-config (shared)
│ └── tsconfig/ # @kalvner/tsconfig (shared)
└── tools/
└── theme-mapping/ # tweakcn → primitive mapping scriptToken architecture (3 layers)
Three layers, each with a distinct responsibility:
| Layer | Lives in | Naming | Changes |
|---|---|---|---|
| 1. Primitive | @theme {} blocks | --color-<palette>-<stop> | Almost never (follows Tailwind) |
| 2. Semantic | :root / [data-theme] selectors | --<role> (no prefix) | Per theme switch |
| 3. Chart | @theme inline {} blocks | --color-chart-<group>-<n> | Per chart-data context |
Editing a primitive cascades through every theme that references
it. Switching data-theme="X" updates every semantic token
in-place — components stay ignorant of which theme is active.
See Tokens / Visão geral for the full picture.
Component file structure
Every primitive lives in
packages/kds/src/primitives/<categoria>/<Component>/:
Button/
├── Button.tsx # Component implementation
├── Button.stories.tsx # CSF3 stories (variants, states, composed)
└── index.ts # Barrel exportThe companion documentation MDX lives in apps/docs/content/primitives/<categoria>/<component>.mdx
(per ADR-017 — centralised in the docs app, not co-located in the
package). Stories without an MDX page, or MDX without stories, fail
review. The 11 MDX sections come from the
storybook-component-doc skill in the Kalvner skill library.
Categories (9 functional groups)
Components are organised by what they do, not what they look like. The 9 canonical categories are:
Containers · Typography · Forms · Display · Data
Feedback · Navigation · Overlays · AIAI is one category alongside the other 8 — not a special case.
Within AI, components are sub-categorised in Chatbot (18) and
Code (15) to mirror Vercel AI Elements.
See knowledge/ui/design-systems/storybook-structure.md for the
canonical decision matrix when a component's category is ambiguous.
Patterns / Layouts / Blocks
Three layers above primitives:
- Patterns — multi-component compositions that solve a recurring problem (DataTable, EmptyState, FormSection)
- Layouts — full-page shells (AppShell, AuthShell)
- Blocks — copy-pasteable page templates (CrudListPage, DashboardGrid, SettingsPage)
Each layer is a separate sidebar section.
Distribution
@kalvner/kds publishes to GitHub Packages under the
@kalvner scope, restricted to Kontar and Kalvner's personal
projects. Path-per-component subpath exports give consumers
guaranteed tree-shaking:
import { Button } from "@kalvner/kds/forms/button"; // preferredPer ADR-012, barrel imports (@kalvner/kds) work as a fallback
but aren't documented for new code.
Build & deploy
This site deploys to ds.kalvner.com via Vercel. Component PRs run
lint + typecheck + build + (Phase 5+) Chromatic visual regression
on every push.