Skip to main content

Interactives

Per-object regular stream • Files: InteractivesData_<ObjectName>.csv (one per interactive) • Writer: InteractiveDataCapture.cs

Not strictly irregular

Interactives doesn't cleanly fit the regular-vs-irregular framing used for the other streams. It's listed under Irregular here because each interactive's file only exists when that interactive exists and is running — files come and go rather than being a single session-wide stream. But while running, the writer emits one row per LateUpdate, so within any given file the cadence is regular.

If you only read one part of this page, read When it writes.

At a glance

Interactives captures per-interactive-object state — one file per running interactive (named InteractivesData_<ObjectName>.csv), with one row per LateUpdate while the interactive's isRunning flag is true. Each row contains the shared prefix plus runtime object state (position, rotation, scale, active/visible/solid flags, held-object reference) and the object's base, rigidbody, and physic-material settings.

Use Interactives for:

  • Per-object pose/interaction timelines.
  • "What happened to object X during this epoch?" analyses.
  • Held-object / grab / release sequences.

For event-level interactive events (EventPoint fires from interactives, action triggers), use Events — those are logged there as part of the unified event log.

When it writes

LateUpdate, per interactive instance, while both of the following are true:

  • interactive.isRunning (the interactive is active in the current epoch), AND
  • The shared InteractivesDataCapture config has enabledLogging = true.

When either is false, no row is emitted. Note: the InteractivesDataCapture config is auto-created on experience open (see Configuration), so by default new experiences just work — you only need to touch it to disable or override settings.

This is regular per-frame cadence per interactive, but the set of files in a run depends on which interactives existed and ran. A run with ten interactives produces up to ten InteractivesData_*.csv files.

File & location

  • Pattern: InteractivesData_<ObjectName>.csv per interactive, in the run directory.
  • If InteractivesDataCapture.fileName is overridden to e.g. "MyInteractives.csv", per-interactive files become MyInteractives_<ObjectName>.csv.
  • Writer: InteractiveDataCapture.cs in Runtime/UnityComponents/EpochObjects/Interactives/.
  • Observation: Runtime/DataCapture/Observations/InteractiveObservation.cs.
  • State model: Runtime/DataCapture/DataModels/InteractiveState.cs.

Configuration

Shared InteractivesDataCapture SO (subclass of DataCaptureConfig) on the experience controls all per-interactive writers:

FieldWhat it does
enabledLoggingMaster enable/disable for all interactive capture.
fileNameBase filename; each interactive's file appends _<ObjectName>. Default InteractivesData.csv (so files become InteractivesData_<ObjectName>.csv).
flushEveryNRowsBatched flush cadence. Default 30.
writeHeaderWrite the header row on first emission. Default true.

Auto-created on experience open. WindowUtility.OpenExperience() populates this slot if missing. Per-object overrides live on the per-interactive InteractiveDataCaptureSettings (an ExperienceSetting), separate from this shared SO.

Columns

The header combines five column sources in order:

  1. LaboExperienceState.GetColumns() — the shared prefix.
  2. InteractiveRunTimeUtility.GetColumns() — runtime interactive state (pos / rot / scale / flags / held).
  3. interactive.goSettings.objectBase.GetColumns() — base object settings (tag, layer, etc.).
  4. interactive.goSettings.rigidBody.GetColumns() — rigidbody settings (mass, drag, etc.).
  5. interactive.goSettings.physicMaterial.GetColumns() — physic material settings.

Exact column names are defined in those utilities — for the authoritative list, read the header line of a real CSV output.

Runtime interactive state (partial)

From InteractiveState:

ColumnTypeDescription
tagstringUnity tag of the object.
position (X / Y / Z)floatWorld-space position of the object (metres).
rotation (X / Y / Z)floatRotation — likely Euler angles (check header).
scale (X / Y / Z)floatLocal scale.
activeboolUnity activeSelf.
visibleboolRenderer enabled.
solidboolCollider enabled.
held-object reference / idstringThe interactive currently held by this one, if any. NaN when nothing held.

Sample rows

...shared...,tag,posX,posY,posZ,rotX,rotY,rotZ,scaleX,scaleY,scaleZ,active,visible,solid,heldObjectId,...objectBase...,...rigidBody...,...physicMaterial...
...,Stimulus,0.5,1.2,-1.5,0.0,90.0,0.0,1.0,1.0,1.0,True,True,True,NaN,...
...,Stimulus,0.55,1.2,-1.48,0.0,95.0,0.0,1.0,1.0,1.0,True,True,True,ParticipantHand,...

(Trailing columns truncated for readability — a real row has all five column groups.)

Join with other streams

Each interactive's file joins to ExperienceState on FrameNumber, same as any regular stream:

import pandas as pd
exp = pd.read_csv("ExperienceState.csv")
stim = pd.read_csv("InteractivesData_Stimulus.csv")

joined = exp.merge(stim, on="FrameNumber", how="left", suffixes=("_exp", "_stim"))

# Track Stimulus position over the Trial epoch:
trial_track = joined[joined["EpochName"] == "Trial"][["FrameNumber", "posX", "posY", "posZ"]]

To compare two interactives, join each to ExperienceState independently then merge, or join them directly on FrameNumber:

stim = pd.read_csv("InteractivesData_Stimulus.csv")
target = pd.read_csv("InteractivesData_Target.csv")
both = stim.merge(target, on="FrameNumber", how="inner", suffixes=("_stim", "_target"))

Gotchas

  • One file per interactive. File set depends on which interactives ran. Don't assume a fixed list; glob InteractivesData_*.csv and parse the <ObjectName> portion of each filename.
  • Files only exist when the interactive ran. If an interactive was defined but never reached isRunning == true during the session, its file won't exist.
  • Per-interactive headers may differ. Different interactives may have different object/rigidbody/physic-material configurations, so their column sets can diverge. Read each header dynamically.
  • heldObjectId is a string, not a foreign key. It's usually the object name, but "NaN" literal is used for "nothing held". Handle the NaN-as-string case explicitly — it's not a numeric NaN.
  • Event-level interactive behaviour goes to Events, not here. If you want "when was the stimulus triggered" as an event, look in EventPoints.csv with Event_Source = Interactive.
  • Regular cadence inside each file, but the per-interactive framing is irregular across the session. Analyses that assume a single unified stream don't apply — aggregate per-file, or merge multiple files through FrameNumber joins first.

Analysis recipes