{
  "schema": "leumas.docs.page/1",
  "id": "pkg:@leumas/domain-kit",
  "slug": "packages/domain-kit",
  "kind": "capabilities",
  "bucket": "package",
  "title": "@leumas/domain-kit — a domain door, once",
  "name": "@leumas/domain-kit",
  "eyebrow": "a domain door, once",
  "chip": null,
  "summary": "A DOMAIN DOOR, once — the overview HUD, its view host, the console nav view and the manifest→routes/aside/crumbs/⌘K derivation every product's admin repeats. The 3D room is a separate, optional...",
  "keywords": [
    "domain-kit",
    "character-select deck",
    "aside",
    "subpath",
    "overview",
    "domain kit api",
    "leumas domain kit",
    "how to use domain kit"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# `@leumas/domain-kit` — a domain door, once\n\nLeumas Studio and Leumas Admin are different products for different people, and they draw a **domain**\nthe same way on purpose: a door you land on, a deck of what is inside it, view modes over that same\nlist, a tab strip under each page, one aside, one breadcrumb trail, one ⌘K. An operator moves between\nthe two consoles all day, so \"the same\" has to mean the same code, not the same screenshot.\n\nThis package is that code. It was Studio-local until every one of its behaviours had to exist in the\ncontrol plane too.\n\n## Subpaths\n\n| Import | What you get | Touches `three`? |\n|---|---|---|\n| `@leumas/domain-kit` | `DomainOverviewHud`, `useSeededFocus`, `DomainViewHost`, `DOMAIN_VIEWS`, `useArrowStep`, `registerDomainRoom`, `getDomainRoom`, `HudDeckFigure`, `useSettledFocus`, `useDomainScope`, `scopeHref`/`unscopeHref`/`scopeFromPath` | **no** |\n| `@leumas/domain-kit/routes` | `DomainRoutes`, `DomainLanding`, `DomainHub`, `domainsToRoutes`, `blockingFeature`, `CrumbTitleContext`, `useCrumbTitle` | **no** |\n| `@leumas/domain-kit/console-view` | side effect: registers the `console` nav view | no |\n| `@leumas/domain-kit/room` | side effect: registers the 3D room | **yes** |\n| `@leumas/domain-kit/room/backdrop` | `DomainWorldBackdrop` for a surface drawing its own stage | **yes** |\n| `@leumas/domain-kit/domain-hud.css` | `.lms-dhud__*` (the shell imports it itself) | no |\n\n## The room is opt-in, and that is a bundle decision\n\n`DomainOverviewHud` does not import the backdrop. It asks `roomRegistry.js` for a component, and a\nproduct opts in with one line in its entry:\n\n```js\nimport '@leumas/domain-kit/console-view';\nimport '@leumas/domain-kit/room';        // ← without this line, no renderer in the build\n```\n\n`lazy(() => import('./DomainWorldBackdrop.jsx'))` inside the shell would *look* free — it is behind a\npromise — but it is an unconditional **module edge**, so every consumer emits a `three` chunk whether\nor not any door passes a `load`. Runtime already degrades correctly, so the defect is invisible in a\nbrowser and only ever shows up as a renderer in someone's `dist/`. A product without the room import\ngets identical doors minus the backdrop: they render their `fallbackStage`.\n\n`pnpm check:huds` asserts the shell mentions neither `three` nor `@leumas/cinematic`, and that no\ndomain console imports `/room` directly.\n\n## A character-select deck: `HudDeckFigure` + `useSettledFocus`\n\nTwo doors draw a deck where the item IS the picture (`chrome=\"none\"`) — AI's personas and Hosting's\nwebsites — and they arrived at the same box independently. `HudDeckFigure` is that box: a **poster**\nthat is always there and always cheap, an optional **live** layer over it, a **plate**, and **pills**\nthat render only on the centred item.\n\nThe poster is never unmounted, only faded. That is the entire failure story: it costs one composited\nelement, the card never reflows when the expensive layer swaps in, and there is no code path to write\nfor a snapshot that never rendered, a document that refused to frame, or a dead WebGL context —\nbecause the failure state *is* the resting state.\n\n`useSettledFocus(focusId, ms)` reports the focus id only once the deck has stopped moving. Both decks\nneed it for the same reason: a held arrow key steps several cards a second, and mounting the expensive\nlayer per step churns WebGL contexts (browsers cap them near sixteen and drop the **oldest**, so a long\ndeck starts killing the room drawn behind it — with the symptom appearing nowhere near the cause).\n\n[warning] Not `useSeededFocus`, which picks the *initial* focus. Adjacent name, unrelated job.\n\nFive layout rules live in `domainhud.css` beside the code they constrain, each one a defect that\nalready shipped: the media is `position: absolute; inset: 0` and **never** `block-size: 100%`; one\n`z-index` puts both layers over a door's decorative pseudo-elements; transitions are `transform` and\n`opacity` only; no `backdrop-filter` anywhere on a deck over a live canvas; a `filter` may sit on a\nstill element and never on a moving one.\n\n## A scoped domain: the thing is in the URL\n\nSome domains are *about* one of the operator's things — Hosting is about one website, and every one of\nits tabs is. That subject belongs in the address, not in a component's state:\n\n```\n/admin/hosting/sites/<siteId>/domains\n```\n\nThe nav manifest declares those tabs **unscoped** (`/admin/hosting/sites/domains`) and marks the\nsub-item `scoped: true`. It has to: four guard scripts and the diagram generator read the manifest in\nbare Node, where there is no current site and never can be. So the manifest states the *shape* and\n`DomainRoutes` reads the id out of the location, publishing it on `DomainScopeContext`.\n\n**Compare unscoped, emit scoped.** `sectionRows` decides which row is active by matching its hrefs\nagainst the location, so it is given the location with the id removed; the rows it returns get the id\nput back. Reversing that is silent — nothing matches, no row is active, and the aside looks like it\nlost its place rather than like it has a bug. `scopePath.js` is plain JS so a bare-Node test can pin\nboth directions (`test/domain-scope.test.js`).\n\nWith no scoped sub-item in a domain, `useDomainScope()` returns `null` and every consumer behaves\nexactly as it did before scopes existed — which is what keeps the other doors byte-identical.\n\n## The two rules the shell will not break\n\n- **It never fetches.** Every domain keeps its own data source and hands down `items`, `status`,\n  `loading`, `onRetry`.\n- **It never gates.** `useCanvasCapable()` belongs in the caller's default export — except under\n  `downgrade: 'stage'`, where the registered room asks it and swaps only the stage.\n\nOne `AdminSurface`, ever. It is rendered by `DomainOverviewHud`, so a caller must not wrap it in\nanother.\n\n## Adding a domain to a product\n\n1. `<domain>/model/tabs.js` — THE tab list, pure data, no JSX (guards import it in bare Node).\n2. `<domain>/hud/overview.js` — the spec: `{ id, base, hudLabel, deckLabel, surface, select, footer,\n   downgrade, room? }`. `id` must equal the folder name.\n3. `<domain>/hud/<Domain>Populators.js` — `(api) => Promise<inhabitant[]>`, **contracted never to\n   reject**. Only if the door draws a room.\n4. `<domain>/hud/<Domain>Hud.jsx` — the door: `DomainViewHost` whose `renderConsole` is a\n   `DomainOverviewHud` spread from the spec.\n5. `<domain>/pages/<Domain>Hub.jsx` — the tabbed surface: `RouteTabs` + a nested `<Routes>` of lazy\n   panels. `activeTabId()` is the only source of \"which tab is open\".\n6. One manifest sub-item carrying `tabs`, and one `LANDINGS` entry for the door.\n\n`node ops/tools/domain-scaffold/index.mjs --product admin --domain <id>` writes 1, 2, 4 and 5 from\nthe manifest.\n",
  "source": {
    "path": "shared/packages/domain-kit/README.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 6993,
    "hash": "84004338fe6b74ca6fb0ef56f20455e257e68279"
  },
  "urls": {
    "html": "/p/packages/domain-kit",
    "json": "/docs/packages/domain-kit.json",
    "md": "/docs/packages/domain-kit.md"
  },
  "links": {
    "composes": [
      "pkg:@leumas/config-registry",
      "pkg:@leumas/features",
      "pkg:@leumas/ui"
    ],
    "usedBy": [
      "pkg:@leumas/admin",
      "pkg:@leumas/studio"
    ],
    "product": [
      "pkg:@leumas/admin",
      "pkg:@leumas/studio"
    ],
    "howTo": [],
    "skills": [
      "skill:leumas-domains"
    ]
  },
  "exports": {
    "total": 66,
    "component": 28,
    "hook": 11,
    "helper": 27,
    "names": [
      {
        "n": "ACT_VERBS",
        "k": "component"
      },
      {
        "n": "ActiveDomainContext",
        "k": "component"
      },
      {
        "n": "ActiveDomainContext",
        "k": "component"
      },
      {
        "n": "CrumbTitleContext",
        "k": "component"
      },
      {
        "n": "DOMAIN_VIEWS",
        "k": "component"
      },
      {
        "n": "DomainDoor",
        "k": "component"
      },
      {
        "n": "DomainHub",
        "k": "component"
      },
      {
        "n": "DomainLanding",
        "k": "component"
      },
      {
        "n": "DomainOverviewHud",
        "k": "component"
      },
      {
        "n": "DomainRail",
        "k": "component"
      },
      {
        "n": "DomainRoom",
        "k": "component"
      },
      {
        "n": "DomainRoutes",
        "k": "component"
      },
      {
        "n": "DomainScopeContext",
        "k": "component"
      },
      {
        "n": "DomainScopeProvider",
        "k": "component"
      },
      {
        "n": "DomainViewHost",
        "k": "component"
      },
      {
        "n": "DomainWorldBackdrop",
        "k": "component"
      },
      {
        "n": "DRILL_PARAM",
        "k": "component"
      },
      {
        "n": "GenericDomainOverview",
        "k": "component"
      },
      {
        "n": "HudDeckBadge",
        "k": "component"
      },
      {
        "n": "HudDeckFigure",
        "k": "component"
      },
      {
        "n": "MAX_ACTS",
        "k": "component"
      },
      {
        "n": "PILLAR_FALLBACK",
        "k": "component"
      },
      {
        "n": "PILLAR_ROOM",
        "k": "component"
      },
      {
        "n": "RedirectSubtree",
        "k": "component"
      },
      {
        "n": "SETTLE_MS",
        "k": "component"
      },
      {
        "n": "STAGE_MAX",
        "k": "component"
      },
      {
        "n": "ToneScope",
        "k": "component"
      },
      {
        "n": "X",
        "k": "component"
      },
      {
        "n": "useActiveDomain",
        "k": "hook"
      },
      {
        "n": "useActiveDomain",
        "k": "hook"
      },
      {
        "n": "useArrowStep",
        "k": "hook"
      },
      {
        "n": "useCrumbTitle",
        "k": "hook"
      },
      {
        "n": "useDomainCounts",
        "k": "hook"
      },
      {
        "n": "useDomainEntities",
        "k": "hook"
      },
      {
        "n": "useDomainScope",
        "k": "hook"
      },
      {
        "n": "useDomainSections",
        "k": "hook"
      },
      {
        "n": "useDrill",
        "k": "hook"
      },
      {
        "n": "useSeededFocus",
        "k": "hook"
      },
      {
        "n": "useSettledFocus",
        "k": "hook"
      },
      {
        "n": "actsFor",
        "k": "helper"
      },
      {
        "n": "blockingFeature",
        "k": "helper"
      },
      {
        "n": "clearDomainCounts",
        "k": "helper"
      },
      {
        "n": "clearDomainEntities",
        "k": "helper"
      },
      {
        "n": "countsByKind",
        "k": "helper"
      },
      {
        "n": "deckItemsFor",
        "k": "helper"
      },
      {
        "n": "domainsToRoutes",
        "k": "helper"
      },
      {
        "n": "getDomainRoom",
        "k": "helper"
      },
      {
        "n": "indexItem",
        "k": "helper"
      },
      {
        "n": "inhabitantsFromEntities",
        "k": "helper"
      },
      {
        "n": "inhabitantsFromTabs",
        "k": "helper"
      },
      {
        "n": "isOn",
        "k": "helper"
      },
      {
        "n": "lookFor",
        "k": "helper"
      },
      {
        "n": "overviewFor",
        "k": "helper"
      },
      {
        "n": "peekDomainEntities",
        "k": "helper"
      },
      {
        "n": "pillarRoom",
        "k": "helper"
      },
      {
        "n": "primaryActFor",
        "k": "helper"
      },
      {
        "n": "readDomainEntities",
        "k": "helper"
      },
      {
        "n": "readScopeSearch",
        "k": "helper"
      },
      {
        "n": "registerDomainRoom",
        "k": "helper"
      },
      {
        "n": "scopeFromPath",
        "k": "helper"
      },
      {
        "n": "scopeHref",
        "k": "helper"
      },
      {
        "n": "scopeSearch",
        "k": "helper"
      },
      {
        "n": "stripBase",
        "k": "helper"
      },
      {
        "n": "toneFor",
        "k": "helper"
      },
      {
        "n": "turnFor",
        "k": "helper"
      },
      {
        "n": "unscopeHref",
        "k": "helper"
      }
    ]
  }
}
