Radius
Corner radius is unified and intentional (ADR-0003). Two values do most of the work:
radius-control (12) and radius-card (16). The full pill is reserved. The scale is
one shared truth across platforms; radius is brand expression, not interaction behavior,
so it does not fork per OS.
The scale
Section titled “The scale”| Token | Value | Use |
|---|---|---|
radius-none |
0px | Square edges |
radius-track |
2px | Slider fills / progress tracks (the real Android NockerlProgressTrackShape) |
radius-control |
12px | Buttons, fields, most controls |
radius-panel |
12px | Nested panels, tool cards, chips-as-panels |
radius-card |
16px | Cards and surfaces |
radius-bubble |
20px | Chat message bubbles |
radius-bubble-tail |
6px | Tightened “tail” corner of a bubble, pointing at the speaker |
radius-pill |
9999px | Chips + the input bar only |
The law (see Design laws): pill is reserved for chips and the input bar. Every other control uses the 12px control radius, a rounded rectangle, never a “broken pill”. Cards step up to 16px. The gap between 12 and the full pill is kept visually obvious so a button can never read as a truncated chip.
Where each radius is used
Section titled “Where each radius is used”Grounded in the primitives, not aspiration:
radius-control(12):Button,Well(the recessed field), plainIconButton,Menu/ListboxOptionrows,Tooltip,Popoverfields and buttons, and theSegmentedControlframe (its thumb nests one step inside atcalc(control − 0.5)).radius-card(16):Surface/Cardin the defaultcardvariant (the lifted plane).radius-panel(12):Surfacein thepanelvariant (nested panels, tool cards).radius-pill:Chip,Badge,Avatar,StatusDot, and theSlidertrack + thumb.radius-track(2):ProgressTrack(squared rails, deliberately not a pill).
Per-platform values
Section titled “Per-platform values”Radius is unified: the same numeric intent ships everywhere, only the unit changes with
the platform’s native type. The semantic tokens are authored in px; the Compose build emits
the same numbers as dp, and the Swift build emits them as points, so radius-control
is 12px on web, 12dp on Android, and 12pt on Swift, and radius-card is 16 on all three. This
is the industry pattern (Fluent 2’s global → alias → control layering; Spotify’s near-identical
cross-platform shape) and the explicit ADR-0003 posture: unify brand expression, honor only
real platform behavior.
The web card → 4px shadcn default that once diverged was drift, not a decision. ADR-0003
dropped it, so web now inherits the unified 16. The only genuinely platform-specific shape token
left is Android’s chamfer.
Tokens
Section titled “Tokens”The radius scale is published in @dizyx/nockerl-tokens as CSS custom properties
(--radius-*). The intent names (control, card, pill) live in the semantic layer;
the concrete value/unit per platform (px vs dp vs pt, plus Android’s chamfer) lives in the
platform layer. See the Token hierarchy for how the layers
compose.