v0.1 · DESIGN SYSTEM

Built from the app, not beside it.

Hivemind's colours, type, status meanings and motion live in the renderer's stylesheet. This page reads that file at build time, so what you see here is what the app paints — not a picture of it.

01Foundations

Two surfaces. One of them is canonical.

The app is where the system lives: apps/desktop/src/renderer/src/styles.css holds the palette, the status meanings, the curves and the tracking. The website vendors those values at build time. When the two disagree, the app is right and this page is stale — which is why it is generated rather than written.

Where a rule belongs

TWO SURFACES

The app

Tokens, status buckets, glass, the view SDK's --hm-* variables. Anything a plugin can read is defined here.

The site

Page rhythm, the classical plates, the catalog. It borrows the app's colour and motion and adds nothing to them.

02The mark

Three cells. One of them is lit.

A hive of three rounded cells, with the top one at full strength and the others at 40%. It is the product's whole argument in one glyph: several agents, one of them wanting you.

Lockups

THREE FILES
The Hivemind mark on a dark ground
mark.svg · on dark
The Hivemind mark on a light ground
mark-dark.svg · on light
The favicon
favicon.svg · 28px and below

Clearspace: one cell on every side. Never redraw the cells, never recolour the lit one to a status colour — amber means an agent needs you, and the mark must not claim that.

03Typography

Two faces. Each with one job.

Geist sets everything a person reads. JetBrains Mono carries anything the machine produced — commands, paths, status lines, ids, counts. The split is the point: mono is a signal that something is real output, so it is never used for atmosphere.

The ramp

SIX ROLES

Use the role, not the size. Display roles are Geist at 600; anything a machine produced is JetBrains Mono.

ROLESAMPLESPEC
display

Bring your own agents.

clamp(40, 6vw, 80) · 600 · -0.035em
heading

The workspace is a plugin too

clamp(28, 3.6vw, 48) · 600 · -0.03em
lede

An agent here is a file you can read.

clamp(17, 1.3vw, 20) · 400 · 52ch
body

It names the command to run and how to read that command's screen.

15 / 1.65 · 400
mono

hive ctl spawn --agent claude --frame api

12.5 / 1.6 · tabular-nums
caption

NEEDS YOU · 2 WORKING

11 · +0.04em · uppercase

DO

Put a session id, an exit code or a file path in mono. It tells the reader a machine produced it.

DON'T

Set a paragraph in mono because it looks technical. Mono stops meaning anything the moment it is decoration.

04Colour

Graphite everywhere, colour only where it means something.

Signal is the default palette: neutral surfaces in one hue family, and the few colours that remain are meanings. Every swatch below is read from the app's stylesheet, with the app's own note beside it.

Surfaces

DARKEST TO LIGHTEST
--color-bgoklch(0.165 0.004 250)
--color-bg2var(--surface-2)
--color-bg3var(--surface-3)
--color-bg4var(--surface-4)
--color-lineoklch(0.27 0.005 250)
--color-line2oklch(0.34 0.006 250)

Text

THREE TIERS
--color-fgoklch(0.93 0.004 250)
--color-fg2oklch(0.80 0.005 250)
--color-fg3oklch(0.62 0.006 250)

Brand

QUIET ON PURPOSE
--color-brandoklch(0.52 0.03 250)
--color-brand-hoveroklch(0.57 0.03 250)
--color-selectoklch(0.80 0.005 250)
--color-accentoklch(0.74 0.035 245)

Semantic

FOUR MEANINGS
--color-okoklch(0.74 0.07 155)
--color-warnoklch(0.80 0.13 72)
--color-erroklch(0.66 0.11 32)
--color-infooklch(0.74 0.035 245)

05Status

One state is one colour, everywhere.

Layers rows, tile headers, the canvas, and every installed view through the SDK's --hm-status-* variables paint from the same six tokens. A preset changes the palette; the meanings follow it.

The six

MEANING · TOKEN
working

The agent is running. Near-white, because work in progress is not a call to action.

--color-status-working
attention

It stopped and asked you something. The one warm colour on screen.

--color-status-attention
done

It finished what it was asked to do.

--color-status-done
idle

Alive, waiting, nothing owed.

--color-status-idle
exited

The process ended. Nothing is running.

--color-status-exited
failed

It ended badly, and the exit code says so.

--color-status-failed

DO

Keep amber for the agent that stopped and asked. It is the only warm colour on screen, so it can be seen across a room.

DON'T

Borrow amber for a highlight, a hover or a brand flourish. Every decorative use spends the signal.

06Surfaces

Hairlines, not shadows.

Panels separate by a one-pixel rule and a step in surface colour, not by elevation. A dark app full of drop shadows reads as a dashboard; a dark app full of hairlines reads as an instrument.

Glass

ONE RULE

Glass is translucency over a wallpaper. With no wallpaper set there is nothing behind the panel, so glass turns itself off rather than washing the theme's own colour out — effectiveGlass() checks both.

No wallpaper

Solid surface. The theme's colour is the colour.

Wallpaper set

Tinted surface over the picture, with a blur behind it.

07Motion

Motion is a state, not a flourish.

Two curves and three durations, all from the app. Something moves because it is telling you it is running; when nothing is happening, nothing moves.

The vocabulary

TWO CURVES · THREE DURATIONS
--hm-ease-outcubic-bezier(0.32, 0.72, 0, 1)decelerate; the house curve
--hm-ease-incubic-bezier(1, 0, 0.68, 0.28)its mirror, for exits (symmetric paths)
--hm-dur-1100mspress feedback — must feel instant
--hm-dur-2150mshover / color / small transforms
--hm-dur-3220mspanels, toasts, drawers

A working agent pulses. An idle one is still. Reduced motion stops the pulse and keeps the colour, because the colour is the information.

08Imagery

Marble on the page, the product in the frame.

Five public-domain museum photographs (Met Open Access, CC0) sit behind the site's sections, each chosen for the claim beside it. They never appear inside the product, and they never carry text.

How a photograph joins a dark page

GRAIN THE ART

Screen-blend it so the museum's black ground drops out, mask it away before it reaches any text, and lay the noise inside the art rather than over the page. Grain on the ground is what makes an image look pasted on.

Screenshots get the opposite treatment: one hairline, 8px radius, the width of the section, no shadow and no perspective — so a dark screenshot stays continuous with a dark page.

09Tokens

The file this page was built from.

Generated from apps/desktop/src/renderer/src/styles.css at build time. Copy a line and it is the same string the renderer uses.

TOKENVALUEUSAGE
--color-bgoklch(0.165 0.004 250)
--color-bg2var(--surface-2)
--color-bg3var(--surface-3)
--color-bg4var(--surface-4)
--color-lineoklch(0.27 0.005 250)
--color-line2oklch(0.34 0.006 250)
--color-fgoklch(0.93 0.004 250)
--color-fg2oklch(0.80 0.005 250)
--color-fg3oklch(0.62 0.006 250)
--color-brandoklch(0.52 0.03 250)
--color-brand-hoveroklch(0.57 0.03 250)
--color-selectoklch(0.80 0.005 250)
--color-accentoklch(0.74 0.035 245)
--color-okoklch(0.74 0.07 155)
--color-warnoklch(0.80 0.13 72)
--color-erroklch(0.66 0.11 32)
--color-infooklch(0.74 0.035 245)
--color-status-workingoklch(0.91 0.005 250)near-white: at work is not a call to action
--color-status-attentionvar(--color-warn)It stopped and asked you something. The one warm colour on screen.
--color-status-donevar(--color-ok)It finished what it was asked to do.
--color-status-idlevar(--color-fg3)Alive, waiting, nothing owed.
--color-status-exitedvar(--color-fg3)The process ended. Nothing is running.
--color-status-failedvar(--color-err)It ended badly, and the exit code says so.

98 custom properties are defined in the renderer; this page shows the ones a designer needs. The rest are structural.