A React design system and three project templates, so a new project starts at the interesting part instead of at Tailwind configuration.
pnpm stack create provenance --type app
cd provenance
pnpm install
pnpm devThat gives you React, TypeScript, TanStack Router, TanStack Query, design tokens, the component library, an API layer, error handling, linting, tests and a sensible project structure — running, with a mock backend, before you have written anything.
apps/
├── docs/ the documentation site, with live previews
└── playground/ a sandbox for working on components
packages/
├── tokens/ design tokens as CSS custom properties
├── ui/ the React component system
├── hooks/ reusable React hooks
├── utils/ cn, cv, and small framework-independent helpers
├── icons/ the icon contract and the brand marks Lucide omits
├── config-eslint/ shared flat ESLint configurations
└── config-typescript/
templates/
├── app/ Vite + TanStack Router — dashboards and internal tools
├── site/ Astro with React islands — project and marketing sites
└── fullstack/ TanStack Start — SSR with server functions
tooling/
└── create-stack/ the project generator
A small stable core, and progressively more opinionated layers on top:
project code → features → template → @bwmp-dev/ui → Base UI → @bwmp-dev/tokens
The lower something sits, the more stable and generic it has to be. Things move down only when they have earned it — not because they might be reusable one day.
Three things follow from that:
Tokens are CSS, not JavaScript. @bwmp-dev/tokens has no dependencies and no
React. Colours are declared once with light-dark(), so a brand override is one
block and the whole system works with JavaScript disabled.
Base UI does what is genuinely hard. Focus trapping, focus restoration, Escape, scroll locking, typeahead, roving focus. We own the API, the styling, the variants and the composition; we do not rewrite the parts that are invisible when they are wrong.
Escape hatches are real. className always wins, every component exports
its variant map so you can extend rather than fork, and nothing depends on you
using our components at all. A canvas editor has no business being expressed in
Button and Card.
The dependency direction is checked rather than described: pnpm check:boundaries
fails if @bwmp-dev/tokens ever imports React, or @bwmp-dev/ui ever imports a
router. A documented rule that nothing enforces stops being true.
There is no examples/ directory. The templates are the worked examples,
because a template nobody runs rots, and an example nobody generates from drifts
from the template it was copied out of.
They are ordinary workspace packages. CI builds, lints, type-checks and tests them on every change, and the application template's end-to-end suite runs against a real browser.
pnpm dev # docs and playground — the loop for the system itself
pnpm dev:docs # just the documentation site
pnpm dev:playground # just the component sandbox
pnpm dev:app # the application template
pnpm dev:site # the website template
pnpm dev:fullstack # the full-stack template
pnpm build
pnpm lint
pnpm typecheck
pnpm test
pnpm test:e2e
pnpm format
pnpm check:boundaries # the dependency direction still holdsWorking on one thing:
pnpm --filter @bwmp-dev/ui test:watch
pnpm --filter @bwmp-dev/template-app dev
pnpm turbo run build --filter=@bwmp-dev/ui... # and everything it depends onTurbo knows the dependency graph, so packages build before their consumers and unchanged packages are not rebuilt.
Every third-party version lives in the catalog: block of
pnpm-workspace.yaml. Packages reference catalog: rather than pinning their
own ranges, so nothing drifts and an upgrade is one edit.
Two constraints worth knowing:
- TypeScript is on 6.x, not 7.x. typescript-eslint supports
>=4.8.4 <6.1.0; moving to 7 means losing type-aware linting until it catches up. - The Base UI package is
@base-ui/react.@base-ui-components/reactis the deprecated old name.
pnpm changeset # describe the change
pnpm version-packages # apply it
pnpm release # build and publishPackages version independently, and the architecture is not tied to a registry. See the publishing guide.
pnpm dev:docs, or read the source under apps/docs/src/pages:
- Getting started
- Architecture
- Theming
- Styling
- Data and API
- Forms
- Testing
- Adding a component
- Publishing
- Upgrading
Component API tables are extracted from the TypeScript declarations at build time, so they cannot drift from the source.
Node 22.12 or newer, and pnpm 11. corepack enable if you do not have pnpm.