MentalWorkload (MentalWorkloadData, OnMentalWorkloadResult). Fatigue, Attention, and Mental Readiness use their platform names. Code identifiers below are shown verbatim.Install the base dependencies if they are not already present.
TextMeshPro (com.unity.textmeshpro) ships with Unity. No separate install needed. The first time a scene requires TMP, click Import TMP Essentials when prompted.
https://github.com/harmoneyes/HarmonEyesSDK/raw/main/HarmonEyesSDK.unitypackage
In Unity, choose Assets › Import Package › Custom Package… and open the HarmonEyesSDK.unitypackage you downloaded. Leave all boxes checked and click OK.
The SDK ships with a Mock Tracker sample that lets you exercise the SDK and validate your license key without a Vive or Meta Quest Pro headset connected. It can also replay CSV recordings captured by the Vive or Meta sample collectors, so you can re-run the SDK against a known data stream.
Assets/HarmonEyesSDK/Samples/HarmonEyesMockTrackerSample/Scenes/HarmonEyesMockTrackerSampleScene.eyetrackingsample_meta_quest_pro.csv) is assigned by default; drag in your own recording to replay it.The Unity SDK turns raw eye-tracking data from a supported headset or webcam into four real-time capabilities: Cognitive Load, Fatigue, Attention, and Mental Readiness. It is delivered as a Unity package: a native theia library, a C# wrapper, three platform sample scenes (Meta Quest Pro, HTC Vive Focus Vision, and a headset-free Mock player), and editor scripts.
| Capability | Levels | Cadence | Key payload fields |
|---|---|---|---|
| Cognitive Load | Low / Moderate / High | per native batch (~1s) | level, confidence, prob_high, batch_number |
| Fatigue | Alert / Neither / RatherDrowsy / Drowsy | per native batch (~1s) | level, confidence, batch_number, ttt_level, ttt_minutes |
| Attention | Narrow / Mod-Narrow / Neither / Mod-Broad / Broad | continuous | level, label, composite_score, total_observations |
| Mental Readiness | low % / moderate % / high % | once min session length met | low_percentage, moderate_percentage, high_percentage, total_predictions |
| Tracker | Native preset | Sample scene |
|---|---|---|
| Meta Quest Pro | Quest (72 Hz) | Meta Quest Pro sample |
| HTC Vive Focus Vision | Quest preset (closest match) | Vive Focus Vision sample |
| Pupil Labs Neon | PupilLabs (200 Hz) | Mock Tracker sample (CSV playback) |
| Webcam desktop trackers | Webcam (30 Hz) | — |
| Ganzin | Ganzin (60 Hz) | — |
For any tracker not listed, select the nearest lower-Hz preset.
A license key is required. Contact us to obtain one. The same key is entered on the AnalyzeEyeTrackingData component in each sample scene.
A custom integration is three steps.
Add the AnalyzeEyeTrackingData component to a GameObject, enter the license key, and pick the tracker preset that matches your hardware (or the closest sample-rate match, rounding down). The component handles native SDK creation, license validation, and session start automatically on Start. Read AnalyzeEyeTrackingData.Instance.EyeTrackingInitCompleted to know when initialisation has completed.
using UnityEngine;
using HarmonEyes.EyeTracking.Common;
public class MyCollector : MonoBehaviour
{
[SerializeField] private Camera headCamera;
void FixedUpdate()
{
var analyze = AnalyzeEyeTrackingData.Instance;
if (analyze == null || !analyze.EyeTrackingInitCompleted) return;
long timestampNs = (long)(Time.timeAsDouble * 1e9);
// Pull per-eye origin, orientation, closed-weight and a blink
// decision from your platform's API.
Vector3 leftEyeOrigin = Vector3.zero;
Quaternion leftEyeOrientation = Quaternion.identity;
float leftEyeClosed = 0f;
Vector3 rightEyeOrigin = Vector3.zero;
Quaternion rightEyeOrientation = Quaternion.identity;
float rightEyeClosed = 0f;
bool isBlinking = false;
Sample s = GazeDataSampleFactory.CreateGazeSample(
analyze.SessionId, timestampNs,
leftEyeOrigin, leftEyeOrientation, leftEyeClosed,
rightEyeOrigin, rightEyeOrientation, rightEyeClosed,
headCamera.fieldOfView,
isBlinking);
analyze.SubmitGazeSample(s);
}
}
Polling: read the latest payload on demand:
var mw = analyze.EyeTrackingAnalyzer.CurrentMentalWorkload; // Cognitive Load
if (mw != null) Debug.Log($"Cognitive Load: {mw.LevelName} (conf {mw.confidence:F2})");
Event-driven: subscribe once, react to each new prediction:
analyze.EyeTrackingAnalyzer.OnMentalWorkloadResult += mw =>
Debug.Log($"Cognitive Load: {mw.LevelName} (conf {mw.confidence:F2})");
Real-time Cognitive Load, Fatigue, Attention, and Mental Readiness from eye-tracking hardware. Every type below lives in the HarmonEyes.EyeTracking.Common namespace.
Cognitive Load and Fatigue refresh once per second (edge-triggered when a new native batch arrives); Attention updates continuously as fixations and saccades accumulate; Mental Readiness is computed on demand from accumulated Cognitive Load predictions. Each payload carries a monotonically increasing counter (batch_number, total_observations, or total_predictions) so consumers can edge-trigger UI updates.
LicenseKey field. It is validated synchronously during Start(); success or failure is logged to the Unity console.Instance.EyeTrackingData.Samples each tracker frame.On scene start, validation happens automatically. Two boolean flags expose the outcome:
if (AnalyzeEyeTrackingData.Instance.LicenseKeyValidated) { /* SDK is live; start submitting samples */ }
if (!AnalyzeEyeTrackingData.Instance.EyeTrackingInitCompleted) { /* missing/invalid key */ }
Per-frame eye data is built into a neutral Sample via GazeDataSampleFactory.CreateGazeSample, then submitted via SubmitGazeSample. Accumulated samples are pushed to the native SDK once per second. The factory projects each eye’s gaze ray onto a 1600×1200 virtual screen at 600 mm using the supplied FOV.
Subscribe to callbacks, or poll the Current* properties (all nullable, so null-check before use).
var a = AnalyzeEyeTrackingData.Instance.EyeTrackingAnalyzer;
a.OnMentalWorkloadResult += mw => Debug.Log(mw.LevelName); // Cognitive Load
a.OnFatigueResult += fat => Debug.Log(fat.LevelName);
a.OnAttentionResult += att => Debug.Log(att.label);
a.OnMentalReadinessResult += mr => Debug.Log($"low {mr.low_percentage:F0}% / high {mr.high_percentage:F0}%");
a.CurrentMentalWorkload // MentalWorkloadData, nullable (Cognitive Load) a.CurrentFatigue // FatigueData, nullable a.CurrentAttention // AttentionData, nullable a.CurrentMentalReadiness // MentalReadinessData, nullable
Scene-level singleton MonoBehaviour. Owns the native SDK lifecycle and the 1 Hz analyzer pump. Exactly one instance must exist in the scene.
| Inspector field | Type | Description |
|---|---|---|
| LicenseKey | string | Your HarmonEyes license key. Required. Validated synchronously in Start(). |
| Tracker | TrackerType | Native preset. Default Quest. Values: Nexus (Webcam 30 Hz), Ganzin (60 Hz), Quest (72 Hz, also Vive Focus Vision), PupilLabs (200 Hz). Pick the closest sample rate, rounding down. |
| logMentalWorkload, logFatigue, logAttention, logMentalReadiness | bool | When true, writes each new prediction for that capability to the Unity console. |
| Property | Type | Description |
|---|---|---|
| Instance | static | In-scene singleton and interface to the SDK. |
| EyeTrackingInitCompleted | bool | True once the SDK is ready to accept samples. |
| LicenseKeyValidated | bool | True if the license key passed validation. |
| EyeTrackingData | EyeTrackingData | Shared per-session buffer of collected Samples. |
| CurrentMentalWorkload / CurrentFatigue / CurrentAttention / CurrentMentalReadiness | nullable | Latest prediction for each capability (on EyeTrackingAnalyzer). Null until the first result arrives. |
Static class. Builds Sample records; hides the XY projection, per-session blink-ID iteration, and pupil-diameter computation.
public static Sample CreateGazeSample(
string sessionId, long timestampNs,
Vector3 leftEyeOrigin, Quaternion leftEyeOrientation,
Vector3 rightEyeOrigin, Quaternion rightEyeOrientation,
float fovDeg, bool isBlinking,
double pupilDiameterLeft = 0.0,
double pupilDiameterRight = 0.0);
Returns a Sample populated with the timestamp, left/right eye screen XY (pixels), optional pupil diameters, and a monotonic blink ID. EndSession(string sessionId) clears the per-session blink-ID counter, an optional cleanup when many sessions run in one app.
Thin C# wrapper around the native theia C API, managed by AnalyzeEyeTrackingData. Documented for advanced users. Normal integrations don’t call it directly.
GetCurrentMentalWorkload/Fatigue/Attention/MentalReadiness(EyeTrackingData)SetMentalReadinessMinSessionSeconds(double)IsRunning()FeatureVersion()GetLicenseInfo()One frame of eye data in the neutral shape the analyzer consumes. Build with CreateGazeSample.
| Field | Type | Description |
|---|---|---|
| timestampNs | long | Monotonic timestamp in nanoseconds relative to session start. |
| leftEyeX, leftEyeY, rightEyeX, rightEyeY | float | Per-eye gaze point in virtual-screen pixels (0–1600, 0–1200). Zero during blink frames. |
| pupilDiameterLeft, pupilDiameterRight, pupilDiameter | double | Pupil diameters in mm. 0 if unknown. |
| blinkId | int | Monotonic per-blink ID during a blink (1, 2, 3…); -1 when not blinking. |
| Class | Capability | Fields |
|---|---|---|
| MentalWorkloadData | Cognitive Load | level (0/1/2), confidence, batch_number, LevelName ("Low"/"Moderate"/"High") |
| FatigueData | Fatigue | level (0–3), confidence, batch_number, ttt_level, ttt_minutes, LevelName |
| AttentionData | Attention | level (1–5), label, composite_score (0–1), total_observations |
| MentalReadinessData | Mental Readiness | low_percentage, moderate_percentage, high_percentage, total_predictions |