LUIDA Docs

Unique avatar per participant

Assign a researcher-supplied VRM to each participant — same avatar every session, or a different one per condition.

Goal

Replace the participant's normal Cluster avatar with a VRM you supply. Either everyone in the experiment gets the same one, or you assign a different avatar per condition for an embodiment manipulation.

Smallest setup

  • A LUIDA scene with at least one state.
  • A .vrm file you can use as the assigned avatar.
  • A Web Console experiment registered (so you can set participantAvatarMode = HIDE).

This recipe is the short version of Tutorial 2 — Priming + Proteus Effect (with LUIDA automation). If you've never done avatar assignment before, do the tutorial once — there are three settings that need to line up and the tutorial walks them all. This page is the lookup-when-you've-forgotten version.

The recipe

Wrap the VRM in the LUIDA avatar wrapper

Import the .vrm into Unity (UniVRM auto-converts it to a prefab). Duplicate the example wrapper from Assets/ClusterMetaverseLab/LuidaExpTemplate/Runtime/Prefabs/Avatars/ and drag the VRM into the wrapper's slot. Save the wrapper somewhere like Assets/_Experiment_/Avatars/my_avatar_wrapper.prefab.

The wrapper provides the CCK Item and AvatarSyncClone.js script — the VRM alone won't animate.

Register the wrapper

LUIDA › Configure avatars+ Add Avatar. Enter my_avatar as the avatarID, drag the wrapper prefab into the slot. Save.

Set participantAvatarMode = HIDE in the Web Console

On the experiment detail page, scroll to World & Platform, set Participant Avatar to HIDE. Save.

Without this, the participant's normal Cluster avatar renders behind your assigned VRM — you'll see double.

Add the assign action on entry

In LUIDA › Configure experiment automation → State-listening Items, find a controller item (any state-listener-bearing GameObject) at the first state of the experiment. Under On State Start, add:

  • Action: AssignAvatarToParticipant
  • avatarID: my_avatar
  • participantIndex: 1

Add the unassign action on exit

In the same row, under On State Exit of the experiment's End state, add:

  • Action: UnassignAvatarFromParticipant
  • participantIndex: 1

Press Play in CSEmulator. The participant's view shifts to the assigned avatar at the start, follows their head and hands throughout the experiment, and disappears at the end.

Why this works

AssignAvatarToParticipant spawns the wrapper prefab as a CCK item at the participant's current world position, then AvatarSyncClone.js reads the participant's bone transforms each frame and applies them to the wrapper. The participant's underlying Cluster avatar is still rendered behind it — participantAvatarMode = HIDE is what makes the underlying avatar invisible so only your wrapper shows.

The wrapper is just a regular CCK item under the hood. The participant doesn't "become" the avatar; they're still controlling their own (now-hidden) Cluster avatar, and the wrapper is a separate visible item that mimics them. This is why bone-attached props (SyncWithParticipantBone) work alongside it without conflict.

See Concepts → Conditions, sessions, participants for how the participant index is resolved, and Editor → Configure avatars for the registry's full UI.

Variants

Different avatar per condition (embodiment manipulation). Add a between-subjects variable role: doctor,control. Register two wrappers (doctor_coat and trainee_outfit). Use the if toggle on the action row:

if (CONDITION["role"] === "doctor") {
  AssignAvatarToParticipant("doctor_coat", 1);
} else {
  AssignAvatarToParticipant("trainee_outfit", 1);
}

LUIDA's balancer alternates role across sessions; each participant gets exactly one of the two avatars for the full session.

Two participants, different avatars each. For a dyad study (pNum = 2):

AssignAvatarToParticipant("instructor_outfit", 1);
AssignAvatarToParticipant("trainee_outfit", 2);

Pair with two unassigns on End:

UnassignAvatarFromParticipant(1);
UnassignAvatarFromParticipant(2);

Mid-experiment avatar swap. Add another AssignAvatarToParticipant("different_avatar", 1) on a later state's On State Start. The action despawns the prior wrapper before spawning the new one — safe to call repeatedly. No explicit unassign needed between the two assigns.

Avatar from the Web Console instead of Unity-side. Upload the VRM via the Web Console's Avatars tab. The runtime falls back to the Web Console registry if the Unity-side AvatarRegistry doesn't contain the ID. Mostly useful for swapping avatars without rebuilding the Unity project.

Defensive unassign at experiment start. If you're worried about state leaking between sessions:

// Very first On State Start of the experiment
UnassignAvatarFromParticipant(1);
AssignAvatarToParticipant("my_avatar", 1);

The unassign is a safe no-op if there's nothing to clean.

Common pitfalls

  • avatarID mismatch. AssignAvatarToParticipant("My_Avatar", 1) won't find anything registered as my_avatar. Case-sensitive, exact string match.
  • Forgetting HIDE mode. With UNRESTRICTED or DEFAULT, you'll see the participant's original avatar rendering behind your wrapper.
  • Spawning the raw VRM. The wrapper structure (with AvatarSyncClone.js) is what makes the avatar follow the participant's pose. The raw VRM just sits in world space.
  • Skipping the unassign. The wrapper persists into the next session if you don't clean up. Always pair an assign with an unassign on a symmetric state boundary.

Where to go next