Design Overview
What a console app looks like, and the rules that make host and apps read as one product.
The Riftix Console is one product assembled from many. The host draws a 40px navbar; everything below it is an app, served from its own origin, built by its own team, on its own stack. A user crossing from the console's own settings page into an embedded app should not be able to tell where the seam is.
These pages are the contract that makes that true. They are prescriptive: each rule states what to do and why, so you can conform without reading anyone else's source.
Framework-agnostic by construction
The bridge is framework-neutral — a vanilla snippet, web components, and optional React hooks. The design system is too.
Every rule here is expressed as design tokens, markup and CSS, because that is what actually crosses a framework boundary. Where framework code appears it is labelled as an illustration of a rule, never the rule itself.
The reference implementations happen to use TanStack Router, TanStack Query, shadcn/ui and Base UI. None of that is required. An app built on Vue, Svelte, HTMX or plain DOM is conformant if it satisfies the rules below. What you must share is the token file, the type scale, the spacing rhythm, and the host integration contract.
The ten non-negotiables
| # | Rule | Where |
|---|---|---|
| 1 | Use the shared token set. Never hardcode a hex or a raw palette color. | Foundations |
| 2 | --radius: 0. The product is square. | Foundations |
| 3 | text-xs is the body size; the page title is text-xl. That is the scale. | Foundations |
| 4 | Borders are a 1px ring at 10% foreground, not a border plus a shadow. | Foundations |
| 5 | The app owns its scroll container. The document never scrolls. | Layout |
| 6 | Theme comes from the host. An app never ships a theme toggle. | Embedded apps |
| 7 | Breadcrumbs are pushed to the host, not rendered as a second trail. | Embedded apps |
| 8 | Toasts and destructive confirmations go through the bridge. | Embedded apps |
| 9 | Every page is a real URL, reported to the host. | Embedded apps |
| 10 | Loading is a layout-matched skeleton, never a centered spinner. | Components |
The shape of the product
The host owns a fixed 40px navbar and nothing else. Its three columns are the app launcher, the breadcrumb trail, and the org switcher plus theme toggle.
┌──────────────────────────────────────────────────────────────┐
│ ⊞ launcher │ Billing › Invoices › #1234 │ Acme ▾ ☾ │ h-10, host
├──────────────────────────────────────────────────────────────┤
│ ┌────────────┬───────────────────────────────────────────┐ │
│ │ │ ▣ │ Invoices › #1234 │ │ h-10, app
│ │ sidebar ├───────────────────────────────────────────┤ │
│ │ (app) │ │ │
│ │ 16rem │ scroll container (app) │ │ iframe
│ │ │ │ │
│ └────────────┴───────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘Two facts about that picture drive most of the layout rules:
- The host is a fixed-height grid whose content row is
overflow: hidden. The iframe fills it exactly. There is no page scroll to inherit — see the scroll contract. - The host navbar already shows the trail. An app that also renders breadcrumbs shows the user the same thing twice.
Reading this as a machine
Every page here is also served as Markdown, so a coding agent can pull the current rules instead of relying on a copy that drifted.
| Endpoint | What it returns |
|---|---|
/llms.txt | Index — every page, its description, and its Markdown URL |
/llms-full.txt | Every page concatenated, in sidebar order |
/md/<slug>.md | One page, e.g. /md/design/foundations.md |
Do not vendor these pages into an app repo. Point at the URLs. The
guidelines change more often than the tokens do, and a copy is a copy that will
be wrong. Each app's CONTEXT.md carries only the ten non-negotiables plus
these links.
Reference implementations
| App | Role | Read it for |
|---|---|---|
riftix/console → apps/console | The host | Token source of truth, navbar, theme broadcast, host page shell |
filavirtual/apps/admin | An embedded app | Page primitives, the console component kit, bridge integration |
Both are TanStack Start on Cloudflare Workers, which is why their code looks alike. Read them for the decisions, not the stack.
Known gaps in the reference implementations
The reference apps are the best example we have, not a finished one. These are places where the rule above supersedes what the code currently does — don't copy these.
| Gap | The rule that supersedes it |
|---|---|
Only two animations are guarded by motion-safe:; skeletons, spinners, sheets and toasts are unguarded. | Ship a prefers-reduced-motion base rule. See Motion. |
| Wide tables only scroll horizontally, and the scroll region is not keyboard-reachable. | Give the scroll container a tab stop and an accessible name; stack past four columns. See Tables. |
Page padding is a flat p-6 at every viewport — 24px gutters on a 360px screen. | Ramp it: p-4 md:p-6. |
filavirtual/apps/admin renders a breadcrumb trail in its own top bar and pushes it to the host, so it appears twice. | Render local crumbs only when no host is connected. See Breadcrumbs. |
The sidebar writes a sidebar_state cookie that nothing reads back, so it always starts expanded. | Either read it during SSR or drop the write. |
--ease-out-strong is declared but unused, while the toast hardcodes a different curve. | One easing token, used. See Motion. |
<html lang> is hardcoded to a language the UI is not written in. | Set it from the host locale; pick a neutral default for first paint. |
| Tokens are vendored by hand with a "keep in sync" comment. | Tracked: publish the token file as a package. Until then, the sync rule in Foundations applies. |
The console's own pages use space-y-6, a text-2xl title and p-8/max-w-4xl, all predating these rules. | Follow Spacing rhythm, The scale and the host page shell. |