Data produced by the Varjo gaze module
This module parses and republishes whatever SimulationFrame bytes the bundled native bridge
produces - it does not rebuild the frame or generate its own entity id or name.
Entity
Every frame carries a single fixed entity: id 0x56415246, name Varjo_Data.
Gaze and head pose - every tick, independent of video
The bridge emits head pose and gaze/pupillometry as their own frame every tick, decoupled from
whether video capture is running. If the Varjo runtime reports no valid gaze for a tick - the
headset removed, gaze tracking not calibrated, and so on - no frame is emitted for that tick at
all, rather than one with zeroed fields. Check GetGazeTrackingStatus behavior in
Troubleshooting before assuming a gap is a bug.
Populated on GazeComponent: IPD, gaze_origin,
left_gaze_origin, right_gaze_origin, gaze_direction, left_gaze_direction,
right_gaze_direction, left_eye_occluded, right_eye_occluded, blink. Not populated:
has_glasses, gaze_point, gaze_screen_point, or any *_quality field.
The direction fields’ Z axis is sign-flipped from Varjo’s own coordinate convention before publishing - a deliberate axis conversion in the bridge, applied identically to the combined and both per-eye direction vectors.
left_eye_occluded/right_eye_occluded come directly from Varjo’s own per-eye gaze validity
status, not from an eyelid-openness measurement; blink is then derived as
left_eye_occluded OR right_eye_occluded. This is the reverse of how some other eye-tracking
modules in this catalogue derive the two - here, occlusion is the primary signal and blink is
derived from it, not the other way round.
Populated on PupillometryDataComponent:
left_eyelid_openness, right_eyelid_openness, left_eye_pupil_diameter,
right_eye_pupil_diameter. Not populated: the combined eyelid_openness or pupil_diameter
fields (this bridge does not average left and right into a combined value), any *_quality
field, or other_pupil_data.
Video - only when enabled and licensed
When EnableVideoCapture is on, each eye’s encoder emits its own independent frame as its H264
access unit completes - the two eyes are not combined into one frame. Each video frame also
carries the same head pose for that tick on SpatialComponent.pose, and may additionally carry
its own copy of that tick’s gaze/pupillometry snapshot. If a video frame does carry gaze data,
treat it as the same sample already seen on that tick’s dedicated gaze frame, not a second,
independent reading - do not double-count or average the two.
Carried on StreamComponent, as one VideoSource per
frame, named eye.left or eye.right:
| Parameter | Value |
|---|---|
| Codec | H264, Annex-B access units, one independent stream per eye |
| Bitrate | ~8 Mbps per eye, constant bitrate |
| GOP size | 90 frames (~1 second at native cadence), no B-frames |
This module does not decode H264 or inspect its content; a consumer needs its own H264 decoder, and must feed each eye’s access units to it in the order received - the encoding depends on frame order, so skipping one corrupts everything after it until the next keyframe.
Backpressure
The bridge holds up to about a second of frames (gaze and video together) in a bounded queue. If this module does not drain it fast enough, the bridge drops the oldest queued entry and forces a fresh keyframe on the affected eye rather than let the queue grow further - a visible discontinuity in that eye’s video, not a delay. See Configure for the setting that controls how often this module drains the queue.