Design system
Monochrome, engineered, alive under the finger.
A standalone SvelteKit component library for Anomalia — published as an npm package and consumed by the app like any other dependency. The surface is near-monochrome and close to flat: hairlines and surface steps carry structure, colour carries meaning, and nothing decorates. Everything that happens after you touch it is Material: ripples from the contact point, state layers, emphasized easing, gestures that track the finger 1:1.
Principles
Quiet surfaces
Near-monochrome, close to flat, tight radii. Structure comes from hairlines and surface steps rather than shadow and fill, so a dense screen stays legible instead of loud.
Expressive interaction
Material owns everything after contact: ripples from the touch point, state layers, emphasized easing, and gestures that commit on distance or velocity rather than distance alone.
Colour is information
Ink is the interactive colour; the brand hue is reserved for identity, not controls; status hues appear only when something has a state. That is also what makes every pair clear WCAG without a fight.
Tokens, not overrides
Components read semantic tokens only. Restyle the whole system by redefining one layer — never by fighting a component with a more specific selector.
Install
npm install @anomalia/ui<!-- src/routes/+layout.svelte -->
<script lang="ts">
import '@anomalia/ui/styles.css';
import { ThemeProvider, Toaster } from '@anomalia/ui';
let { children } = $props();
</script>
<ThemeProvider>
{@render children()}
<Toaster />
</ThemeProvider>Add the exported themeScript to app.html as well — it resolves the
theme before first paint, which ThemeProvider alone cannot do (it runs after
hydration, one frame too late).
Use
<script lang="ts">
import { Button, Card, TextField, toast } from '@anomalia/ui';
let email = $state('');
</script>
<Card>
<TextField label="Email" bind:value={email} placeholder="you@studio.com" />
<Button onclick={() => toast.success({ title: 'Saved' })}>Save</Button>
</Card>What is in the box
- Tokens — primitives (palette, type ramp, space, radius, motion) and the semantic layer components actually read, with light and dark resolved from one attribute.
- Components — buttons, forms, overlays, navigation and feedback, each with its own scoped CSS and no styling dependency.
- Gestures —
use:ripple,use:pressanduse:swipe, plus haptics, focus trapping, scroll locking and anchored positioning. - Motion — the Material 3 duration and easing scales, mirrored in CSS and JS so a Svelte transition and a CSS transition use the identical curve.
- Accessibility — contrast enforced at the token layer by an audit that fails the build, full keyboard patterns, and answers for reduced motion, increased contrast, reduced transparency and forced colours.