Skip to main content
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.
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/.

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:
  • ?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:
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.
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.