Skip to content

Build master @ bc50cd5bunreleased — 31 commits past v1.282.0Last reviewed Last changed Grade fresh (aging >120d, stale >240d)Source / History

Launchpad Design ​

The Launchpad is the page a browser opens on localhost: every project, its links, and what is running. This brief (#2144) sets how it looks. It should feel like the control surface of a working system. The surface is dark and has depth, live things glow quietly, motion has a reason, and a few clear sizes of type say what matters. The page must still load instantly.

The brief comes first; the stylesheet in scripts/launchpad/render-page.js follows it. Every colour, font, type size, radius, shadow and animation length in that stylesheet is a custom property named here, and tests/test-launchpad-design.js fails on one that is not. Spacing stays on the 4px grid below. If the CSS needs a value with no token, add the token to this brief first.

Limits ​

These are fixed. A design idea that breaks one is dropped.

  • No requests. No webfont, no icon font, no image, no script or style from anywhere. The page is one HTML file. A test checks it.
  • No framework. Plain CSS and a small amount of plain JavaScript.
  • 60 KB. The inline CSS plus the inline JavaScript, as served, stay under 60 KB uncompressed. A test asserts the ceiling. The page compacts what it emits: it drops comments and indentation, and the source keeps both. The ceiling was 40 KB until the graph view (#2153). It was raised once for the graph and the command palette (decision #3535).
  • Both themes follow the system. The page follows prefers-color-scheme. Light is not dark with the colours flipped. Each theme has its own tokens, chosen for that background.

Colour tokens ​

Each token has one job. The CSS uses the token for that job, never a hex value.

TokenJobDarkLight
--bgPage background#0b0f17#f3f5f8
--panelTiles, cards, columns, the filter box#121925#ffffff
--raisedA surface lifted above a panel (popover, dragged tile)#18212f#ffffff
--lineHairlines and resting borders (decorative)#243042#d5dbe3
--inkBody text, names#e6edf6#0f1722
--dimSecondary text: ports, stack, counts, hints#8d99ab#56606e
--pill / --pill-inkA link pill at rest#1c2635 / #dbe4f0#e9edf2 / #1b2430
--live / --live-inkUp: a dev server that answers; the dev pill; the active view#3ddc84 / #04130a#0f7a3d / #ffffff
--downDown: a server that does not answer; the start action#ff6b6b#c0272d
--warnProduction links, a starting server, a port collision#e3b341#8a5a00
--focusThe keyboard focus ring#6cb6ff#0a5fd6

Contrast (WCAG 2.x), checked by tests/test-launchpad-design.js from the CSS itself, so a token change that breaks it fails the build:

PairDarkLight
--ink on --bg / --panel16.3 / 15.016.5 / 18.0
--dim on --bg / --panel / --pill6.7 / 6.1 / 5.35.8 / 6.4 / 5.4
--pill-ink on --pill11.913.3
--live-ink on --live (the dev pill)10.75.4
--live on --panel (Up counts, hover text)9.95.4
--down on --panel (start, Down counts)6.45.9
--warn on --bg / --panel (prod, warnings)9.9 / 9.15.4 / 5.9
--focus on --bg (the ring, a non-text 3:1 minimum)8.95.3

Every text pair is at least 4.5:1 (AA). --line is decorative and is never the only way to tell two states apart.

What the liveness colours mean ​

The colour of a dot, band or column means one thing everywhere on the page:

StateColourTreatment
Up: the server answers--liveFilled dot. A live surface has a soft glow that breathes slowly (see Motion).
Down: it does not answer--downFilled dot, flat. No glow: a down thing never looks alive.
Unknown: not probed yet, or nothing to probe--dimHollow dot, flat.
Starting: bob dev up is running--warnThe dot or button pulses until the probe answers.

A live surface is a tile whose dev server is up, a card in the board's Up column, and a port-map band whose dev port is up. The glow is CSS only: no script decides it. Down and unknown surfaces have no glow.

Type ​

  • UI text uses the system sans stack (--font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif). The page never fetches a webfont.
  • Identifiers use a mono stack (--font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace). These are project names, ports, keys and stack terms: things you would type.
  • Ports and counts use tabular numerals (font-variant-numeric: tabular-nums), so :5200 and :5210 line up.
TokenSizeUsed for
--fs-xs0.75rem (12px)Column headings, GitHub pills, the port-map strip
--fs-sm0.8125rem (13px)Ports, stack terms, counts, hints
--fs-md0.875rem (14px)Body, pills, buttons
--fs-lg1rem (16px)Project names
--fs-xl1.125rem (18px)The page title

Hierarchy comes from weight and colour before size. A name is --ink at 600; everything about it is --dim.

Spacing, shape, depth ​

  • Spacing is a 4px grid: --sp-1 0.25rem, --sp-2 0.5rem, --sp-3 0.75rem, --sp-4 1rem, --sp-5 1.25rem.
  • Radius: --r-sm 4px (keys, small buttons), --r-md 8px (tiles, cards, columns), --r-pill 999px (pills, counts).
  • Depth is three steps. --shadow-1 is a panel at rest, --shadow-2 is a hovered or focused panel, and --shadow-3 is something you are dragging. Panels also carry a faint top highlight (--sheen), so a surface reads as lit from above. In light the shadows are softer and the highlight is not needed.

Motion ​

Motion shows that something changed or that something is alive. It is never decoration.

TokenValueUsed for
--dur-fast120msHover and press feedback
--dur180msA tile settling, a card moving column (FLIP), a popover opening
--easecubic-bezier(0.2, 0.8, 0.2, 1)Everything that moves
--breathe2.8sThe live glow's slow cycle
--pulse1sA server starting: the dot or start button pulses
  • Nothing that moves takes longer than 200ms. The live glow and the starting pulse only change brightness, so they are slower.
  • Under prefers-reduced-motion: reduce there is no animation and no transition, and live surfaces have no glow. Changes still happen; they just land. State stays readable from colour and the filled dot.

States ​

Every control has a designed state for each way you can touch it:

StateTreatment
HoverThe border goes from --line to --dim (panels) or --live (pills, buttons), and a panel steps up to --shadow-2
Focus (keyboard)A 2px --focus ring outside the control. It is never removed: a control may restyle its border, but the ring stays
Active (pressed)The control dips 1px and loses its lift
Drag (tiles)--shadow-3, a --live border, slightly see-through; the slot it would drop into is a dashed outline
Selected (view, group key)Filled with --live (view) or outlined in --live (group key)

These apply to tiles, board cards, pills, the view switcher, the group-by buttons, the start buttons and the port-map segments.

What it looks like ​

Every view in both themes after this pass, from a fixture index with stubbed liveness (atlas and delta-web up). The port map is shown with a band hovered. The pass started from the page in the last column.

ViewDarkLightBefore
TilesTiles, darkTiles, lightdark · light
ListList, darkList, lightdark · light
BoardBoard, darkBoard, lightdark · light
PortsPorts, darkPorts, lightdark · light