← Commit history

Reframe around the AI build-show-drive-ralph loop; usability-first hero

John Lauer ·767b8ecdde ·4mo ago ·parent cb95b93
5 files changed +477−474
README.md+221−200
@@ -1,309 +1,329 @@ # Adom UI Design System -The single source of truth for how every Adom surface looks and behaves. Color tokens, typography, the app header, panels, 3D viewers, hero images, AI-drivability, and the copy voice, plus the linter that enforces them. One page so that a person or an AI can build something new and have it come out unmistakably Adom on the first try.+How the AI builds and tests interfaces that people genuinely love to use. In Adom you do not hand-write an app and then click through it to check it. You ask the AI to build it, and the AI builds it, shows it to you, drives it over a live channel, watches the result, and fixes it, looping until the experience is right. This page is the standard that makes that loop land on something pleasurable: a UI that treats the person using it as the center of everything, and an app that is built from the first commit to be driven and observed. Color and typography are the final polish, maybe three percent of the work. The rest is interaction quality and drivability. -![Adom UI Design System](screenshots/hero.png)+![Build interfaces people love to use](screenshots/hero.png) -> **Why this page exists.** Adom ships a lot of small surfaces: webview apps, CLIs, 3D viewers, wiki pages, hero art. Without one written standard, each one drifts and the family stops looking like a family. This page collects every rule that was previously spread across a dozen skills into a system you can read top to bottom. If you only remember one thing: **Adom is dark, teal, monochrome-iconed, and driven by clean APIs.**+> **Why this page exists.** Two things are true in Adom that are not true elsewhere. First, good UI is not decoration, it is respect for the person on the other side of the screen. Second, the AI is the one building and driving the UI, so the app has to be controllable and observable end to end, or the AI cannot perfect it. This page teaches both: how to make an interface a pleasure to use, and how to build and test it the Adom way. If you only remember one thing: **build for the user first, make every action answer back, and make the whole app drivable so the AI can prove it.**  --- -## The 90-second contract+## The contract -The rules that get broken the most. If you do nothing else, do these.+The principles that matter most, in order. Usability and drivability first, polish last. -1. **Dark by default.** Page background is `#0d1117`, panels are `#161b22`. Never a white or light primary background.-2. **Teal is the one accent.** Primary interactive color is `#00b8b0`. Purple `#8c6bf7` for grouping. Nothing else competes for attention.-3. **Every icon is monochrome white.** `#e6edf3` or `currentColor`. No colored icons, no emoji, in app UI, tab strips, or favicons. Brand color appears only in marketing art (hero, thumbnail).-4. **Three fonts, by role.** Familjen Grotesk for headings and identity, Satoshi for body, JetBrains Mono for code and numeric data. Never Inter, Arial, or a system stack as the primary face.-5. **One 44px header, three zones.** Brand on the left, subject in the middle, icon actions on the right. Per pixel above content is wasted screen.-6. **Every UI action has a matching API.** If a button does it, a plain HTTP call must do it too. State lives on the server, the UI polls `GET /state`. This is what makes an app AI-drivable.-7. **CLIs answer `OK:` or `ERROR:`,** and every error carries a `Hint:` with the exact command to run next.-8. **3D is Babylon.js,** never Three.js. Gradient background, zoom to cursor, two-light minimum.-9. **No em-dashes, no gimmick emoji** in any shipped copy.-10. **Lint before you publish.** `adom-ui-linter` turns most of this page into ~50 deterministic checks.+1. **Put the user at the center.** Every screen answers three questions at a glance: what is this, what can I do here, and what just happened.+2. **Every action answers back.** A toast, a state change, or a live preview. Never a silent click, never a spinner with no end, never a dead end.+3. **Controls explain themselves.** Every control says what it does and what changes, in a tooltip on desktop and inline on touch.+4. **Errors are help, not blame.** Say what went wrong and the exact next step. Destructive actions say what is kept and offer an undo.+5. **Adapt to the screen.** Rich and dense on a desktop, lean and thumb-friendly on a phone. The same app reshaped, never a cramped desktop layout squeezed onto mobile.+6. **Built and driven by the AI.** The AI writes the app, shows it to you, and drives it over a live SSE or WebSocket channel to test and perfect it. Anything the UI can do, a command can do, so state lives on the server and the channel keeps the UI, the CLI, and the AI in lockstep.+7. **One 44px header, three zones,** so people always know which app they are in and where the controls are.+8. **CLIs answer `OK:` or `ERROR:`,** with a `Hint:` that names the exact next command.+9. **Then the polish:** dark `#0d1117` and `#161b22`, one teal accent `#00b8b0`, monochrome-white icons, three fonts by role. On-brand matters, but it comes last.+10. **Lint before you publish.** `adom-ui-linter` turns most of this into deterministic checks.  --- -## 1. Color+## 1. How a UI is built and tested in Adom -![Adom design tokens at a glance](screenshots/tokens.png)+This is the loop the whole system is designed around. The AI is both the builder and the tester, the user watches and steers. -Adom is a dark system. Color is used sparingly so that the one teal accent always means "this is interactive or important."+1. **The AI builds the app:** a small server plus a webview UI, made AI-drivable from the first commit (state on the server, a live channel, a CLI).+2. **The AI shows it to the user** in one of three surfaces (below), chosen for what is being tested.+3. **The AI drives the front-end** over the live channel to exercise every path: click each button in turn, open and close the floating toolbar, load a different symbol or footprint, hit "send to KiCad", and read back state, the console buffer, and screenshots.+4. **The AI ralph-loops:** screenshot, analyze what looks wrong, fix the code, reload, repeat, until the UI is correct and a pleasure to use.+5. **The AI narrates** what it is doing through toasts and the chat, so the user can follow the test as it happens. -### Core theme tokens+The design rules on this page exist so that this loop converges on something a person loves, not merely something that runs. -| Token | Value | Use |-|---|---|---|-| `--bg` | `#0d1117` | Page, deepest background |-| `--surface` | `#161b22` | Panels, toolbars, cards |-| `--elevated` | `#1c2128` | Elevated cards, hover surfaces |-| `--overlay` | `#21262d` | Tooltips, dropdowns, modals |-| `--border` | `#30363d` | Standard border |-| `--border-muted` | `#21262d` | Subtle inner borders |-| `--text` | `#e6edf3` | Primary text |-| `--text-2` | `#8b949e` | Secondary text, labels |-| `--text-3` | `#484f58` | Disabled, placeholders |-| `--accent` | `#00b8b0` | Primary accent, the Adom teal |-| `--accent-bright` | `#00e6dc` | Hover and focus highlights |+### The three display surfaces -### Status and grouping+The AI picks the surface by what it needs to test, and it can use more than one at once. -| Token | Value | Use |+| Surface | What it is | Use it for | |---|---|---|-| `--purple` | `#8c6bf7` | Group labels, secondary accent |-| `--blue` | `#58a6ff` | Links, informational accents |-| `--green` | `#3fb950` | Success only |-| `--red` | `#f85149` | Destructive only |-| `--yellow` | `#d29922` | Warning only |+| **Native browser** | The user's real Chrome or Edge, reached through the `adom-browser-extension` | The real, signed-in experience. The browser already holds the user's auth cookies, so the app opens **logged in or auto-logs-in with zero friction**. Huge for demoing and testing anything behind a login. |+| **pup** | A clean, scriptable Chrome the AI fully owns, via `adom-desktop` | The **fresh, logged-out, first-time-user** experience, and automated screenshot loops that should not fight the user's own tabs. |+| **Hydrogen webview** | An in-workspace browser tab | Showing a result inside the workbench, next to the code and the chat. | -### Brand palette (marketing and illustration)+The native-browser and pup split is the point: the AI can open the **logged-in path in the native browser** (real cookies) and the **logged-out path in pup** at the same time, and verify both experiences. Choose deliberately, and tell the user which one and why. -| Name | Hex | Use |-|---|---|---|-| Teal (primary) | `#00B8B1` | The brand color |-| Blue Light | `#64ABFF` | Accents, links, illustration |-| Purple Light | `#C5B3FF` | Hover states, secondary accent |-| Blue Dark | `#0061EF` | Strong CTAs |-| Purple | `#8C6BF7` | Grouping, secondary accent |-| Navy | `#00204F` | Deep dark backgrounds |-| Teal Dark | `#003C3F` | Dark teal panels |+--- -### Rules+## 2. The live channel: driving and observing -- Never use **pure black** (`#000`) or **pure white** (`#fff`) for a large surface. Black kills contrast against dark UI parts, white blows out a dark theme. Use the tokens above.-- Hover transitions are smooth, not snappy: `0.15s ease`.-- The signature gradient is teal to blue to purple: `linear-gradient(100deg, #00e6dc, #39b8ff 60%, #8c6bf7)`. Use it for headline accents and flagship art, not for body UI.+The spine that makes the loop possible. Build it into every app. ------## 2. Typography+- **State lives on the server.** The UI never keeps its own copy of "am I recording?" or "which symbol is loaded?". Buttons fire commands to the server, the server owns the truth.+- **A live channel pushes state to everyone.** Expose **Server-Sent Events** for one-way push, or a **WebSocket** for two-way. The UI subscribes and updates the instant anything changes. The CLI subscribes too. A 300 to 500ms poll of `GET /state` is the minimum fallback, but the live channel is what makes driving feel instant.+- **The channel is two-way, so the AI drives the front-end from the CLI.** Every user-visible action has a command that does exactly what the click does:+  ```+  mytool ui click "send-to-kicad"      # press a button+  mytool ui toolbar show               # reveal the floating toolbar, then `hide`+  mytool ui load-symbol LM358          # swap the loaded symbol or footprint+  mytool ui toast "file downloaded"    # raise a toast (see section 3)+  ```+  Each command drives the real UI through the same path a user would, so the AI can walk every interaction, assert the resulting state, screenshot it, and move on. This is the test harness and the demo driver in one.+- **Observe, do not scrape.** Expose `GET /state` for current state and `GET /console` for the app's log: override `console.log/warn/error` to also post to the server, keep a ring buffer, and catch `window.onerror` and `unhandledrejection`. Now the AI reads what the UI is doing without DevTools.+- **The acceptance test:** an AI driving the app over the channel and a person clicking the UI produce identical visible results. -Three faces, each with one job. Mixing them up is the fastest way to make an app feel off-brand.+### Ralph-testing the UI -| Face | Weights | Job |-|---|---|---|-| **Familjen Grotesk** | 500, 600, 700 | Headlines, app name, section headers, identity |-| **Satoshi** | 400, 500, 700 | Body copy, descriptions, paragraphs |-| **JetBrains Mono** | 400, 500 | Source code, inline code, numeric and data rows |+The visual feedback loop that turns "it runs" into "it is right": edit, reload, drive a step over the channel, screenshot, read the console buffer, analyze, fix, repeat. Drive it in pup (or the native browser), capture each frame to the screenshot log, and keep looping until the UI looks and behaves correctly. This is how the AI debugs UI with no human in the loop, and it is also the proof that the app is genuinely drivable. -### Rules+### Reaching a container app from outside -- **Monospace is only for code and data.** Labels, descriptions, status pills, tooltips, headings, and body never use a monospace face. A version number or a pad count is data, so it is mono. A button label is not.-- **Never ALL CAPS body text.** Small uppercase is allowed for tiny eyebrow labels and chips with wide letter spacing, never for sentences.-- Do not fall back to Inter, Arial, Helvetica, or the system stack as the primary face. Load the brand fonts from `https://adom.inc/fonts/`.+- A webview and a browser window both render **outside** the container, so they cannot reach `http://localhost:<port>` or `http://127.0.0.1:<port>`. Always use the public proxy URL: `https://<slug>.adom.cloud/proxy/<port>/`.+- **Inside a webview, always use relative URLs.** A leading slash resolves to the host origin and bypasses the proxy. Every `fetch`, `href`, `src`, and CSS `url()` must be relative.  --- -## 3. Spacing, radius, and icons+## 3. Interaction and feedback -- **Spacing grid:** 8px, 12px, 16px. Stay on the grid.-- **Border radius:** `8px` for buttons and cards, `12px` for larger containers, `999px` for pills and chips.-- **Icons are monochrome white. No exceptions.** `#e6edf3` or `currentColor` inheriting from white text. This covers in-app icons, the Hydrogen tab-strip icon, and the favicon. A teal favicon is a UX lie because the tab strip is Adom chrome, not your art.-  - Prefer a clean custom SVG (`viewBox="0 0 24 24"`, stroke weight 1.5 to 2px) over a generic icon unless the concept is fully generic.-  - No emoji as icons, ever.-  - **Pre-publish icon audit.** Both of these greps must return zero hits:-    ```bash-    grep -nE 'fill="(#00b8b0|#00d4cb)"|stroke="(#00b8b0|#00d4cb)"' docs/icon.svg src/**/*.html src/**/*.svg-    grep -nE '\.logo[^{]*\{[^}]*color:\s*var\(--accent\)|\.icon[^{]*\{[^}]*color:\s*var\(--accent\)' src/**/*.html src/**/*.css-    ```-- The **only** place brand color is allowed is marketing art: the hero image and the thumbnail on the wiki page.+An interface that responds, explains, and forgives is the difference between a tool people tolerate and one they enjoy. It is also what the AI drives and verifies in the loop above. ----+### Every action answers back -## 4. The app header+- **Immediate visible feedback on every action:** a toast, a class change, a live preview, a progress line. A click that produces no visible response reads as broken, to a person and to the AI watching the screenshot.+- **Show, do not block.** Long work shows progress and stays interactive where it can. A bare spinner with no estimate is a last resort. -Every Adom webview app wears the same header so that a person always knows which app they are in and where the controls are. It is a **single row, 44px tall, three zones.**+### Toasts, for the user and for the AI -```-[ icon  app-name · subtitle ] | [ Subject Name  meta ]            [ btn btn ]-        brand (left)            vsep      subject (center)          actions (right)-```+Toasts are the standard transient-feedback element, and in Adom they do double duty: because the AI is driving the front-end, **a toast is also how the AI talks to the user live**, on top of the running app, during a test or a demo. "Running test 3 of 8", "file downloaded", "loaded LM358, re-routing", all land as toasts over the app rather than buried in chat. -- **Brand zone (left):** a 16x16 monochrome icon, the app name, a middot, and a one to four word subtitle. Familjen Grotesk 600, in the accent color. Hovering the brand block reveals an app-info popover with version, build date, engine, author, and a clickable wiki link. None of that metadata sits in the header row itself.-- **Subject zone (center):** the current document or object name (bold, truncates with an ellipsis when narrow) plus a muted monospace meta line for secondary stats. The meta line hides below roughly 720px and returns on hover.-- **Actions zone (right):** icon buttons only, right aligned with `margin-left:auto`. Skip the zone entirely if there are no actions.-- A `1px` vertical hairline separates brand from subject.+- **Build a `POST /ui/toast` hook from day one.** One mechanism serves both the user (feedback) and the AI (narration). The AI raises a toast with the same `mytool ui toast "..."` command it uses to drive everything else.+- **Position:** bottom center, consistent across the app.+- **Types:** success (green `#3fb950`), error (red `#f85149`), info (teal `#00b8b0`), each with a clear icon and message.+- **Duration:** about 4 seconds for a confirmation, sticky for an error the user must read. Pause on hover.+- **Stack** newest on top, cap the visible count, allow dismiss, and **carry an action when one exists**, above all **Undo** for anything destructive. -### Header rules+### Controls that explain themselves -- Never a multi-row header. Never a sticky header. Never the app version inline in the row. Never the app name in a monospace face. Never an all-caps app name.-- The popover that appears on hover must be reachable: give it `pointer-events:auto`, a 600ms show delay, and a ~220ms hide grace so the cursor can cross the gap to click a link inside it.+- **Every interactive element carries an explanation.** On desktop this is a tooltip, on touch it is inline helper text or a tap-to-reveal sheet, because hover does not exist on a phone (section 4).+- A good explanation says what the control does, what changes after the action, what is and is not preserved for anything destructive, and it spells out jargon for a newcomer. -Copy the canonical header block rather than reinventing it. It is captured in the `adom-app-header` skill.+### Tooltips (desktop) ----+- **Body-appended `position:fixed` elements at `z-index:99999`.** Never a CSS `::after` pseudo-element, which gets clipped by panel `overflow:hidden`, `backdrop-filter`, or `transform` stacking contexts.+- Reveal after a **600ms** hover delay so a fast cursor fly-by stays quiet. Motion is a short fade plus translate, `0.18s ease`.+- Anchor near the cursor, offset about 14px into a quadrant that does not cover the cursor or the hovered element. Flip on-screen near an edge. Reset `text-transform:none`. -## 5. Components and interaction+### Buttons, toggles, and previews -### Tooltips+- A toggle must **look** like its state. Flat styling for both on and off is a lie.+- Primary actions use teal `#00b8b0`. Green means success, red means destructive, reserved for those meanings.+- **Any irreversible-feeling action gets a live preview** before it commits: a snap point, a deletion glow, a highlighted target. -- **Tooltips are body-appended `position:fixed` elements at `z-index:99999`.** Never a CSS `::after` pseudo-element, because it gets clipped by panel `overflow:hidden`, `backdrop-filter`, or `transform` stacking contexts.-- **Every interactive element carries a tooltip.** No orphan controls.-- Reveal delay is **600ms.** Motion is a short fade plus translate, `0.18s ease`.-- Reset `text-transform:none` so the tooltip never inherits uppercase.-- A good tooltip says what the control does, what changes after the click, and for destructive actions what is and is not preserved. Explain jargon for non-experts.+### Floating tool windows and HUDs -### Buttons and toggles+- Draggable by a visible grip, never clamped to a screen edge. The AI can show and hide them on command to test them.+- `max-height: calc(100% - margin)` with internal scroll and a pinned header and footer. Offer minimize, close, and double-click to collapse. -- A toggle must **look** like its state. Flat push-button styling for both on and off is a lie. Show the difference.-- Primary actions use teal `#00b8b0`. Success is green, destructive is red, and those colors are reserved for those meanings.-- Every action gives **immediate visible feedback**: a toast, a class change, or a live preview.+### A note on animation -### HUDs and floating panels+When several iterations of the same animation each help only a little, stop tuning and reframe. The fix for a janky content fade is usually not a smoother content fade, it is to cover the content with a solid block, let it paint underneath, then fade the block off. Animate a trivial proxy, not the expensive thing. -- Draggable by a visible grip, never clamped to a screen edge.-- `max-height: calc(100% - margin)` with internal scroll and a pinned header and footer.-- Offer minimize, close, and double-click to collapse.+--- -### A note on animation+## 4. Responsive and touch -When several iterations of the same animation each help only a little, stop tuning and reframe. The classic fix for a janky content fade is not a smoother content fade, it is to cover the content with a solid block, let it paint underneath, then fade the block off. Animate a trivial proxy, not the expensive thing.+The same app should feel native on a 32 inch monitor and on a phone.++- **Design the layout to reshape, not to shrink.** Define a few breakpoints (phone, tablet, desktop) and change the layout at each, rather than scaling one fixed desktop layout down until it is unusable.+- **Rich on desktop, focused on mobile.** A desktop has room for side panels, dense tables, persistent toolbars, secondary stats. On a phone, collapse those into a single column, move actions into a bottom bar or a menu, and reveal secondary detail on demand. The header models this already: the subject meta line hides below roughly 720px and returns on request.+- **Touch targets are at least 44 by 44 px.** Fingers are not cursors.+- **Hover does not exist on touch, so tooltips cannot be the only way to learn a control.** Under `@media (hover: none), (pointer: coarse)`, replace hover tooltips with a visible label, a tap that reveals an info sheet, or a long-press. Never hide essential meaning behind a hover a phone can never trigger.+- **Respect the safe areas and the soft keyboard.** Keep primary actions reachable with a thumb, and do not let the keyboard cover the active field.+- Test every app at a phone width before publishing, not just at desktop. The AI can resize the pup window to a phone viewport and ralph-loop the mobile layout too.  --- -## 6. AI-drivability+## 5. The app header -This is the rule that makes an Adom app more than a web page: **anything a person can do in the UI, the AI can do over plain HTTP.** Build for it from the start.+Every Adom app wears the same header so a person always knows which app they are in and where the controls are. It is a **single row, 44px tall, three zones.** -- **Server is the single source of truth.** State changes go through the server, not in-memory JavaScript. Buttons fire `POST` commands only, they do not mutate local state.-- **Expose `GET /state`** returning JSON. The UI polls it every 300 to 500ms and drives every transition from it. The AI reads the same endpoint to check progress without scraping HTML.-- **Expose `GET /console`.** Override `console.log/warn/error` to also `POST /console`, keep a server-side ring buffer, and catch `window.onerror` and `unhandledrejection`. Now the AI can read the app's log output without DevTools.-- **Return structured JSON** from every `POST`, not an HTML redirect.-- The acceptance test: an AI driving the app with `curl` and a person clicking the UI should produce identical visible results.+```+[ icon  app-name · subtitle ] | [ Subject Name  meta ]            [ btn btn ]+        brand (left)            vsep      subject (center)          actions (right)+``` -### Talking to a container app from outside+- **Brand zone (left):** a 16x16 monochrome icon, the app name, a middot, a one to four word subtitle, in Familjen Grotesk 600 and the accent color. Hovering it reveals an app-info popover (version, build date, engine, author, clickable wiki link); none of that sits in the row itself.+- **Subject zone (center):** the current document or object name (bold, ellipsis-truncated when narrow) plus a muted monospace meta line for secondary stats that hides below ~720px and returns on hover or tap.+- **Actions zone (right):** icon buttons only, right aligned with `margin-left:auto`. Skip it if there are none.+- A `1px` vertical hairline separates brand from subject. -- A Hydrogen webview and a desktop browser window both render **outside** the container. They cannot reach `http://localhost:<port>` or `http://127.0.0.1:<port>`. Always use the public proxy URL: `https://<slug>.adom.cloud/proxy/<port>/`.-- **Inside a webview, always use relative URLs.** A leading slash resolves to the host origin and bypasses the proxy. Every `fetch`, `href`, `src`, and CSS `url()` must be relative.+Never a multi-row or sticky header, never the version inline, never the app name in monospace or all caps. The hover popover must be reachable: `pointer-events:auto`, a 600ms show delay, a ~220ms hide grace. Copy the canonical block from the `adom-app-header` skill.  --- -## 7. CLIs and hints+## 6. CLIs and hints -Most Adom tools ship a CLI, and the CLI is how the AI recovers when a skill has scrolled out of context. The output format is a contract.+Most Adom tools ship a CLI, usually in Rust, and the CLI is both the AI's driving wheel for the front-end (section 2) and how it recovers when a skill scrolls out of context. The output format is a contract. -- **Every response starts with `OK:` or `ERROR:`.** The AI reads the prefix to know instantly whether it worked.+- **Every response starts with `OK:` or `ERROR:`,** so the AI knows instantly whether it worked. - **Every error carries at least one `Hint:`** that is an actionable command, not an explanation.   ```   ERROR: Cannot connect to the server on port 8820.   Hint: Start it with `mytool serve &`   ```-  Hints name the exact command, flag, or file. Chain multiple hints for multi-step recovery. Hints can teach a pattern, for example steering the AI to use the CLI instead of calling an endpoint directly.-- **Strip ANSI color when stdout is not a TTY.** Gate every color on an `isatty` check so logs and command substitution stay clean.-- Ship a `health` subcommand and an `install` subcommand. `install` fetches the latest skill from the wiki rather than relying on an embedded copy.-- **Relay servers gate on User-Agent.** The CLI sets `User-Agent: <tool>-cli/<version>`. The relay rejects anything else with a structured hint telling the caller to use the CLI:-  ```json-  { "ok": false, "error": "direct_http_use_cli_instead",-    "_adom_use_cli_instead": "Use the `mytool` CLI: mytool <command>." }-  ```--Why hints matter: a skill is read once and then degrades as context fills. A hint in error output is read at the exact moment of need, always fresh. Hints are the most reliable way to steer an AI.+  Hints name the exact command, flag, or file, and chain for multi-step recovery. A hint read at the moment of need steers an AI far more reliably than a skill read once and forgotten.+- **Strip ANSI color when stdout is not a TTY.** Gate every color on an `isatty` check.+- Ship `health` and `install` subcommands. `install` fetches the latest skill from the wiki rather than relying on an embedded copy.+- **Relay servers gate on User-Agent.** The CLI sets `User-Agent: <tool>-cli/<version>`; the relay rejects anything else with a structured hint telling the caller to use the CLI.+- Build the **front-end driving subcommands** (`ui click`, `ui toolbar`, `ui load-*`, `ui toast`) as first-class CLI verbs, each wired to the live channel, so driving the UI is as scriptable as any other command.  --- -## 8. 3D viewers+## 7. 3D viewers -Adom has many 3D viewports: CAD, PCB, mechanical, component preview. They share one design so they feel like one tool.+Adom has many 3D viewports: CAD, PCB, mechanical, component preview. They share one design so they feel like one tool, and they are driven the same way (the AI can load a different model or click a viewer tool over the channel). -- **Babylon.js, always. Never Three.js.** Better PBR materials, better GLB fidelity, a first-class orbit camera, and a built-in ViewCube. This holds even for quick prototypes.-- **Start from the canonical Adom Babylon viewer.** Embed it, import it, or extend it before you ever roll your own. If you do roll your own, you inherit every rule below.-- **Background is a vertical gradient, never a flat color.** Pure black hid black IC bodies in the lower frame, which is why the gradient is mandatory. Dark mode default, light mode toggle required.+- **Babylon.js, always. Never Three.js.** Better PBR materials, GLB fidelity, a first-class orbit camera, and a built-in ViewCube.+- **Start from the canonical Adom Babylon viewer.** Embed, import, or extend it before rolling your own. If you roll your own, you inherit every rule below.+- **Background is a vertical gradient, never a flat color.** Pure black hid black IC bodies in the lower frame. Dark mode default, light mode toggle required.   - Dark: `linear-gradient(180deg, #1e2a3d 0%, #1e2a3d 20%, #0a121f 100%)`   - Light: `linear-gradient(180deg, #5a6b7e 0%, #5a6b7e 20%, #2a3340 100%)` - **Zoom to cursor is non-negotiable:** `camera.zoomToMouseLocation = true`.-- **Two lights minimum,** never a single-light rig: an HDRI environment plus a hemispheric light, with a bottom-light toggle for dark parts.-- **World-origin axis helpers default on** (X red, Y green, Z blue), with a screen-space corner triad always visible and a ViewCube in the top-right. Do not rebuild the buttons the ViewCube already provides.-- Camera limits are soft, and wheel, pan, and pinch precision adapt to the model size on each load rather than being hard-coded.+- **Two lights minimum,** never a single-light rig: HDRI environment plus a hemispheric light, with a bottom-light toggle for dark parts.+- **World-origin axis helpers default on** (X red, Y green, Z blue), a screen-space corner triad always visible, a ViewCube in the top-right. Do not rebuild the buttons the ViewCube already provides.+- Camera limits are soft, and wheel, pan, and pinch precision adapt to model size on each load.  ### The measure tool -When a viewer needs measurement, match Fusion 360 and SolidWorks behavior:+Match Fusion 360 and SolidWorks: **live hover preview, not click-only**; smart-pick edge then face then vertex; the committed marker matches the preview; dimension line distinct from markers (markers teal `#00B8B1`, line blue `#64ABFF`); millimeters primary with mils secondary, never inches; Esc is multi-stage (pop last pick, then the previous, then close).++---++## 8. Foundations: color++The finishing tokens. They make an app on-brand once the interaction is already right. Adom is a dark system, and color is used sparingly so the one teal accent always means "this is interactive or important."++![Adom design tokens at a glance](screenshots/tokens.png)++### Core theme tokens++| Token | Value | Use |+|---|---|---|+| `--bg` | `#0d1117` | Page, deepest background |+| `--surface` | `#161b22` | Panels, toolbars, cards |+| `--elevated` | `#1c2128` | Elevated cards, hover surfaces |+| `--overlay` | `#21262d` | Tooltips, dropdowns, modals |+| `--border` | `#30363d` | Standard border |+| `--text` | `#e6edf3` | Primary text |+| `--text-2` | `#8b949e` | Secondary text, labels |+| `--text-3` | `#484f58` | Disabled, placeholders |+| `--accent` | `#00b8b0` | Primary accent, the Adom teal |+| `--accent-bright` | `#00e6dc` | Hover and focus highlights | -- **Live hover preview, not click-only.** Show the geometry you would snap to before the click commits it.-- Smart-pick priority is edge, then face, then vertex.-- The committed marker matches the previewed geometry. An edge preview commits to an edge tube, not a generic sphere.-- The dimension line is a distinct color from the snap markers: markers teal `#00B8B1`, dimension line blue `#64ABFF`.-- Show millimeters as the primary unit with mils as a secondary, never inches.-- Esc is multi-stage: pop the last pick, then the previous, then close the HUD. Never a single-stage close-everything.+### Status and grouping++| Token | Value | Use |+|---|---|---|+| `--purple` | `#8c6bf7` | Group labels, secondary accent |+| `--blue` | `#58a6ff` | Links, informational accents |+| `--green` | `#3fb950` | Success only |+| `--red` | `#f85149` | Destructive only |+| `--yellow` | `#d29922` | Warning only |++- Never use **pure black** (`#000`) or **pure white** (`#fff`) for a large surface.+- Hover transitions are smooth, not snappy: `0.15s ease`.+- Signature gradient, teal to blue to purple: `linear-gradient(100deg, #00e6dc, #39b8ff 60%, #8c6bf7)`. Headline accents and flagship art, not body UI.  --- -## 9. Hero images+## 9. Foundations: type, spacing, and icons -A hero is the 16:10 billboard at the top of a wiki page. It is reused unchanged on the page header, the landing card, the installer, the homepage, and the screensaver, so it has to read in about one second.+| Face | Weights | Job |+|---|---|---|+| **Familjen Grotesk** | 500, 600, 700 | Headlines, app name, section headers, identity |+| **Satoshi** | 400, 500, 700 | Body copy, descriptions, paragraphs |+| **JetBrains Mono** | 400, 500 | Source code, inline code, numeric and data rows | -- **One app, one screenshot.** No collages. A single great shot of the real UI beats any montage.-- **Dark, on-brand background.** No white box around a logo. The only allowed texture is a faint dot grid or arc pattern, kept subtle.-- **Headline is the app name or a punchy value phrase,** with the signature gradient on one key word, plus a one-line value prop with a couple of words bolded white for scanning.-- **The product sits in a floating window** with a drop shadow, bleeding off the bottom. The window chrome is **Windows-style: minimize, maximize, and close at the top right.** Never macOS traffic-light dots.-- **Margins are sacred.** Keep every element at least 80px from the canvas edge and give text and the product window real separation. The most common failure is the window touching the copy.-- **The call to action is an AI prompt,** for example `"flash my board as a USB keyboard"`, not a shell install command. The install section of the page can show the CLI, the hero sells the outcome.-- Use the real app UI with realistic example data. A placeholder or a striped no-image panel is a failure, not a fallback.+- **Monospace is only for code and data.** A version number or a pad count is data, so it is mono. A button label is not.+- **Never ALL CAPS body text.** Small uppercase is fine for tiny eyebrow labels and chips, never for sentences.+- Do not fall back to Inter, Arial, Helvetica, or the system stack as the primary face. Load the brand fonts from `https://adom.inc/fonts/`.+- **Spacing grid:** 8px, 12px, 16px. **Radius:** `8px` for buttons and cards, `12px` for larger containers, `999px` for pills.+- **Icons are monochrome white. No exceptions.** `#e6edf3` or `currentColor`, in-app icons, the tab-strip icon, and the favicon. Prefer a clean custom SVG (`viewBox="0 0 24 24"`, stroke 1.5 to 2px). No emoji as icons. The only place brand color is allowed is marketing art: the hero and the page thumbnail.+  - Pre-publish icon audit, both must return zero hits:+    ```bash+    grep -nE 'fill="(#00b8b0|#00d4cb)"|stroke="(#00b8b0|#00d4cb)"' docs/icon.svg src/**/*.html src/**/*.svg+    grep -nE '\.logo[^{]*\{[^}]*color:\s*var\(--accent\)|\.icon[^{]*\{[^}]*color:\s*var\(--accent\)' src/**/*.html src/**/*.css+    ```++---++## 10. Hero images++A hero is the 16:10 billboard at the top of a wiki page, reused on the page header, the landing card, the installer, the homepage, and the screensaver. It has to read in about one second and sell the **outcome**, not the brand.++- **One app, one screenshot.** No collages.+- **Lead with the value, not the logo.** The headline is the outcome a person gets, with the signature gradient on one key word, plus a one-line value prop with a couple of words bolded white.+- **Show a real, friendly app moment** with realistic data, ideally one that demonstrates the experience: a clear action, a helpful tooltip, a success toast.+- **The product sits in a floating window** with a drop shadow, bleeding off the bottom, with **Windows-style chrome** (minimize, maximize, close at the top right), never macOS dots.+- **Margins are sacred:** every element at least 80px from the edge, real separation between text and window.+- **The call to action is an AI prompt,** for example `"make my app a joy to use"`, not a shell command. -The `adom-wiki-hero` skill renders all of this from a template.+The `adom-wiki-hero` skill renders this from a template.  --- -## 10. Copy and voice+## 11. Copy and voice -The words are part of the design.+The words are part of the experience. -- **No em-dashes or en-dashes** in any shipped copy. Use commas, colons, periods, parentheses, or "to" for ranges. Dashes read as machine-written and undercut credibility.+- **Write for the person, plainly.** Say what a thing does and what will happen, in their language.+- **No em-dashes or en-dashes** in shipped copy. Use commas, colons, periods, parentheses, or "to" for ranges. - **No gimmick emoji** in product UI text.-- **Name products by their short name,** never with the tagline baked in. The tagline belongs in a subtitle or a page brief.-- **Lead with Adom's own value:** fast turns, low cost, drone delivery, the Fort Worth facility. Keep the copy professional, for engineers and serious makers, rather than hobbyist.-- Provenance over magic. A diagnostic or computed view shows where its data came from and never silently auto-corrects.+- **Name products by their short name,** never with the tagline baked in.+- **Lead with the value** the user gets. Tone is professional, for engineers and serious makers.+- Provenance over magic: a computed view shows where its data came from and never silently auto-corrects.  --- -## 11. The enforcement gate+## 12. The enforcement gate -Reading this page is step one. Proving an app follows it is `adom-ui-linter`, which encodes most of these rules as roughly 50 deterministic checks across six categories.+Reading this page is step one. Proving an app follows it is `adom-ui-linter`, which encodes most of these rules as roughly 50 deterministic checks.  | Category | Checks | |---|---|+| ui-patterns | tooltips body-appended and not `::after`, feedback on actions, toast hook, toggle state, color tokens, no all-caps |+| ai-drivability | `GET /state`, `GET /console`, live channel, front-end driving commands, relay User-Agent gate, CLI hints | | header | 44px height, brand and subject zones, fonts, popover, favicon |-| ui-patterns | tooltips body-appended and not `::after`, color tokens, toggle state, no all-caps |-| ai-drivability | `GET /state`, `GET /console`, relay User-Agent gate, CLI hints | | cli-compliance | `OK:`/`ERROR:` prefix, `Hint:` lines, health and install subcommands, isatty gating | | skills-docs | skill frontmatter and triggers, README with inline screenshots | | build-publish | version files in sync, release profile, port registration |  ```bash-adom-ui-linter lint . --category header,ui-patterns,ai-drivability+adom-ui-linter lint . --category ui-patterns,ai-drivability,header ``` -Fix every FAIL (the hint tells you exactly what to do), address relevant WARNs, and re-run to zero before publishing.+Fix every FAIL (the hint tells you exactly what to do), address relevant WARNs, re-run to zero before publishing.  --- -## 12. The skill map+## 13. The skill map  This system is split across focused skills. The AI loads them by trigger word. Use this as the index of where each rule lives.  | Skill | Governs | |---|---|-| `brand` | Colors, typography, logo, icon law, the dark theme tokens |-| `human-ui-patterns` | Tooltips, HUDs, toggles, text rules, feedback, AI-drivability primitives |+| `human-ui-patterns` | Tooltips, HUDs, toggles, feedback, the user-first interaction primitives |+| `app-creator` | Building a webview app: two-way comms, the live channel, proxy URL, favicon, publish flow | | `adom-app-header` | The 44px three-zone header and the app-info popover | | `adom-app-model` | How an Adom app is structured, distributed, and versioned |-| `app-creator` | Building a webview app: favicon, proxy URL, two-way comms, publish flow |-| `pup-vs-webview` | Choosing a desktop browser window versus a Hydrogen webview tab |-| `carbon-preferences` | Per-user settings that persist across sessions |-| `adom-panels` | The panel catalog and per-panel control APIs |-| `adom-workspace-control` | Adding, splitting, moving, and resizing workspace panes safely |-| `adom-layouts` | The workcell layout JSON grammar |-| `3d-viewer-design` | Every rule for Adom 3D viewports |-| `measure-tool-design` | Fusion-grade measurement inside a Babylon viewer |-| `screen-capture-wake-lock` | Releasing the display lock after a screen capture |-| `adom-cli-design` | The `OK:`/`ERROR:`/`Hint:` CLI contract |+| `adom-screenshot` | Ralph loops and the visual feedback loop for debugging UI |+| `pup-vs-webview` / `adom-desktop-pup` | Choosing and driving pup, webview, or the native browser |+| `adom-browser-extension` | Driving the user's real Chrome or Edge (auth-cookie, auto-login) |+| `adom-cli-design` | The `OK:`/`ERROR:`/`Hint:` CLI contract, in Rust | | `ai-hints-in-clis` | Writing hints that actually steer the AI | | `relay-hint-pattern` | Teaching a relay server to redirect callers to the CLI |-| `adom-ui-linter` | The deterministic check suite that enforces this page |-| `readme-creator` | READMEs with inline screenshots for visual tools |-| `adom-screenshot` | Capturing and logging screenshots for visual feedback loops |+| `3d-viewer-design` / `measure-tool-design` | Every rule for Adom 3D viewports and measurement |+| `adom-panels` / `adom-workspace-control` | The panel catalog and safe workspace layout control |+| `carbon-preferences` | Per-user settings that persist across sessions |+| `brand` | Colors, typography, logo, the icon law, the dark theme tokens | | `adom-wiki-hero` | Rendering a billboard-grade hero image |+| `adom-ui-linter` | The deterministic check suite that enforces this page |  --- @@ -312,20 +332,21 @@ This system is split across focused skills. The AI loads them by trigger word. U You drive all of this by asking. Useful prompts:  **Build**-- "build me an on-brand Adom webview app for X"-- "add a standard Adom 44px header to this app"-- "make this CLI follow the Adom OK/ERROR/Hint contract"--**Design**-- "what are the Adom color tokens"-- "give me the Adom 3D viewer defaults"-- "make a hero image for my app"--**Check**+- "build me an Adom webview app for X that is a joy to use"+- "make this app fully drivable from the CLI over a live channel"+- "make this app work well on a phone, not just desktop"++**Test and drive**+- "show me the app in my native browser so it is already logged in"+- "open it in pup and test the logged-out experience"+- "ralph-test this app: click every button and show me where the UI breaks"+- "auto-click send-to-kicad and toast me when the file is downloaded"++**Improve**+- "make my app a joy to use"+- "add instant feedback and toasts to every action" - "lint my app against the Adom UI rules"-- "audit my icons for brand-color leaks"-- "is this app AI-drivable"  --- -*Adom UI Design System. Dark, teal, monochrome-iconed, API-driven. Build it once, build it right.*+*Adom UI Design System. The AI builds it, drives it, and perfects it, around a user who is the center of everything.*
SKILL.md+238−213
@@ -2,327 +2,351 @@ name: adom-ui-design user-invocable: true description: >--  The Adom UI Design System: the single source of truth for how every Adom surface looks and-  behaves. Read this BEFORE building any Adom UI, app, CLI, 3D viewer, or hero image so it comes-  out on-brand the first time. Covers exact color tokens (#0d1117 / #161b22 / #00b8b0 teal), the-  three brand fonts (Familjen Grotesk, Satoshi, JetBrains Mono), the monochrome-white icon law,-  spacing and radius, the 44px three-zone app header, tooltips and HUDs, AI-drivability-  (GET /state, GET /console), the OK/ERROR/Hint CLI contract, Babylon 3D viewer rules, hero-image-  rules, the copy voice (no em-dashes, no gimmick emoji), and the adom-ui-linter enforcement gate.-  Trigger words: ui design, design system, adom design, brand colors, color tokens, adom tokens,-  theme tokens, dark theme, typography, fonts, familjen grotesk, satoshi, jetbrains mono, icon-  rules, monochrome icons, favicon, app header, 44px header, top bar, tooltip, toggle state, HUD,-  spacing grid, border radius, on-brand, make it on-brand, ai-drivable, ai-drivability, GET /state,-  OK ERROR Hint, cli design, 3d viewer design, babylon not three, measure tool, hero image,-  billboard, windows chrome not mac, no em-dashes, copy voice, ui linter, lint my app, design audit.+  The Adom UI Design System: how the AI builds AND tests interfaces people love to use in the Adom+  ecosystem. The AI writes the app, shows it to the user (in the native browser via the+  adom-browser-extension so it is already logged in with the user's auth cookie, in pup for the+  logged-out experience, or in a Hydrogen webview), drives the front-end over a live SSE/WebSocket+  channel to exercise every path (auto-click buttons, show/hide floaty toolbars, load a different+  symbol or footprint, click send-to-kicad), and ralph-loops with screenshots until the UI is+  perfect. Covers the user-first interaction rules (instant feedback, controls that explain+  themselves, toasts that double as the AI's live narration channel to the user, forgiving errors),+  responsive and touch (mobile layouts, tooltips without hover), the 44px app header, AI-drivability+  (state on the server, GET /state + /console, the live channel, CLI driving commands), the+  OK/ERROR/Hint Rust CLI contract, Babylon 3D viewers, hero rules, and the polish tokens (colors,+  fonts, icons) last. Read BEFORE building or testing any Adom UI. Trigger words: ui design, design+  system, build an app, build a ui, test the ui, ralph test, ralph loop, drive the front-end,+  ai-drivable, ai drivable app, live channel, sse, websocket, server-sent events, show app in+  native browser, show app in pup, webview vs pup, auto-click, auto click buttons, toast, ui toast,+  app header, 44px header, tooltip, mobile tooltip, responsive, mobile layout, on-brand, color+  tokens, theme tokens, cli design, hints, 3d viewer, hero image, ui linter, make my app a joy to use. ---  # Adom UI Design System -The single source of truth for how every Adom surface looks and behaves. Color tokens, typography, the app header, panels, 3D viewers, hero images, AI-drivability, and the copy voice, plus the linter that enforces them. One page so that a person or an AI can build something new and have it come out unmistakably Adom on the first try.+How the AI builds and tests interfaces that people genuinely love to use. In Adom you do not hand-write an app and then click through it to check it. You ask the AI to build it, and the AI builds it, shows it to you, drives it over a live channel, watches the result, and fixes it, looping until the experience is right. This page is the standard that makes that loop land on something pleasurable: a UI that treats the person using it as the center of everything, and an app that is built from the first commit to be driven and observed. Color and typography are the final polish, maybe three percent of the work. The rest is interaction quality and drivability. -![Adom UI Design System](screenshots/hero.png)+![Build interfaces people love to use](screenshots/hero.png) -> **Why this page exists.** Adom ships a lot of small surfaces: webview apps, CLIs, 3D viewers, wiki pages, hero art. Without one written standard, each one drifts and the family stops looking like a family. This page collects every rule that was previously spread across a dozen skills into a system you can read top to bottom. If you only remember one thing: **Adom is dark, teal, monochrome-iconed, and driven by clean APIs.**+> **Why this page exists.** Two things are true in Adom that are not true elsewhere. First, good UI is not decoration, it is respect for the person on the other side of the screen. Second, the AI is the one building and driving the UI, so the app has to be controllable and observable end to end, or the AI cannot perfect it. This page teaches both: how to make an interface a pleasure to use, and how to build and test it the Adom way. If you only remember one thing: **build for the user first, make every action answer back, and make the whole app drivable so the AI can prove it.**  --- -## The 90-second contract+## The contract -The rules that get broken the most. If you do nothing else, do these.+The principles that matter most, in order. Usability and drivability first, polish last. -1. **Dark by default.** Page background is `#0d1117`, panels are `#161b22`. Never a white or light primary background.-2. **Teal is the one accent.** Primary interactive color is `#00b8b0`. Purple `#8c6bf7` for grouping. Nothing else competes for attention.-3. **Every icon is monochrome white.** `#e6edf3` or `currentColor`. No colored icons, no emoji, in app UI, tab strips, or favicons. Brand color appears only in marketing art (hero, thumbnail).-4. **Three fonts, by role.** Familjen Grotesk for headings and identity, Satoshi for body, JetBrains Mono for code and numeric data. Never Inter, Arial, or a system stack as the primary face.-5. **One 44px header, three zones.** Brand on the left, subject in the middle, icon actions on the right. Per pixel above content is wasted screen.-6. **Every UI action has a matching API.** If a button does it, a plain HTTP call must do it too. State lives on the server, the UI polls `GET /state`. This is what makes an app AI-drivable.-7. **CLIs answer `OK:` or `ERROR:`,** and every error carries a `Hint:` with the exact command to run next.-8. **3D is Babylon.js,** never Three.js. Gradient background, zoom to cursor, two-light minimum.-9. **No em-dashes, no gimmick emoji** in any shipped copy.-10. **Lint before you publish.** `adom-ui-linter` turns most of this page into ~50 deterministic checks.+1. **Put the user at the center.** Every screen answers three questions at a glance: what is this, what can I do here, and what just happened.+2. **Every action answers back.** A toast, a state change, or a live preview. Never a silent click, never a spinner with no end, never a dead end.+3. **Controls explain themselves.** Every control says what it does and what changes, in a tooltip on desktop and inline on touch.+4. **Errors are help, not blame.** Say what went wrong and the exact next step. Destructive actions say what is kept and offer an undo.+5. **Adapt to the screen.** Rich and dense on a desktop, lean and thumb-friendly on a phone. The same app reshaped, never a cramped desktop layout squeezed onto mobile.+6. **Built and driven by the AI.** The AI writes the app, shows it to you, and drives it over a live SSE or WebSocket channel to test and perfect it. Anything the UI can do, a command can do, so state lives on the server and the channel keeps the UI, the CLI, and the AI in lockstep.+7. **One 44px header, three zones,** so people always know which app they are in and where the controls are.+8. **CLIs answer `OK:` or `ERROR:`,** with a `Hint:` that names the exact next command.+9. **Then the polish:** dark `#0d1117` and `#161b22`, one teal accent `#00b8b0`, monochrome-white icons, three fonts by role. On-brand matters, but it comes last.+10. **Lint before you publish.** `adom-ui-linter` turns most of this into deterministic checks.  --- -## 1. Color+## 1. How a UI is built and tested in Adom -![Adom design tokens at a glance](screenshots/tokens.png)+This is the loop the whole system is designed around. The AI is both the builder and the tester, the user watches and steers. -Adom is a dark system. Color is used sparingly so that the one teal accent always means "this is interactive or important."+1. **The AI builds the app:** a small server plus a webview UI, made AI-drivable from the first commit (state on the server, a live channel, a CLI).+2. **The AI shows it to the user** in one of three surfaces (below), chosen for what is being tested.+3. **The AI drives the front-end** over the live channel to exercise every path: click each button in turn, open and close the floating toolbar, load a different symbol or footprint, hit "send to KiCad", and read back state, the console buffer, and screenshots.+4. **The AI ralph-loops:** screenshot, analyze what looks wrong, fix the code, reload, repeat, until the UI is correct and a pleasure to use.+5. **The AI narrates** what it is doing through toasts and the chat, so the user can follow the test as it happens. -### Core theme tokens+The design rules on this page exist so that this loop converges on something a person loves, not merely something that runs. -| Token | Value | Use |-|---|---|---|-| `--bg` | `#0d1117` | Page, deepest background |-| `--surface` | `#161b22` | Panels, toolbars, cards |-| `--elevated` | `#1c2128` | Elevated cards, hover surfaces |-| `--overlay` | `#21262d` | Tooltips, dropdowns, modals |-| `--border` | `#30363d` | Standard border |-| `--border-muted` | `#21262d` | Subtle inner borders |-| `--text` | `#e6edf3` | Primary text |-| `--text-2` | `#8b949e` | Secondary text, labels |-| `--text-3` | `#484f58` | Disabled, placeholders |-| `--accent` | `#00b8b0` | Primary accent, the Adom teal |-| `--accent-bright` | `#00e6dc` | Hover and focus highlights |+### The three display surfaces -### Status and grouping+The AI picks the surface by what it needs to test, and it can use more than one at once. -| Token | Value | Use |+| Surface | What it is | Use it for | |---|---|---|-| `--purple` | `#8c6bf7` | Group labels, secondary accent |-| `--blue` | `#58a6ff` | Links, informational accents |-| `--green` | `#3fb950` | Success only |-| `--red` | `#f85149` | Destructive only |-| `--yellow` | `#d29922` | Warning only |+| **Native browser** | The user's real Chrome or Edge, reached through the `adom-browser-extension` | The real, signed-in experience. The browser already holds the user's auth cookies, so the app opens **logged in or auto-logs-in with zero friction**. Huge for demoing and testing anything behind a login. |+| **pup** | A clean, scriptable Chrome the AI fully owns, via `adom-desktop` | The **fresh, logged-out, first-time-user** experience, and automated screenshot loops that should not fight the user's own tabs. |+| **Hydrogen webview** | An in-workspace browser tab | Showing a result inside the workbench, next to the code and the chat. | -### Brand palette (marketing and illustration)+The native-browser and pup split is the point: the AI can open the **logged-in path in the native browser** (real cookies) and the **logged-out path in pup** at the same time, and verify both experiences. Choose deliberately, and tell the user which one and why. -| Name | Hex | Use |-|---|---|---|-| Teal (primary) | `#00B8B1` | The brand color |-| Blue Light | `#64ABFF` | Accents, links, illustration |-| Purple Light | `#C5B3FF` | Hover states, secondary accent |-| Blue Dark | `#0061EF` | Strong CTAs |-| Purple | `#8C6BF7` | Grouping, secondary accent |-| Navy | `#00204F` | Deep dark backgrounds |-| Teal Dark | `#003C3F` | Dark teal panels |+--- -### Rules+## 2. The live channel: driving and observing -- Never use **pure black** (`#000`) or **pure white** (`#fff`) for a large surface. Black kills contrast against dark UI parts, white blows out a dark theme. Use the tokens above.-- Hover transitions are smooth, not snappy: `0.15s ease`.-- The signature gradient is teal to blue to purple: `linear-gradient(100deg, #00e6dc, #39b8ff 60%, #8c6bf7)`. Use it for headline accents and flagship art, not for body UI.+The spine that makes the loop possible. Build it into every app. ------## 2. Typography+- **State lives on the server.** The UI never keeps its own copy of "am I recording?" or "which symbol is loaded?". Buttons fire commands to the server, the server owns the truth.+- **A live channel pushes state to everyone.** Expose **Server-Sent Events** for one-way push, or a **WebSocket** for two-way. The UI subscribes and updates the instant anything changes. The CLI subscribes too. A 300 to 500ms poll of `GET /state` is the minimum fallback, but the live channel is what makes driving feel instant.+- **The channel is two-way, so the AI drives the front-end from the CLI.** Every user-visible action has a command that does exactly what the click does:+  ```+  mytool ui click "send-to-kicad"      # press a button+  mytool ui toolbar show               # reveal the floating toolbar, then `hide`+  mytool ui load-symbol LM358          # swap the loaded symbol or footprint+  mytool ui toast "file downloaded"    # raise a toast (see section 3)+  ```+  Each command drives the real UI through the same path a user would, so the AI can walk every interaction, assert the resulting state, screenshot it, and move on. This is the test harness and the demo driver in one.+- **Observe, do not scrape.** Expose `GET /state` for current state and `GET /console` for the app's log: override `console.log/warn/error` to also post to the server, keep a ring buffer, and catch `window.onerror` and `unhandledrejection`. Now the AI reads what the UI is doing without DevTools.+- **The acceptance test:** an AI driving the app over the channel and a person clicking the UI produce identical visible results. -Three faces, each with one job. Mixing them up is the fastest way to make an app feel off-brand.+### Ralph-testing the UI -| Face | Weights | Job |-|---|---|---|-| **Familjen Grotesk** | 500, 600, 700 | Headlines, app name, section headers, identity |-| **Satoshi** | 400, 500, 700 | Body copy, descriptions, paragraphs |-| **JetBrains Mono** | 400, 500 | Source code, inline code, numeric and data rows |+The visual feedback loop that turns "it runs" into "it is right": edit, reload, drive a step over the channel, screenshot, read the console buffer, analyze, fix, repeat. Drive it in pup (or the native browser), capture each frame to the screenshot log, and keep looping until the UI looks and behaves correctly. This is how the AI debugs UI with no human in the loop, and it is also the proof that the app is genuinely drivable. -### Rules+### Reaching a container app from outside -- **Monospace is only for code and data.** Labels, descriptions, status pills, tooltips, headings, and body never use a monospace face. A version number or a pad count is data, so it is mono. A button label is not.-- **Never ALL CAPS body text.** Small uppercase is allowed for tiny eyebrow labels and chips with wide letter spacing, never for sentences.-- Do not fall back to Inter, Arial, Helvetica, or the system stack as the primary face. Load the brand fonts from `https://adom.inc/fonts/`.+- A webview and a browser window both render **outside** the container, so they cannot reach `http://localhost:<port>` or `http://127.0.0.1:<port>`. Always use the public proxy URL: `https://<slug>.adom.cloud/proxy/<port>/`.+- **Inside a webview, always use relative URLs.** A leading slash resolves to the host origin and bypasses the proxy. Every `fetch`, `href`, `src`, and CSS `url()` must be relative.  --- -## 3. Spacing, radius, and icons+## 3. Interaction and feedback -- **Spacing grid:** 8px, 12px, 16px. Stay on the grid.-- **Border radius:** `8px` for buttons and cards, `12px` for larger containers, `999px` for pills and chips.-- **Icons are monochrome white. No exceptions.** `#e6edf3` or `currentColor` inheriting from white text. This covers in-app icons, the Hydrogen tab-strip icon, and the favicon. A teal favicon is a UX lie because the tab strip is Adom chrome, not your art.-  - Prefer a clean custom SVG (`viewBox="0 0 24 24"`, stroke weight 1.5 to 2px) over a generic icon unless the concept is fully generic.-  - No emoji as icons, ever.-  - **Pre-publish icon audit.** Both of these greps must return zero hits:-    ```bash-    grep -nE 'fill="(#00b8b0|#00d4cb)"|stroke="(#00b8b0|#00d4cb)"' docs/icon.svg src/**/*.html src/**/*.svg-    grep -nE '\.logo[^{]*\{[^}]*color:\s*var\(--accent\)|\.icon[^{]*\{[^}]*color:\s*var\(--accent\)' src/**/*.html src/**/*.css-    ```-- The **only** place brand color is allowed is marketing art: the hero image and the thumbnail on the wiki page.+An interface that responds, explains, and forgives is the difference between a tool people tolerate and one they enjoy. It is also what the AI drives and verifies in the loop above. ----+### Every action answers back -## 4. The app header+- **Immediate visible feedback on every action:** a toast, a class change, a live preview, a progress line. A click that produces no visible response reads as broken, to a person and to the AI watching the screenshot.+- **Show, do not block.** Long work shows progress and stays interactive where it can. A bare spinner with no estimate is a last resort. -Every Adom webview app wears the same header so that a person always knows which app they are in and where the controls are. It is a **single row, 44px tall, three zones.**+### Toasts, for the user and for the AI -```-[ icon  app-name · subtitle ] | [ Subject Name  meta ]            [ btn btn ]-        brand (left)            vsep      subject (center)          actions (right)-```+Toasts are the standard transient-feedback element, and in Adom they do double duty: because the AI is driving the front-end, **a toast is also how the AI talks to the user live**, on top of the running app, during a test or a demo. "Running test 3 of 8", "file downloaded", "loaded LM358, re-routing", all land as toasts over the app rather than buried in chat. -- **Brand zone (left):** a 16x16 monochrome icon, the app name, a middot, and a one to four word subtitle. Familjen Grotesk 600, in the accent color. Hovering the brand block reveals an app-info popover with version, build date, engine, author, and a clickable wiki link. None of that metadata sits in the header row itself.-- **Subject zone (center):** the current document or object name (bold, truncates with an ellipsis when narrow) plus a muted monospace meta line for secondary stats. The meta line hides below roughly 720px and returns on hover.-- **Actions zone (right):** icon buttons only, right aligned with `margin-left:auto`. Skip the zone entirely if there are no actions.-- A `1px` vertical hairline separates brand from subject.+- **Build a `POST /ui/toast` hook from day one.** One mechanism serves both the user (feedback) and the AI (narration). The AI raises a toast with the same `mytool ui toast "..."` command it uses to drive everything else.+- **Position:** bottom center, consistent across the app.+- **Types:** success (green `#3fb950`), error (red `#f85149`), info (teal `#00b8b0`), each with a clear icon and message.+- **Duration:** about 4 seconds for a confirmation, sticky for an error the user must read. Pause on hover.+- **Stack** newest on top, cap the visible count, allow dismiss, and **carry an action when one exists**, above all **Undo** for anything destructive. -### Header rules+### Controls that explain themselves -- Never a multi-row header. Never a sticky header. Never the app version inline in the row. Never the app name in a monospace face. Never an all-caps app name.-- The popover that appears on hover must be reachable: give it `pointer-events:auto`, a 600ms show delay, and a ~220ms hide grace so the cursor can cross the gap to click a link inside it.+- **Every interactive element carries an explanation.** On desktop this is a tooltip, on touch it is inline helper text or a tap-to-reveal sheet, because hover does not exist on a phone (section 4).+- A good explanation says what the control does, what changes after the action, what is and is not preserved for anything destructive, and it spells out jargon for a newcomer. -Copy the canonical header block rather than reinventing it. It is captured in the `adom-app-header` skill.+### Tooltips (desktop) ----+- **Body-appended `position:fixed` elements at `z-index:99999`.** Never a CSS `::after` pseudo-element, which gets clipped by panel `overflow:hidden`, `backdrop-filter`, or `transform` stacking contexts.+- Reveal after a **600ms** hover delay so a fast cursor fly-by stays quiet. Motion is a short fade plus translate, `0.18s ease`.+- Anchor near the cursor, offset about 14px into a quadrant that does not cover the cursor or the hovered element. Flip on-screen near an edge. Reset `text-transform:none`. -## 5. Components and interaction+### Buttons, toggles, and previews -### Tooltips+- A toggle must **look** like its state. Flat styling for both on and off is a lie.+- Primary actions use teal `#00b8b0`. Green means success, red means destructive, reserved for those meanings.+- **Any irreversible-feeling action gets a live preview** before it commits: a snap point, a deletion glow, a highlighted target. -- **Tooltips are body-appended `position:fixed` elements at `z-index:99999`.** Never a CSS `::after` pseudo-element, because it gets clipped by panel `overflow:hidden`, `backdrop-filter`, or `transform` stacking contexts.-- **Every interactive element carries a tooltip.** No orphan controls.-- Reveal delay is **600ms.** Motion is a short fade plus translate, `0.18s ease`.-- Reset `text-transform:none` so the tooltip never inherits uppercase.-- A good tooltip says what the control does, what changes after the click, and for destructive actions what is and is not preserved. Explain jargon for non-experts.+### Floating tool windows and HUDs -### Buttons and toggles+- Draggable by a visible grip, never clamped to a screen edge. The AI can show and hide them on command to test them.+- `max-height: calc(100% - margin)` with internal scroll and a pinned header and footer. Offer minimize, close, and double-click to collapse. -- A toggle must **look** like its state. Flat push-button styling for both on and off is a lie. Show the difference.-- Primary actions use teal `#00b8b0`. Success is green, destructive is red, and those colors are reserved for those meanings.-- Every action gives **immediate visible feedback**: a toast, a class change, or a live preview.+### A note on animation -### HUDs and floating panels+When several iterations of the same animation each help only a little, stop tuning and reframe. The fix for a janky content fade is usually not a smoother content fade, it is to cover the content with a solid block, let it paint underneath, then fade the block off. Animate a trivial proxy, not the expensive thing. -- Draggable by a visible grip, never clamped to a screen edge.-- `max-height: calc(100% - margin)` with internal scroll and a pinned header and footer.-- Offer minimize, close, and double-click to collapse.+--- -### A note on animation+## 4. Responsive and touch -When several iterations of the same animation each help only a little, stop tuning and reframe. The classic fix for a janky content fade is not a smoother content fade, it is to cover the content with a solid block, let it paint underneath, then fade the block off. Animate a trivial proxy, not the expensive thing.+The same app should feel native on a 32 inch monitor and on a phone.++- **Design the layout to reshape, not to shrink.** Define a few breakpoints (phone, tablet, desktop) and change the layout at each, rather than scaling one fixed desktop layout down until it is unusable.+- **Rich on desktop, focused on mobile.** A desktop has room for side panels, dense tables, persistent toolbars, secondary stats. On a phone, collapse those into a single column, move actions into a bottom bar or a menu, and reveal secondary detail on demand. The header models this already: the subject meta line hides below roughly 720px and returns on request.+- **Touch targets are at least 44 by 44 px.** Fingers are not cursors.+- **Hover does not exist on touch, so tooltips cannot be the only way to learn a control.** Under `@media (hover: none), (pointer: coarse)`, replace hover tooltips with a visible label, a tap that reveals an info sheet, or a long-press. Never hide essential meaning behind a hover a phone can never trigger.+- **Respect the safe areas and the soft keyboard.** Keep primary actions reachable with a thumb, and do not let the keyboard cover the active field.+- Test every app at a phone width before publishing, not just at desktop. The AI can resize the pup window to a phone viewport and ralph-loop the mobile layout too.  --- -## 6. AI-drivability+## 5. The app header -This is the rule that makes an Adom app more than a web page: **anything a person can do in the UI, the AI can do over plain HTTP.** Build for it from the start.+Every Adom app wears the same header so a person always knows which app they are in and where the controls are. It is a **single row, 44px tall, three zones.** -- **Server is the single source of truth.** State changes go through the server, not in-memory JavaScript. Buttons fire `POST` commands only, they do not mutate local state.-- **Expose `GET /state`** returning JSON. The UI polls it every 300 to 500ms and drives every transition from it. The AI reads the same endpoint to check progress without scraping HTML.-- **Expose `GET /console`.** Override `console.log/warn/error` to also `POST /console`, keep a server-side ring buffer, and catch `window.onerror` and `unhandledrejection`. Now the AI can read the app's log output without DevTools.-- **Return structured JSON** from every `POST`, not an HTML redirect.-- The acceptance test: an AI driving the app with `curl` and a person clicking the UI should produce identical visible results.+```+[ icon  app-name · subtitle ] | [ Subject Name  meta ]            [ btn btn ]+        brand (left)            vsep      subject (center)          actions (right)+``` -### Talking to a container app from outside+- **Brand zone (left):** a 16x16 monochrome icon, the app name, a middot, a one to four word subtitle, in Familjen Grotesk 600 and the accent color. Hovering it reveals an app-info popover (version, build date, engine, author, clickable wiki link); none of that sits in the row itself.+- **Subject zone (center):** the current document or object name (bold, ellipsis-truncated when narrow) plus a muted monospace meta line for secondary stats that hides below ~720px and returns on hover or tap.+- **Actions zone (right):** icon buttons only, right aligned with `margin-left:auto`. Skip it if there are none.+- A `1px` vertical hairline separates brand from subject. -- A Hydrogen webview and a desktop browser window both render **outside** the container. They cannot reach `http://localhost:<port>` or `http://127.0.0.1:<port>`. Always use the public proxy URL: `https://<slug>.adom.cloud/proxy/<port>/`.-- **Inside a webview, always use relative URLs.** A leading slash resolves to the host origin and bypasses the proxy. Every `fetch`, `href`, `src`, and CSS `url()` must be relative.+Never a multi-row or sticky header, never the version inline, never the app name in monospace or all caps. The hover popover must be reachable: `pointer-events:auto`, a 600ms show delay, a ~220ms hide grace. Copy the canonical block from the `adom-app-header` skill.  --- -## 7. CLIs and hints+## 6. CLIs and hints -Most Adom tools ship a CLI, and the CLI is how the AI recovers when a skill has scrolled out of context. The output format is a contract.+Most Adom tools ship a CLI, usually in Rust, and the CLI is both the AI's driving wheel for the front-end (section 2) and how it recovers when a skill scrolls out of context. The output format is a contract. -- **Every response starts with `OK:` or `ERROR:`.** The AI reads the prefix to know instantly whether it worked.+- **Every response starts with `OK:` or `ERROR:`,** so the AI knows instantly whether it worked. - **Every error carries at least one `Hint:`** that is an actionable command, not an explanation.   ```   ERROR: Cannot connect to the server on port 8820.   Hint: Start it with `mytool serve &`   ```-  Hints name the exact command, flag, or file. Chain multiple hints for multi-step recovery. Hints can teach a pattern, for example steering the AI to use the CLI instead of calling an endpoint directly.-- **Strip ANSI color when stdout is not a TTY.** Gate every color on an `isatty` check so logs and command substitution stay clean.-- Ship a `health` subcommand and an `install` subcommand. `install` fetches the latest skill from the wiki rather than relying on an embedded copy.-- **Relay servers gate on User-Agent.** The CLI sets `User-Agent: <tool>-cli/<version>`. The relay rejects anything else with a structured hint telling the caller to use the CLI:-  ```json-  { "ok": false, "error": "direct_http_use_cli_instead",-    "_adom_use_cli_instead": "Use the `mytool` CLI: mytool <command>." }-  ```--Why hints matter: a skill is read once and then degrades as context fills. A hint in error output is read at the exact moment of need, always fresh. Hints are the most reliable way to steer an AI.+  Hints name the exact command, flag, or file, and chain for multi-step recovery. A hint read at the moment of need steers an AI far more reliably than a skill read once and forgotten.+- **Strip ANSI color when stdout is not a TTY.** Gate every color on an `isatty` check.+- Ship `health` and `install` subcommands. `install` fetches the latest skill from the wiki rather than relying on an embedded copy.+- **Relay servers gate on User-Agent.** The CLI sets `User-Agent: <tool>-cli/<version>`; the relay rejects anything else with a structured hint telling the caller to use the CLI.+- Build the **front-end driving subcommands** (`ui click`, `ui toolbar`, `ui load-*`, `ui toast`) as first-class CLI verbs, each wired to the live channel, so driving the UI is as scriptable as any other command.  --- -## 8. 3D viewers+## 7. 3D viewers -Adom has many 3D viewports: CAD, PCB, mechanical, component preview. They share one design so they feel like one tool.+Adom has many 3D viewports: CAD, PCB, mechanical, component preview. They share one design so they feel like one tool, and they are driven the same way (the AI can load a different model or click a viewer tool over the channel). -- **Babylon.js, always. Never Three.js.** Better PBR materials, better GLB fidelity, a first-class orbit camera, and a built-in ViewCube. This holds even for quick prototypes.-- **Start from the canonical Adom Babylon viewer.** Embed it, import it, or extend it before you ever roll your own. If you do roll your own, you inherit every rule below.-- **Background is a vertical gradient, never a flat color.** Pure black hid black IC bodies in the lower frame, which is why the gradient is mandatory. Dark mode default, light mode toggle required.+- **Babylon.js, always. Never Three.js.** Better PBR materials, GLB fidelity, a first-class orbit camera, and a built-in ViewCube.+- **Start from the canonical Adom Babylon viewer.** Embed, import, or extend it before rolling your own. If you roll your own, you inherit every rule below.+- **Background is a vertical gradient, never a flat color.** Pure black hid black IC bodies in the lower frame. Dark mode default, light mode toggle required.   - Dark: `linear-gradient(180deg, #1e2a3d 0%, #1e2a3d 20%, #0a121f 100%)`   - Light: `linear-gradient(180deg, #5a6b7e 0%, #5a6b7e 20%, #2a3340 100%)` - **Zoom to cursor is non-negotiable:** `camera.zoomToMouseLocation = true`.-- **Two lights minimum,** never a single-light rig: an HDRI environment plus a hemispheric light, with a bottom-light toggle for dark parts.-- **World-origin axis helpers default on** (X red, Y green, Z blue), with a screen-space corner triad always visible and a ViewCube in the top-right. Do not rebuild the buttons the ViewCube already provides.-- Camera limits are soft, and wheel, pan, and pinch precision adapt to the model size on each load rather than being hard-coded.+- **Two lights minimum,** never a single-light rig: HDRI environment plus a hemispheric light, with a bottom-light toggle for dark parts.+- **World-origin axis helpers default on** (X red, Y green, Z blue), a screen-space corner triad always visible, a ViewCube in the top-right. Do not rebuild the buttons the ViewCube already provides.+- Camera limits are soft, and wheel, pan, and pinch precision adapt to model size on each load.  ### The measure tool -When a viewer needs measurement, match Fusion 360 and SolidWorks behavior:+Match Fusion 360 and SolidWorks: **live hover preview, not click-only**; smart-pick edge then face then vertex; the committed marker matches the preview; dimension line distinct from markers (markers teal `#00B8B1`, line blue `#64ABFF`); millimeters primary with mils secondary, never inches; Esc is multi-stage (pop last pick, then the previous, then close).++---++## 8. Foundations: color++The finishing tokens. They make an app on-brand once the interaction is already right. Adom is a dark system, and color is used sparingly so the one teal accent always means "this is interactive or important."++![Adom design tokens at a glance](screenshots/tokens.png)++### Core theme tokens++| Token | Value | Use |+|---|---|---|+| `--bg` | `#0d1117` | Page, deepest background |+| `--surface` | `#161b22` | Panels, toolbars, cards |+| `--elevated` | `#1c2128` | Elevated cards, hover surfaces |+| `--overlay` | `#21262d` | Tooltips, dropdowns, modals |+| `--border` | `#30363d` | Standard border |+| `--text` | `#e6edf3` | Primary text |+| `--text-2` | `#8b949e` | Secondary text, labels |+| `--text-3` | `#484f58` | Disabled, placeholders |+| `--accent` | `#00b8b0` | Primary accent, the Adom teal |+| `--accent-bright` | `#00e6dc` | Hover and focus highlights | -- **Live hover preview, not click-only.** Show the geometry you would snap to before the click commits it.-- Smart-pick priority is edge, then face, then vertex.-- The committed marker matches the previewed geometry. An edge preview commits to an edge tube, not a generic sphere.-- The dimension line is a distinct color from the snap markers: markers teal `#00B8B1`, dimension line blue `#64ABFF`.-- Show millimeters as the primary unit with mils as a secondary, never inches.-- Esc is multi-stage: pop the last pick, then the previous, then close the HUD. Never a single-stage close-everything.+### Status and grouping++| Token | Value | Use |+|---|---|---|+| `--purple` | `#8c6bf7` | Group labels, secondary accent |+| `--blue` | `#58a6ff` | Links, informational accents |+| `--green` | `#3fb950` | Success only |+| `--red` | `#f85149` | Destructive only |+| `--yellow` | `#d29922` | Warning only |++- Never use **pure black** (`#000`) or **pure white** (`#fff`) for a large surface.+- Hover transitions are smooth, not snappy: `0.15s ease`.+- Signature gradient, teal to blue to purple: `linear-gradient(100deg, #00e6dc, #39b8ff 60%, #8c6bf7)`. Headline accents and flagship art, not body UI.  --- -## 9. Hero images+## 9. Foundations: type, spacing, and icons -A hero is the 16:10 billboard at the top of a wiki page. It is reused unchanged on the page header, the landing card, the installer, the homepage, and the screensaver, so it has to read in about one second.+| Face | Weights | Job |+|---|---|---|+| **Familjen Grotesk** | 500, 600, 700 | Headlines, app name, section headers, identity |+| **Satoshi** | 400, 500, 700 | Body copy, descriptions, paragraphs |+| **JetBrains Mono** | 400, 500 | Source code, inline code, numeric and data rows | -- **One app, one screenshot.** No collages. A single great shot of the real UI beats any montage.-- **Dark, on-brand background.** No white box around a logo. The only allowed texture is a faint dot grid or arc pattern, kept subtle.-- **Headline is the app name or a punchy value phrase,** with the signature gradient on one key word, plus a one-line value prop with a couple of words bolded white for scanning.-- **The product sits in a floating window** with a drop shadow, bleeding off the bottom. The window chrome is **Windows-style: minimize, maximize, and close at the top right.** Never macOS traffic-light dots.-- **Margins are sacred.** Keep every element at least 80px from the canvas edge and give text and the product window real separation. The most common failure is the window touching the copy.-- **The call to action is an AI prompt,** for example `"flash my board as a USB keyboard"`, not a shell install command. The install section of the page can show the CLI, the hero sells the outcome.-- Use the real app UI with realistic example data. A placeholder or a striped no-image panel is a failure, not a fallback.+- **Monospace is only for code and data.** A version number or a pad count is data, so it is mono. A button label is not.+- **Never ALL CAPS body text.** Small uppercase is fine for tiny eyebrow labels and chips, never for sentences.+- Do not fall back to Inter, Arial, Helvetica, or the system stack as the primary face. Load the brand fonts from `https://adom.inc/fonts/`.+- **Spacing grid:** 8px, 12px, 16px. **Radius:** `8px` for buttons and cards, `12px` for larger containers, `999px` for pills.+- **Icons are monochrome white. No exceptions.** `#e6edf3` or `currentColor`, in-app icons, the tab-strip icon, and the favicon. Prefer a clean custom SVG (`viewBox="0 0 24 24"`, stroke 1.5 to 2px). No emoji as icons. The only place brand color is allowed is marketing art: the hero and the page thumbnail.+  - Pre-publish icon audit, both must return zero hits:+    ```bash+    grep -nE 'fill="(#00b8b0|#00d4cb)"|stroke="(#00b8b0|#00d4cb)"' docs/icon.svg src/**/*.html src/**/*.svg+    grep -nE '\.logo[^{]*\{[^}]*color:\s*var\(--accent\)|\.icon[^{]*\{[^}]*color:\s*var\(--accent\)' src/**/*.html src/**/*.css+    ```++---++## 10. Hero images++A hero is the 16:10 billboard at the top of a wiki page, reused on the page header, the landing card, the installer, the homepage, and the screensaver. It has to read in about one second and sell the **outcome**, not the brand.++- **One app, one screenshot.** No collages.+- **Lead with the value, not the logo.** The headline is the outcome a person gets, with the signature gradient on one key word, plus a one-line value prop with a couple of words bolded white.+- **Show a real, friendly app moment** with realistic data, ideally one that demonstrates the experience: a clear action, a helpful tooltip, a success toast.+- **The product sits in a floating window** with a drop shadow, bleeding off the bottom, with **Windows-style chrome** (minimize, maximize, close at the top right), never macOS dots.+- **Margins are sacred:** every element at least 80px from the edge, real separation between text and window.+- **The call to action is an AI prompt,** for example `"make my app a joy to use"`, not a shell command. -The `adom-wiki-hero` skill renders all of this from a template.+The `adom-wiki-hero` skill renders this from a template.  --- -## 10. Copy and voice+## 11. Copy and voice -The words are part of the design.+The words are part of the experience. -- **No em-dashes or en-dashes** in any shipped copy. Use commas, colons, periods, parentheses, or "to" for ranges. Dashes read as machine-written and undercut credibility.+- **Write for the person, plainly.** Say what a thing does and what will happen, in their language.+- **No em-dashes or en-dashes** in shipped copy. Use commas, colons, periods, parentheses, or "to" for ranges. - **No gimmick emoji** in product UI text.-- **Name products by their short name,** never with the tagline baked in. The tagline belongs in a subtitle or a page brief.-- **Lead with Adom's own value:** fast turns, low cost, drone delivery, the Fort Worth facility. Keep the copy professional, for engineers and serious makers, rather than hobbyist.-- Provenance over magic. A diagnostic or computed view shows where its data came from and never silently auto-corrects.+- **Name products by their short name,** never with the tagline baked in.+- **Lead with the value** the user gets. Tone is professional, for engineers and serious makers.+- Provenance over magic: a computed view shows where its data came from and never silently auto-corrects.  --- -## 11. The enforcement gate+## 12. The enforcement gate -Reading this page is step one. Proving an app follows it is `adom-ui-linter`, which encodes most of these rules as roughly 50 deterministic checks across six categories.+Reading this page is step one. Proving an app follows it is `adom-ui-linter`, which encodes most of these rules as roughly 50 deterministic checks.  | Category | Checks | |---|---|+| ui-patterns | tooltips body-appended and not `::after`, feedback on actions, toast hook, toggle state, color tokens, no all-caps |+| ai-drivability | `GET /state`, `GET /console`, live channel, front-end driving commands, relay User-Agent gate, CLI hints | | header | 44px height, brand and subject zones, fonts, popover, favicon |-| ui-patterns | tooltips body-appended and not `::after`, color tokens, toggle state, no all-caps |-| ai-drivability | `GET /state`, `GET /console`, relay User-Agent gate, CLI hints | | cli-compliance | `OK:`/`ERROR:` prefix, `Hint:` lines, health and install subcommands, isatty gating | | skills-docs | skill frontmatter and triggers, README with inline screenshots | | build-publish | version files in sync, release profile, port registration |  ```bash-adom-ui-linter lint . --category header,ui-patterns,ai-drivability+adom-ui-linter lint . --category ui-patterns,ai-drivability,header ``` -Fix every FAIL (the hint tells you exactly what to do), address relevant WARNs, and re-run to zero before publishing.+Fix every FAIL (the hint tells you exactly what to do), address relevant WARNs, re-run to zero before publishing.  --- -## 12. The skill map+## 13. The skill map  This system is split across focused skills. The AI loads them by trigger word. Use this as the index of where each rule lives.  | Skill | Governs | |---|---|-| `brand` | Colors, typography, logo, icon law, the dark theme tokens |-| `human-ui-patterns` | Tooltips, HUDs, toggles, text rules, feedback, AI-drivability primitives |+| `human-ui-patterns` | Tooltips, HUDs, toggles, feedback, the user-first interaction primitives |+| `app-creator` | Building a webview app: two-way comms, the live channel, proxy URL, favicon, publish flow | | `adom-app-header` | The 44px three-zone header and the app-info popover | | `adom-app-model` | How an Adom app is structured, distributed, and versioned |-| `app-creator` | Building a webview app: favicon, proxy URL, two-way comms, publish flow |-| `pup-vs-webview` | Choosing a desktop browser window versus a Hydrogen webview tab |-| `carbon-preferences` | Per-user settings that persist across sessions |-| `adom-panels` | The panel catalog and per-panel control APIs |-| `adom-workspace-control` | Adding, splitting, moving, and resizing workspace panes safely |-| `adom-layouts` | The workcell layout JSON grammar |-| `3d-viewer-design` | Every rule for Adom 3D viewports |-| `measure-tool-design` | Fusion-grade measurement inside a Babylon viewer |-| `screen-capture-wake-lock` | Releasing the display lock after a screen capture |-| `adom-cli-design` | The `OK:`/`ERROR:`/`Hint:` CLI contract |+| `adom-screenshot` | Ralph loops and the visual feedback loop for debugging UI |+| `pup-vs-webview` / `adom-desktop-pup` | Choosing and driving pup, webview, or the native browser |+| `adom-browser-extension` | Driving the user's real Chrome or Edge (auth-cookie, auto-login) |+| `adom-cli-design` | The `OK:`/`ERROR:`/`Hint:` CLI contract, in Rust | | `ai-hints-in-clis` | Writing hints that actually steer the AI | | `relay-hint-pattern` | Teaching a relay server to redirect callers to the CLI |-| `adom-ui-linter` | The deterministic check suite that enforces this page |-| `readme-creator` | READMEs with inline screenshots for visual tools |-| `adom-screenshot` | Capturing and logging screenshots for visual feedback loops |+| `3d-viewer-design` / `measure-tool-design` | Every rule for Adom 3D viewports and measurement |+| `adom-panels` / `adom-workspace-control` | The panel catalog and safe workspace layout control |+| `carbon-preferences` | Per-user settings that persist across sessions |+| `brand` | Colors, typography, logo, the icon law, the dark theme tokens | | `adom-wiki-hero` | Rendering a billboard-grade hero image |+| `adom-ui-linter` | The deterministic check suite that enforces this page |  --- @@ -331,20 +355,21 @@ This system is split across focused skills. The AI loads them by trigger word. U You drive all of this by asking. Useful prompts:  **Build**-- "build me an on-brand Adom webview app for X"-- "add a standard Adom 44px header to this app"-- "make this CLI follow the Adom OK/ERROR/Hint contract"--**Design**-- "what are the Adom color tokens"-- "give me the Adom 3D viewer defaults"-- "make a hero image for my app"--**Check**+- "build me an Adom webview app for X that is a joy to use"+- "make this app fully drivable from the CLI over a live channel"+- "make this app work well on a phone, not just desktop"++**Test and drive**+- "show me the app in my native browser so it is already logged in"+- "open it in pup and test the logged-out experience"+- "ralph-test this app: click every button and show me where the UI breaks"+- "auto-click send-to-kicad and toast me when the file is downloaded"++**Improve**+- "make my app a joy to use"+- "add instant feedback and toasts to every action" - "lint my app against the Adom UI rules"-- "audit my icons for brand-color leaks"-- "is this app AI-drivable"  --- -*Adom UI Design System. Dark, teal, monochrome-iconed, API-driven. Build it once, build it right.*+*Adom UI Design System. The AI builds it, drives it, and perfects it, around a user who is the center of everything.*
package.json+2−2
@@ -1,8 +1,8 @@ {   "slug": "adom-ui-design",-  "version": "1.0.0",+  "version": "1.1.0",   "type": "skill",-  "description": "The Adom UI Design System: color tokens, typography, the 44px app header, AI-drivability, Babylon 3D viewers, hero rules, and the linter that enforces them.",+  "description": "How the AI builds and tests interfaces people love to use in Adom: user-first interaction, the build-show-drive-ralph loop across native browser / pup / webview, a live SSE/WebSocket channel, toasts as the AI's narration, responsive UI, and the polish tokens last.",   "dependencies": {},   "files": [     "SKILL.md",
page.json+16−59
@@ -1,66 +1,23 @@ {+  "type": "doc",   "slug": "adom-ui-design",-  "version": "1.0.0",-  "type": "skill",-  "description": "The Adom UI Design System: color tokens, typography, the 44px app header, AI-drivability, Babylon 3D viewers, hero rules, and the linter that enforces them.",-  "dependencies": {},-  "files": [-    "SKILL.md",-    "README.md",-    "page.json",-    "install.sh",-    "uninstall.sh",-    "screenshots/hero.png",-    "screenshots/tokens.png"-  ],-  "scripts": {-    "install": "./install.sh",-    "uninstall": "./uninstall.sh"-  },-  "tags": [-    "design-system",-    "brand",-    "ui",-    "ux",-    "guidelines",-    "tokens"-  ],-  "author": {-    "name": "John Lauer",-    "email": "[email protected]"-  },+  "title": "Adom UI Design System",+  "brief": "How the AI builds and tests interfaces people love to use in Adom: user-first interaction, the build-show-drive-ralph loop across native browser / pup / webview, a live SSE/WebSocket channel, toasts as the AI's narration, responsive UI, and the polish tokens last.",   "hero": {     "type": "image",     "path": "screenshots/hero.png"   },-  "discovery_triggers": [-    "ui design",-    "design system",-    "adom design",-    "brand colors",-    "color tokens",-    "theme tokens",-    "dark theme",-    "app header",-    "tooltip",-    "on-brand",-    "make it on-brand",-    "ai-drivable",-    "cli design",-    "3d viewer design",-    "hero image",-    "ui linter",-    "design audit"-  ],-  "discovery_pitch": "The Adom UI Design System: exact color tokens, the three brand fonts, the 44px app header, AI-drivability, Babylon 3D viewer rules, hero rules, and the linter that enforces them. Read before building any Adom UI.",-  "sample_prompts": [-    "what are the Adom color tokens",-    "build me an on-brand Adom webview app",-    "add a standard Adom 44px header to this app",-    "lint my app against the Adom UI rules",-    "give me the Adom 3D viewer defaults"-  ],-  "updated_at": "2026-06-20T15:25:12.057Z",-  "title": "Adom UI Design System",-  "brief": "The single source of truth for how every Adom surface looks and behaves: color tokens, typography, the app header, panels, 3D viewers, hero images, AI-drivability, and the linter that enforces them."+  "visibility": {+    "public": true+  },+  "metadata": {+    "tags": [+      "design-system",+      "brand",+      "ui",+      "ux",+      "guidelines",+      "tokens"+    ]+  } }\ No newline at end of file
screenshots/hero.png
⋯ 1 unchanged line ⋯