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 |
— |
CSS variables (recommended implementation)¶
: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-container → surface-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-scan — OpenJournalReaderButton.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:
- Modal / dialog — centered overlay; follow Modals.
- Popup — separate window or host-controlled surface when the flow is inherently separate (e.g. journal reader) or the host already manages windowing.
- Draw-in panel — last 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-scan — EdosModal.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¶
| 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.
Link behavior (normative)¶
- 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"withrel="noopener noreferrer". - Do not use
window.openwithout the samenoopenerbehavior unless the platform cannot setrel(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.vue — q-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"andrel="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-containerfill) 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-scanCSS from legacy aliases (#121212, 8px radius) to full canonical tokens and0pxradius. - Bundle Roboto Flex and JetBrains Mono in hosted apps that adopt the typography table.