Skip to content

Visual identity (design guidance)

Audience: Agent + maintainer

Optional corporate design guidance for EDOS first-party web apps and for external projects that want a similar look. This is not a shared UI component library, not a runtime contract (see HOSTED_APP_CONTRACT.md), and not required for ecosystem participation.

Canonical source on this page: design tokens, typography, layout, and component habits below (codified from Stellar Scan). Implement them in whatever stack you use (React, Solid, Vue without Quasar, etc.). Do not treat legacy Quasar file paths as the spec.

Intent

  • Family resemblance across tools users open in the same session (browser tabs, popups, Tauri webviews, clustered embeds), without merging repos or forcing one framework.
  • Embeddable tools: layouts prioritize the main function in small viewports; chrome stays dense and out of the way (see Layout patterns).
  • Game-adjacent feel: Elite Dangerous ship UI is often described as orange highlights on dark / black surfaces — high contrast, minimal chrome, functional panels over decorative chrome.
  • Tokens and patterns only: colors, typography, spacing habits, and layout rules. Each app chooses its own components and dependencies.

Adoption

Audience Expectation
First-party EDOS apps (new and existing) SHOULD use the tokens and habits here when adding or restyling UI.
External / third-party apps MAY adopt any subset; no compliance gate.
Agents For new UIs, apply this page directly — do not scaffold Quasar unless the task explicitly targets a legacy app.

Brand and visual language

The design system targets high-density information environments — aerospace telemetry and tactical HUD inspiration. The aesthetic is high-contrast minimalist: structural lines, monochromatic surfaces, and a single vibrant accent for attention. The interface should feel like a ship cockpit computer: precise, cold, efficient — rigorous grid alignment, technical iconography, and a clear hierarchy of data importance.

Reference implementation: elite-dangerous-stellar-scan (src/index.css) — first app to codify the full token set below. elite-dangerous-interstellar-scan shares the same patterns when present in the workspace.

Color tokens

Palette optimized for OLED and low-light use. Foundation is deep Void black (#131313), not mid-gray application chrome.

Role Guidance
Primary accent (primary #ffb785, container #f07b05) Interactive elements, active states, critical branding only — use sparingly so orange reads as “active / warning”.
Surfaces Main canvas on background / surface. Panels step through container tokens for subtle depth without heavy shadows.
Data / secondary Muted greys (on-surface-variant, secondary) for labels and metadata.
Status High-saturation success/error only in tables and alerts — not general chrome.

Full palette (canonical — Stellar Scan)

Token Hex Role
background / surface #131313 Main canvas (“Void”)
surface-container-lowest #0e0e0e Deepest inset wells
surface-container-low #1c1b1b Table headers, recessed regions
surface-container #201f1f Default raised panels
surface-container-high #2a2a2a Modals, slide-outs, forward layers
surface-container-highest #353534 Topmost tonal step
surface-bright #393939 Hover / emphasis surfaces
on-surface #e5e2e1 Primary body text
on-surface-variant #dec1af Secondary labels, warm muted text
outline #a58c7c Default 1px borders
outline-variant #574335 Subtle dividers
primary #ffb785 Accent text, glow, ghost buttons
on-primary #502400 Text on solid primary fills
primary-container #f07b05 Solid primary buttons, .edos-panel left border
on-primary-container #532600 Text on primary-container fills
inverse-primary #954a00 Pressed / inverse accents
secondary #c8c6c5 Neutral chrome text
secondary-container #474746 Neutral filled controls
tertiary #97cbff Informational / link accents (sparingly)
tertiary-container #00a2fb Info fills
error #ffb4ab Error text
error-container #93000a Error banners
positive (semantic) #029e4c Success in data tables (retained from earlier EDOS apps)
negative (semantic) #ff0000 Hard errors where M3 error tokens are not wired yet

Overlays: secondary controls may use rgba(0, 0, 0, 0.35) on the canvas.

Loading / glow: use primary (#ffb785) or primary-container (#f07b05) for focus rings and active glow — not IDE host blue. Legacy surface-map animation #fd7000 may stay on that asset only.

Avoid extra brand hues unless a feature needs semantic color beyond this table.

Simplified aliases (legacy apps and canvases)

Older EDOS UIs and canvas mockups may still use short names. Map them to the canonical palette when migrating:

Legacy alias Canonical token Hex
bg-page background / surface #131313 (was #121212)
bg-surface surface-container-high #2a2a2a (was #1d1d1d)
primary (buttons) primary-container #f07b05
primary (accent text) primary #ffb785
text on-surface #e5e2e1
text-muted on-surface-variant / secondary #dec1af / #c8c6c5
border outline at low opacity, or #333333 structural
:root {
  /* Surfaces */
  --edos-surface: #131313;
  --edos-surface-container-lowest: #0e0e0e;
  --edos-surface-container-low: #1c1b1b;
  --edos-surface-container: #201f1f;
  --edos-surface-container-high: #2a2a2a;
  --edos-surface-container-highest: #353534;
  --edos-on-surface: #e5e2e1;
  --edos-on-surface-variant: #dec1af;
  --edos-outline: #a58c7c;
  --edos-outline-variant: #574335;
  /* Brand */
  --edos-primary: #ffb785;
  --edos-primary-container: #f07b05;
  --edos-on-primary: #502400;
  --edos-on-primary-container: #532600;
  /* Semantic (retained) */
  --edos-color-positive: #029e4c;
  --edos-color-negative: #ff0000;
  --edos-color-info: #00a2fb;
  --edos-color-warning: #ffb000;
  /* Layout */
  --edos-spacing-unit: 4px;
  --edos-gutter: 16px;
  --edos-margin: 24px;
  --edos-panel-padding: 12px;
  --edos-container-max-width: 1440px;
  --edos-overlay-inset: 18px;
  --edos-radius: 0;
  /* Legacy aliases — point at canonical tokens */
  --edos-color-primary: var(--edos-primary-container);
  --edos-color-bg-page: var(--edos-surface);
  --edos-color-bg-surface: var(--edos-surface-container-high);
  --edos-color-text: var(--edos-on-surface);
  --edos-color-text-muted: var(--edos-on-surface-variant);
  --edos-color-border: rgba(255, 255, 255, 0.12);
  --edos-color-border-accent: rgba(240, 123, 5, 0.45);
}

Framework-specific theme files (e.g. Quasar Sass variables) should mirror these values, not define a different palette.

Typography

Systematic, compact scale for data density. Prefer Roboto Flex for UI; JetBrains Mono for tabular numbers, coordinates, and toolbar labels.

Token Family Size Weight Line height Notes
display-lg Roboto Flex 32px 700 1.2 Branding; font-variant: small-caps; letter-spacing: 0.05em
headline-md Roboto Flex 20px 600 1.4 Section titles
headline-md-mobile Roboto Flex 18px 600 1.3 Sections below 768px
body-md Roboto Flex 14px 400 1.6 Default body
body-sm Roboto Flex 12px 400 1.5 Secondary copy
label-mono JetBrains Mono 11px 500 1.2 Metadata, compact actions; letter-spacing: 0.02em; often text-transform: uppercase
Item Guidance
Branding and headers Roboto Flex + font-variant: small-caps + increased letter spacing
Data display JetBrains Mono in tables so numeric columns align
Icons Material Icons or Material Symbols — optional; not required for data-dense apps
Scale Keep sizes compact; 11px for metadata maximizes visible rows

No custom EDOS wordmark is specified; keep third-party attribution subtle (see Third-party service attribution).

Layout and spacing

Fixed–fluid hybrid: 12-column mental grid, 16px gutters (--edos-gutter), 4px modular scale (--edos-spacing-unit).

Token Value Use
unit 4px Padding/margin steps (8px, 12px, 16px, …)
gutter 16px Column gutters
margin 24px Legacy outer inset only — not for embeddable tool canvases (see Content bleed below)
panel-padding 12px Inside .edos-panel and toolbars
container-max-width 1440px Centered desktop shell cap
Pattern Guidance
Main area One fluid primary column (table, map, editor) — avoid permanent multi-column shells unless there is a strong reason (see Layout patterns).
Density Tight internal padding (8–12px) for more rows per viewport
Content bleed Avoid decorative outer padding around the primary view (large page margins, centered “card” shells, boxed layouts). Main content SHOULD reach viewport edges; padding belongs inside controls (cells, compact toolbars, modal bodies), not as whitespace framing the app.
Auxiliary UI Prefer modals or popups for settings, forms, and secondary tasks — not sidebars or drawers (see Embeddable / clustered layouts)
Mobile (< 768px) Draw-ins → full-screen overlays; keep main canvas edge-to-edge (no decorative page margins)

Elevation and depth

Depth via tonal layering and border accents, not soft shadows.

Layer Surface step Example
Canvas background #131313 Main table area
Panel surface-containersurface-container-high Toolbars, cards
Forward surface-container-highest Modals, slide-outs
Technique Guidance
Outlines 1px solid #333333 (or outline / outline-variant) for panel edges
Active / focus Glow — subtle box-shadow using primary / primary-container, not elevation
.edos-panel 3px solid left border in primary-container (#f07b05) on every major panel

Shapes

Sharp and geometric — industrial equipment, not consumer rounded UI.

Element Radius
Buttons, panels, inputs 0px (--edos-radius: 0)
Decorative accents 45° clipped corners where appropriate (radar / telemetry motif)
Dividers 1px vertical/horizontal grid lines

Legacy apps may still use 6–8px radius until restyled; new data-dense UIs SHOULD use 0px.

Components (informal)

Not a shared library — apply tokens when building or restyling UI.

Buttons

Variant Style
Primary Solid primary-container, dark text on fill, 0px radius
Ghost 1px primary border, primary text, transparent fill
Action / compact 24px height; uppercase label-mono
Shell outlined Normative for Open journal reader and Install on desktop — see Global shell action buttons

Global shell action buttons

Reference implementation: elite-dangerous-stellar-scanOpenJournalReaderButton.tsx, InstallOnDesktopButton.tsx, .btn-top-bar-outlined in src/index.css, grouped in AppTopBar.app-top-bar__actions.

First-party hosted apps SHOULD use this pattern for the two cross-app affordances (and any similar global shell controls). Do not use solid Primary fills for these — they are secondary global chrome, not the app’s main call-to-action.

Topic Normative detail
Placement Top-right cluster inside a thin top bar (.app-top-bar__actions, margin-left: auto, gap: 8px) or equivalent floating overlay at top-right (~--edos-overlay-inset).
Variant Outlined shell — class name convention: btn-top-bar-outlined (apps copy the CSS block; no shared package yet).
Layout inline-flex, align-items: center, gap: 8px, min-height: 24px, padding: 6px 12px.
Typography JetBrains Mono / label-mono: 11px, weight 500, letter-spacing: 0.02em, text-transform: uppercase.
Colors Label: on-surface-variant. Background: surface-container. Border: 1px structural (#333333 / --edos-color-border). Icon: primary (#ffb785). Hover: label → on-surface, border → primary, subtle orange glow — not filled primary-container.
Icon Left of label; ~17×17 SVG, fill="currentColor", aria-hidden="true". Journal: document/lines motif. Desktop: download-to-tray motif.
Labels (visible) Short: Journal and Desktop. Busy install: Preparing….
Labels (accessible) title on the <button> with full phrase, e.g. “Open journal reader in a separate window” and “Install on desktop (Windows journal bridge with embedded …)”.
Disabled / busy Install: disabled + aria-busy while build runs; modifier btn-top-bar-outlined--busy pulses the icon opacity.
Visibility Hide Open journal reader when edosEmbedded / edos.mode=embedded. Hide Install on desktop when embedded, when not HTTPS, or when already inside the Tauri local journal reader webview — per app capsule.

Suggested CSS (token names may use legacy --edos-color-border aliases):

.btn-top-bar-outlined {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 24px;
  padding: 6px 12px;
  font-family: var(--edos-font-mono, 'JetBrains Mono', ui-monospace, monospace);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--edos-on-surface-variant);
  background: var(--edos-surface-container);
  border: 1px solid var(--edos-color-border, #333333);
  border-radius: var(--edos-radius, 0);
}
.btn-top-bar-outlined-icon {
  flex-shrink: 0;
  color: var(--edos-primary);
}
.btn-top-bar-outlined:hover:not(:disabled) {
  color: var(--edos-on-surface);
  border-color: var(--edos-primary);
  box-shadow: 0 0 10px rgba(255, 183, 133, 0.12);
}

Data tables

Behavioral norms (saved views, filters, highlights, field registry, modals for editors): TABLE_GUIDANCE.md. Reference implementation: elite-dangerous-stellar-scan (BodiesTable.tsx, TableWorkspace.tsx).

Part Style
Header surface-container-low (#1c1b1b); bold mono; 2px bottom border #333333
Rows Subtle zebra striping; 1px bottom borders; hover → full-row highlight + dim orange left accent
Cells Vertical dividers at very low opacity (~0.1)

Inputs

Part Style
Field surface-container-lowest background; 1px grey border; focus → orange border + outer glow
Label Above field; small-caps; 11px

.edos-panel

Core container: elevated surface token, 1px border, 3px left border primary-container. Use compact titles (headline-md or label-mono) — not page-scale display-lg hero headers.

Status indicators

Type Style
Dot 8px square; pulse animation for active scan / critical
Modified toolbar 4px orange dot beside control label

Secondary UI (modals and popups preferred)

When extra UI does not fit inline, use this order:

  1. Modal / dialog — centered overlay; follow Modals.
  2. Popup — separate window or host-controlled surface when the flow is inherently separate (e.g. journal reader) or the host already manages windowing.
  3. Draw-in panellast resort only if a modal would block too much of a spatial main view (e.g. map) and the panel must stay open while interacting with the canvas. Collapsed by default; slides over the main view without reflow; scrim with 4px backdrop blur.

Avoid docked sidebars, persistent drawers, and slide-out panels that compete with the main function for space.

Modals

Reference implementation: elite-dangerous-stellar-scanEdosModal.tsx, .edos-modal-* in src/index.css, panel content using .edos-modal-header / .edos-modal-body / .edos-modal-footer (e.g. FilterBuilder.tsx, ColumnPicker.tsx).

Every modal MUST use a three-region layout inside the dialog panel. Scrim click MAY dismiss, but is not a substitute for an explicit close control in the header.

Region Required Guidance
Header Yes Title (compact headline-md or uppercase mono h2/h3) and a Close control (button or icon button) on the same row (justify-content: space-between). Close MUST be visible without scrolling. Optional one-line hint below the title row stays inside the header.
Body Yes Scrollable main content. Padding on all sides so text, inputs, and lists do not touch the dialog border — use at least --edos-panel-padding (12px) or --edos-gutter (16px); tighter than page margins is fine, zero inset is not.
Footer When actions exist If the modal has primary / secondary actions (Save, Apply, Cancel, Delete, …), place them in a footer bar separated by a top border — not inline at the bottom of the body. Footer: display: flex, gap: 8px, padding 12px × gutter.
Topic Normative detail
Shell Fixed overlay (.edos-modal), scrim with blur, centered .edos-modal-dialog on surface-container-highest, 1px border + 3px left accent (primary-container).
Close Header button labeled Close (or aria-label="Close" on an icon control). onClick calls the same handler as dismiss; keyboard Escape SHOULD dismiss when focus is inside the dialog.
Accessibility role="dialog", aria-modal="true", aria-labelledby pointing at the title id (or aria-label on the dialog).
Density Keep headers/footers thin; body carries forms and lists. Do not add hero spacing inside modals.

Suggested structure (class names are conventional — copy from Stellar Scan):

<div class="edos-modal">
  <button type="button" class="edos-modal-scrim" aria-label="Close dialog" />
  <div class="edos-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="…">
    <div class="edos-modal-panel">
      <header class="edos-modal-header">
        <div class="side-head">
          <h3 id="…">Title</h3>
          <button type="button">Close</button>
        </div>
      </header>
      <div class="edos-modal-body">… padded content …</div>
      <footer class="edos-modal-footer">… action buttons …</footer>
    </div>
  </div>
</div>

Modals without footer actions (read-only confirm with only header Close) MAY omit <footer>; any bottom-aligned action row still MUST use <footer class="edos-modal-footer"> when present.

Other patterns

Situation Guidance
Errors error / error-container tokens, or legacy negative
Low-priority chrome secondary / muted mono
Loading / empty Full viewport near-black with on-surface copy and optional orange glow animation

Reuse this palette in forms, tables, and dialogs — do not introduce a second brand system per app.

Layout patterns (map and tool UIs)

Oriented toward tool UIs (maps, readers, viewers), not marketing sites. Apps are often shown embedded in clustered layouts (iframes, Tauri webviews, multi-pane hosts) — design so the main function stays usable at small sizes. Wording is framework-neutral.

Embeddable / clustered layouts

Principle Guidance
Main function first The primary task (table, map, route list, …) SHOULD occupy most of the viewport. Menus, global buttons, headers, and chrome SHOULD be small, dense, and non-blocking — integrate controls into the main surface (toolbar row, table header, inline chips) when possible.
Column layouts Avoid permanent two- or three-column shells. Use a single fluid column unless a column split is clearly justified (e.g. map + narrow inspector where both stay readable).
Headers and footers No hero banners, marketing headers, or tall footers. Thin status/tool bars (~32–40px) are fine.
Sidebars and drawers Avoid docked sidebars, drawers, and slide-out panels. Prefer modals or popups for secondary UI. Draw-in overlays are a last resort (collapsed by default, do not push layout) — see Secondary UI.
In-app navigation Prefer one context — users should not need to switch “pages” for the core workflow. Do not cram so much secondary UI into the main view that the primary content collapses. Rule of thumb: if the view needs heavy scrolling for the main task, or the primary content uses less than half the viewport, consider sub-navigation (tabs, segmented control) or collapsible sections instead of more permanent chrome. Collapsibles are often better than a separate nav layer. When sub-navigation exists, apps SHOULD expose panels as URL paths and manifest navigation per HOSTED_APP_CONTRACT.md — In-app navigation views.
Decoration Minimize non-functional visuals (large logos, illustration, ornamental frames). Decoration competes with data at small resolutions.
Content padding Avoid decorative padding around the primary view — no generous outer margins, inset “cards,” or framed boxes that shrink the working area. Tables, maps, and editors SHOULD use the full viewport; reserve padding for functional density (cell spacing, compact toolbars, modal interiors).

Overlay placement

flowchart TB subgraph viewport["Full viewport — main content"] MAIN["Primary view edge-to-edge"] end subgraph overlays["Floating overlays ~18px from edges"] TL["top-left: context / metadata — collapsible"] TR["top-right: Open journal reader · Install on desktop · other global shell actions"] end subgraph footer["bottom center — thin only"] ATTR["Attribution / credits"] end MAIN --- overlays MAIN --- footer
Pattern Guidance
Main content Edge-to-edge primary view (100vw / 100vh or equivalent) with no decorative outer padding. Controls as overlays or inline in the main widget — not a permanent sidebar column.
Global shell actions Top-right (preferred): Open journal reader and Install on desktop using the outlined shell button pattern (Journal / Desktop labels, orange icon, muted outlined fill — not solid primary).
App-specific primary actions Place on or in the main element (toolbar, selection bar, bottom of table) — wherever they stay visible without covering data. Not required to be bottom-left; avoid fighting the top-right shell cluster.
Context / metadata Top-left collapsible panel; dense typography; collapsed by default when possible.
Attribution Bottom center — thin row only; see Third-party service attribution.
Embedded mode When edosEmbedded is set, hide flows that duplicate the host shell (journal popup, desktop download) — see HOSTED_APP_CONTRACT.md; each app documents behavior in its capsule. Attribution MAY be shortened or hidden when the host already credits the same services — document in the app capsule.

Overlay inset: ~18px from viewport edges unless a host iframe needs different safe areas (document exceptions in the app capsule).

Third-party service attribution

Hosted EDOS web apps that integrate third-party assets, HTTP APIs, or frameworks MUST show clickable link attributions so users can identify upstream services. This is separate from ARCHITECTURE.md fair-use rules (routing through api-cache): attribution is user-visible credit, not the proxy implementation.

Framework-agnostic: implement with plain HTML in a footer, sticky bar, or chips — there is no shared @edos/* attribution component; copy the placement and link rules below, not a specific UI library.

When attribution is required

Integrate… Attribute…
Community HTTP APIs (SPANSH, EDSM, Inara, etc.) The upstream service by its usual public name; if all browser traffic goes through EDOS api-cache, say so (e.g. “via EDOS api-cache”).
Third-party assets (textures, models, tile sets) The asset host or project (e.g. EDAssets).
Third-party libraries / map engines used in the UI The project (e.g. OpenGlobus).
Journal / game data sourced only from the player’s files Optional short note (e.g. “Data: journal”) — no external URL required unless you also call an API.

First-party EDOS apps with a user-facing web UI SHOULD ship attributions before release. External apps MAY adopt the same pattern; there is no compliance gate.

Out of scope: attributions for cited wiki tables transcribed in-repo (sourceUrl in JSON) — those belong in data files and project READMEs per DOC_CONVENTIONS.md.

Placement (normative)

Rule Detail
Position Bottom center of the viewport — horizontally centered, fixed or sticky above the bottom edge.
Z-order Above the main canvas but below modal dialogs; do not cover top-right shell actions or in-main primary controls (~18px inset).
Size Small body text (~0.75rem), muted default color; links may use primary orange for emphasis.
Density One compact row (or two short rows: “data sources” then optional “developed by”). Avoid tall credit blocks.

Suggested CSS habit (names are conventional, not a shared package):

.edos-attribution {
  position: fixed;
  bottom: var(--edos-overlay-inset, 18px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 15;
  font-size: 0.75rem;
  text-align: center;
  pointer-events: none; /* let clicks pass through padding */
}
.edos-attribution a {
  pointer-events: auto;
}

Apps MAY use a local class name (e.g. app-attribution) if it follows the same layout rules.

  • Each external service MUST be a link to its canonical public HTTPS URL (project home or API docs landing page).
  • Links MUST open in a new browsing context: target="_blank" with rel="noopener noreferrer".
  • Do not use window.open without the same noopener behavior unless the platform cannot set rel (then document the exception in the app capsule).

Naming and copy

Use names users recognize from the Elite Dangerous community — consistent spelling helps across tools:

Service Preferred label Typical URL
SPANSH SPANSH (or “spansh” in informal chip UIs) https://spansh.co.uk/
EDSM EDSM https://www.edsm.net/
EDAssets EDAssets https://edassets.org/
OpenGlobus OpenGlobus https://openglobus.org/
EDOS api-cache EDOS api-cache or “via EDOS api-cache” Link to your deployment’s cache docs or https://api-cache.howfe.org only if that URL is meaningful to users; otherwise plain text after the upstream link.

Optional groupings (combine in one bottom-center cluster):

Group Example prefix Contents
Data / APIs / assets Data: or This tool uses Data/APIs/Assets/Frameworks from SPANSH, EDSM, EDAssets, OpenGlobus, …
Cache layer suffix on the data line via EDOS api-cache when the UI never calls SPANSH/EDSM origins directly — see ARCHITECTURE.md.
Maintainer (optional) Developed by Link to the app’s repo or author page — secondary to third-party credits.

Separate groups with · or a second row; keep the third-party links visually primary.

Embedded / iframe mode

When edosEmbedded (or edos.mode=embedded) is active, the app MAY:

  • Hide the attribution bar if the host displays equivalent credits, or
  • Show a short single-line attribution only.

Document the choice in the app capsule (HOSTED_APP_CONTRACT.md).

Reference implementations (do not treat as a shared library)

App Implementation Notes
Surface map elite-dangerous-surface-map/ui/src/components/PoweredBy.vue — chip links; ui/src/layouts/MainLayout.vueq-page-sticky position="bottom" with SPANSH, EDSM, EDAssets, OpenGlobus + optional “Developed by”. Quasar-specific UI; placement is bottom-centered sticky.
Stellar Scan Attribution: src/App.tsx<footer class="app-attribution">. Shell buttons: src/components/OpenJournalReaderButton.tsx, InstallOnDesktopButton.tsx, AppTopBar.tsx, .btn-top-bar-outlined in src/index.css. Solid + CSS variables; normative Journal / Desktop shell controls.

New apps SHOULD match bottom-center placement and link behavior; they need not match Quasar chips or Solid markup.

Checklist (agents and maintainers)

  • [ ] Every integrated third-party API, asset pack, or map/framework runtime used in the UI has a named link in the bottom-center attribution area (or documented exception for embedded mode).
  • [ ] Community APIs are credited and implemented via api-cache (attribution does not replace the cache rule).
  • [ ] Links use target="_blank" and rel="noopener noreferrer".
  • [ ] Attribution does not obscure top-right shell actions or in-main primary controls.
  • [ ] App capsule notes any embed-mode attribution shortcut.

Cursor canvas mockups (Phase 0 UI)

Some EDOS apps use Cursor canvases (*.canvas.tsx beside the chat) for layout mockups before implementation.

Topic Guidance
Host vs EDOS Canvas components (Text, Button, Select, …) use the Cursor IDE theme. They do not inherit color from a parent wrapper. useHostTheme() is not EDOS orange.
Colors Copy hex tokens from Color tokens into an inline E constant (include primary #ffb785 and primaryContainer #f07b05); set style={{ color: E.text }} on every label and control.
Pattern Use a small BodyText helper wrapping Text; style Select / TextInput / ghost buttons explicitly; use a custom orange primary button for app-specific actions only; mock Open journal reader / Install on desktop as outlined shell controls (Journal / Desktop, muted fill, orange icon) in the top-right.
Live app src/ CSS variables behave normally — do not assume the canvas preview matches without explicit per-component styles.

Agent rules (install both when the app is inside the edos/ checkout):

Copy Path
Workspace edos/.cursor/rules/edos-canvas-mockups.mdc (when Cursor root is edos/)
Per app <app>/.cursor/rules/edos-canvas-mockups.mdc (when Cursor root is the app alone — required for new repos)
Template docs/templates/cursor-rules/edos-canvas-mockups.mdc (copy source; git-only)

Legacy reference (Quasar / surface map)

elite-dangerous-surface-map was the first app to embody this look. It uses Quasar 2 + Vue 3 and is not the template for new projects.

Use this page for… Use the surface map repo for…
Hex values, CSS variables, layout habits Maintaining or debugging that app only
New React / vanilla / other stacks

If you must touch the legacy app, see apps/elite-dangerous-surface-map.md for project entrypoints. Palette there is defined in ui/src/css/quasar.variables.scss and should stay aligned with the token table above.

Other legacy Quasar UIs (e.g. remote journal reader) share the same orange/black hex values; new apps should still follow this document, not copy Quasar component patterns.

Anti-patterns

  • Light gray application chrome as the default (breaks “orange on black”).
  • Overusing primary / primary-container — reserve orange for interactive and active states.
  • Rounded corners on new data-dense table UIs (conflicts with sharp cockpit geometry).
  • A new primary brand color per app without maintainer intent.
  • Scaffolding Quasar for greenfield apps because an old repo used it.
  • Treating this doc as mandatory for IPC, cache, or manifest compliance.
  • Adding a shared component package “while you’re here” — out of scope unless maintainers explicitly create one later.
  • Hero headers, marketing footers, or tall credit blocks that steal vertical space from the main function.
  • Docked sidebars, drawers, or default multi-column layouts without a clear, documented reason.
  • Draw-in panels or slide-outs for flows that fit a modal or popup (settings, forms, pickers).
  • Decorative outer padding — large page margins, centered card wrappers, or boxed shells around the main canvas.
  • Modals without a header title + Close, body content flush to the dialog edge, or action buttons at the bottom of the body instead of a footer — see Modals.
  • Page-style navigation for workflows that could stay on one screen (or use collapsibles / compact sub-nav when the main view is overcrowded).
  • Placing Open journal reader / Install on desktop in large bottom or left clusters when top-right compact controls would preserve main content area.
  • Solid primary (primary-container fill) or full-sentence labels for Journal / Desktop shell buttons — use Global shell action buttons instead.

Relationship to other docs

Document Relationship
ARCHITECTURE.md Runtime/data contracts; visual identity is optional.
TABLE_GUIDANCE.md Data-dense table behavior and view/filter contracts — styling cross-links here.
HOSTED_APP_CONTRACT.md URL bootstrap and manifests — orthogonal to colors/fonts.
apps/elite-dangerous-surface-map.md Legacy app capsule — not the default stack for new UIs.

Future work (optional)

  • Publish @howfe/edos-design-tokens (CSS only) so apps import variables instead of copying the block above.
  • Migrate elite-dangerous-stellar-scan CSS from legacy aliases (#121212, 8px radius) to full canonical tokens and 0px radius.
  • Bundle Roboto Flex and JetBrains Mono in hosted apps that adopt the typography table.