Cory Policht
← Back to the Devlog
DEVLOG · 2026-09-20 .. 2026-09-24 · BUILD

The look-and-feel wave: Control Room substrate, type scales, and Helper voice.

Spatial Cognition Platform replaces the flat AgentOps room with the immersive Control Room: unifying VR typography, rebuilding pure C# catalogs across scene reloads, tuning orb grab physics, and giving the Helper companion a voice.

WINDOW
Start2026-09-20
End2026-09-24
Kindbuild
Projectsspatial-cognition-platform
Delivered
  • spatial-cognition-platform
    Pure C# substrate catalog restoration across scene reloads
    Fixes the planning table so InstancedPrimitiveCatalogs rebuild lazily from serialized mesh/material arrays on Awake, surviving scene reloads without throwing uninitialized errors.
    spatial-cognition-xr · #575
  • spatial-cognition-platform
    Room-wide two-size type scale and VR typography rules
    Establishes a standardized primary/secondary type scale derived from approved agent labels, utilizing 10x font asset scaling to eliminate TextMeshPro distance blur in headset viewports.
    spatial-cognition-xr · #606
  • spatial-cognition-platform
    Decoupled orb follow physics and flick-to-home classifier
    Implements engine-free HeldOrbFollowModel, decoupling orb orientation from wrist tumbling with gentle yaw springs and adding a flick gesture to return orbs to their seats.
    spatial-cognition-xr · #588
  • spatial-cognition-platform
    Outbound TTS voice synthesis and PCM16 streaming playback
    Connects the Helper companion to homelab TTS routes via a stateless IHelperVoice port and custom RIFF PCM16 decoder, playing audio lines with graceful silent fallback.
    spatial-cognition-xr · #612
  • spatial-cognition-platform
    Universal State Grammar and Control Room fixture integration
    Establishes the state contract across Control Room fixtures, retiring the monolithic AgentOps room in favor of modular gate benches and gateway racks.
    spatial-cognition-xr · #504spatial-cognition-xr · #562

Late August got the Spatial Cognition Platform running on physical Quest headsets without crashing tracking. Late September was about transforming that scaffold into an environment an engineer would actually want to spend hours inside: the Control Room.

We retired the early, monolithic AgentOps room (#504) in favor of modular spatial substrates: a planning table (#575), gate benches (#562), gateway racks, and dedicated orb sockets. Moving from wireframe prototypes to an integrated room revealed dozens of ergonomic and serialization edge cases that only appear under real headset usage.

The first major bug affected the planning table substrate (#575). To achieve zero-allocation rendering for thousands of node links, we use a custom InstancedPrimitiveCatalog. In the initial implementation, Configure() stored the catalog in plain private C# fields. Because plain C# instances are not serialized by Unity, saving a composed scene and reopening it left the catalog null. The moment an operator or integration test loaded the saved scene and applied state, the table threw an uninitialized exception. We resolved this by persisting the underlying mesh and material references in [SerializeField] arrays on the renderer component and lazily rebuilding the runtime catalog on Awake and OnEnable.

VR typography brought its own physical constraints (#606). Rendering small text labels directly in 3D space causes severe TextMeshPro sampling artifacts, leaving node labels muddy and unreadable from distance. We standardized on a strict two-size type scale (Primary and Secondary), authoring font assets at 10x resolution and scaling them down via local component transforms. This produced tack-sharp text across both near-field inspection desks and wall-mounted boards.

Physical interactions were smoothed out with HeldOrbFollowModel (#588). When an operator grabs an agent reasoning orb, rigidly pinning its orientation to the hand controller causes the orb to tumble wildly with every micro-twitch of the wrist. The new model eases position to a forward offset using a tuned spring rate while decoupling orientation entirely, letting the orb maintain a calm, slow yaw rotation. A flick classifier was added to let operators toss an orb back toward its seat with a natural release gesture.

Finally, we gave the Helper companion an audible presence (#612). Built as a stateless outbound port (IHelperVoice) against local TTS endpoints, it streams audio through an engine-free RIFF PCM16 decoder. If network latency spikes or the TTS endpoint is offline, the synthesis fails completely silent, ensuring voice playback never blocks core room simulation.

Lessons learned

  • Rebuild pure C# catalogs lazily from serialized arrays across scene loads. Unity’s scene serialization will silently drop any state held in standard C# data structures that do not inherit from UnityEngine.Object. To survive scene reloads, serialize raw primitives (mesh IDs, material arrays) in component fields and expose a lazy restore method that reconstructs runtime caches on first access.
  • Scale down large font assets in transforms to keep VR text crisp. Small font point sizes in TextMeshPro render poorly when magnified in stereoscopic VR. Rendering fonts at ten times normal size onto high-resolution SDF atlases and scaling the transform down by 0.1 creates crisp, legible text across varying view distances.
  • Decouple held object rotation from controller wrist tumbling. Rigidly coupling 3D interactive objects to raw controller quaternions exaggerates wrist movement and makes inspected data difficult to read. Easing position to controller-forward while keeping object rotation on a calm, independent spring produces an interaction feel that is tactile rather than erratic.
  • Keep audio synthesis ports stateless and fail-silent. Ancillary features like companion voice acting or sound cues should never be load-bearing. Modeling voice synthesis as a stateless HTTP client with automatic fallback ensures that a missing audio pack or an inference timeout never interrupts room-scale tracking.