{palette}
Aa Bb Cc 0123
The quick brown fox jumps over the lazy dog.
font-sans
Aa Bb Cc 0123
The quick brown fox jumps over the lazy dog.
font-mono
Every pmndrs project gets the same colours, fonts and radii by copying code in, not by depending on a package.
``` ### Lead
A design system shipped as a shadcn registry.
``` ### Large
Add the dark class to html for the dark scheme.
``` ### Blockquote
Whatever the preset or the registry fixes is a pmndrs decision.
``` ### List```tsx
- Colours from the theme
- Inter from the preset
- Inconsolata from the registry
``` ### Inline code
```tsxnpx shadcn@latest add``` ]]>Every spacing utility is a multiple of one base unit, `--spacing`. A utility `n` is `n × 0.25rem`: `p-4` is `1rem`, `gap-2` is `0.5rem`. > [!NOTE] > Inherited from Tailwind v4 defaults, not yet a pmndrs decision. See [Tailwind's padding docs](https://tailwindcss.com/docs/padding). ## Base unit | Token | Value | | ----------- | --------- | | `--spacing` | `0.25rem` | The same scale drives padding (`p-*`), margin (`m-*`), gaps (`gap-*`, `space-*`), sizes (`w-*`, `h-*`, `size-*`, `min-*`, `max-*`), offsets (`inset-*`, `top-*`…) and translations (`translate-*`). Any multiple works, not only the steps below: `p-13` is `3.25rem`. Prefix a utility with `-` for a negative value (`-mt-2`), and use brackets for a one-off (`p-[5px]`). ## Scale The common steps, with the value your project gets. Pixels assume the browser's default 16px root. The bars are live `w-*` utilities, rendered with this site's CSS: its root is 17px, so they draw slightly wider than in your project. The table is the source of truth. | Utility | Value | Pixels | Preview | | ------- | ---------- | ------ | ---------------------------------------- | | `0` | `0` | 0 | | | `px` | `1px` | 1px | | | `0.5` | `0.125rem` | 2px | | | `1` | `0.25rem` | 4px | | | `1.5` | `0.375rem` | 6px | | | `2` | `0.5rem` | 8px | | | `2.5` | `0.625rem` | 10px | | | `3` | `0.75rem` | 12px | | | `3.5` | `0.875rem` | 14px | | | `4` | `1rem` | 16px | | | `5` | `1.25rem` | 20px | | | `6` | `1.5rem` | 24px | | | `7` | `1.75rem` | 28px | | | `8` | `2rem` | 32px | | | `9` | `2.25rem` | 36px | | | `10` | `2.5rem` | 40px | | | `11` | `2.75rem` | 44px | | | `12` | `3rem` | 48px | | | `14` | `3.5rem` | 56px | | | `16` | `4rem` | 64px | | | `20` | `5rem` | 80px | | | `24` | `6rem` | 96px | | | `28` | `7rem` | 112px | | | `32` | `8rem` | 128px | | | `36` | `9rem` | 144px | | | `40` | `10rem` | 160px | | | `44` | `11rem` | 176px | | | `48` | `12rem` | 192px | | | `52` | `13rem` | 208px | | | `56` | `14rem` | 224px | | | `60` | `15rem` | 240px | | | `64` | `16rem` | 256px | | | `72` | `18rem` | 288px | | | `80` | `20rem` | 320px | | | `96` | `24rem` | 384px | | ]]> Every corner in a pmndrs project derives from one value, `--radius`. The `rounded-*` utilities are multiples of it, so changing that one value rescales every corner at once. ## Base ```css :root { --radius: 0.625rem; /* 10px at a 16px root */ } ``` It comes from the poimandres shadcn preset (`b1VlIttI`, style `base-luma`, radius `default`), applied by `npx shadcn@latest init --preset b1VlIttI`. ## Scale The preset's `base-luma` style derives the scale by multiplication: each step is `--radius` times a factor. Values below are at a 16px root. | Token | Utility | Value | rem | px | | -------------- | -------------- | ----------------------------- | ---------- | ---- | | `--radius-xs` | `rounded-xs` | inherited from Tailwind v4 | `0.125rem` | 2px | | `--radius-sm` | `rounded-sm` | `calc(var(--radius) * 0.6)` | `0.375rem` | 6px | | `--radius-md` | `rounded-md` | `calc(var(--radius) * 0.8)` | `0.5rem` | 8px | | `--radius-lg` | `rounded-lg` | `var(--radius)` | `0.625rem` | 10px | | `--radius-xl` | `rounded-xl` | `calc(var(--radius) * 1.4)` | `0.875rem` | 14px | | `--radius-2xl` | `rounded-2xl` | `calc(var(--radius) * 1.8)` | `1.125rem` | 18px | | `--radius-3xl` | `rounded-3xl` | `calc(var(--radius) * 2.2)` | `1.375rem` | 22px | | `--radius-4xl` | `rounded-4xl` | `calc(var(--radius) * 2.6)` | `1.625rem` | 26px | The table is the source of truth: the previews below render this site's own radius scale, which can differ slightly from what your project gets. ## Preview ]]>rounded-smrounded-mdrounded-lgrounded-xlrounded-2xlrounded-3xlrounded-4xlThree families of shadow, each a scale of Tailwind utilities: `shadow-*` for elevation, `inset-shadow-*` for recessed surfaces, and `drop-shadow-*` for shapes that are not boxes. > [!NOTE] > Inherited from Tailwind v4 defaults, not yet a pmndrs decision. See [Tailwind's box-shadow docs](https://tailwindcss.com/docs/box-shadow). Every shadow is black at low opacity. On a dark surface, the lighter ones barely show. Each family also has a `-none` utility that removes the shadow. ## Box shadow `shadow-*` sets `box-shadow` from the `--shadow-*` theme variable: | Utility | Variable | Value | | ------------ | -------------- | --------------------------------------------------------------- | | `shadow-2xs` | `--shadow-2xs` | `0 1px rgb(0 0 0 / 0.05)` | | `shadow-xs` | `--shadow-xs` | `0 1px 2px 0 rgb(0 0 0 / 0.05)` | | `shadow-sm` | `--shadow-sm` | `0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)` | | `shadow-md` | `--shadow-md` | `0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)` | | `shadow-lg` | `--shadow-lg` | `0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)` | | `shadow-xl` | `--shadow-xl` | `0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)` | | `shadow-2xl` | `--shadow-2xl` | `0 25px 50px -12px rgb(0 0 0 / 0.25)` | {['shadow-2xs', 'shadow-xs', 'shadow-sm', 'shadow-md', 'shadow-lg', 'shadow-xl', 'shadow-2xl'].map((shadow) => (## Inset shadow `inset-shadow-*` sets an inner `box-shadow` from the `--inset-shadow-*` theme variable. It stacks with `shadow-*` on the same element: | Utility | Variable | Value | | ------------------ | -------------------- | ----------------------------------- | | `inset-shadow-2xs` | `--inset-shadow-2xs` | `inset 0 1px rgb(0 0 0 / 0.05)` | | `inset-shadow-xs` | `--inset-shadow-xs` | `inset 0 1px 1px rgb(0 0 0 / 0.05)` | | `inset-shadow-sm` | `--inset-shadow-sm` | `inset 0 2px 4px rgb(0 0 0 / 0.05)` |))}{shadow}{['inset-shadow-2xs', 'inset-shadow-xs', 'inset-shadow-sm'].map((shadow) => (## Drop shadow `drop-shadow-*` applies `filter: drop-shadow()` from the `--drop-shadow-*` theme variable. It follows the painted shape, transparent pixels excluded, so it suits icons, SVGs and cut-out images: | Utility | Variable | Value | | ----------------- | ------------------- | ------------------------------ | | `drop-shadow-xs` | `--drop-shadow-xs` | `0 1px 1px rgb(0 0 0 / 0.05)` | | `drop-shadow-sm` | `--drop-shadow-sm` | `0 1px 2px rgb(0 0 0 / 0.15)` | | `drop-shadow-md` | `--drop-shadow-md` | `0 3px 3px rgb(0 0 0 / 0.12)` | | `drop-shadow-lg` | `--drop-shadow-lg` | `0 4px 4px rgb(0 0 0 / 0.15)` | | `drop-shadow-xl` | `--drop-shadow-xl` | `0 9px 7px rgb(0 0 0 / 0.1)` | | `drop-shadow-2xl` | `--drop-shadow-2xl` | `0 25px 25px rgb(0 0 0 / 0.15)` |))}{shadow}{['drop-shadow-xs', 'drop-shadow-sm', 'drop-shadow-md', 'drop-shadow-lg', 'drop-shadow-xl', 'drop-shadow-2xl'].map((shadow) => (]]>))}{shadow}Two families of motion utilities: `duration-*` sets how long a transition runs, and `ease-*` the curve it follows. A transition that names neither runs on one default for each. > [!NOTE] > Inherited from Tailwind v4 defaults, not yet a pmndrs decision. See [Tailwind's transition-duration docs](https://tailwindcss.com/docs/transition-duration). ## Defaults A `transition-*` utility (`transition`, `transition-colors`, `transition-transform`…) without a `duration-*` or an `ease-*` runs on these two theme variables: | Variable | Value | | -------------------------------------- | ------------------------------ | | `--default-transition-duration` | `150ms` | | `--default-transition-timing-function` | `cubic-bezier(0.4, 0, 0.2, 1)` | The default curve is the one `ease-in-out` sets. ## Duration `duration-*` sets `transition-duration` in milliseconds: `duration-300` is `300ms`. No theme variable stands behind it, so any number works, not only the steps below: `duration-250` is `250ms`. Use brackets for another unit (`duration-[2s]`). | Utility | Value | | --------------- | -------- | | `duration-0` | `0ms` | | `duration-75` | `75ms` | | `duration-100` | `100ms` | | `duration-150` | `150ms` | | `duration-200` | `200ms` | | `duration-300` | `300ms` | | `duration-500` | `500ms` | | `duration-700` | `700ms` | | `duration-1000` | `1000ms` | Hover the panel to run every step at once, on the default curve: {['duration-0', 'duration-75', 'duration-100', 'duration-150', 'duration-200', 'duration-300', 'duration-500', 'duration-700', 'duration-1000'].map((duration) => (## Easing `ease-*` sets `transition-timing-function`, from the `--ease-*` theme variables. See [Tailwind's transition-timing-function docs](https://tailwindcss.com/docs/transition-timing-function). | Utility | Variable | Value | | ------------- | --------------- | ------------------------------ | | `ease-linear` | none | `linear` | | `ease-in` | `--ease-in` | `cubic-bezier(0.4, 0, 1, 1)` | | `ease-out` | `--ease-out` | `cubic-bezier(0, 0, 0.2, 1)` | | `ease-in-out` | `--ease-in-out` | `cubic-bezier(0.4, 0, 0.2, 1)` | `ease-in` starts slow, so it suits an element leaving the screen. `ease-out` ends slow, so it suits an element arriving. `ease-in-out` suits an element that moves from one place to another. Hover the panel to run every curve at once, over `duration-1000`:))}{duration}{['ease-linear', 'ease-in', 'ease-out', 'ease-in-out'].map((ease) => (## Reduced motion Prefix a utility with `motion-reduce:` to drop a transition for people who ask their system for less motion: `motion-reduce:transition-none`. The previews above do. ]]>))}{ease}The pmndrs assets, each one installed into your app from the registry with one command. The logo is the first. ## Logo The pmndrs logo, in four states, as four SVG files. Install them with one command: ```sh npx shadcn@latest add pmndrs/design-system/logo#v0.9.0 ``` That writes them to `public/pmndrs/` at the root of your project, under the names below. Every file is 600×600 and paints its own black square background: there is no transparent variant yet. ### Variants | Variant | Preview | File | Behavior | | -------- | ------------------------------------------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------- | | Complete | | `public/pmndrs/logo_complete.svg` | The full mark. | | Idle |
| `public/pmndrs/logo_idle.svg` | The resting state: four concentric rings. | | Animated |
| `public/pmndrs/logo_animated.svg` | Idle → complete, once, in 0.73 s. Under reduced motion, the complete mark shows without moving. | | Loading |
| `public/pmndrs/logo_loading.svg` | Loops idle → each corner → idle, every 5.3 s. Under reduced motion, the mark only fades. | ### Usage Once installed (or copied into your app's `public/pmndrs/` by hand), each file is an image URL. Both animations are CSS inside the SVG, so a plain `
` plays them, and so does `next/image` with `unoptimized`: ```tsx
``` ## License These assets are MIT-licensed, like the rest of the repository: see [LICENSE](https://github.com/pmndrs/design-system/blob/main/LICENSE). No attribution required. ]]>