<!-- 04_VISUAL/xwui/xwui-lib/xwui-lib-super/src/layout/XWUIOrbitStage/XWUIOrbitStage.md -->
# XWUIOrbitStage

Nodes placed around a centre (plnx REF_06 C15): an ellipse of chips with depth cues and auto spin or turn-to-selection, value
rings (a funnel seen from above), a globe of latitude and longitude beacons, a card cylinder seen from the front, a fan of
cards around the selected one, and a dial of gauges joined to the centre by spokes. A centre slot holds any XWUI content; the
centre and the nodes are the anchors of the beams (the XWUIBeamLayer C17 contract). It composes XWUISceneStage (C12) for the
camera, the scene surface, the toolbar, the states and the flat twin, and draws its world through xw3d, so the whole scene is
one view tree with targeted updates.

## How it is drawn (xw3d)

All 3D comes from xw3d; this folder writes no CSS 3D (the old sheet is `XWUIOrbitStage.css.set-aside-20261023`).

| Shape | Backend | World (xw3d) | Overlay (this component, 2D) |
| --- | --- | --- | --- |
| `ellipse`, `dial` | css3d, no GPU context | Guide rings (a `ring` part tilted into the ellipse) and the default centre orb (`orb` part) in one layer | Chips or gauges, spokes, a page-filled centre |
| `concentric` | css3d | One tilted `ring` part per node, lifted along the disc normal, its hue and a turning dot while motion plays | Chips |
| `cylinder` | css3d | Nothing: each card body leans about its own point through xw3d's `lean` effect | Cards |
| `fan` | css3d | Nothing | Cards (rolled and scaled in 2D) |
| `sphere` | webgl (one leased context) | 8 meridian and 7 parallel tori (unlit wires), ONE instanced sphere part for the beacons, a pulse ring on the selection (3 pings) | Focusable chips: hit area, focus ring and tag (the n nearest on the front side: 12 on a phone, 40 on desktop) |

- The nodes stay focusable, named DOM in the 2D overlay on the screen spot of their world point (the stage's own projection, the
  same pixel xw3d draws), so text never blurs in a 3D transform and the DOM order is the angle order.
- The sphere keeps the PX-Cockpit `proj()`: a unit test puts the beacon parts through xw3d's projection and compares with the
  prototype's own function. Webgl wires are tori, not `line` parts: a line ignores rotation, so a turning meridian would rebuild
  its ribbon every frame while a torus is turned in place.
- Spokes stay 2D screen segments between two projected points (xw3d has no line part), so `beamLayerData()` is unchanged.
- When webgl cannot run (no WebGL2, no context, low power) the flat twin is the face; it contains no CSS 3D. The five css3d
  shapes never touch the context manager. Phones draw with antialiasing off.
- The camera is the logic's (it eases, sways and drags); the surface hands every `cameraChange` to xw3d.

## Basic Usage

```example
file: examples/BasicUsage.ts
html: examples/BasicUsage.html
title: Basic Usage
description: Six plan types on a slowly turning ellipse around an orb, with a Pause control and a flat list twin.
```

```example
file: examples/PlanGlobe.ts
html: examples/PlanGlobe.html
title: Plan Globe
description: The PX-Cockpit globe: beacons by latitude and longitude, drag to turn, a Rotate to list.
```

```example
file: examples/GovernanceDial.ts
html: examples/GovernanceDial.html
title: Governance Dial
description: The PX-AIHub dial: feature gauges, spokes to a policy centre, the selected feature eased to the front.
```

```example
file: examples/TemplateShelf.ts
html: examples/TemplateShelf.html
title: Template Shelf
description: The PX-Templates shelf: cards on a cylinder, only the centre card in the tab order.
```

## Data

| Field | Shape | Meaning |
| --- | --- | --- |
| `nodes` | `XWUIOrbitNode[]` | In angle order: the DOM, tab and twin order (never the depth order). |
| `rings` | `{ id, rx, ry, speedDegPerSec?, dashed? }[]` | Ellipse and dial rings in world px of the authored scene; `node.ring` picks one. A ring's own speed (negative turns back) overrides `degPerSecond`. Default one ring per shape. |
| `links` | `{ id, from, to, tone?, label? }[]` | Node to node connections (beams `'links'`); labelled links are read in a hidden list. |
| `selectedId` | string or null | Host-owned; `select` reports a change. |
| `summary` | string | One sentence read with the 3D face (and shown above the twin list). |
| `status`, `statusText` | `'ready' \| 'loading' \| 'empty' \| 'error'`, string | Content state (C12's). No nodes and no centre reads as empty; error offers Try again (`retry`). |
| `centreSlot` | `(host, { shape }) => cleanup?` | Page fill of the centre (runtime only). Runs once per host and survives re-renders. Without it the ellipse, dial and sphere draw an orb. |
| `nodeSlot` | `(host, { node }) => cleanup?` | Page fill of a node body: a chip's extra, a card's content (runtime only). |

`XWUIOrbitNode`: `id`, `label`, `sub?`, `hue?` (token NAME: `teal`, `indigo`, `purple`, `sky`, `fuchsia`, `rose`, `slate`,
`yellow` or a host name; unknown names fall back to slate), `icon?` (XWUIIcon name), `status?` (`ok`, `warn`, `bad`, `info`,
`idle`: health colour AND glyph, and the word in the name), `badge?` (`{ label, tone? }`), `href?` (a link instead of a
button), `ring?`, `angle?` (90 is the front), `lat?`, `lon?` (sphere), `value?` (concentric radius; dial gauge 0..1),
`direction?` (`in`, `out`, `both`: flow on its spoke), `busy?`, `disabled?`, `satellites?`, `content?` (card text).

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `shape` | `'ellipse'` | `ellipse`, `concentric`, `sphere`, `cylinder`, `fan`, `dial`. |
| `depth` | per shape | `{ scale: [back, front], opacity: [back, front] }` (ellipse 0.78..1 and 0.55..1, dial 0.8..1.02 and 0.62..1, sphere 0.62..1.07 and 0.25..1). |
| `rotation` | per shape | `'auto'` spins (ellipse, sphere), `'to-selection'` brings the selected node to the front (dial, cylinder, fan), `'none'` (concentric). |
| `degPerSecond` | `6` | Auto spin speed. |
| `pauseOnHover` | `true` | The spin holds under the pointer (keyboard focus inside always holds it). |
| `valueRadius` | `0.3`, `14` | Concentric radius `max(min, R (value / max) ^ exponent)`. |
| `beams` | `'centre'` for dial, else `'none'` | Spokes to the centre, `links` between nodes, or none. |
| `flowDots` | `true` | Dots travel along beams by direction (only while motion plays). |
| `flatBelow` | `560` | Stage width below which the flat list is the default face (C12 `narrowBelow`). |
| `mirrorInRtl` | `true` | Mirror the arrangement in RTL (never the sphere). |
| `camera` | per shape | C12 config merged over the shape's (mode, rest, range, perspective, scaleToFit, fit, minBlockSize, toolbar, presets, quality, touch). `camera: { fit: 'fill' }` takes the host's whole box. See XWUISceneStage.md, "Sizing: design and fill". Ellipse and concentric tilt with the pointer, the sphere drag-orbits (pitch -42 to 14, free yaw, perspective 1000), the others are fixed. |
| `easing` | `0.08` | Share of the remaining turn per 60 fps frame when turning to a node; 0 snaps. |
| `stepDeg`, `radius` | `24`, per shape | Cylinder step and radius (480); sphere radius (164); concentric outer radius (168). |
| `jumpList` | sphere only | A Rotate to list in the toolbar for nodes the scene can hide. |
| `ariaLabel`, `nodesLabel`, `emptyText` | locale pack | Scene name, node group and twin list name, empty text. |
| `locale`, `numberingSystem` | page language, `'latn'` | Percent and count digits. |

## Events and methods

Events (`on<Event>(handler)` or `logic.on(name)`): `select { id }`, `hover { id | null }`, `rotate { deg }` (every drawn frame),
and through the stage `viewChange`, `cameraChange`, `retry`.

Methods: `select(id)`, `getSelectedId()`, `rotateTo(id)` (shorter way, eased, pauses the spin), `next()`, `prev()`, `play()`,
`pause()`, `getRotation()`, `setRotation(deg, { animate? })`, `setCamera()`, `getCamera()`, `flyTo(name)`, `command(cmd)`,
`setView(view)`, `getView()`, `toggleView()`, `beamLayerData()` (anchors and beams in the C17 contract), `getNodeElement(id)`,
`getSlot('centre' | 'node', id?)`, `getNodes()`, `getElement()`, `getViewport()`, `updateData()`, `updateConfig()`, `destroy()`.
Headless: `logic.stage` is the composed `XWUISceneStageLogic`.

Also `getCanvas()` (the XWUISceneCanvas of the world: `pick`, `project`, `capture`, `getStage()`).

CSS hooks: nodes, beams and the centre move through plain inline `transform`, `opacity` and `z-index` written per frame (no
custom property, REF_11 O-7); `--xwui-orbit-stage-hue` (from `hue`); `--xwui-orbit-stage-card-inline-size` (cards); `[data-side]`,
`[data-flip]` and `[data-tag]` on sphere beacons. The xw3d parts carry `xw3d-part-*` classes plus `xwui-orbit-stage-ring-guide`,
`-ring-disc` (and `-selected`) and `-orb`, which the sheet paints with XWUI tokens.

## Accessibility and RTL

- Nodes are buttons (links with `href`) in DOM order by angle, named label first, then sub, status word, badge (or the dial's
  percent), so colour never carries meaning alone; the selected node is `aria-pressed` (`aria-current` on links). One roving
  tab stop: arrows move it in angle order (mirrored in RTL) and turn the node to the front on a turning shape; Home and End;
  Enter and Space are the native activation. The cylinder and the fan select as the arrows move and only the centre card is
  tabbable. Sphere beacons on the far side are `aria-hidden` and `tabindex=-1`; the Rotate to list reaches them.
- The scene is C12's labelled 3D group (world `aria-hidden`); the nodes sit in its overlay as a labelled group. The flat twin
  (a list of the same nodes) is the default face under reduced motion and below `flatBelow`, and a visible 2D switch.
- Motion: anything that moves on its own (the spin, flow dots, satellites, disc dots, the pulse ring) has a Pause control (WCAG 2.2.2), holds
  under the pointer and while focus is inside, stops off screen and in hidden tabs (the shared playback controller), and does
  not autoplay under reduced motion or on touch-first devices; turns snap under reduced motion. Touch keeps `pan-y`.
- RTL: direction from the parent `dir`. The arrangement mirrors (x negated, the fan and shelf turn the other way), node text
  reads in the page direction, the globe never flips. Western digits unless `numberingSystem` says otherwise.

## Provenance and limits

New component (rung 6, REF_06 C15; reuse ladder in `docs/changes/CHANGE_*_ORBIT_STAGE.md`). Shape maths from PX-Studio,
PX-Integrations, PX-AIHub, PX-Cockpit (`proj()` reproduced by test), PX-Business, PX-Templates and PX-Reports (see the
`XWUIOrbitStage.calc.ts` header). Beams are drawn as straight segments built in; curves, pulses and labels on beams belong to
XWUIBeamLayer (C17), which a host can lay over the stage with `beamLayerData()`.

```api
```
