> ## Documentation Index
> Fetch the complete documentation index at: https://sdlc-rstack.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Studio (3D)

> Agent Force Studio — a live 3D office visualization of a governed RStack run, with rooms per governance area, agents walking between desks, and a cinema-mode camera director.

Agent Force Studio (`/studio3d`) is a real-time 3D rendering of a run's operational state — the same
governed data the Business Hub's dashboard pages render, staged as an office building: rooms for
Governance, the Evidence Vault, the Skills Library, Orchestrator HQ, and desk pods for builder and
validator agents, with an orchestrator "manager" model that walks the floor in response to real
observed events. It exists to make an unattended, long-running governed pipeline legible at a
glance — pending approvals read as a red desk light and a closed gate, not a row in a table. The
semantic (2D) DOM is built first and remains the canonical interaction tree; the 3D scene is a
layer on top that can fail or be turned off without losing any information.

<Info>
  This is a separate page/document from the dashboard's 2D "Studio" tab (`ui/pages/studio.js`, served
  inside the main Hub SPA). `/studio3d` is its own standalone HTML document (`ui/studio3d.js`) with
  its own bundle of client modules under `ui/studio3d/`.
</Info>

## How it works

**Document and module loading.** `studio3dHtml()` in `ui/studio3d.js` writes an inline
`<script type="importmap">` before any module loads, because the WebGL and WebGPU builds of
`three` cannot be mixed in one module graph:

```js theme={null}
var force = new URLSearchParams(location.search).get('gpu');
var useGpu = force === 'force' ? true : force === 'off' ? false : Boolean(navigator.gpu);
var three = useGpu ? '/studio3d/vendor/three.webgpu.js' : '/studio3d/vendor/three.module.js';
```

* `?gpu=off` always pins the classic WebGL build.
* `?gpu=force` exercises the WebGPU-node build's WebGL2 backend fallback path, for verification on
  any browser.
* Otherwise the choice follows `navigator.gpu` — browsers without WebGPU get the classic build.

Even on the WebGPU-node build, `scene.js` self-falls-back: if the adapter is refused, `WebGPURenderer`
runs on its WebGL2 backend rather than failing. Diagnostics expose which path is actually active via
`gpuTier`: `'webgl'` (classic build), `'webgpu'` (real WebGPU backend), or `'webgpu-node:webgl2'`
(node build, WebGL2 fallback engaged).

**Composition root (`studio3d/app.js`).** `createStudioDom()` builds the semantic DOM first; a
WebSocket-driven transport (`createStudioTransport`) feeds it validated snapshots
(`validateStudioSnapshot`). Only if the browser supports WebGL2 (`supportsWebGL2()`, an actual
`canvas.getContext('webgl2', ...)` probe) does `ensureScene()` dynamically `import('./scene.js')`
and build the 3D scene; any failure — no WebGL2, an import error, or a runtime
`onRendererState('semantic-fallback')` callback — falls back to `data-renderer="semantic"`, hiding
the canvas and showing the `#studio-fallback` banner with the semantic mirror still fully live. A
`Semantic view` toggle button lets a user force `data-renderer="semantic-only"` regardless of 3D
support.

**Theme.** `currentTheme` is `'twin'` (Digital Twin, the default) or `'classic'`, persisted in
`localStorage` under `rstack.studio.theme`. Toggling rebuilds the scene from scratch
(`scene.destroy()` + re-`ensureScene()`) rather than live-restoring materials — "cheap and rare"
per the code comment, and the only path that can't drift.

**Rooms and layout (`studio3d/topology.js`).** `STUDIO_TOPOLOGY` is a single frozen object
describing a rectangular cutaway floor: a north wing (Skills Library, Orchestrator HQ, Governance,
Evidence Vault), a central east-west corridor, and a south wing (Builder Bullpen, glass Validator
Lab, dispatch/reception). It owns positions, door coordinates (`DOORS.library`, `.hq`,
`.governance`, `.vault`, `.bullpen`, `.lab`), and deterministic corridor routes (`corridorRoute()`,
`routePoints()`) — purely spatial data with no runtime state, so it can't drift from the server's
projection. `pipelineStageX()` maps a stage index onto the compact department spine; department,
mission-board, builder-desk, and validator-desk slots are generated with `row()`/`slot()` helpers.

**Click-a-room.** `scene.js`'s `enterRoom(ref)` resolves an authored anchor + doorway per room id
(`roomDoor()` recognizes `library`, `hq`, `governance`, `evidence`, `builder`, `validator`,
`dispatch`), drops the camera just inside the doorway looking in, and lights an interior point
light. Pointer clicks are raycast (`onPointerUp`) against the scene: an agent/entity hit (any mesh
carrying `userData.entityRef`/`entityRefs`) takes priority over the room it stands in; otherwise a
hit on a room-tagged mesh or an ancestor group's `userData.roomRef` resolves via `roomRefFromHit()`
and calls `selectRoom()`.

**Cinema camera director.** `directorShot()` (called every `DIRECTOR_HOLD_MS` = 9000ms while
`director.mode === 'cinema'`, the default mode) picks a shot from the same live projection the
semantic DOM renders, in priority order:

1. If `projection.approval_summary.pending_count` is truthy, frame the Governance room.
2. Else round-robin through sessions with `status` `'active'` or `'starting'` that have a resolved
   workstation, holding each for one cycle (`director.tourIndex`).
3. Else fall back to the authored overview camera (`STUDIO_TOPOLOGY.overviewCamera` /
   `overviewTarget`).

Any manual camera grab, a click-selection, `enterRoom()`, or the `Overview` button exits cinema to
`'explore'` mode instantly (`setDirectorMode`). A `Follow` mode also exists: the camera preserves
its current offset and glides after one entity's live position every frame
(`updateFollowCamera()`), stepping instead of gliding under reduced motion.

**Agents as robots.** Agent sessions render via `reconciler.js`/`robot.js`/`locomotion.js` as
walking figures that move along `corridorRoute()`-generated paths between desks (builder pods vs.
the validator lab, chosen by `session.role` in `workstationSlot()`), synthesizing stride animation
procedurally rather than depending on baked walk clips.

**Reduced motion / diagnostics.** `app.js` reads `prefers-reduced-motion` and a persisted
`rstack.studio.motion` override, applied via `scene.setMotion(mode)`. `onDiagnostics` reports
`qualityTier`, `gpuTier`, draw calls, triangle count, active rigs/transitions/captions, and manager
position/action back onto `app.dataset.*` attributes for external inspection.

## Try it

Open the Business Hub (`npm run business`) and navigate to `/studio3d` from a run scope, or link
directly:

```text theme={null}
http://localhost:3008/studio3d              # default: WebGPU if the browser supports it
http://localhost:3008/studio3d?gpu=off       # force the classic WebGL build
http://localhost:3008/studio3d?gpu=force     # force the WebGPU-node build (WebGL2 backend fallback)
```

In the 3D view:

* Click any room (Governance, Evidence Vault, Skills Library, Orchestrator HQ, Builder Bullpen,
  Validator Lab, Dispatch) to focus the camera and open its inspector panel.
* Use **Take control** / **Cinema mode** to toggle between the hands-free director and manual
  orbit controls; **Overview** returns to the authored wide shot.
* **Classic look** / **Studio look** switches the Digital Twin ↔ classic palette (rebuilds the
  scene).
* **Semantic view** forces the 2D DOM-only mirror, useful for accessibility review or when the 3D
  view can't run.

If the browser lacks WebGL2 or the 3D module fails to load, the page degrades automatically to the
semantic mirror — same data, no 3D.

<Note>
  The 3D module list (`office.js`, `robot.js`, `animator.js`, `captions.js`, `transitions.js`,
  `behavior.js`, `geometry.js`, `assets.js`, `model.js`, `transport.js`) was skimmed rather than
  fully read for this page; room *identities*, the click-a-room mechanism, the cinema director's shot
  priority, and the WebGPU/`?gpu=` fallback behavior above are drawn directly from `app.js`,
  `topology.js`, and the read sections of `scene.js`. Finer detail on robot rigging, captions, and the
  office mesh-building code is not covered here.
</Note>

## Related

* [Business Hub overview and navigation](/business-hub/overview-and-navigation)
* [Cockpit controls](/business-hub/cockpit-controls)
* [Data visualizations](/business-hub/data-visualizations)
* [Operations Center](/business-hub/operations-center)
