Frontend Convention — UI naming, composition, and visual vocabulary
Source path: knowledge-base/knowledge/conventions/FRONTEND_CONVENTION.md
# Frontend Convention — UI naming, composition, and visual vocabulary > How code names are *formed* in this codebase (companion to [LANGUAGE.md](../vocabulary/index.md), which defines the *domain* vocabulary). This is the present convention — match it when adding or renaming code. ## The formula: `Domain + Role` Every component / surface name = a **domain** term (from LANGUAGE.md) + a **role** word for its physical place/shape. Reads as "what it's about" + "where it is". e.g. `ScenePanel`, `StageBar`, `ForceTimeline`, `DecisionView`. ### Role lexicon (precise) | Role | Means | Notes | |---|---|---| | **Shell** | a **top-level page frame** that hosts a whole surface | one per surface: `WorkspaceShell` (domain workspace), `GatewayShell` (instance home + auth — a misnomer, see Platform naming), `ScenarioShell` (live game table), `PortalShell` (the meridians.global site). `MobileWorkspace` is the phone variant of `WorkspaceShell`. | | **Rail** | thin **vertical** strip of items/icons | left story rail; inspector icon rail | | **Bar** | thin **horizontal** strip of controls | top of a region (`StageBar`, `RunBar`, `FuturesBar`) | | **Panel** | a **large rectangular region** of content | resizable / dockable; the inspector/sidebar bodies. When a concept has **both** (e.g. Readings): **View** = the stage surface, **Panel** = the inspector mirror of the same thing. | | **View** | a **full center surface** the Stage swaps between | keep the `…View` suffix; `BoardView`, `ReadingsView`, `NetworkView`, `DecisionView`, … | | **Stage** | the **center surface** that hosts one View at a time | switched by `StageBar` → `state.stageView` | | **Timeline** | a horizontal **time-ordered** band | scenes, forces | | **Modal** | overlay dialog | `BranchModal`, `ScenarioModal`, `ApiKeyModal` | | **Popover** | small **anchored** overlay | | | **Chart** | one visualization | | | **Dashboard** | a full **analytics** surface | | | **Detail** | inspector body for **one entity** | panel content (`CharacterDetail`, `SceneDetail`, …) | | **Slide** | one deck slide | | | **Palette** | floating action menu | `StagePalette` | ### Domain lexicon (draw names from LANGUAGE.md, not synonyms) `Domain · Scene · Arc · Branch · Thread · Belief · Stance · Stream · Merge · Priors · Capture · Scenario · Explore · Readings · Variables · Phase Reasoning Graph / Phase Graph (PRG) · Causal Reasoning Graph / Causal Graph (CRG) · Decision · Mind (the stance/machinery cluster) · Signals (the Capture cluster) · Force (Fate/World/System) · Network · World · System · Board · Substrate · Perspective · Member · Agent · Invitation`. Retired aliases — do **not** use as code names: `Driver` (→ Capture / Prior), `Queue` (→ Priors), `Series` (→ Domain), `Mode` (→ Phase, for the PRG), `Control` (→ Mind), `canvas` (→ Stage), `Playback` (→ Scenario), `Conviction` (the game → **Scenario**; `ConvictionShell`→`ScenarioShell`, `useConviction`→`useScenario`, etc.). **Exception:** the in-game *currency* you pay to commit stays **`conviction`** (`Seat.conviction`, `ConvictionEconomy`, `CONVICTION_*`, `evidenceFromConviction`) — you still "pay conviction" inside the Scenario game. The load-bearing four are **`*Shell` · `*View` · `*Panel` · `*Detail`** — get those right and the rest follow. This file owns the convention; agent briefs and skills should link here rather than restate it. ## Platform & gateway naming (shipped — see [GATEWAY.md](../operations/GATEWAY.md)) The platform layer adds terms that **collide with shipped ones** if we're not deliberate. These decisions are settled and in code: - **The `GatewayShell` trap → the meridians.global site is `PortalShell`, NOT `GatewayShell`.** The `GatewayShell` is the **instance home console** (spine + stage: Games / Domains / Extraction / Invitations) — a slight misnomer, but it's shipped and stays. The **hosted gateway** at `meridians.global` (landing · account · Admin console) is a *different* frame → **`PortalShell`** (`src/features/gateway/landing/PortalShell.tsx`; cosmos + glass). Never call the meridians.global site "GatewayShell". - **"Director" spans two layers — keep the word, know the layer.** *Platform Director* = the Supabase account owner (owns products, pays). *In-instance `director`* = the top role in the shipped 5-tier access ladder (Guest→Viewer→Contributor→**Manager**→Director). They **coincide** (the owner *is* their instance's director) but are separate systems: platform Director lives in `directors` (Supabase); in-instance director lives in `instanceMembers` (the master's registry). Say **"platform account"** vs **"in-instance member / people"** when the layer matters. - **"Admin" (platform) vs "Manager" (in-instance role) — no crossing.** **Admin** = the platform operator (`platform_admins` / the gateway `/admin`; us). **Manager** = the ladder role just below director (the director's deputy inside one instance), *renamed from "admin"* so the word is free for the platform. There is **no** in-instance "admin" and **no** platform "manager". The `MemberRole` literal is `'manager'` (`src/types/domain/access.ts`); the platform table is `platform_admins`. - **Products: `License` and `Hosted`** (settled). *License* = the BYOK Electron app (cheap flat). *Hosted* = the managed Fly VM (pricier). Avoid "Managed" (ambiguous) and "tier"/"seat" (there are no tiers — one License plan; the tunnel is a BYOK ngrok key). A director's products are **per-subscription** (`hasLicense` / `hasHosted`), not a field — both can be true. - **"Instance" = one running host.** The Electron app (License) or a Fly VM (Hosted). Its DB row is `instances` (Hosted only). Don't call it a "tenant" (control-plane word we don't use) or a "server". - **"Domain" is triple-overloaded — disambiguate every time.** (1) *domain* = the product knowledge structure (LANGUAGE.md — the thing users build). (2) *domain name* = the DNS host an instance runs on (`<slug>.meridians.global` / a custom domain). (3) *`directors`/account domain* = platform data. In gateway code + copy, say **"domain name"** or **"hosting domain"** for DNS, never bare "domain". - **Entitlement predicates: `hasLicense(director)` / `hasHosted(director)`** — read the `subscriptions` rows; never a `directors.product` column (it doesn't exist). - **Suffixes carry over:** the gateway's frames are `PortalShell` + `*View` / `*Panel` / `*Modal` as usual (e.g. `FleetConsole` is a Dashboard; `SubdomainClaim` / `CustomDomainSetup` are onboarding panels; `LicenseStatusChip` a chip). Same lexicon, new surface. ## What's consistent (leave alone) - **Casing:** PascalCase components, kebab-case lib, domain-foldered prompts. - **File families:** `…-graph.ts` (`world` / `system` / `network` / `phase-graph`); `…-export.ts`; the `futures-engine` / `-state` / `-remap` trio; the `game-theory*` family; `*Slide` / `*Modal` / `*Chart` / `*Detail` suffixes. - **`stageView` literals track their UI labels.** The union in [`src/types/domain/view-state.ts`](../../../src/types/domain/view-state.ts) is the source of truth, and most members now read as the user sees them (`'opinion'`, `'notes'`, `'streams'`, `'cycles'`, `'projections'`, `'runs'`, `'operations'`) so code and screen use one word. Two kinds of exception, both deliberate: - **Legacy literals kept for persisted state** — `'mode'` is labelled **Phase** / **Phase Graph** in the interface, and `'present'` labels as **Present**. Renaming them would strip stored `viewState`, so they stay; only the *label* moved. - **Retired deep-link values are mapped at the boundary, never re-persisted** — `useDomainDeepLinks` translates old URLs (`?view=sources`→`cycles`, `schedule`→`operations`, `loop`/`stories`→`inbox`) so old links keep working without the retired literal re-entering state. Adding a mode: name the literal after its label, and if you rename an existing one, add the old value to the deep-link mapping rather than leaving a dead URL. - **Pentad archetypes** are 32 Domain work forms over exact formed/latent force profiles. Use the canonical names from `pentad-archetype.ts`; do not concatenate force labels or reuse Scene Sign names. The same five-bit coordinate has two altitudes: a Sign names Scene movement, an archetype names whole-work composition. A counterform reverses all five bits and is a semantic contrast, never a quality verdict.Open on GitHub
Raw Markdown source