Setup and copy

Six blocks, in order. Each says where it goes, and the first two set the project up once. Copy them one at a time.

@anytv:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${ANYTV_M3_TOKEN}

Once per project. Commit this file — it names the token, it does not carry it. Keep the value in .env.local, which git ignores, as ANYTV_M3_TOKEN.

"registries": {
  "@m3": {
    "url": "https://api.github.com/repos/anyTV/m3-ui/contents/r/{name}.json",
    "params": { "ref": "components-v0.2.0" },
    "headers": {
      "Accept": "application/vnd.github.raw",
      "Authorization": "Bearer ${ANYTV_M3_TOKEN}",
      "X-GitHub-Api-Version": "2022-11-28"
    }
  }
}

Once per project. It is a top-level key, so add a comma after the block above it. The CLI fills in ${ANYTV_M3_TOKEN} from .env.local. The ref pins the released snapshot components-v0.2.0. Set it to main to take every change as it lands.

pnpm dlx shadcn-vue@latest search @m3
pnpm dlx shadcn-vue@latest add @m3/button

Run these from your project root, after the two files above — search lists all 41 items, and add takes any number of them.

pnpm dlx shadcn-vue@latest add @m3/agent-rules

Writes two files under .agents/. Nothing reads them on its own — the command prints the line to add to your AGENTS.md or CLAUDE.md.

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&amp;display=block">

Loads the typeface from Google. To self-host, swap these links for your own @font-face rules and keep the CSS block as it is.

/* m3-ui theme — import after the base M3 tokens
 * Source: #6750A4
 * Scheme: tonalSpot
 * Typeface: Roboto
 * Generated typography and one declaration per color role via light-dark(); the mode is
 * chosen by color-scheme, and the .light / .dark rules below let this block stand alone.
 */
:root {
  --md-ref-typeface-brand: 'Roboto', system-ui, sans-serif;
  --md-ref-typeface-plain: 'Roboto', system-ui, sans-serif;
  --md-ref-typeface-weight-regular: 400;
  --md-ref-typeface-weight-medium: 500;
  --md-ref-typeface-weight-bold: 700;
  font-optical-sizing: auto;
  font-stretch: normal;
  font-variation-settings: normal;
  --m3-brand-font-optical-sizing: auto;
  --m3-brand-font-stretch: normal;
  --m3-brand-font-variation-settings: normal;
  --m3-plain-font-optical-sizing: auto;
  --m3-plain-font-stretch: normal;
  --m3-plain-font-variation-settings: normal;
}

body {
  font-family: var(--md-ref-typeface-plain);
}

code,
kbd,
pre,
samp {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
    "Courier New", monospace;
  font-optical-sizing: auto;
  font-stretch: normal;
  font-variation-settings: normal;
}

:root {
  color-scheme: light dark;
  --md-sys-color-background: light-dark(#fdf7ff, #141218);
  --md-sys-color-on-background: light-dark(#1d1b20, #e6e0e9);
  --md-sys-color-surface: light-dark(#fdf7ff, #141218);
  --md-sys-color-surface-dim: light-dark(#ded8e0, #141218);
  --md-sys-color-surface-bright: light-dark(#fdf7ff, #3b383e);
  --md-sys-color-surface-container-lowest: light-dark(#ffffff, #0f0d13);
  --md-sys-color-surface-container-low: light-dark(#f8f2fa, #1d1b20);
  --md-sys-color-surface-container: light-dark(#f2ecf4, #211f24);
  --md-sys-color-surface-container-high: light-dark(#ece6ee, #2b292f);
  --md-sys-color-surface-container-highest: light-dark(#e6e0e9, #36343a);
  --md-sys-color-on-surface: light-dark(#1d1b20, #e6e0e9);
  --md-sys-color-surface-variant: light-dark(#e7e0eb, #49454e);
  --md-sys-color-on-surface-variant: light-dark(#49454e, #cac4cf);
  --md-sys-color-outline: light-dark(#7a757f, #948f99);
  --md-sys-color-outline-variant: light-dark(#cac4cf, #49454e);
  --md-sys-color-inverse-surface: light-dark(#322f35, #e6e0e9);
  --md-sys-color-inverse-on-surface: light-dark(#f5eff7, #322f35);
  --md-sys-color-shadow: #000000;
  --md-sys-color-scrim: #000000;
  --md-sys-color-surface-tint: light-dark(#65558f, #cfbdfe);
  --md-sys-color-primary: light-dark(#65558f, #cfbdfe);
  --md-sys-color-primary-dim: light-dark(#594982, #c7b4f5);
  --md-sys-color-on-primary: light-dark(#ffffff, #36275d);
  --md-sys-color-primary-container: light-dark(#e9ddff, #4d3d75);
  --md-sys-color-on-primary-container: light-dark(#4d3d75, #e9ddff);
  --md-sys-color-primary-fixed: #e9ddff;
  --md-sys-color-primary-fixed-dim: #cfbdfe;
  --md-sys-color-on-primary-fixed: #201047;
  --md-sys-color-on-primary-fixed-variant: #4d3d75;
  --md-sys-color-inverse-primary: light-dark(#cfbdfe, #65558f);
  --md-sys-color-secondary: light-dark(#625b71, #cbc2db);
  --md-sys-color-secondary-dim: light-dark(#564f64, #e8def8);
  --md-sys-color-on-secondary: light-dark(#ffffff, #332d41);
  --md-sys-color-secondary-container: light-dark(#e8def8, #4a4458);
  --md-sys-color-on-secondary-container: light-dark(#4a4458, #e8def8);
  --md-sys-color-secondary-fixed: #e8def8;
  --md-sys-color-secondary-fixed-dim: #cbc2db;
  --md-sys-color-on-secondary-fixed: #1e192b;
  --md-sys-color-on-secondary-fixed-variant: #4a4458;
  --md-sys-color-tertiary: light-dark(#7e5260, #efb8c8);
  --md-sys-color-tertiary-dim: light-dark(#704654, #fec5d6);
  --md-sys-color-on-tertiary: light-dark(#ffffff, #4a2532);
  --md-sys-color-tertiary-container: light-dark(#ffd9e3, #633b48);
  --md-sys-color-on-tertiary-container: light-dark(#633b48, #ffd9e3);
  --md-sys-color-tertiary-fixed: #ffd9e3;
  --md-sys-color-tertiary-fixed-dim: #efb8c8;
  --md-sys-color-on-tertiary-fixed: #31101d;
  --md-sys-color-on-tertiary-fixed-variant: #633b48;
  --md-sys-color-error: light-dark(#ba1a1a, #ffb4ab);
  --md-sys-color-error-dim: light-dark(#a80710, #ff554a);
  --md-sys-color-on-error: light-dark(#ffffff, #690005);
  --md-sys-color-error-container: light-dark(#ffdad6, #93000a);
  --md-sys-color-on-error-container: light-dark(#93000a, #ffdad6);
}

.light {
  color-scheme: light;
}

.dark {
  color-scheme: dark;
}

No runtime color generator needed. For build-time or runtime theming, use generateM3Theme and toCssVariables from @anytv/m3-tokens.

Setup for your agent

One prompt: the whole setup, and this theme. Paste it into your agent.

Set up the anyTV Material 3 component library in this project, using the theme configured
below. Work from the project root and do these in order.

1. Create or edit `.npmrc`:

```ini
@anytv:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${ANYTV_M3_TOKEN}
```

Commit `.npmrc` — it names the token, it does not carry it.

2. The token value lives in `.env.local`, which git ignores, under the name
`ANYTV_M3_TOKEN`. Ask me for the value rather than obtaining one, and keep it out of every
tracked file. Two tools need it: the shadcn-vue CLI reads `.env.local`, and pnpm reads the
same name from the shell environment.

3. Add this as a top-level key in `components.json`, beside `"aliases"`. Run
`pnpm dlx shadcn-vue@latest init` first if `components.json` is absent. `{name}` and
`${ANYTV_M3_TOKEN}` are placeholders the CLI expands, so keep both literal.

```json
"registries": {
  "@m3": {
    "url": "https://api.github.com/repos/anyTV/m3-ui/contents/r/{name}.json",
    "params": { "ref": "components-v0.2.0" },
    "headers": {
      "Accept": "application/vnd.github.raw",
      "Authorization": "Bearer ${ANYTV_M3_TOKEN}",
      "X-GitHub-Api-Version": "2022-11-28"
    }
  }
}
```

4. Run `pnpm add @anytv/m3-tokens`.

5. In the Tailwind entry stylesheet, import the theme after Tailwind itself and set the
source colour configured below:

```css
@import 'tailwindcss';
@import '@anytv/m3-tokens/css/theme.css';

:root {
  --m3-source-color: #6750A4;
}
```

6. In the same file, after those imports, paste this generated theme block exactly as it
stands. Every color role and the typeface in it are already resolved from the configuration
below, so nothing here is a placeholder to fill in:

```css
/* m3-ui theme — import after the base M3 tokens
 * Source: #6750A4
 * Scheme: tonalSpot
 * Typeface: Roboto
 * Generated typography and one declaration per color role via light-dark(); the mode is
 * chosen by color-scheme, and the .light / .dark rules below let this block stand alone.
 */
:root {
  --md-ref-typeface-brand: 'Roboto', system-ui, sans-serif;
  --md-ref-typeface-plain: 'Roboto', system-ui, sans-serif;
  --md-ref-typeface-weight-regular: 400;
  --md-ref-typeface-weight-medium: 500;
  --md-ref-typeface-weight-bold: 700;
  font-optical-sizing: auto;
  font-stretch: normal;
  font-variation-settings: normal;
  --m3-brand-font-optical-sizing: auto;
  --m3-brand-font-stretch: normal;
  --m3-brand-font-variation-settings: normal;
  --m3-plain-font-optical-sizing: auto;
  --m3-plain-font-stretch: normal;
  --m3-plain-font-variation-settings: normal;
}

body {
  font-family: var(--md-ref-typeface-plain);
}

code,
kbd,
pre,
samp {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
    "Courier New", monospace;
  font-optical-sizing: auto;
  font-stretch: normal;
  font-variation-settings: normal;
}

:root {
  color-scheme: light dark;
  --md-sys-color-background: light-dark(#fdf7ff, #141218);
  --md-sys-color-on-background: light-dark(#1d1b20, #e6e0e9);
  --md-sys-color-surface: light-dark(#fdf7ff, #141218);
  --md-sys-color-surface-dim: light-dark(#ded8e0, #141218);
  --md-sys-color-surface-bright: light-dark(#fdf7ff, #3b383e);
  --md-sys-color-surface-container-lowest: light-dark(#ffffff, #0f0d13);
  --md-sys-color-surface-container-low: light-dark(#f8f2fa, #1d1b20);
  --md-sys-color-surface-container: light-dark(#f2ecf4, #211f24);
  --md-sys-color-surface-container-high: light-dark(#ece6ee, #2b292f);
  --md-sys-color-surface-container-highest: light-dark(#e6e0e9, #36343a);
  --md-sys-color-on-surface: light-dark(#1d1b20, #e6e0e9);
  --md-sys-color-surface-variant: light-dark(#e7e0eb, #49454e);
  --md-sys-color-on-surface-variant: light-dark(#49454e, #cac4cf);
  --md-sys-color-outline: light-dark(#7a757f, #948f99);
  --md-sys-color-outline-variant: light-dark(#cac4cf, #49454e);
  --md-sys-color-inverse-surface: light-dark(#322f35, #e6e0e9);
  --md-sys-color-inverse-on-surface: light-dark(#f5eff7, #322f35);
  --md-sys-color-shadow: #000000;
  --md-sys-color-scrim: #000000;
  --md-sys-color-surface-tint: light-dark(#65558f, #cfbdfe);
  --md-sys-color-primary: light-dark(#65558f, #cfbdfe);
  --md-sys-color-primary-dim: light-dark(#594982, #c7b4f5);
  --md-sys-color-on-primary: light-dark(#ffffff, #36275d);
  --md-sys-color-primary-container: light-dark(#e9ddff, #4d3d75);
  --md-sys-color-on-primary-container: light-dark(#4d3d75, #e9ddff);
  --md-sys-color-primary-fixed: #e9ddff;
  --md-sys-color-primary-fixed-dim: #cfbdfe;
  --md-sys-color-on-primary-fixed: #201047;
  --md-sys-color-on-primary-fixed-variant: #4d3d75;
  --md-sys-color-inverse-primary: light-dark(#cfbdfe, #65558f);
  --md-sys-color-secondary: light-dark(#625b71, #cbc2db);
  --md-sys-color-secondary-dim: light-dark(#564f64, #e8def8);
  --md-sys-color-on-secondary: light-dark(#ffffff, #332d41);
  --md-sys-color-secondary-container: light-dark(#e8def8, #4a4458);
  --md-sys-color-on-secondary-container: light-dark(#4a4458, #e8def8);
  --md-sys-color-secondary-fixed: #e8def8;
  --md-sys-color-secondary-fixed-dim: #cbc2db;
  --md-sys-color-on-secondary-fixed: #1e192b;
  --md-sys-color-on-secondary-fixed-variant: #4a4458;
  --md-sys-color-tertiary: light-dark(#7e5260, #efb8c8);
  --md-sys-color-tertiary-dim: light-dark(#704654, #fec5d6);
  --md-sys-color-on-tertiary: light-dark(#ffffff, #4a2532);
  --md-sys-color-tertiary-container: light-dark(#ffd9e3, #633b48);
  --md-sys-color-on-tertiary-container: light-dark(#633b48, #ffd9e3);
  --md-sys-color-tertiary-fixed: #ffd9e3;
  --md-sys-color-tertiary-fixed-dim: #efb8c8;
  --md-sys-color-on-tertiary-fixed: #31101d;
  --md-sys-color-on-tertiary-fixed-variant: #633b48;
  --md-sys-color-error: light-dark(#ba1a1a, #ffb4ab);
  --md-sys-color-error-dim: light-dark(#a80710, #ff554a);
  --md-sys-color-on-error: light-dark(#ffffff, #690005);
  --md-sys-color-error-container: light-dark(#ffdad6, #93000a);
  --md-sys-color-on-error-container: light-dark(#93000a, #ffdad6);
}

.light {
  color-scheme: light;
}

.dark {
  color-scheme: dark;
}

```

7. Inside `<head>` in `index.html`, paste these font links exactly as they stand:

```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&amp;display=block">
```

8. Run `pnpm dlx shadcn-vue@latest add @m3/agent-rules`. It writes `.agents/m3-ui.md` and
`.agents/m3-ui-components.md` and prints one pointer line; put that line in this project’s
`AGENTS.md` or `CLAUDE.md` so every later session reaches them.

9. Read `.agents/m3-ui.md` and `.agents/m3-ui-components.md` in full, and follow them for
every component you add from here, one at a time:
`pnpm dlx shadcn-vue@latest add @m3/<name>`.

Done when `pnpm dlx shadcn-vue@latest search @m3` lists the registry’s items. A 404 from it
means the token value has not reached the CLI — an empty header is dropped rather than sent
blank. If an install fails with `ERR_PNPM_IGNORED_BUILDS`, allow `esbuild` and `vue-demi`
under `allowBuilds` in `pnpm-workspace.yaml`.

It writes the files, runs the installs, and asks you for the token value. The color and typeface you picked here are already in it.

Reset theme?

This restores the source color, color scheme, appearance, relative colors, and typography to their defaults.

M3 UI Playground

Component playground

Build with Material 3

Tune one component at a time, then copy setup code that includes your source color and saved radius choices.

Focused playgrounds, fewer grids

Each page presents one live example and a compact control list. Use the sidebars to move between components or update the theme.

How it works

Components are copied into your project. Design tokens remain in the shared package.

Components

ButtonLabeled actions and toggles
Button groupConnected selections
Split buttonPrimary and related actions
ChipsAssist, filter, input, and suggestion
Icon buttonCompact actions and toggles
Floating action buttonPrimary screen action
FAB menuRelated actions from a FAB
MenuActions and compact choices
PopoverNative anchored overlay infrastructure
TooltipContext for unfamiliar controls
SnackbarShort-lived process feedback
BadgeStatus and bounded counts
DividerContent grouping boundaries
TabsPeer content views
Navigation barCompact destinations
Navigation railMedium destinations
Navigation drawerExpanded destinations
Top app barScreen title and actions
Bottom app barLegacy screen actions and FAB
DialogsFocused decisions and information
Bottom sheetsSupporting content from below
Side sheetsSecondary work beside content
SearchExpandable content search
Linear progressHorizontal process status
Circular progressCompact process status
Loading indicatorExpressive indeterminate loading
CarouselSix responsive content layouts
ToolbarFlexible action collections
Date pickerSingle calendar dates
Date range pickerCalendar date spans
Time pickerDial and text time input
Color pickerProject extension for color input
CardStatic and interactive containers
Text fieldFilled and outlined inputs
CheckboxIndependent selections
Radio buttonSingle-choice groups
SwitchBinary settings
SelectM3-inspired native single choice
ListStructured rows
Material symbolLocal outlined icon glyphs
SliderExpressive values and bounded ranges