Intent
One vocabulary across surfaces. The tokens that paint
build-on-ai.com are the same tokens that paint the
desktop apps. The Button on this page is the same
Button in Notes, Vox, Inbox, and Document Processor.
Light and dark are first-class — flipping the theme on this site
flips it in every app that links the package.
Below: every token and every component currently in production on this site, ready to be packaged.
Color tokens
Eleven semantic tokens. Light values shown; dark equivalents in the next swatch row.
Surfaces
Text
Accent + state
:root {
/* Surfaces */
--bg-primary: #FFFFFF; /* page background */
--bg-secondary: #F8F7F2; /* alternating sections */
--bg-tertiary: #FDFCF8; /* subtle elevation */
/* Text */
--text-primary: #0F172A;
--text-secondary: #5F5E5A;
--text-muted: #888780;
/* Lines */
--border: #E5E7EB;
--border-muted: #F1EFE8;
--border-w: 0.5px;
/* Accent + state */
--accent: #1E3A8A; /* primary CTA, links */
--accent-soft: #E6F1FB;
--warn: #BA7517;
--warn-soft: #FAEEDA;
--danger: #A32D2D;
}
[data-theme="dark"] {
--bg-primary: #0F172A;
--bg-secondary: #0A0F1C;
--bg-tertiary: #1E293B;
--text-primary: #F8FAFC;
--accent: #60A5FA;
/* …rest follows the same pattern */
} Typography
Inter for body, JetBrains Mono for code and monospace labels. Sizes scale fluidly with viewport.
inline.code() Icons
Lucide — outline 1.5 px stroke, 24×24 grid, MIT licence. The set used by Vercel, shadcn/ui, and most premium SaaS surfaces. Below: the starter set for the ecosystem.
---
import { Icon } from "astro-icon/components";
---
<Icon name="lucide:search" width="20" height="20" />
<Icon name="lucide:settings" width="20" height="20" /> The full Lucide set (1,500+ icons) is browseable at lucide.dev/icons. New icons can be added by name without changes to the build config.
Buttons
Two variants. Primary for the single most important action; secondary for everything else. No tertiary.
<a href="#" class="cta-primary">Quickstart →</a>
<a href="#" class="cta-secondary">View on GitHub</a> Cards
The base .card sets padding, border, and elevation. Variants like .product-card add header rows or footer CTAs.
Product card
v1.0Single-line tagline describing what this card represents in the grid.
Plain card
No header pill, no CTA. Just a container with the same border, radius, and padding.
<a href="#" class="card product-card">
<div class="header">
<h3 class="name">Card title</h3>
<span class="pill">v1.0</span>
</div>
<p class="tagline">Single-line tagline describing what this card represents.</p>
<div class="footer-row">
<span class="cta-text">Read more →</span>
</div>
</a> Pills
Small inline labels for version, status, or category.
Callouts
Boxed notes for non-blocking information. Three states; never used for emotional disclaimers.
Note: a normal callout — used for additional context or pointers.
Warning: use sparingly for non-blocking caveats — e.g. platform-specific install steps.
Danger: destructive or irreversible actions.
<div class="callout">
<p><strong>Note:</strong> a normal callout.</p>
</div>
<div class="callout callout--warn">
<p><strong>Warning:</strong> use sparingly for non-blocking caveats.</p>
</div>
<div class="callout callout--danger">
<p><strong>Danger:</strong> destructive or irreversible actions.</p>
</div> Inputs
Text inputs and search fields. Mirror the same border, radius, and focus ring as buttons.
<label class="ds-field">
<span class="ds-field__label">Email</span>
<input type="email" class="ds-input" placeholder="[email protected]" />
</label>
<label class="ds-field">
<span class="ds-field__label">Search</span>
<input type="search" class="ds-input" placeholder="Search the docs…" />
</label> Tabs
Inline tab strip for switching panels within a page. Click a tab to swap the panel below.
A desktop application for capturing notes locally. Semantic search runs through Consciousness Server.
npm install, then npm run tauri build. Linux + Windows binaries, ~12 MB each.
In refinement. Working internally; being unified with Document Processor's stack.
<div class="ds-tabs" role="tablist">
<button role="tab" aria-selected="true">Overview</button>
<button role="tab">Install</button>
<button role="tab">Status</button>
</div>
<div class="ds-tab-panel" role="tabpanel">…</div> Dropdown
Click to expand a list of options. Built on the native <details> element — works without JavaScript, gracefully degrades, keyboard-accessible by default.
Choose a model
<details class="ds-dropdown">
<summary>
Choose a model
<Icon name="lucide:chevron-down" />
</summary>
<ul class="ds-dropdown__menu">
<li><a href="#">qwen3-coder</a></li>
<li><a href="#">llama3.2</a></li>
<li><a href="#">mixtral</a></li>
</ul>
</details> Modal
Built on the native HTML <dialog> element — backdrop, focus trap, Esc-to-close are handled by the browser. No external library.
<button class="cta-secondary" onclick="document.querySelector('#demo-dialog').showModal()">
Open dialog
</button>
<dialog id="demo-dialog" class="ds-modal">
<h3 class="h3">Confirm action</h3>
<p>This will rebuild the index. Existing search results will be invalidated.</p>
<form method="dialog" class="ds-modal__actions">
<button class="cta-secondary">Cancel</button>
<button class="cta-primary">Rebuild</button>
</form>
</dialog> Command palette
Press Ctrl K (or ⌘ K) on this page. Single overlay for navigation, actions, recent items, settings — fuzzy-searchable, keyboard-first. Same pattern in Linear, Vercel, Notion, GitHub, Slack, Stripe; same idea as Ulauncher / Spotlight, scoped to the app.
In @buildonai/ui this ships as a Svelte component:
<script>
import { CommandPalette } from "@buildonai/ui";
const actions = [
{ group: "Navigate", name: "Products", run: () => goto("/products") },
{ group: "Navigate", name: "Documentation", run: () => goto("/docs") },
{ group: "Actions", name: "Toggle theme", run: () => toggleTheme(), shortcut: "⌘D" },
{ group: "Actions", name: "New note", run: () => createNote(), shortcut: "⌘N" },
];
</script>
<CommandPalette {actions} hotkey="ctrl+k" /> Code blocks
Syntax for inline code (above) and full code blocks. Code blocks stay dark in both themes — readers don't get whiplash flipping the theme on a long page of snippets.
# Install
npm install @buildonai/ui
# Use
import { Button, Card } from "@buildonai/ui"; Section labels
Small uppercase mono labels — used for section headers and metadata rows.
<div class="section-label">SECTION LABEL</div>
<div class="label-mono">inline label · 10px mono</div> @buildonai/ui
The package this preview becomes:
- Tokens — every
--bg-*,--text-*,--accent*,--radius-*,--border*exported as a single CSS file. - Svelte 5 components —
Button,Card,Pill,Callout,Input,Textarea,CodeBlock,SectionLabel,ThemeToggle. - Theme primitive — a
data-theme="dark"handler matching the website's pattern, persisted to localStorage. - Shipped to — Document Processor, Vox (voice-assistant), Notes, Inbox once it's on the unified stack.
Repo: github.com/build-on-ai/ui. Licence: AGPL-3.0-only + Commercial, matching the rest of the ecosystem.
Toggle the theme in the nav above and watch every block on this page flip — that is the same toggle that will live in every desktop app.