16 KiB
SHD.build Design System
This document defines the visual language for SHD.build. New pages should feel like part of the same tactical data network as the admin dashboard, while public pages may use more space and larger editorial typography.
Design principles
- Tactical, not military cosplay. Use operational language, compact information density, restrained status indicators, and precise alignment. Avoid camouflage, distressed textures, or decorative weapon imagery in utility interfaces.
- Data first. Hierarchy comes from grouping, typography, borders, and spacing. Admin tools should resemble a dependable control surface rather than a collection of marketing cards.
- Orange means action. SHD orange identifies primary actions, active navigation, focus, and important values. It should not cover large areas.
- State is always visible. Loading, disabled, active, archived, configured, error, and success states need both visual and textual indicators.
- Square and engineered. Panels and controls use square corners, fine borders, tight spacing, and deliberate grid alignment.
- Links use interface feedback, not underlines. Links do not use native text underlines. Communicate hover and focus through SHD accent color, borders, brightness, and the required focus-visible outline.
Tokens
The canonical tokens live in src/app.css under :root.
| Purpose | Token | Value |
|---|---|---|
| Page background | --shd-bg |
#0a0c0d |
| Base surface | --shd-surface |
#111415 |
| Raised surface | --shd-surface-raised |
#141718 |
| Primary border | --shd-border |
#303536 |
| Main text | --shd-text |
#ecebe5 |
| Muted text | --shd-text-muted |
#858b8d |
| SHD action orange | --shd-orange |
#f6a821 |
| Success | --shd-success |
#75c08c |
| Destructive/error | --shd-danger |
#df8069 |
| Informational/defensive | --shd-info |
#70b9d6 |
Use the spacing tokens for new components. Prefer 8px, 12px, and 20px gaps. Dashboard controls use the shared 40px height when practical.
Typography
- The current UI stack is
Arial, Helvetica, sans-serif. - Page and module headings are uppercase, heavy, and tightly spaced.
- Eyebrows and table labels use 7–10px text with 1–2px letter spacing.
- Body and form text should normally remain between 9–12px in dashboards.
- Public/editorial copy may use Georgia for a restrained field-manual character.
- Never use low-contrast tiny text for information required to complete a task.
Layout patterns
Public pages
- Maximum content width: approximately 1400–1640px.
- Larger headings and more generous vertical rhythm are appropriate.
- Preserve the grid background and orange accents.
- Catalogue and editorial pages use
catalogue-herofor an angular introductory panel and may pair it with a compact operational control bar. - Community build cards retain the colored top rule, abstract loadout artwork, concise tags, agent attribution, and a full-width terminal action.
Agent and authentication surfaces
- Account pages should read as an agent dossier: identity and access at the top, activity metrics beside it, archives in the primary column, and security controls in a narrower console column.
- Dense account consoles use a tabbed control surface for profile, credentials, linked identities, and account lifecycle actions. Only one panel is shown at a time; validation failures reopen the panel containing the failed action. Closely related mutually exclusive workflows, such as selecting a preset portrait or uploading a custom portrait, use a compact secondary tab row. Tabs retain native button semantics plus tablist, tab, and tabpanel roles, textual selected state, keyboard focus, and pressed feedback.
- Authentication pages use a split frame: contextual SHD network information on the left and the actionable secure-access console on the right.
- OAuth providers appear as connection nodes with a recognizable provider color; SHD orange remains reserved for the primary local action and navigation.
- Authentication prioritizes passkeys, followed by one-time email magic links. Discord remains a prominent provider option, while username/password is an explicitly labeled optional fallback in a collapsed control. Passkey controls name the platform interaction rather than exposing WebAuthn terminology.
- Verified email identities and registered passkeys appear as compact method rows in Account Access. Every method displays its verification or device state, registration date where useful, and protected removal behavior that prevents an agent from deleting their last usable sign-in method.
- Local username and password are one optional authentication method, separate from the public display name and the immutable internal account identifier. Agents may remove both local credentials together after adding another method, and may restore them later with a new unique login username and password.
- The “at least one sign-in method” rule is a server-side invariant shared by self-service and ISAC actions. Passkeys, verified magic-link email, Discord, and a complete local username/password pair each count as usable methods. Controls may disable unsafe removal for clarity, but server validation remains authoritative. Intentional soft account deletion is the sole exception.
- Linked identity nodes show provider display name, account handle or stable ID,
and an explicit textual
LINKEDstate. Unlink controls sit beneath the node, require credential confirmation, and remain disabled with an explanation when unlinking would remove the user's only sign-in method. - ISAC user dossiers reuse the same linked-identity node. Administrative unlinking requires a scoped identity-management capability, produces an audit event, and must never remove the user's only available sign-in method.
- On small screens, the split frame becomes a single column and account controls move before archival content.
- Public display names and private login usernames are distinct. Display names support normalized Unicode and relaxed visible characters; login usernames remain unique, ASCII-only credentials and must never appear on public-facing community surfaces. Authorized ISAC user operations may show both.
Third-party identity buttons
- Follow the identity provider's current official brand and sign-in guidelines.
- Use official, unmodified assets downloaded from the provider's brand resources.
- Discord sign-in uses the official white Discord symbol on Blurple
#5865F2with the explicit label “Continue with Discord.” - Discord account connection controls use the same official symbol and Blurple treatment with the explicit label “Link Discord.”
- Preserve the provider's required clearspace, logo proportions, approved color, readable contrast, and text/logo alignment even when the surrounding surface follows the SHD theme.
- Provider buttons still require SHD.build's focus-visible, pressed, pending, and duplicate-interaction protection where those states do not conflict with the provider's branding requirements.
Admin dashboard
- Use
admin-page,admin-command,admin-dashboard,admin-sidebar, andadmin-content. - The administrative system is named ISAC. Separate navigation into explicit operational domains such as User Operations and Data Management; visibility must reflect server-provided capabilities.
- Each module starts with
module-toolbar, followed bymodule-kpis. - Editors use
dashboard-editorand appear before the affected table. - Data collections use
dashboard-table,dashboard-row, andtable-heading. - Keep tables dense and horizontally scrollable rather than wrapping columns unpredictably.
- User dossiers pair access controls and moderation in a two-column console, followed by compact login and content-history streams. Restriction state must be textual and use the danger color; inactivity remains a separate activity classification rather than a punishment state.
- Role names describe durable organizational responsibility.
Adminis the unrestricted administrative role;Moderatoris reserved for community content moderation and does not imply ISAC access. Operational ISAC access is delegated separately through scoped roles and permissions. - Account deletion uses a collapsed danger zone, explicit identity confirmation, and plain-language retention guidance. Soft-deleted accounts retain authored content under a deleted-agent identity while releasing credentials, usernames, external identity links, sessions, roles, and permissions.
- Threshold-based set bonuses use compact
effect-bandgroups. Each threshold is displayed as a fixed piece-count marker followed by its mapped stat and value, keeping progression readable in editors and table summaries. - Multi-value compatibility fields use a dense
selection-gridof checkbox rows with a visible selected-count summary. Keep the entire row clickable and preserve native checkbox semantics for keyboard and assistive-technology use. - When compatibility is conditional on another field, show only valid choices, clear stale selections when the controlling field changes, and state required minimum selections in both the section label and validation feedback.
- Tiered records with shared structure use one shared selector and side-by-side value columns rather than duplicating the entire editor. Template-driven copy must show live previews for every tier and document its placeholder syntax.
Forms
- Labels are uppercase and letter-spaced.
- Inputs use dark surfaces, one-pixel borders, and clear disabled styling.
- Related min/max fields remain visually paired.
- Small mutually exclusive option sets use a compact segmented radio control, even when visually presented like selectable checkbox cells. Include an explicit “None” option when the field is optional.
- Primary save actions sit at the lower right. Cancel is secondary.
- Destructive/archive actions are visually separated from save actions.
Interaction rules
- Every interactive element needs a pointer cursor unless disabled.
- Buttons have hover, pressed, focus-visible, pending, and disabled states.
- Forms that send requests should use
PendingForm.svelteor equivalent enhancement to prevent duplicate submissions. - Pending buttons use
aria-busy="true"and remain disabled until the request completes. - Respect
prefers-reduced-motion.
Color semantics
- Orange: primary action, current location, selected operational value.
- Green: online, active, configured, or successful.
- Red: destructive action, error, or offensive classification when context requires it.
- Blue: defensive or informational classification.
- Gray: inactive, archived, unavailable, or supporting metadata.
Do not communicate state by color alone; include a label, icon, or pattern.
Responsive behavior
- Collapse the dashboard sidebar into a two-column module grid below 900px.
- KPI tiles become two columns on small screens.
- Tier editors stack vertically on tablets.
- Tables retain a useful minimum width and scroll horizontally.
- Primary and secondary toolbar actions may expand equally on narrow screens.
Adding a new admin module
- Add the route beneath
src/routes/admin. - Register it in the admin layout navigation.
- Start with the module toolbar and KPI row.
- Reuse dashboard editor and table classes.
- Use the shared tokens instead of introducing near-duplicate colors.
- Verify keyboard focus, pending behavior, empty states, mobile layout, and archived data behavior.
If a new interface needs a genuinely new pattern, document it here when introducing it.
Design-system governance
Significant visual and interaction changes must update this document and the shared implementation in the same change. A change is significant when it introduces or materially revises a reusable token, component pattern, layout, responsive rule, accessibility behavior, motion behavior, or state convention.
Small alignment corrections and isolated visual bug fixes do not require a documentation change unless they establish a rule that other interfaces should follow.
Repository agents and contributors should follow the maintenance checklist in
AGENTS.md.
Agent avatars
Agent portraits use a circular crop in identity headers and square tactical thumbnails in selectors. Preset choices appear in a compact four-column grid; the active choice uses the orange action border and an explicit pressed state. Custom images are normalized server-side to a metadata-free 256 × 256 WebP. Selectors must retain visible hover, focus-visible, pressed, pending, and disabled states, and collapse naturally with their containing account console. ISAC user dossiers show the current portrait, distinguish preset and custom sources textually, and place destructive custom-image removal behind the existing moderation permission and pending-action pattern. Moderation actions use full-width engineered controls: neutral outlined buttons for reversible identity changes and muted red controls for destructive or restrictive changes. Every control must expose pointer, hover, focus-visible, pressed, disabled, and inline pending-spinner states; adjacent navigation links use the same height, typography, and interaction motion.
Weapon definition editor
Complex progression definitions use a stacked control-surface editor: identity and fixed values first, then parallel tier cards, mutually exclusive talent pools, fixed base bonuses, and the augmentation sequence. Tier cards retain identical row ordering so values can be compared horizontally on wide screens and stack without changing meaning on narrow screens. System-derived augment steps appear as read-only numbered cells; editable effects use the shared attribute/value row pattern. Exotic is a status layered onto a weapon family, never a replacement for the family classification. Fixed base bonuses remain visually separate from tactical augmentation effects. Exotic definitions add a dedicated exotic-only talent after the two standard talent pools; their sixth augmentation cell communicates that this talent advances to Tier II.
Large relationship sets use the searchable assignment control instead of checkbox walls. It keeps assigned records visible as removable chips, filters available records by name, renders at most thirty results at once, and exposes counts for both assignments and matches. Mutually exclusive pools pass their assigned IDs to one another as exclusions so invalid combinations cannot be selected. Keyboard focus, pressed state, empty results, and overflow remain explicit. Where a relationship has a global slot invariant, filter each assignment control at the data boundary instead of presenting cross-slot choices. Weapon talents are classified once as Talent 1 / Top or Talent 2 / Bottom in the talent registry; weapon editors only curate subsets from the matching slot.
ISAC editor lifecycle
Successful saves have a consistent outcome throughout data management: editing an existing record closes the editor and returns the user to the registry; creating a new record keeps the editor open with a fresh blank definition for rapid consecutive entry. Failed validation leaves the current editor and entered values intact. Use a unique action result token so reactive handling runs exactly once and does not create update loops.
Tiered-definition registries should show their rendered tier effects when the text is operationally useful. Use compact wrapping description cells rather than replacing meaningful data with a generic “configured” label; retain an explicit textual missing state when a tier has no rendered description.
Registry pagination
Every primary ISAC registry uses server-side pagination. The shared control appears immediately above and visually attached to its table. It shows the visible record range and total, previous/next navigation, a compact window of page numbers, and row-count presets of 10, 25, 50, and 100. Existing filter query parameters must survive page navigation, while changing page size returns to page one. Summary metrics remain global or filter-global and must never silently describe only the visible page. On narrow screens, retain previous, next, current page, and page-size controls before optional page numbers.