| name | Open WebUI (Canva Fork) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| description | An internal AI workspace where agents, not models, are the primary noun. Dark by default, themed with the Tokyo Night family. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultTheme | tokyo-night | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| themePresets |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colors |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| typography |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rounded |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| spacing |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| components |
|
Creative North Star: "The Lit Workshop"
This is a craftsman's bench at night. The surface is where a Canva employee sits down with their named agents — picks one up, uses it, puts it back — alongside their tools, history, and context. The room is dim and the work is what is lit. Distinct surfaces (top bar, sidebar, message pane, code block) sit at distinct ramp steps within the chosen palette so the eye reads "rooms" rather than a single flat plane. Density and calm coexist because the colour does the spatial work that uniform padding and walls of cards used to do.
The aesthetic philosophy is deep dark base, ramped panel surfaces, saturated accents on a budget. The default palette is Tokyo Night (source) — a navy/indigo dark base with cyan, magenta, green, orange, and a soft red accent set, all muted by the OKLCH lightness of the base so they read as informed rather than neon. Four presets ship in M1: Tokyo Day (the only light variant; OS-mapped when prefers-color-scheme: light), Tokyo Storm (slate-blue dark), Tokyo Moon (warmer dark), Tokyo Night (deepest dark, OS-default for prefers-color-scheme: dark).
Colour does three jobs in this system, and only these three:
- Information — status (success / warning / danger / info),
@-mentions, live-stream dot, focus ring. - Atmosphere — which room you are in. The sidebar, the top bar, and the message pane each get a distinct ramp step from the same palette; modals and popovers lift to a fourth step.
- Personalisation — which preset you chose. The four presets are functionally interchangeable (every component renders against the same role-based tokens) but tonally distinct.
This system explicitly rejects ChatGPT's centered-prompt void, model-forward chrome (long slug IDs used as labels), SaaS hero-metric dashboards, crypto-neon (saturated and gradient and glow — we are saturated only), consumer-social warmth (Discord purple, confetti, sparkle emoji), Notion's "everything is a document" flatness when it fights app density, and pure-greyscale "minimalism" (which reads as draft, not restraint). Where other AI surfaces perform excitement, this one performs competence — but it dresses for the work.
Key Characteristics:
- Tokyo Night palette family as the canonical reference; four shipping presets (Day / Storm / Moon / Night).
- Distinct ramp step per surface (top bar, sidebar, message pane, elevated) within every preset.
- Dark-by-default;
prefers-color-schemehonoured for the page-load default; user's explicit theme always wins. - Saturated accents on a budget — five named accent tokens (
selection,mention,headline,stream, plus the fourstatus-*semantic hues). No second-tier decorative colour. - Hybrid elevation: flat at rest, blurred-and-lifted for modals and popovers; shadow strength is low because the depth comes from the ramp-step contrast.
- Inter as the working face; Archivo for chrome headlines; JetBrainsMono for code; InstrumentSerif held in reserve.
- Radius language runs from 4px utility up to 32px for modal envelopes — large radii signal "floating," tight radii signal "embedded."
- Motion is under 200ms, functional, eased out. No bounce, no choreography. Theme switches are instant — no fade — so the user reads the palette change as deliberate.
The four presets are the only theme choices the user sees. Each preset is a complete, self-contained set of values for every token in the colors: block above. Components never reach for a preset name; they reach for a role token (background-sidebar, accent-selection, etc.) and the active preset binds the token.
| Preset | Mode | OS-mapped when | Mood | Typical user |
|---|---|---|---|---|
| Tokyo Day | light | prefers-color-scheme: light |
Crisp paper with restrained ink and saturated accents. The only light variant. | Outdoor café day, projector demo. |
| Tokyo Storm | dark | — (explicit choice) | Slate-blue dark; less saturated than Night, more contrast than Moon. | Office monitor in mixed lighting. |
| Tokyo Moon | dark | — (explicit choice) | Warmer dark with a softer ramp; the calmest of the four. | Long focus sessions. |
| Tokyo Night | dark | prefers-color-scheme: dark |
Deepest dark with the most saturated accents. The default for the dark OS preference. | Late-night work; the brand-canonical look. |
Resolution order (canonical, locked by rebuild/docs/plans/m1-theming.md):
- If the user has explicitly chosen a theme this device, use it.
- Otherwise, read
prefers-color-scheme:light→tokyo-day,dark→tokyo-night. - Otherwise (UA does not report a preference), use
tokyo-night.
The choice is persisted client-side per device (a cookie for SSR-correct first paint, mirrored to localStorage as the client source of truth). It is never persisted to the server database. A user switching devices intentionally re-picks. See rebuild/docs/plans/m1-theming.md § Persistence.
Every token below exists in every preset. Components ALWAYS reference the role token, never the literal value.
| Token | Job |
|---|---|
background-app |
The message pane — the surface where the user is working. |
background-sidebar |
The conversation/channel/automation sidebar. One ramp step deeper than background-app so the eye reads a panel. |
background-topbar |
The top bar / page header. One ramp step lighter than background-app so the chrome reads as "elevated above" the work. |
background-elevated |
Modals, popovers, the message-input lift, dropdown menus. The "floating" surface. |
background-code |
Code blocks inside chat messages. Deepest of the surface ramp so the code reads as embedded. |
background-mention |
The fill behind @-mention pills. Sits at the same lightness as background-elevated but tinted toward the accent-mention hue. |
| Token | Job |
|---|---|
hairline |
1px borders, dividers, message bubbles, code-block edges. Low contrast against the parent surface. |
hairline-strong |
Modal edge, focused input border, hover'd hairline. One step up from hairline. |
ink-placeholder |
Input placeholder, disabled body text. |
ink-muted |
Timestamps, metadata, "shared by" sublines. |
ink-secondary |
Sidebar items at rest, secondary body, supporting UI. |
ink-body |
Default body text. The reading surface. |
ink-strong |
Emphasis, modal titles, button-secondary text, sidebar-item active text. |
| Token | Job | Allowed surfaces |
|---|---|---|
accent-selection |
Primary CTA fill, focus ring, selected-row left-edge cap, range selection. | Buttons, focus rings. Never: chrome decoration. |
accent-mention |
@-mention pill text, in-prose links, click-targets in markdown. |
@-mention pills, hyperlinks. Never: button fills. |
accent-headline |
Markdown #/##/### headings inside chat messages. |
Markdown content only. Never: chrome titles, navigation labels. |
accent-stream |
Live-stream dot, "agent is typing" pulse, the "streaming" SSE animation. | Realtime indicators only. |
| Token | Job |
|---|---|
status-success |
Success badge, positive telemetry, completed automation run. |
status-warning |
Warning badge, rate-limit nudge, "you have unsaved changes." |
status-danger |
Error badge, destructive-action confirm, failed automation run. |
status-info |
Info badge, "did you know" tip. |
Status hues appear at 20% opacity fill with the same hue at full saturation for the text (e.g. bg-{status-success}/20 text-{status-success}). They are informational, never decorative, and never adjacent to each other.
The Role-Token Rule. Components reference background-app, accent-selection, ink-body. They never reference a Tokyo Night hex value, never reference a preset name. This is what makes the four presets interchangeable.
The One-Surface-Per-Room Rule. Top bar, sidebar, message pane, elevated, code each get one ramp step. New surfaces map to one of the existing five — they don't introduce a sixth ramp step.
The Accent-Budget Rule. Four accent tokens (selection, mention, headline, stream) plus four semantic status hues. That's the entire decorative palette. New "decorative" colour requirements get rejected; the answer is weight, size, ink contrast, or one of the existing accents.
The Model-Name Exile Rule. Raw model identifiers (gpt-4o-2024-08-06, claude-3-5-sonnet-*) must never sit in primary chrome. If a model string is surfaced at all, it is secondary metadata under the agent's name, in ink-muted at label scale.
The No-Greyscale-Default Rule. Greyscale is not the canonical look. Every shipping preset has chroma in its base. Pull-requests that revert a coloured token to a zero-chroma neutral need a documented reason.
Display Font: Archivo (with Vazirmatn for RTL, sans-serif fallback)
Body Font: Inter (with Vazirmatn, ui-sans-serif, system-ui fallback chain)
Label/Mono Font: JetBrainsMono (with ui-monospace fallback)
Markdown-heading accent: accent-headline from the active preset (Tokyo Night → soft magenta #bb9af7)
Reserve accent: InstrumentSerif (rare; used only for named editorial moments, never in app chrome)
Character: Archivo carries chrome headlines with a humanist-geometric snap that reads more "tool" than "app." Inter does the heavy lifting for body and UI — neutral, tight, legible at 13–14px. Vazirmatn is specified on both so RTL surfaces don't fall back to a mismatched system font.
- Display (Archivo 600,
clamp(1.75rem, 2.5vw, 2.25rem), line-height 1.15,ink-strong): workspace landing headers, section titles on marketing-adjacent surfaces. Rare in the app shell. - Headline (Archivo 600, 1.25rem, line-height 1.25,
ink-strong): page-level titles inside the app — workspace headers, settings pages, modal titles above body. - Title (Inter 500, 1.125rem, line-height 1.3,
ink-strong): card and section titles. Modal title row uses this weight. - Body (Inter 400, 0.875rem / 14px, line-height 1.5,
ink-body): the dominant UI text size. Chat messages, list rows, form labels. Cap prose at 65–75ch where long-form content appears. - Label (Inter 500, 0.75rem / 12px, line-height 1.4, letter-spacing 0.02em,
ink-secondary): badge text (uppercase), metadata, hotkey hints, timestamps. - Code (JetBrainsMono 400, 0.85em inline / 0.85rem block, line-height 1.5,
ink-bodyonbackground-code): inline code spans and fenced code blocks. Syntax highlighting per § 8. - Markdown H1/H2 (
accent-headline, weights and sizes per the YAML front-matter): markdown heading levels inside chat messages. The colour is the differentiator; in Tokyo Night this is the soft magenta#bb9af7. H3+ falls back toink-strong.
The Serif-In-Reserve Rule. InstrumentSerif (.font-secondary) exists in the app and must stay rare. It is reserved for named editorial moments — never for generic emphasis, never for body, never for labels.
The RTL-First Rule. Every font stack includes Vazirmatn. New stacks must include it. RTL parity is a latent requirement of this surface.
The Scale-Text-Scale Rule. The app supports --app-text-scale on :root. Custom line-heights and min-heights declared in pixel units must multiply through this variable. Hard-coding pixel line-heights outside the scale system is forbidden.
The Markdown-Heading-Hue Rule. Chat messages render markdown # and ## in accent-headline. This is the only place an accent hue is used as text colour in body content (mentions and links use accent-mention, but those are inline atoms; headings are block-level). The value swaps with the preset.
This system is flat by default, blurred-and-lifted on demand. Application surfaces — sidebar, main pane, chat rows, settings — carry no shadow; depth is conveyed by the ramp-step contrast in the colour system. Floating layers earn their lift: modals, popovers, tooltips, and the primary message input use a specific vocabulary.
- Message Input Lift (
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.35), 0 4px 6px -4px rgb(0 0 0 / 0.35)in dark presets; halved alpha intokyo-day): the composing surface sits just above the chat with a gentle soft shadow. Signals "this is where you act." Shadow alpha is preset-aware so the dark presets get the deeper shadow they need to read above an already-dark base. - Modal Lift (Tailwind
shadow-3xlpaired withbackdrop-blur-smand a 1pxhairline-strongborder onbackground-elevated): the primary modal envelope. The blur is the actual depth cue; the shadow is supporting; the ramp-step jump frombackground-apptobackground-elevateddoes most of the work. - Popover Blur (
background-elevated/90+backdrop-blur-2xl): tooltip-adjacent popovers (drag previews, transient hint cards). Very rarely used for persistent surfaces.
The Flat-Until-Floating Rule. If a surface stays on the page flow, it is flat. Shadows exist only on elements that detach from the flow (dialogs, menus, the message input, drag previews). A card that sits in a grid does not get a shadow — it gets a ramp-step background instead.
The Ramp-Is-The-Depth Rule. Our primary depth cue is the colour-ramp step between adjacent surfaces (sidebar deeper than app, top bar lighter than app, modal lifted via background-elevated). Reach for the ramp before reaching for a shadow.
The Ghost-Border Rule. Modals carry a 1px border of hairline-strong. This hairline replaces what a larger shadow would otherwise do — it defines the edge against the blurred backdrop without shouting.
Components feel tactile and confident: crisp edges, decisive state changes, clear inversion on primary actions. Hover is visible. Selected state is unambiguous. Transitions are under 200ms.
- Shape: Pill radius for dialog actions (
rounded-3xl, 24px); rounded-rectangle for compact inline buttons (rounded-lg, 8px); full-round only for icon chips. - Primary:
accent-selectionbackground withbackground-apptext — the primary CTA carries the active preset's selection accent (cyan in Tokyo Night). The text colour reaches forbackground-app(not white) so the contrast plays nicely against the saturated accent in every preset. - Hover / Focus: Background shifts to
accent-selection-pressed(one step deeper in chroma + lightness). No scale, no shadow change, no glow. Transition 150ms ease-out on background only. - Secondary:
background-elevatedwithink-bodytext. Used for cancel, dismiss, and "less weighty" companions to a primary. - Tertiary / Ghost: transparent at rest,
background-elevatedon hover. Used inside dense rows where a filled button would be too loud.
- Style:
bg-{status}/20(20% opacity) with text at the full status hue (e.g.bg-status-success/20 text-status-success); uppercase;rounded-lg;text-xs(label scale);px-[5px]. Same shape across all four presets — the hue swaps via thestatus-*tokens. - State: Badges are not interactive. Use chip-style buttons (same shape, solid fill, hover-darken) when interactivity is needed.
- Corner Style:
rounded-xl(16px) for row-level containers;rounded-2xl(20px) for pane-level cards;rounded-3xl(24px) for large composing surfaces. - Background:
background-appfor the primary surface; subcontainers step tobackground-elevated. Sidebar usesbackground-sidebar; top bar usesbackground-topbar. The ramp does the spatial work — adjacent surfaces are always one ramp step apart. - Shadow Strategy: None by default. See § 5 Elevation.
- Border: Inherited from
@layer baseashairline(1px). Cards that need stronger separation usehairline-strong. Thick or coloured borders are forbidden — depth comes from the ramp. - Internal Padding:
px-[11px] py-[6px]for list rows,p-4for compact cards,px-[1.75rem] py-6for dialog interior.
- Style:
background-appbackground (so an input embedded in a card onbackground-elevatedreads as inset, not lifted).rounded-lgfor form fields,rounded-3xlfor the large composing surface. Border ishairlineat 1px. - Focus: Border steps to
accent-selection; no glow, no outer ring. Placeholder inink-placeholder. - Error / Disabled: Disabled inputs drop to 50% text opacity; error states use the
status-dangerring at 1.5px.
- Style:
background-sidebarpanel. Items are full-width rows withrounded-xlcorners,px-[11px] py-[6px]padding,ink-secondarytext at body scale. Selected row fills withbackground-elevatedand lifts text toink-strong; on hover (unselected) row fills withbackground-elevatedat 50% to telegraph the interaction without committing. - Typography: Body scale, weight 400. Active item does not bold — the background fill is the tell.
- Mobile treatment: Sidebar becomes a drawer; hit targets remain at the 32px min-height.
- Style:
background-topbar(one ramp step lighter thanbackground-app) withhairlinebottom border. 48px tall. Carries the agent name on the left, the model selector + share + settings on the right. - Typography: Title (Inter 500, 1.125rem) for the agent name; Body for the model metadata under it.
The composing surface is the single most distinctive element in the app. rounded-3xl with background-elevated, backdrop-blur-sm, a shadow-lg lift (alpha tuned per preset), and a hairline border that shifts from hairline/30 at rest to hairline on hover and accent-selection on focus-within. It sits above the chat without carving into it, and it answers to the agent — not a model dropdown. Model identifiers, when surfaced, appear as secondary metadata only.
An agent's avatar appears at size-[2.7rem] with a rounded-full crop and a 1px hairline ring. Overlapping avatar stacks use -space-x-4 to suggest a small roster. This chip is the primary identity marker for the agent-over-model hierarchy.
A small dropdown in Settings (and reachable from the command palette as Theme: …). Renders the four presets as a 2×2 grid of preview tiles, each tile showing a miniature of the chosen preset's surface ramp + accent. The active preset is outlined in accent-selection. Switching is instant — no fade — so the user reads the change as deliberate. The picker is a settings-tier affordance, not an onboarding moment.
Code blocks, markdown headings, and mermaid diagrams swap their palette with the chrome. The same accent-headline, syntax-*, and surface tokens drive Shiki's syntax highlighter and Mermaid's theme block. There is no "always-on" highlighter theme; the highlighter is a function of the active preset.
- Surface:
background-code(the deepest ramp step),rounded-lg,hairlineborder. - Inline
code:ink-bodyonbackground-codeat 50% opacity; no border. - Fenced blocks: Shiki theme
tokyo-night-{preset}for each preset; the four bundled themes match the four presets, generated from the source palette so chrome and content harmonise. - Copy button: ghost button at top-right; appears on row hover;
ink-muted→ink-bodyon hover.
# H1and## H2render inaccent-headline(soft magenta in Tokyo Night). The hue swaps with the preset.### H3and below render inink-strong. (We don't want a wall of magenta on a long doc paste.)
A mermaid.initialize({ theme: 'base', themeVariables: { … } }) block is generated from the active preset's tokens. primaryColor → accent-selection, lineColor → hairline-strong, textColor → ink-body, mainBkg → background-elevated. The same generator runs on every preset switch; mermaid re-renders the visible diagrams.
- Do reach for role tokens (
background-app,accent-selection,ink-body) in every component. Never hard-code a Tokyo Night hex. - Do ship Tokyo Night as the dark default and Tokyo Day as the light default; honour
prefers-color-schemefor the page-load default. - Do keep the four-accent budget (
selection,mention,headline,stream) plus four semantic status hues. New decorative colour requests get rejected; the answer is weight, size, ink contrast, or one of the existing accents. - Do use
Workshop-grade depth via the ramp-step contrast. Sidebar deeper than app; top bar lighter than app; elevated for floating; code deepest. - Do cap body prose at 65–75ch where long-form content appears.
- Do use large radii (
rounded-3xl,rounded-4xl) to signal "this surface is floating" (modals, input pills), and small radii (rounded-lg) to signal "this surface is embedded" (inputs, badges). - Do name agents in the chrome. The model is metadata under the agent, never the primary title.
- Do include
Vazirmatnin every new font stack for RTL parity. - Do respect
prefers-reduced-motion— transitions should become instant, not merely slower. - Do swap the Shiki and Mermaid palette with the chrome. A code block on a Tokyo Storm chrome should feel like the same room.
- Do make theme switches instant (no crossfade). Deliberate change reads as user agency; fade reads as "the system is loading."
- Don't introduce a fifth decorative hue. The four-accent budget is the rule.
- Don't put raw model identifiers (
gpt-4o-…,claude-3-5-sonnet-…) in primary chrome. The model is metadata under the agent's name, inink-mutedat label scale. - Don't recreate the ChatGPT "centered prompt in a void" landing. Sidebar stays. History is structured. Agents are named.
- Don't reach for a hero-metric dashboard layout (big number + three stat cards + gradient CTA) when building admin or settings surfaces.
- Don't use gradient anything. No gradient text, no gradient buttons, no gradient backgrounds. Tokyo Night is saturated; it is not neon. Solid colour only.
- Don't use side-stripe borders (
border-leftgreater than 1px as a coloured accent) for status. Use full hairlines, background tints, or leading icons instead. - Don't reach for a modal as the first thought. Exhaust inline and progressive disclosure before adding a dialog.
- Don't apply shadows to surfaces that sit in the page flow. Flat-until-floating; ramp-step is the depth.
- Don't revert any of the role tokens to a zero-chroma neutral without a documented reason. Greyscale is a fallback, not the look.
- Don't introduce confetti, emoji bursts, celebratory bounces, or any consumer-social warmth (Discord-style purple-on-purple, sparkle-emoji chrome, rounded-everything). Wrong register for a work tool.
- Don't break RTL by hard-coding left/right. Use logical properties (
inline-start,inline-end) or Tailwind'sms-/me-utilities. - Don't animate CSS layout properties. Transform and opacity only.
- Don't persist the user's theme choice to the server database. It is a per-device preference; cookie + localStorage is the entire storage surface.
- Don't show a theme-switch onboarding popup on first load. The theme picker lives in Settings and the command palette; the OS-mapped default is correct for ~95% of users on first paint.