ds
one design language, one implementation, every app on mianda.dev. tokens and components ship as framework-agnostic custom elements — link two files, import a module, or install the package. this page is built out of them.
use it
The script is deliberately render-blocking: it applies the stored theme before
first paint and defines the elements before <body> parses, so
nothing flashes and nothing shifts.
<!-- drop-in: any framework, any host, no build step -->
<link rel="stylesheet" href="https://ds.mianda.dev/v1/ds.css">
<script src="https://ds.mianda.dev/v1/ds.js"></script>
<dev-header app="shaderlab"></dev-header>
<dv-button variant="primary" size="lg">generate</dv-button>
<dev-footer app="shaderlab" version="0.3.0"></dev-footer>
// as a module, when you want the api too
import { theme, loadConfig } from 'https://ds.mianda.dev/v1/ds.mjs';
theme.toggle();
theme.subscribe(({ theme }) => console.log('now', theme));
// as a package, when you already have a bundler npm install @mianda/ds import '@mianda/ds'; // registers every element import '@mianda/ds/ds.css'; import { theme, type ThemeName } from '@mianda/ds';
buttons
<dv-button> owns a real <button> — or an
<a> when you give it href — and steps out of layout
itself, so your flex parent sees the control, not a wrapper.
<dv-button variant="primary" size="lg">generate</dv-button> <dv-button href="/somewhere">open</dv-button> <dv-button loading>connecting</dv-button> <dv-icon-button label="fullscreen">⛶</dv-icon-button>
chips
A selectable filter token — denser than a button, interactive unlike a tag.
Controlled: reflect your state onto selected and listen for the click,
which bubbles from the native button inside.
<dv-chip selected>webgl</dv-chip>
badges & tags
<dv-badge dot>live</dv-badge> <dv-tag>webgl</dv-tag>
tabs
Emits change with detail.value; also readable and settable as .value.
<dv-tabs items="generate,lab,library" value="lab"></dv-tabs>
tabs.addEventListener('change', (e) => console.log(e.detail.value));
inputs & switch
<dv-input label="prompt" hint="plain language" placeholder="…"></dv-input>
<dv-switch label="loop preview" checked></dv-switch>
input.value // proxies the native control
sw.addEventListener('change', (e) => e.detail.checked);
cards & placeholder
A card with href becomes one link end to end, keeping the whole
surface clickable without nesting an anchor around a div.
plain card
the class lands on the host — no wrapper between this and the grid.
hover me
steps a surface and border on hover, scales .99 on press.
the hub →
one anchor around the whole card.
tokens
CSS custom properties on :root, re-declared under
[data-theme="dark"]. Read them, never hard-code their values.
One accent hue — rank and state are carried by surface, weight and fill instead.
| token | value |
|---|
shell
The header and footer at the top and bottom of this page are the same elements every app renders. The app switcher is fetched from the hub, so shipping a new app updates every app's menu without redeploying any of them.
<dev-header app="shaderlab" root="#/" shape="asym"></dev-header>
<dev-footer app="shaderlab" version="0.3.0"></dev-footer>
app name in the wordmark suffix "" for none
home where the ⌂ button goes root wordmark target, "#/" on an SPA
shape pills | asym | angle config registry url, or "off"