Design system

svemir is my personal universe of references: blocks, channels, a knowledge graph, and a research layer for papers.

This is the system it runs on. A tight set of primitives sits over a single token layer, so nothing is hardcoded and every screen re-themes on command. Change one token and the whole product follows. Everything below is the real code, composed atoms to organisms.

Theme

Principles

The four rules the rest of the system falls out of.

1Token-first

Every value is a CSS variable. Components never hardcode a hex, so all four themes work for free: restyle the tokens, not the components.

2Monochrome + one accent

A single neutral ramp carries the whole UI. Colour is earned: red is reserved for destructive actions, nothing else competes with the imagery.

3Quiet by default

Image-forward and calm at rest. Context (titles, sources, actions) fades in on hover instead of crowding the wall of references.

4Harmonized geometry

One radius floor (xl), one spacing rhythm, one elevation and layering ladder. Consistency is the system; primitives make it repeatable.

Foundations

Tokens, not hardcoded values. Only the neutral ramp + semantic tokens, so the 4 themes keep working.

Brandwordmark + Bebas Neue display type
svemir logo
SVEMIRBebas Neue · display / headings · uppercase, wide tracking
logo: /svemir.svg · display: font-[family-name:var(--font-display)] / font-display
Colour · neutral rampneutral-50 … 950 (inverts per theme to preserve contrast pairs)
neutral-50·
neutral-100·
neutral-200·
neutral-300·
neutral-400·
neutral-500·
neutral-600·
neutral-700·
neutral-800·
neutral-900·
neutral-950·
Colour · semantic tokenssurface / text / chrome roles
background·
foreground·
muted·
border·
card-hover·
selection-bg·
selection-fg·
TypographyBebas Neue (display) · Inter (text), ss01/cv11 · Caveat (handwriting)
Display · Bebas NeueHeading · Inter text-2xl font-lightBody · text-sm text-neutral-200Meta · text-xs text-neutral-500Label · text-[10px] uppercase tracking-wideHandwriting · Caveat · guestbook notes
display: font-display uppercase tracking-wider · headings: text-2xl/text-lg font-light · body: text-sm · meta: text-xs · labels: text-[10px] uppercase tracking-wide · handwriting: font-[family-name:var(--font-hand)] / Caveat (guestbook notes only)
Spacinga 4px rhythm (with 2/6px half-steps)
gap/p-0.5 · 2px
gap/p-1 · 4px
gap/p-1.5 · 6px
gap/p-2 · 8px
gap/p-3 · 12px
gap/p-4 · 16px
gap/p-5 · 20px
gap/p-6 · 24px
Radiusfloor harmonized to xl · md/lg/sm retired
xl floor · controls, inputs, menus, tiles
2xl · dialogs, spec cards
3xl · cards
full · pills, circles, dots
rounded-xl (floor) · rounded-2xl · rounded-3xl · rounded-full
Elevationshadow-xl (light) · shadow-panel (overlays)
shadow-xl
shadow-2xl
Layeringthe z-index ladder · one rung per surface kind
z-10content · stretched links, card overlays
z-20menus / panels
z-30top bar
z-40dropdowns · floating bar
z-50modals · dialogs
Motionpanel-in (side panel) · dialog-in (centered)
panel-in
dialog-in
animation: panel-in 0.2s ease-out · dialog-in 0.18s ease-out · transition-colors on interactive states

Atoms

Single-purpose elements. These render the real components/ui primitives.

Buttonvariant: primary | secondary | icon
<Button variant="primary">Save</Button>
Pillchannel / category / theme tag
DesignInspirationResearch Papers
<Pill>Design</Pill> · px-2 py-1 rounded-full
TextInputsize: default | small
<TextInput placeholder="…" /> · <TextInput size="small" />
Chevrondropdown affordance; rotates when open
SelectionCirclemulti-select toggle (block cards)
click to toggle → idle
idle = ring · selected = filled + check
IconsFlero icon library, recolored to currentColor
search / view
edit
download
folder
info
share
copy
duplicate
trash
archive
plus
pin
bell
sort
grid
list
expand
undo
redo
save
home
logout
check
dropdown
external
refresh
star
Status textsuccess / error inline feedback
Saved.Not authorized.

Molecules

Compositions of atoms. The Menu here is the exact primitive used by the sort, channel, and block-action menus.

Tag listwrapped Pills below a card / in a picker
DesignAITypographyMotion
<div className="flex flex-wrap gap-1">…</div>
Action rowsecondary buttons + optional Edit/Save (BlockDetail)
Dialog / ConfirmDialogbranded popup · replaces window.confirm()
Enter confirms · Esc / backdrop cancels
<ConfirmDialog open tone="danger" title="Delete?" … /> · shell: Dialog (portal + dialog-in)

Organisms

Page-level compositions. BlockCard and ChannelCard render live with mock data; the TopBar above this page is itself an organism.

ChannelCardchannels view · title + thumb strip + ⋯ menu
Design12 blocks
A text block shows its body when there's no image.
User Experience: A Research Agenda2006Papers lead with metadata at rest: title, authors, year, and abstract.
A text block shows its body when there's no image.
User Experience: A Research Agenda2006Papers lead with metadata at rest: title, authors, year, and abstract.
Guestbook notepaper surface · 4 styles · handwritten (Caveat) · warm tints
Lined

Hello Tanja!

- T

Grid

Hello Tanja!

- T

Torn

Hello Tanja!

- T

Taped

Hello Tanja!

- T

.paper-note + .paper-note--{grid|torn|tape} (lib/guestbook GUESTBOOK_STYLES) · tint via cardBg(color) · text: font-[family-name:var(--font-hand)] · card: aspect-[4/5]
Other organismsAdminForm · BlockDetail · ChannelPicker · SelectionBar
Data-driven organisms (they fire server actions) are documented, not instantiated here.

How it's built

A hybrid system: shared primitives are the source of truth; older screens migrate onto them piece by piece.

Primitives · in components/ui
MenuButtonPillTextInputSelectionCircleChevronDialogConfirmDialog
Migrating · still inline
AdminFormSignInModalChannelPickerPaperDetail
designed & built by Tanja Radovanovic