loworbit

▲ loworbit.ai / design

the design system. every decision here is earned or it shouldn't exist. source: docs/design.md.

loworbit design system

source of truth. the hub follows this. the template's CLAUDE.md inlines the critical rules. every new prototype inherits them.

if you're an agent reading this to build a prototype: follow every section marked rule. treat the rest as context.


the short version


principles

1. one accent, and it's earned.

#7dd3fc is the only color outside of the grayscale fg/bg/muted palette. use it to mark interactive elements, active states, live values, or anything the eye should go to first. applying it for decoration dilutes it.

rule: any element rendered in accent must be doing one of: linking, indicating active/live state, or highlighting a value that changed.

2. lowercase is structural.

not quirky. the ui is in lowercase because this is a place where sentences happen, not headlines. it signals that the site is a working document rather than a broadcast.

rule: all ui chrome is lowercase (nav, buttons, labels, section headers, badges, empty states). prose body copy uses sentence case. proper nouns (AWS, APMP, FedRAMP, Clerk, Vercel, Anthropic) keep their case. code/identifiers (slugs, hex codes, urls, commit hashes) preserve literal case.

3. monospace for honesty.

the site handles precise, structured text — prompts, api keys, slugs, commit hashes, log entries. monospace treats every character equally. it's not costume; it's accurate.

rule: JetBrains Mono, with ligatures enabled. no other typeface anywhere in the ui.

4. radius is 2px.

sharp corners feel mechanical. fully rounded feels friendly-corporate. 2px is the architectural compromise.

rule: every element with corners uses 2px border-radius. no exceptions.

5. motion must communicate.

decorative motion is banned. motion is acceptable when it represents a real state transition: a value changing, a status flipping, a deploy starting, an agent working.

rule: no ambient motion except the glyph, which breathes only while the system is actively doing something. all other motion must correspond to a state change the user should notice.

6. absence is a choice, not a gap.

no gradients. no stock photography. no decorative illustrations. no mouse-tracking spotlights. no microgrids. no scanning-line animations. no "uplink: active" sci-fi language. the blankness is the product.

rule: if a visual element cannot be justified by communication (text, data, live state), it does not exist.

7. refuse the category.

the "dark dev-site aesthetic" has a current fashion: mouse-tracking gradients, grid backgrounds, pulse animations, sci-fi status labels. loworbit refuses that category. we are in the lineage of sites where every gap is tuned and every interaction earned.

rule: before adding anything, ask: "does this exist on 5+ other dev sites in 2026?" if yes, it should probably not exist here unless it serves a specific loworbit-only purpose.


voice

banned phrases

leverage, unlock, empower, journey, seamless, intuitive, next-generation, cutting-edge, solution (as a noun meaning "our product"), let's, we're excited to, transformative, best-in-class, robust, synergy, innovative, uplink, mission-critical (outside literal mission contexts), any phrase that would feel at home in a B2B saas marketing email.

preferred patterns

tone

direct, quiet, honest. the voice of a working-document, not a pitch. the reader is assumed to be intelligent and in a hurry.


color

palette

rolehexuse
bg#0a0a0apage background everywhere. not #000.
fg#e5e5e5primary text.
muted#6b7280secondary text, timestamps, meta.
border~#222222dividers, input borders, card edges.
accent#7dd3fclinks, primary buttons, active states, live values.
ok~#86efacsuccess badges, "saved" indicators. muted green, not bright.
error~#fca5a5error messages. muted red, not bright.

rule: no new colors. no gradients. use opacity modifiers (fg/70, fg/50) instead of adding greys. no color outside this list.

accent rules


type

family

JetBrains Mono, variable weight, ligatures on.

font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo,
             Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-feature-settings: "calt", "liga", "ss01", "ss20";

rule: no other typeface. no sans-serif fallback for headings. system mono only as a fallback if the font fails to load.

scale

elementsizeweight
page title (rare)30px400
section heading24px400
body14px or 16px400
section divider (-- section --)12px400
meta / timestamp12px400
code / ids12px400
badge / tag11px400

rule: no bold anywhere. use color (text-fg vs text-muted) and size for hierarchy. monospace typefaces often render bold awkwardly at small sizes.

line length

body prose: max 65-75 characters per line. enforces narrow containers for reading sections.


spacing

strict 8px scale. use only these increments:

tailwind classpxuse
gap-1 / p-1 / m-14pxrare. tight inline spacing only.
gap-2 / p-2 / m-28pxinline text gaps, tight inputs.
gap-3 / p-3 / m-312pxstandard inline.
gap-4 / p-4 / m-416pxcomfortable inline.
gap-6 / p-6 / m-624pxbetween components within a section.
gap-832pxminor breaks.
gap-1248pxmajor section breaks.
gap-1664pxpage-level breaks. rare.

rule: never use arbitrary tailwind values. no p-[17px]. no gap-5 (20px — off-grid). the scale is the scale.

one explicit micro-tier exception: status pills and badges may use gap-1.5 (6px), px-1.5 (6px), or py-0.5 (2px). these are the only contexts where sub-8px vertical spacing is allowed. every other element uses the main scale.

page width

rule: if the eye moves down the page, narrow. if the eye compares across, wide.


components

primitives

all component primitives live in the template and are reused everywhere. do not invent new primitives without a justified need.

terminal-box

terminal-button

terminal-button-primary

terminal-input

terminal-label

terminal-link

status pills


states

hover

two patterns. no third.

  1. hover-lift — containers, rows, cards. hover:bg-fg/5. subtle 5% wash on hover. signals "this is interactive."
  2. hover-underline — inline text links only. underline appears on hover.

buttons inherit hover-lift. everything else inherits one of the two by context.

rule: any hover treatment that isn't one of these two is a bug. no scale-up, no color shift, no border-color change.

focus

one pattern. everywhere.

focus-visible:ring-1 focus-visible:ring-accent
focus-visible:ring-offset-2 focus-visible:ring-offset-bg

1px accent ring with 2px bg offset. uses focus-visible so mouse users don't see it on click; keyboard users always do.

rule: every interactive element has this focus treatment. audit keyboard-navigation for any that's missing. a missing focus ring is an accessibility bug.

loading

no spinners. no skeletons.

empty

nothing live yet.

one line, terminal-box, centered, text-muted. no illustrations. no CTAs unless there's an obvious next action and the page has real authority to push it.

error

terminal-box with border-error and text-error. inline, not modal. prose error text (no codes, no tracebacks). short. ends with what to do next if possible.

couldn't read this file. try pdf or docx under 20mb.

success

✓ saved

checkmark (text, not icon library) in ok color. "saved" in muted. fades after 2s if ephemeral. persists if it affects the page.


motion

the one ambient exception

the glyph at the top-left of every page breathes (opacity cycle, 4s period, 0.7 → 1.0 → 0.7) only when the system is actively doing something. active states:

determined by a single GET /api/system-status call from the client on mount, polled every 30s. when active, the glyph breathes. when quiet, it's still.

rule: no other ambient motion exists in the system. not anywhere. not on any page.

reactive motion (hover/focus/state change)

hover and focus are handled by their two patterns (above). state-change motion happens when:

rule: all reactive motion uses the same easing (ease-out) and similar durations (200ms for state changes, 4000ms for the triangle). no unique easing curves per component.

what's banned


content structure

section dividers (character-as-architecture)

sections on text-heavy pages are demarcated by monospace ascii-inspired strings:

-- bio --

-- log --

-- what's running --

-- now → /now --

rule: section dividers replace traditional <h2> tags on manuscript-style pages (landing, /now, /log, /tools). admin pages still use normal section headings.

the /now page

a microblog of dated entries. the landing shows the most recent. /now shows the archive. each entry gets its own url.

schema: now_entries { id, content (markdown), created_at, slug (YYYY-MM-DD) }

flow:

rule: /now is updated at the author's discretion. no minimum frequency. staleness is acceptable — "last updated 2 months ago" is better than fabricating urgency.

the /log

a mixed auto+manual event log. system events auto-populate. narrative entries come from the author.

schema: log_entries { id, source ('auto'|'manual'), content, event_type (nullable), related_prototype (nullable), created_at }

auto triggers:

manual entries: bug post-mortems, framing commentary, non-prototype shipping, thoughts. written via /admin/log.

landing shows the latest 7, sorted by created_at desc. /log or /archive shows the full history.

rule: system entries should be one short line. manual entries can be longer but still terse by default.

the /tools/[slug] pages

public prototype writeups. one per live prototype. exists to give context to strangers.

content: title, slug, one-line description, longer narrative about why it was built, link to try it (prototype subdomain), link to github repo, optional screenshot.

rule: each prototype linked from the landing opens its /tools/[slug] page, not the prototype directly. random visitors need context before they click into a live tool.


what loworbit deliberately doesn't do

the footer is live metadata, not a byline

the page footer is a single-line json object with real, current data pulled from the system:

{ deploy: "da8cff0", agents_run: 43, live: 4, last_spawn: "2h" }

rule: no "made by", no "© 2026", no "built with". the json is the footer.


applying this in new prototypes

every new prototype (spawned via /admin/new) inherits the template's CLAUDE.md, which references this document and inlines the critical rules. when an agent builds a prototype, it reads:

the agent may add ui patterns specific to its prototype's function (e.g., panel's conversation view, surface's editor canvas) but those patterns must follow the design system's color/type/spacing/motion rules.

the checker runs a shared-chrome-diff against every build. it does not yet lint for design-system compliance — that's a future enhancement. for now, compliance is the agent's responsibility, enforced by the template's CLAUDE.md.


current inconsistencies (cleanup list)

these land as a cleanup commit before or alongside the landing redesign.


changelog