Skip to Content
This documentation is provided with the HEAT environment and describes this HEAT instance.

Interface control document

1. Identification

ItemValue
DocumentICD-CMOPENXR-001 rev 1
ProductOpenXR module (HEAT.OpenXR in the module registry)
Product versions coveredv2.0.4
PeerHEAT OpenXR API layer (CaptureApp-OpenXR, a separate installable OpenXR API layer)
HostHEAT Capture, HEAT.Capture.ModuleSDK 2.0.5
Data modelHEAT ProtoLib (bundled with HEAT.Capture.ModuleSDK 2.0.5); SimulationFrame, SpatialComponent, StreamComponent
Date2026-09-01
OwnerVRAI Simulation

Peer-side facts in this document (Sections 4.5, 4.6, 8) are drawn from the peer’s own design documentation in its repository - CaptureApp-OpenXR, docs/superpowers/specs/ - at the commit this document was written against, not from this module’s own source. Verify against that repository directly if the peer has since changed.

2. Scope

This document defines the local named-pipe transport and push protocol between the OpenXR module and the HEAT OpenXR API layer, and the SimulationFrame shape the layer pushes. It does not define the OpenXR API itself, which is the peer’s own concern as an OpenXR API layer - see the Khronos OpenXR specification .

This module is peer-to-product only: it never sends anything to the peer. The peer pushes continuously; this module only receives and republishes.

3. Interface inventory

IDNameDirectionTransportPeer
IF-CMOPENXR-01OpenXR telemetry and video pushPeer to productWindows named pipe, local machine onlyHEAT OpenXR API layer

4. IF-CMOPENXR-01 OpenXR telemetry and video push

4.1 Transport and addressing

ItemValue
ProtocolWindows named pipe (\\.\pipe\heat_openxr_data_pipe by default), this module as client, the layer as server
Pipe nameHeatOpenXRDataPipe, default heat_openxr_data_pipe. It is a hidden module setting, unavailable in the standard settings UI.
DirectionInbound only. The layer’s own IPC server is documented on its side as “an inbound-only endpoint” - it never reads from this pipe, only writes
Wire framingNewline-delimited UTF-8 text lines
Payload encodingEach line is a base64-encoded SimulationFrame protobuf message

4.2 Connection lifecycle

This module connects when a capture session starts and disconnects when it ends - a fresh connection attempt is made for each. The named-pipe client waits up to 5 seconds to connect; a timeout is logged as a warning and treated as a normal retry condition, not a fatal error.

If the connection drops for any reason (peer closed, connect timeout, an internal fault), this module logs HEAT OpenXR data pipe disconnected, reconnecting and retries after 1 second, indefinitely, for as long as the capture session remains active. There is no reconnect limit.

4.3 Authentication

None. A named pipe of this name on the local machine is trusted implicitly; any local process able to open it as a server would be accepted as the peer.

4.4 Message set

There is exactly one message shape: a serialized SimulationFrame, pushed continuously at native rate with no request or acknowledgement in either direction. The command pipe this module previously used to request a capture mode and poll for a reply has been removed; the peer no longer serves it.

4.5 Data elements

Every pushed frame carries one entity, fixed by the peer: id 0x4F505852 (ASCII “OPXR” packed into a uint64), name OpenXR_Data. This module uses that id and name directly; it does not generate its own.

FieldComponentNotes
poseSpatialComponentHead pose
left_controller_pose, right_controller_poseSpatialComponent
left_hand, right_handSpatialComponent
left_image, right_imageSpatialComponentNot populated by this pipeline - the peer’s CPU pixel-readback path was removed when video moved to StreamComponent
sources (up to two VideoSource, named eye.left/eye.right)StreamComponentH264 access units, one per eye when both are healthy for that tick

See Data produced for the full mapping and the video encoding parameters.

4.6 Timing

Pushed at the peer’s native XR tick rate (typically 90Hz for video-capable ticks, subject to a peer-side submission throttle that may push video less often than every tick; pose and hand data follow the same tick). Both eyes’ video for the same tick are correlated and sent together when possible; a straggler eye beyond a bounded wait does not hold up the tick - that frame is sent with only the healthy eye’s video. There is no guaranteed maximum end-to-end latency published by either side.

4.7 Error behaviour

ConditionObservableModule behaviour
Pipe connect times out (5s)Warning logged, HEAT OpenXR data pipe reader failed, reconnecting or a connect-timeout warningRetries after 1s
Peer closes the pipeHEAT OpenXR data pipe disconnected, reconnectingRetries after 1s
A line fails to base64-decode or parse as SimulationFrameWarning logged: Failed to parse SimulationFrame from OpenXR layer payloadThat line is dropped; the reader continues with the next line
No line availableNothing - this is the normal steady state between pushesThe module’s own per-tick poll (HandleCapture) is a deliberate no-op; publishing happens only from the background reader, never from polling

5. Data model reference

Output is HEAT ProtoLib’s SimulationFrame, populating SpatialComponent and StreamComponent as described in 4.5. See HEAT ProtoLib’s message reference for every field on each. This module never populates any other component.

6. Units, frames and conventions

ConceptConvention
PosesXrPosef - orientation plus position, in the peer’s OpenXR tracking space; this module does not convert or reinterpret it
VideoH264-encoded bytes, opaque to this module; pixel/coordinate conventions are the peer’s and the encoder’s
Time baseThe peer’s own frame construction time as carried in the pushed SimulationFrame; this module does not add or override a timestamp

7. Configuration affecting the interface

SettingInterface effect
HeatOpenXRDataPipeSelects the local named-pipe name. This hidden setting defaults to heat_openxr_data_pipe and is not exposed in the standard module settings UI.
EnabledDetermines whether the module runs at all. The host enforces it, not code inside this module.

See Manage capture modules for the generic setting.

8. Compatibility and versioning

This module and the HEAT OpenXR API layer have no protocol version field or version-negotiation step. Deploy matching module and API-layer versions. A version mismatch does not have a defined observable signature: it can produce parse failures, an incompatible payload that parses partially, or no connection at all.

9. Security considerations

There is no authentication and no transport encryption; a named pipe of a known, fixed name is implicitly trusted. Because the pipe is local-machine-only (Windows named pipes are not reachable over the network without an explicit remote-pipe configuration, which neither side sets up), the practical exposure is limited to other processes already running on the same workstation.

This module declares no ModuleCapability at all - local named-pipe IPC to a peer on the same machine is not classified as a mediated or declarative capability in the HEAT Capture module model the way network sockets or device access are.

10. Conformance

  1. Install and enable the HEAT OpenXR API layer, then start a VR application through it. Start a HEAT Capture session with this module enabled.
  2. Confirm the log records HEAT OpenXR data pipe connected, publishing at native rate.
  3. Confirm an entity named OpenXR_Data with id 0x4F505852 appears in the captured data within one native tick, carrying SpatialComponent pose data.
  4. Move the headset and confirm pose updates accordingly; move a controller and confirm left_controller_pose/right_controller_pose update.
  5. Confirm StreamComponent.sources carries at least one VideoSource with codec: "H264" and non-empty video_data.
  6. Stop the layer process while the session is still running. Confirm the log records HEAT OpenXR data pipe disconnected, reconnecting, and that restarting the layer resumes publishing without restarting the capture session.

11. Revision history

RevDateProduct versionChange
12026-09-01v2.0.4Initial issue.
Opens your browser's print dialog. Choose "Save as PDF" as the destination.