GitHub

/ Foundations — 01

Five layers, one mental model.

Each Kumiki primitive is exactly one layer. Pick the layer that matches your control needs — and ship the bytes for that layer only. Subpath exports keep tree-shaking surgical.

Names borrow from Kumiki joinery. Each layer is a piece that locks into the next without nails or glue.

L名 — NamePackageRole
L0Types@kumiki/typesShared TypeScript surface — the only thing every other layer agrees on.
L1Primitives@kumiki/primitivesFramework-agnostic helpers (focus trap, dismissable, ID, locale, motion).
L2Machines@kumiki/machinesPure-TS finite state machines. ~1 KB runtime, JSON-inspectable.
L3Attachments@kumiki/headlessSvelte 5 {@attach} factories — drive ARIA + data-state on real DOM.
L4Components@kumiki/componentsCompound primitives. Dot-namespace ergonomic API.
L5Atelier@kumiki/atelierLayer 5 preview — copy-pasteable styled variants.

Picking a layer

Most apps live at Layer 4. Reach down only when you need to:

  • Layer 3 (attachments) when you control the DOM tightly — you're styling with native <button>, not a Svelte wrapper.
  • Layer 2 (machines) for SSR / server-side validation, or to run the logic in a non-Svelte context (Cypress, Vitest, a worker).
  • Layer 1 (primitives) when you're authoring your own component on top of the dismissable / focus-trap / ID engines.

Why not pull it all in?

Bundle budgets. Each subpath has a brotli budget enforced in CI — Toggle ships in 1.5 KB, Combobox in 4.5 KB. Pulling Layer 5 styled variants into a project that already owns its design tokens is wasted bytes; the Atelier package is opt-in, not the default.

Authoritative reading

The internal design docs live at /docs/design. Of particular note:

  • 02-architecture.md — this layer model, with diagrams.
  • 03-package-structure.md — package boundaries.
  • 04-state-machines.md — the FSM runtime spec.
  • 09-bundle-budget.md — the per-subpath brotli budgets.