Skip to content
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
Getting startedWebReactSwiftUIJetpack ComposeFlutterReact NativePresetsYour own design systemUsing Tanrei with AI agentsBrandDesign tokensDesign systems and customizationTheme StudioColorTypographyIconsShapeElevationMotionInteraction statesBehaviourLayoutAccessibilityWordsColor tokensTypescale tokensShape tokensElevation tokensMotion tokensState tokensSpace and measure tokensComponentsButtonMain action buttonSegmented buttonButton groupButton with menuToolbarCopy buttonCheckboxRadio buttonSwitchChipMenuSliderSlider fieldCalendarDateTimePickerField groupRadio groupCheckbox groupSelectSelect fieldMenubarFile uploadFile picker AdvancedDrop zoneText input AdvancedText fieldChip fieldFieldCombobox AdvancedCombobox fieldNumber input AdvancedNumber fieldColor input AdvancedColor fieldOne-time-code input AdvancedOne-time-code fieldEmbedded text input AdvancedChat composerCardDividerModal layer AdvancedDialogListList rowBottom sheetSide sheetCarouselCode blockTablePopoverStepsAccordionDescription listFigureApp shellPage headerTree viewTimelineImage previewHandleResizable frameScroll areaBadgeProgress indicatorMeterNumber tickerLoading indicatorSnackbarTooltipKeyboard shortcutTagInline codeCalloutAvatarEmpty stateTag groupSkeletonFile itemSwatchMarquee textTabsTab viewApp barNavigation barNavigation drawerSearchLinkPaginationPrevious and next linksStepperBreadcrumbsTable of contentsLink cardFAB menuStatusHow Tanrei is builtContributingLicense and attribution
HomeGetting startedYour own design system

Your own design system

Keep one layer file in your product. One command writes tokens and code for every platform you ship, in one pull request.

content_copyView as Markdown

Tanrei’s components never change when your product’s look does. What changes is a layer: a small JSON file that sets values of the shared vocabulary and declares your palettes. @tanrei/cli turns that one file into everything each platform needs.

Prerelease

0.1.0-next.0 is published to npm under the dist-tag next: until 0.1.0, install @tanrei/cli@next and @tanrei/mcp@next. During the 0.x prereleases backward compatibility is not kept: any prerelease may break anything, with no deprecation period first, and its changeset says what broke.

Install

From npm

Add the command line tool to your product as a development dependency; every npx tanrei … command on this page then runs that copy. It carries Theme Studio, which tanrei studio serves.

npm install --save-dev @tanrei/cli

The MCP server needs no install: npx fetches @tanrei/mcp when an agent starts it, as registered further down this page.

From source

To use the source as it stands on main, build both packages in a clone of the repository and install the packed files in your product as development dependencies:

git clone https://github.com/chnotchy/tanrei.git
cd tanrei
pnpm install
pnpm --filter @tanrei/studio build:app   # Theme Studio, which `tanrei studio` serves
pnpm --filter @tanrei/cli --filter @tanrei/mcp build
pnpm --filter @tanrei/cli --filter @tanrei/mcp pack --pack-destination ../tanrei-packages
# in your product: the path to the folder the packages were written to
npm install --save-dev path/to/tanrei-packages/tanrei-cli-*.tgz path/to/tanrei-packages/tanrei-mcp-*.tgz

For the MCP server, register the installed copy instead: claude mcp add tanrei -- npx tanrei-mcp, run in your product’s folder.

From a layer to every platform

  1. Start a layer — from the default system or from a preset.

    npx tanrei init acme --extends tanrei

    This writes design/acme.system.json and tanrei.json. Prefer sliders? Shape the layer in the Theme Studio and download it instead.

  2. Say where each output goes in tanrei.json. List only what you ship.

    {
      "system": "design/acme.system.json",
      "kotlinPackage": "com.acme.design",
      "outputs": {
        "tokens": "design/tokens/acme",
        "web": "apps/web/src/styles",
        "swiftui": "apps/ios/Acme/Design",
        "compose": "apps/android/app/src/main/kotlin/com/acme/design",
        "flutter": "apps/flutter/lib/design",
        "react-native": "apps/mobile/src/design"
      }
    }
  3. Build.

    npx tanrei build

    Commit the result. Add npx tanrei build --check to CI: it writes nothing and fails when a committed output is stale.

  4. Use it. The generated files contain your system’s values; the types come from the library, so a vocabulary change breaks the build instead of drifting silently.

    Platform You get You write
    Web acme.css <html data-tanrei-system="acme">
    SwiftUI TanreiSystem+Acme.swift .tanreiTheme(TanreiTheme(system: .acme))
    Compose TanreiSystemAcme.kt TanreiTheme(system = TanreiSystem.Acme) { … }
    Flutter acme_system.g.dart TanreiTheme(data: TanreiThemeData.platform(context, system: acmeSystem), …)
    React Native acme.ts <TanreiProvider system={acme}>

One change, one pull request

Edit a value in the layer, run tanrei build, and every platform’s file changes in the same commit. Making all text a little larger is one line:

"tanrei.dial.type.base": { "$value": { "value": 17, "unit": "px" }, "reason": "Read at arm's length." }

See Design systems and customization for the four things a layer can do to a value — set a dial, scale a token, re-point an alias, pin a value with a reason — for declaring palettes such as a brand color or a quiz’s correct and incorrect, and for adding tokens when values are not enough.

As much control as you want — always the same file

Customization is layered, and every level edits the one <id>.system.json:

You want You use
A quick setup Theme Studio → the rail: the nine rows of the look — brand color, gray, typeface, size, corners, corner smoothing, icons, press feedback, focus — each a press away, with a lock and a shuffle
To tune groups Studio → the rail’s More: all eight dials, every palette, each component, every behaviour
To touch one token at a time, in a GUI Studio → Inspect → Tokens: search the whole vocabulary; each token offers only the edits that are legal for it, and shows what follows it
To edit source Studio → Inspect → Source, or your editor: the JSON, validated against the schema and by the engine
A token that does not exist Add it: a step in a series, a Button size or variant in one line, or tokens of your own
npx tanrei studio

opens Theme Studio on your layer file: edits are saved to it as you make them (review them with git like any change), an edit made in your editor at the same time is never overwritten, and “Build” runs tanrei build. It listens on 127.0.0.1 only and the printed link carries a one-time key. The Studio on this site is the same tool with import and export instead of a file.

Check the code against your system

npx tanrei audit src

reads your product’s code — script (JS, TS, JSX), markup (HTML, Vue, Svelte, Astro) and stylesheets (CSS, Sass, Less) — and reports what your system does not have, each at its file, line and column, with what to write instead:

  • an element of a component the system does not have — <tanrei-fab-menu> in a page, a template, JSX or a string, an imported React wrapper, or a CSS selector that names it — with the components the system ships for the same job, the systems that have it, and the line of your layer that would take it in;
  • an import from an entry that does not fit the system — @tanrei/web/m3-like or @tanrei/react/all in a product of the default system — with the entry that does;
  • a written variant="…" the system leaves out, with the values it offers.

It checks against your product’s system (tanrei.json), or the one --system names: a shipped system such as m3-like, or a layer file. Give it files, directories, or a glob in quotes ('src/**/*.{ts,tsx,html,css}'); a directory is read without node_modules and hidden directories. --format json prints the findings as data. It exits with 1 when it finds something, so it can run in CI beside tanrei build --check, and with 2 when it cannot run. The MCP server’s check_usage runs the same check.

It reads the text, not a running page: comments are skipped, but a variant held in a variable, or a tag put together from pieces, is not seen.

Tailwind CSS and shadcn/ui

Add "tailwind" or "shadcn" to outputs. Both files only map names onto Tanrei’s custom properties, so themes, contrast levels and the live dials keep working underneath.

@import "tailwindcss";
@import "@tanrei/web/tokens.css";
@import "./styles/acme.css";
@import "./styles/acme.tailwind.css"; /* bg-primary · text-on-primary · rounded-medium · p-200 · text-heading-4 */

Sharing a system — with people, tools and AI agents

  • The tokens output is a self-contained DTCG 2025.10 bundle with a standard resolver. Any design-token tool can read it; the layer files that produced it travel inside, and every group carries usage guidance for agents in $extensions["dev.tanrei.llm"].

  • It also holds components.json, the components your system ships: each with its element (or class), its React name and the module that registers it, and the components it does not have, with the layer that left each out and what to use instead. An agent that reads it suggests only components your product can use. Each shipped system has one as well: @tanrei/web/systems/<id>.components.json.

  • @tanrei/mcp is a Model Context Protocol server. An agent working in your repository can search the vocabulary, see where a value comes from, compare systems, propose an extension (a new Button size, a step, a token of your own) with its resulting values, and validate a layer edit before it writes it — and it is told the rules: change values through a layer, extend the vocabulary only by adding and with a rationale, give every pinned value a reason, never touch a threshold. For the UI itself it answers from the system’s components manifest and the specs: which components the system has (and, for one it does not, what to use instead), a component’s props, events and behaviour rules, and which elements, imports and variants in your code the system does not have, with where they are — the check tanrei audit runs.

    Register it from npm, in your product’s folder (Using Tanrei with AI agents has the settings for other clients):

    claude mcp add tanrei -- npx -y @tanrei/mcp

Accessibility

Contrast thresholds and structural checks are constants. In your layer a violation is a warning, never silent: it is printed by tanrei build, written to a11y-report.json, and stamped at the top of every generated file. At medium and high contrast, aim for zero — those schemes exist because a person asked for contrast. The shipped presets themselves are held to fidelity to the systems they imitate, not to Tanrei’s accessibility criteria, in every scheme; their measurements are information. A layer you build on a preset is still your product, and is warned about what it inherits too.