Introduction
Summary
A distributed design-system: nothing to install from npm. It ships as a shadcn preset and a shadcn registry, so every pmndrs app — and yours — gets the same colours, fonts and radii by copying code in, not by depending on a package.

What you get
- shadcn's tokens as the base, Material Design 3 colour roles on top
- The pmndrs palette baked into the CSS: no provider, no client JavaScript
- Light and dark schemes, also exported as Figma tokens
- A git tag as the install address, so every app pins the version it was built against
Quick start
Any app shadcn can init works. With a fresh Next.js one:
Create the app
npx create-next-app@latest my-app --ts --tailwind --app --src-dir --yes
cd my-app
Init shadcn with the poimandres preset
pnpm dlx shadcn@latest init --preset b1VlIttIAdd a pmndrs block
Blocks depend on the colour layer, so adding one pulls it in with it:
pnpm dlx shadcn@latest add pmndrs/docs/keypoints#v4.22.0Use it
import { Keypoints, KeypointsItem } from "@/components/keypoints"
export default function Home() {
return (
<main className="bg-background text-foreground min-h-screen p-10">
<Keypoints title="Hello">
<KeypointsItem>The panel sits on bg-surface-dim, an MD3 role shadcn has none for</KeypointsItem>
</Keypoints>
</main>
)
}
Add the dark class to <html> for the dark scheme.
No block in mind? Add the theme on its own — the palette and the mono font:
pnpm dlx shadcn@latest add pmndrs/design-system/theme#v0.9.0Tokens
Four layers set the tokens, each one deciding what the layer below leaves open:
shadcn's tokens are the base — bg-background,
text-primary, border-border… keep working as usual.
Material Design 3's colour roles are
additive: every --md-sys-color-* role becomes a Tailwind colour, for what shadcn
has no name for (bg-surface-dim, text-on-surface-variant,
bg-tertiary-container…).
Registry items
The design-system is distributed: every pmndrs/* repo can contribute blocks, each one
installable with a single shadcn add. Any public repo becomes a
shadcn registry with a registry.json at its root,
and the CLI installs straight from GitHub — no
registry server, no package to publish, just files. A block ships from the repo that already
owns it, pmndrs/docs' Keypoints for one, so there is nothing to move. This repo holds the
theme only: the shared defaults — colours, radius, every shadcn token — that blocks build on,
and that your app can still override.
Not only UI, either: an item is a set of files, their dependencies and a target path, and the
CLI never looks inside. A shader, a drei helper or a SKILL.md
ships the same way.
An item's address is the registry, the item and a git ref:
pnpm dlx shadcn@latest add pmndrs/design-system/theme#v0.9.0The CLI reads registry.json and the item's files at that
ref — a tag, a branch or a commit SHA. Pin
a tag: an address without one follows the repo's default branch, and changes under you.
npx shadcn@latest view <address> prints an item,
files and all, before you add it.
Namespace
This site also serves every item of this repo as static JSON, under
https://pmndrs.github.io/design-system/r/. Declare it once as a
namespace in components.json:
{
"registries": {
"@pmndrs": "https://pmndrs.github.io/design-system/r/{name}.json"
}
}
Then an item is a name, no repo and no ref:
pnpm dlx shadcn@latest add @pmndrs/theme
pnpm dlx shadcn@latest search @pmndrsThe namespace serves the latest state of main, rebuilt from registry.json on every
deploy of it. Pin the git address above, at a tag, where an app must not move.
A branch's preview deployment serves its own r/ too, but not all the way down: preset
depends on pmndrs/design-system/theme#v0.9.0, so the theme it installs is the released
tag's, not the branch's.
The shadcn MCP server reads the same namespace, so Claude, Cursor or VS Code can list, read and install the items from the conversation:
pnpm dlx shadcn@latest mcp init --client claudeA fresh project can start from it too: preset is the poimandres preset and the theme in one
item, so init with its URL does what the Quick start does, without the preset code, and
declares the namespace in components.json on the way:
pnpm dlx shadcn@latest init https://pmndrs.github.io/design-system/r/preset.jsonTo prototype in v0 with the pmndrs colours, fonts and radius already applied,
open the theme in v0.
Or have v0 build the brand guidelines from it, as slides:
open the brand guidelines in v0.
v0 reads no namespace, so both open the v0 item: a v0 project with a starter page, the logo
in public/pmndrs/, the brand book as guidelines/Guidelines.md, and a globals.css with the
colours resolved, light and dark. Its utilities are the ones a pmndrs project has, shadcn's and
the Material Design 3 roles' (bg-primary-container, bg-surface-container-high, the brand
lime as bg-lime-container), so what v0 writes runs unchanged in one.
Publish a block
A block has one source of truth, and it moves. It starts in the repo it was born in, used there first — the proof it works, not a component cut off from a real app. It is promoted to pmndrs/design-system only once a second repo reuses it, and promoting it is just moving its files. Any earlier is premature optimisation.
So publish it from your own repo: a
registry.json at its root, one entry
per item in the registry-item.json
shape.
{
"$schema": "https://ui.shadcn.com/schema/registry.json",
"name": "pmndrs-<repo>",
"homepage": "https://github.com/pmndrs/<repo>",
"items": [
{
"name": "<block>",
"type": "registry:block",
"registryDependencies": [
"sidebar",
"collapsible",
"pmndrs/design-system/theme#v0.9.0"
],
"files": [{ "path": "registry/<block>/<block>.tsx", "type": "registry:block" }]
}
]
}
sidebar and collapsible are stock shadcn components. pmndrs/design-system/theme is the
pmndrs theme, for a block that paints with an MD3 role; a ref is
not inherited by dependencies, so
it pins its own.
npx shadcn@latest registry validate
checks the file, and npx shadcn@latest add pmndrs/<repo>/<block>#<ref> installs the block
anywhere. To list it below, add the repo to
registry/external.json
and run npm run refresh-catalog.
Catalog
Here they all are, across repos, each linked to its source, then the same list from
shadcn search:
The CLI lists the same items, read live from each repo at the ref to pin:
pnpm dlx shadcn@latest search pmndrs/design-system#v0.9.0 pmndrs/docs#v4.22.0