Theming & noodles
67 design systems, light and dark, scoped anywhere, overridable everywhere.
Choosing a noodle
Set data-noodle on <html>. Without it you get Mian, the black-and-white base every other noodle varies.
<html data-noodle="udon">Light and dark
Every noodle has a light and a dark palette. By default the page follows the operating system. Force a mode with data-mode:
<html data-noodle="lamian" data-mode="dark">Under the hood each token is a light-dark() pair and data-mode sets color-scheme, which inherits, so modes nest correctly.
Scoping
Both attributes work on any element, and they nest. A marketing section can use Mee while the app shell uses Mian, and a code sample can be forced dark:
<body> <!-- mian -->
<section data-noodle="mee"> … </section>
<aside data-noodle="shirataki" data-mode="dark"> … </aside>
</body>Switchers can be scoped too. Add data-mn-target to any theme control and it changes only that element: this is how the previews on this site work while the site itself stays Mian:
<select data-mn-noodle-select data-mn-target="#preview">…</select>
<div id="preview" data-noodle="mian"> … </div>Families
The 67 noodles are grouped by what they share: Minimal (11), Flat (5), Pixel (3), Linear (7), Thin (5), Glass (10), Textured (5), Bold (7), Elegant (7), Rounded (7). Each noodle page opens with its written design language, philosophy, principles, the rules for shape, surface, colour, type, motion and data, and a section on designing new components in that language.
Tokens
Components only read these custom properties. Override any of them on any selector.
| --mn-bg · --mn-surface · --mn-surface-2 | Page, card and muted surfaces. |
| --mn-fg · --mn-muted | Text and secondary text. |
| --mn-border · --mn-input · --mn-ring | Dividers, form borders, focus ring. |
| --mn-primary · --mn-secondary · --mn-accent | Brand roles, each with a matching -fg and -text. |
| --mn-success · --mn-warning · --mn-danger · --mn-info | Status roles, each with -fg and -text. |
| --mn-radius-field · --mn-radius-box · --mn-radius-badge | Controls, containers, small labels. |
| --mn-size-xs … --mn-size-lg · --mn-text-sm | Control heights and control text size (density). |
| --mn-shadow-sm · -md · -lg | Depth. |
| --mn-font · --mn-font-heading · --mn-font-mono | Typography. |
Noodles are design languages, not themes
A noodle has three parts. Tokens: colours, radii, fonts, density, shadows. A skin: rules in the mian.noodles cascade layer that change how components are built: Udon buttons have a thickness edge that compresses, Fensi surfaces are liquid glass with lens rims, Yinzhen draws everything in dots, Sanuki has no radius anywhere, every noodle has its own entrance animation. And a written design language: the philosophy, principles and rules behind the skin, so new components can be designed in the same language.
Skins are written with @scope ([data-noodle="…"]) to ([data-noodle]:not([data-noodle="…"])). The lower boundary is what makes nesting safe: a Shirataki section inside an Udon page gets none of Udon's rules.
Load everything with mian.css, or only what you use:
<link rel="stylesheet" href="https://mian.ro/dist/mian-core.css"> <!-- components + Mian -->
<link rel="stylesheet" href="https://mian.ro/dist/noodles/udon.css"> <!-- one more noodle -->Make your own noodle
A noodle is a selector that sets the tokens, plus (optionally) a scoped skin. Start from one of the noodle JSON files or write it by hand:
[data-noodle="tonkotsu"] {
--mn-bg: light-dark(#fffaf5, #140f0b);
--mn-surface: light-dark(#ffffff, #1c1611);
--mn-surface-2: light-dark(#f6ede3, #271f18);
--mn-fg: light-dark(#24170e, #f6ede3);
--mn-muted: light-dark(#6d5a4a, #b39f8b);
--mn-border: light-dark(#eadccd, #382d23);
--mn-input: light-dark(#d9c6b1, #4a3c2f);
--mn-primary: light-dark(#9a3412, #fdba74);
--mn-primary-fg: light-dark(#ffffff, #2a1206);
--mn-primary-text: light-dark(#9a3412, #fdba74);
--mn-ring: light-dark(#9a3412, #fdba74);
--mn-radius-field: 10px;
--mn-radius-box: 14px;
}
/* Optional skin: change how things are built, not just their colour. */
@layer mian.noodles {
@scope ([data-noodle="tonkotsu"]) to ([data-noodle]:not([data-noodle="tonkotsu"])) {
:scope { --mn-enter: my-simmer; --mn-bar-radius: 999px; }
.mn-btn { border-radius: 999px; box-shadow: 0 4px 0 color-mix(in oklab, var(--_bg), #000 25%); }
.mn-card { border-width: 2px; }
}
}
@keyframes my-simmer { from { opacity: 0; transform: translateY(6px) scale(.98); } }Any token you leave out falls back to Mian. Check your text pairs reach 4.5:1 contrast, MIAN's own noodles are verified by the build.
Designing components MIAN does not ship
Every noodle page has a Designing new components section: concrete do and avoid rules and a CSS recipe. The same guide is published for AI tools at /ai/noodles/<id>.md and through the MCP tool get_design_language. The pattern is always the same:
/* 1. Build from tokens, scoped to the noodle */
[data-noodle="kalguksu"] .pricing-tier {
border: 1px solid var(--mn-border);
background: var(--mn-surface);
color: var(--mn-fg);
}
/* 2. Apply the noodle's own rules (here: knife-cut corner, mono labels) */
[data-noodle="kalguksu"] .pricing-tier {
clip-path: polygon(0 0, calc(100% - 6px) 0, 100% 6px, 100% 100%, 0 100%);
}Colour roles
Components that take colour accept a role class next to them: mn-primary, mn-secondary, mn-accent, mn-success, mn-warning, mn-danger, mn-info, mn-neutral. Roles do not inherit, so a red alert does not turn the buttons inside it red.