# RealBrain Design System — instructions for coding agents Copy this file into a RealBrain repository as `AGENTS.md` (or append it to `CLAUDE.md`). It tells an agent how to apply the design system without being reminded each time. Adjust the one path in "Source of truth" to wherever the repository vendors `tokens.css`. ## Source of truth - In this repository: `src/tokens.css` — a vendored copy of https://realbrain.cc/design-system/tokens.css. Never edit it by hand; refresh it with `curl -o src/tokens.css https://realbrain.cc/design-system/tokens.css`. - Full guide: https://realbrain.cc/design-system/design-system.md - Short reference for agents: https://realbrain.cc/design-system/llms.txt - Tokens as JSON (DTCG): https://realbrain.cc/design-system/tokens.json Read the guide's §2 (non-negotiables) and §6 (components) before writing or editing any CSS, component, or UI copy. ## Rules 1. **Tokens only.** Every colour, size, radius, shadow, duration, and easing in component code is a `var(--token)` from `tokens.css`. No raw hex, no raw px, no `rgba()`. 2. **One accent per screen.** Exactly one `.btn-primary` (or one accent-coloured action). Everything else is `.btn-secondary`, `.btn-ghost`, or neutral text. 3. **Weight ≤ 600.** Never `font-weight: 700` or `bold`. The font import does not even load 700. 4. **Flat.** No `linear-gradient`, `radial-gradient`, `backdrop-filter`, `text-shadow`, glow, or decorative `box-shadow`. `--shadow-*` is only for surfaces that are actually elevated (menus, modals, toasts). 5. **Never white on accent.** Text and icons on `--accent` use `--accent-fg`. 6. **Semantic colour is never the only signal.** Use `.status.ok|warn|err|info` (dot plus text) or an icon plus text. 7. **Copy:** sentence case everywhere. Buttons are verbs ("Sign in", "Create project"). "Sign in", never "Log in" or "Login". Errors say what happened and what to do next. 8. **One density per product.** `.density-comfortable` (default, 44px controls) or `.density-compact` (32px) on a container. Never both. 9. **Use the existing component classes** (`.btn`, `.field`, `.input`, `.select`, `.checkbox`, `.radio`, `.toggle`, `.card`, `dialog.modal`, `.toast`, `.tabs`, `.table`, `.status`, `.scaffold`, `.empty`, `.skeleton`). Do not re-style them locally. Do not build a div-based fake of a native control. 10. **Motion goes through `--dur-1/2/3` and `--ease`.** Nothing else. Reduced motion is handled globally by `tokens.css`. ## When the system doesn't have what you need Do not invent a value. Build the piece from existing tokens if you can. If you genuinely need a new token or component, ship the work with a clearly marked proposal in your final message: ``` ⚑ NEW TOKEN --{category}-{name}: {value} why nothing existing fits: … ``` Do the same for drift you notice in existing code (`⚑ DRIFT file:line #3b82f6 → --accent`) rather than silently patching it. ## Self-check before you finish Run these from the repository root (adjust `src` and the excluded path). Every command should print nothing: ```sh # raw colours or px outside the token file grep -rnE --include=*.css --include=*.vue --include=*.jsx --include=*.tsx --include=*.svelte \ --exclude=tokens.css '#[0-9a-fA-F]{3,8}\b|rgba?\(|\b[0-9]+px\b' src # forbidden weight and effects grep -rnE --include=*.css --include=*.vue --include=*.jsx --include=*.tsx --include=*.svelte \ --exclude=tokens.css 'font-weight:\s*(700|800|900|bold)|linear-gradient|radial-gradient|backdrop-filter|text-shadow' src # copy rules grep -rniE --exclude-dir=node_modules 'log ?in|Sign In\b|Log In\b' src ``` Then check by eye: one `.btn-primary` per screen, focus rings visible when tabbing, and every status or badge has text next to its colour. ## Quick reference ``` --bg #080808 light: #F7F7F9 --surface #121216 light: #FFFFFF --elevated #1A1A20 light: #FFFFFF --text-1 #F4F4F6 light: #16161C --text-2 #A9A9B4 light: #4C4C58 --text-3 #83838F light: #6E6E7A --accent #8FA8FF light: #3450C8 --accent-fg #080808 light: #FFFFFF --accent-hover #9EB5FF light: #4C6BD2 --accent-pressed #6173B1 light: #21358A --success #3ECF8E light: #177A4E --warning #E8B23D light: #8A5A00 --error #F26D6D light: #C2373C --info #62B0F5 light: #1D62A8 --border #26262E light: #E3E3E9 --border-strong #3A3A46 light: #C6C6D0 --font-ui 'IBM Plex Sans', system-ui, sans-serif --font-mono 'IBM Plex Mono', ui-monospace, monospace type steps display:60/64 8:40/48 7:30/38 6:24/32 5:20/28 4:17/26 3:15/24 2:13/20 1:12/16 weights 400 · 500 · 600 (never 700) space 4px 8px 12px 16px 24px 32px 48px 64px 96px radius sm 6px · md 10px · lg 16px · full 999px motion 120ms · 200ms · 360ms · ease cubic-bezier(.22,.61,.36,1) layout marketing 1200px · app 1440px · control-h 44px (compact 32px) ``` Light theme: `document.documentElement.setAttribute('data-theme', 'light')`. Dark: remove the attribute. --- ## Untrace specifics ### Batch workflows (1.6.0, 2026-09-10) `BatchWorkspace.svelte` owns the sequential queue. `processing.js` creates a terminable worker per scan/encode task. `image-worker.js` uses the shared scanner and cleaner with OffscreenCanvas. Keep incomplete scans visibly uncertain. `desktop/preload.cjs` exposes only folder selection and saving; `desktop/output.cjs` validates the sender and creates unique files exclusively in the user-selected directory. Never expose generic IPC or unrestricted filesystem access. Saved export settings use `untrace-export`; theme settings keep their existing key. ### Themes and branding (1.3.0, 2026-09-10) The derivative is named **Untrace Desktop**, as requested by the user. Branding lives in `desktop/brand.json`; build metadata in `package.json` must match it. Keep upstream Untrace attribution and the MIT license. The user explicitly requested more themes. `src/themes.css` is the local palette source: it overrides existing semantic colour tokens for dark, graphite, paper, cobalt and ember without editing vendored `src/tokens.css`. Palette definitions may contain raw colours; components must continue using tokens. Exclude both palette files (`tokens.css`, `themes.css`) from the raw-colour self-check. No new token names are introduced. The theme catalog and shared pre-paint bootstrap are in `src/lib/theme-catalog.js`. Appearance is a native dialog with radio controls. ### Desktop workspace (1.2.0, 2026-09-10) The active application is `src/lib/Workspace.svelte`, mounted by `src/App.svelte`. It uses a full-window preview and inspector, not the historical landing page or stepper. Older website components remain as upstream reference and are not imported. The active stylesheet is `src/app.css`; it composes the existing tokens and keeps comfortable density. There is one primary action: choose an image, clean it, or save its result. Help is a native dialog. Keep the image processing limitations accurate when editing copy. `npm test` verifies the workspace in Electron and `npm run portable` creates the Windows release. Earlier specifics below describe the upstream baseline. Applied to this repository on 2026-09-05, design system v2.0.0. - `src/tokens.css` is the vendored copy. `src/app.css` imports it and adds only app-level composition (layout, dropzone, stepper, disclosure, tiles, the mobile action bar). No component from `tokens.css` is restyled locally. - Density is **comfortable** throughout — this is a consumer surface. - Dark is the default. `src/lib/theme.js` reads a saved choice first and falls back to the operating system, and `index.html` applies the result before first paint so the page never flashes the wrong surface. - One `.btn-primary` per step of the tool: the dropzone step has none, review has "Clean image", download has "Download clean image". - There is no Tailwind and no PostCSS. The design system is plain CSS and the app needs nothing on top of it. ### Open token proposals ``` NEW TOKEN --border-w: 1px why nothing existing fits: every surface in the system draws a 1px hairline, but the width itself is only ever written literally inside tokens.css. Defined locally in src/app.css until the system adopts it. NEW TOKEN --topbar-h: 56px why nothing existing fits: no layout token covers a sticky product bar. Derived locally as calc(var(--space-7) + var(--space-2)). NEW TOKEN breakpoints — 560px / 768px / 900px why nothing existing fits: the system documents container maximums (--max-marketing, --max-app) but no breakpoint scale. Custom properties cannot be used in a media query, so a literal is unavoidable; this app pins itself to exactly these three widths. ``` `src/lib/clean.js` contains one literal hex, `JPEG_MATTE = "#FFFFFF"`. That is image data written to a canvas, not interface styling, so it is intentionally not a token. ### Windows distribution (1.7.0, 2026-10-25) `npm run release:windows` builds separate x64/x86 installer and portable packages. `scripts/build-windows.mjs` pins Electron 44.3.0 for x64 and 43.8.3 for x86 because 44 removed ia32 binaries. Electron 43 support ends in January 2027; do not silently remove that support limitation from the docs. Installed settings use `%APPDATA%\Untrace Desktop`; portable launcher settings remain in the existing adjacent `Untrace-data` folder. `desktop/data-path.cjs` centralizes this distinction. Preserve settings on uninstall. Run installer checks sequentially and separately from app tests, because the installer closes other processes with the application executable name. Both remotes default to `main`. See `docs/UPSTREAM-REVIEW.md` before importing upstream website changes. Regenerate real-workspace screenshots with `npm run screenshots` using only the generated sample artwork.