Narratomidocs
Cast and assets

Looks

How to tint a cast member's avatar per part, name the result, and switch between looks from a variable during play.

A look is a named set of color tints on one cast member. Tints are the only appearance change the studio makes to an avatar: no mesh editing, no texture painting, no swapping parts. A tint multiplies the model's own color, so it shifts a hue and can darken, but it can never repaint a black jacket white.

Add a look

Give the member an avatar

The looks editor only appears on a cast row that has an avatar asset. Pick one first.

Click Add look

You get a row named "Look 1" with no tints yet, and one color swatch per tintable part of that model.

Name it and tint it

Rename the look to something the script can say, such as Salon or Rain-soaked. Then set a swatch. #ffffff is the identity value: white multiplies to nothing, which is why an untouched swatch reads white and the part renders at its original color.

Repeat for each variant. Every look on a member must have a different name, since looks are referenced by name and carry no id. Two looks called Salon on the same member is a DUPLICATE_ID compile error.

Which parts you get

The swatches come from the avatar's material names, read straight out of the file. Narratomi looks for an all-caps semantic suffix, the convention VRoid Studio exports use:

Suffix in the material namePart
HAIRhair
CLOTHcloth
SKINskin
EYEeye
FACEeye

So F00_000_Hair_00_HAIR_01 is hair, F00_001_01_Tops_01_CLOTH is cloth, and M00_000_00_FaceBrow_00_FACE counts as eye, because VRoid's face materials (brow, iris, white) are what eye tinting actually recolors. A trailing number is allowed and ignored.

If no material carries a suffix, which is the normal case for atlas-baked exports and many models made outside VRoid, you get a single swatch labeled whole-model tint instead. The same fallback applies when the file cannot be read for any reason, so a network hiccup degrades to one control rather than none.

Detection is a range request against the file's JSON header, not a full download. The mesh bytes are never fetched to build the swatches.

Switching looks during play

Which look is active is not stored on the member. It resolves from a variable:

Declare the variable

Add an options variable whose choices are the look names, or a text variable. Options is the better fit: the choices are exactly the names, so a typo becomes a compile error instead of a silent no-op.

Point the member at it

Once the member has at least one look, a look var select appears below the swatches. Pick your variable. Single-options variables are listed first, text after.

Set it in the script

set outfit = "Salon" is the whole salon scene. There is no look beat and no stage direction for this.

When a look re-evaluates

Immediately, on every variable change. A tint is a material mutation, not a reload, so there is no scene boundary to wait for: a set beat mid-scene retints the avatar where it stands. This is the one difference from a cast binding, which is sampled once at scene entry.

Applying a look is non-destructive. The first tint captures each material's original color, and every later application re-derives from that capture, so switching between looks never compounds and clearing the variable restores the model exactly.

When nothing happens

If a look does not appear, the resolved value did not match. activeLook returns nothing, silently, in all of these cases:

  • the look variable is unset
  • it holds a value that is not text (a multi-options variable holds a list, which is ignored)
  • it holds a name that matches no look on that member
  • the member has no look variable at all

The compiler catches the typo case ahead of time: a set beat aimed at a look variable with a literal that names none of that member's looks raises UNKNOWN_LOOK_NAME. Setting "" stays legal, since that is how you go back to untinted. A look variable of the wrong type raises LOOK_VARIABLE_TYPE_MISMATCH; it must be text or single-select options.

In the editor's stage viewport there is a helper: a member with looks but no look variable shows its first look, so you can see what you are painting while you paint it.

The ceiling

Tints multiply, and that is where in-app appearance editing stops. Different hair, a new outfit, a changed face: those go back to your avatar tool. See Bring your own VRM.

On this page