Maturity: Draft. Consolidated on 26 September 2026 (the control measurements, natural expressions, cheek range and wrinkle regions of §8 on 27 September) from the installed 2.31 game's resources, its decompiled scripts, the REDmod TweakDB sources shipped with the game, ArchiveXL 1.27.3 and WolvenKit source, installed photo-mode mods, the Modding Docs and the Cyberpunk Blender add-on. Runtime evidence from the bridge's session 4 (28 September; experiment 029) answers which face rig is live and how the expression index is applied (§1, §3). Evidence grades follow the knowledge rules: source engine, framework or tool source or decompiled scripts, resource extracted game or mod resources, wiki Modding Docs text or image, runtime running game, hypothesis not yet established. Provenance, hashes and commands are in the expressions evidence note.
This page answers how V's face gets an expression in photo mode and an idle in the character creator, how mods add to either, and what a Studio expression or idle editor would have to produce. How the facial rig turns controls into bone motion (and the blink in particular) is the subject of Facial animation and the blink; the Studio's current creator-idle preview is described in CC idle. The design options built on these facts are in the expressions and idles brief.
1. The face is driven by controls, not bones
V's face is a solver rig. An animation drives 414 float tracks on the face skeleton, and the facial setup (.facialsetup) turns those values into local bone deltas on 266 of the skeleton's 344 joints resource source.
Track block (in trackNames order) | Count | What it is |
|---|---|---|
| Envelopes | 13 | Global gates: faceEnvelope, upperFace, lowerFace, antiStretch, three lipsync envelopes, jaliJaw, jaliLips, and four "muzzle" mutes for lips, eyes, brows and eye directions |
| Main-pose weights | 141 | The artist-meaningful controls, 0–1 (see below) |
| Lipsync override weights | 86 | …AnimOverrideWeight, reference value 1; lip-sync clips lower them to mute the expression's mouth (lip sync) |
| Lipsync pose outputs | 141 | Despite the name, values lip-sync clips write and the solver adds to the main-pose weights (lip sync) |
| Wrinkle outputs | 33 | Solver outputs, each 1 − (1 − w)² of one control, named after the regions of defaultfaceregions.regionset that the skin shader wrinkles (§8) |
The reference values matter for anything additive: override weights and most envelopes rest at 1 (antiStretch, lipSyncEnvelope and the four muzzles rest at 0), every main pose at 0 resource. The main poses are 121 face poses (with 133 in-betweens, 255 correctives, 68 limits and 31 influences), 12 eye poses and 18 tongue poses that share the two jaw controls [resource: pwa basehead facialsetup, measured by the wiki/add-on survey in the evidence note]. The solver's stages are described, in our own words, in the clean-room facial solver specification, read from the add-on at pinned commit 7a4ee793 source.
Artist-friendly controls exist by name and mostly come in left/right pairs resource:
| Region | Controls |
|---|---|
| Brows | eye_, …raise_, …lower, …lateral |
| Lids | eye_, …widen, …oculi_, …squint_, …squint_ |
| Gaze and pupils | eye_, eye_ |
| Nose and cheeks | nose_, …compress, …breathe_; cheek_, …puff |
| Lips (about 40) | corners up/down/wide/stretch/sharp-up/pull, lips_, …together_, …purse, …funnel, …suck_, …puff_, …tighten_, …upper_, …lower_, …chin_, …mid_, …nasolabialDeepener, sticky-lip cutscene controls |
| Jaw | jaw_, …close, …shift_, …clench |
| Neck and ears | neck_, platysma and sternocleidomastoid flex, neck_, ear_ |
| Tongue | 16 tongue controls |
Because every clip speaks this control vocabulary, an expression is a vector of named control weights, independent of face shape: the same vector plays on any V whose face rig uses the same facial setup [resource; portability across face shapes is a hypothesis to test].
Which facial setup V actually uses
Every vanilla player face_ component, female and male, in the creator, gameplay and photo-mode appearance files, references the male player setup base\, with the gender's own h0_ [resource: face_, …_, ep1\]. Against the female head's own h0_ it has the same track mapping (13/141/86/33), part info, envelopes, limits, influences, main poses and in-betweens, and 254 of 255 face correctives with the same names and drivers (stored in another order; one purse-and-funnel corrective differs by side and in-between), but different pose data: 77 of the 133 main face in-between poses and 238 of the 255 face correctives move other joint lists, by up to 19° and 7 mm; and its useFemaleAnimSet flag is 0 where the female setup's is 1 resource (experiment 031).
In photo mode the engine does use it for the female V [runtime, session 4]. The live face_ sits on the photo-mode stand-in (NPCPuppet), not on the head item Items.PlayerWaPhotomodeHead, which carries no face_, man_ or PhotomodeAnimations at all. The stand-in's face_ reports these path hashes (FNV-1a64 of the lower-case depot path), which match these files [offline]:
| Field | Hash | Depot path |
|---|---|---|
| Facial setup | 6833a322173f7bdd | base\ (the male player setup) |
| Graph | 5e58ab89d2287d68 | base\ |
| Rig | 5af1e771498830a5 | base\ |
The same entity holds man_ (57 gameplay sets) and PhotomodeAnimations (16 sets), all at priority 200, on a profile with the Photomode Facial Expression Mega Pack and one XF Expressions set installed. So the placeholder face_ in player_ isn't the live one in photo mode. Whether the creator and gameplay faces use it too wasn't read.
The difference shows, and the preview now follows the game (design D1, 29 September). Solved on the female skeleton, the two setups put the same expression's joints 1.6 to 5.8 mm apart (median 2.8 mm over the vanilla photo-mode expressions); a smile at 0.5 to 0.7 bunches beside the nose about 9 points less with the male setup (the fold gap closes 38 to 46 % against 47 to 56 %) and lifts the malar cheek 25 to 30 % more [offline] (experiment 031). The Studio's facial host solves with the setup the photo-mode face rig names for the female skeleton, read from the winning .app and its ArchiveXL patches (readFaceRigSetup), so a mod that re-points the face rig is followed; the blink and the idle share that face. The female head's own setup is the fallback and a developer's comparison (XFS_).
2. Which graph drives V's face where
| Context | Face graph (face_ component) | Animation sets on the face | Grade |
|---|---|---|---|
| Character creator and inventory preview ("paperdoll") | _ (male: pma_) | ui_ (priority 128) plus the generic facial sets in man_ | resource |
| Photo mode | player_ (male: player_) | PhotomodeAnimations: ui\ and the empty photomode_ (male twins) | resource; the graph, and both components on the photo-mode stand-in, confirmed in game runtime (§1) |
| Gameplay third-person head | The gameplay face_ appearance also uses the paperdoll graph | as the creator | resource; what plays outside the creator is hypothesis |
| Scenes and dialogue | Scene facial animation and lip sync are pushed through the graph's FacialMixerSlot | facialCinematicAnimSets on the scene; lip-sync sets found through the per-language lipmap, V's included (lip sync) | wiki [resource: slot node present; V has lip-sync sets in 456 scenes, although the wiki's generator guide says V has none] |
Both player face graphs share one spine resource: reference pose, then BlendAdditive (local, tracks added) of the context's clip, then FacialMixerSlot, FacialSharedMetaPose, a facial look-at controller, neck/head twist constraints, eye-direction tracks, and finally the Sermo node that runs the facial setup. The look-at controller plays additive blink clips on gaze changes: additive_ or …blink_ after 0.15 s (minimum transition 0.85 s) and additive_ after 0.25 s (minimum 5 s); these live in generic_ with tiny and normal variants resource. No periodic blink node was found in either graph resource; the creator idle clip bakes its own blinks as tracks (CC idle).
3. Photo-mode expressions
The chain
Arrows
- TweakDB PhotoModeFace record arrow to photo_mode.character.faceAnimations
- photo_mode.character.faceAnimations arrow to Native photo mode sets
- Native photo mode sets arrow to Face graph state machine
- Face graph state machine arrow to photomode_facial_poses.csv
- photomode_facial_poses.csv arrow to Clip by name in the face_rig's
- Clip by name in the face_rig's arrow to BlendAdditive on reference pose,
Boxes
- TweakDB PhotoModeFace record
- (faceId, displayName)
- photo_mode.character.faceAnimations
- (menu list)
- Native photo mode sets
- AnimFeature_PhotomodeFacial.facialPoseIndex
- Face graph state machine
- (two AnimDatabase states,; event updateFacialPose, 1 s blend)
- photomode_facial_poses.csv
- Index → AnimationName
- Clip by name in the face_rig's
- PhotomodeAnimations sets
- BlendAdditive on reference pose,
- look-at, blinks, Sermo solve
Mermaid source
flowchart TD
A["TweakDB PhotoModeFace record<br/>(faceId, displayName)"] --> B["photo_mode.character.faceAnimations<br/>(menu list)"]
B --> C["Native photo mode sets<br/>AnimFeature_PhotomodeFacial.facialPoseIndex"]
C --> D["Face graph state machine<br/>(two AnimDatabase states,<br/>event updateFacialPose, 1 s blend)"]
D --> E["photomode_facial_poses.csv<br/>Index → AnimationName"]
E --> F["Clip by name in the face_rig's<br/>PhotomodeAnimations sets"]
F --> G["BlendAdditive on reference pose,<br/>look-at, blinks, Sermo solve"]
| Link | Evidence | Grade |
|---|---|---|
Record type PhotoModeFace (PhotoModeItem + int faceId; fields displayName, locked) | REDmod database\; PhotoModeFace_ in the decompiled scripts | resource source |
15 vanilla records PhotoModeFaces.facial_ … facial_, faceId 0–14 | REDmod faces.tweak; confirmed present with the same display keys in the installed tweakdb.bin and tweakdb_ | resource |
| The menu lists 12 of them (neutral, charming, furious, bored, pissed, pleased, disgusted, happy, scared, surprised, sadness, whistling); the three singing faces are defined but not listed | photo_ in REDmod photomode.tweak | resource |
AnimFeature_ is the only input | decompiled orphans.script; the graph's animFeatures[0] and two IntInput nodes (group PhotomodeFacial) | source resource |
faceId is passed as facialPoseIndex, and it is the CSV's index, not the menu's option value | photo.expression.index 60 on the stand-in shows "Static: Sleeping" (faceId 60), which the menu offers as option value 56; index 56 shows "Static: Skeptical" (menu value 52). The menu's value is the entry's position in the list; with the Mega Pack and one XF set installed it trails the faceId by 4 at Sleeping and by 10 at the list's end (faceIds 217–219 at menu values 207–209). The Mega Pack's records use faceId = CSV Index for 202 faces | runtime session 4; resource |
Only the stand-in takes the feature: AnimFeature_ applied to the photo-mode stand-in changes the face and holds (5 s and more); applied to the head item it does nothing. Undo through the menu restores it | bridge photo.expression.index on both targets | runtime session 4 |
The CSV anim_ maps Index → AnimationName, streamingContext (photomode), FallbackAnimationName (15 vanilla rows, each its own fallback) | extracted 2D array | resource |
Two AnimDatabase states swap on the external event updateFacialPose with a 1 s linear blend, so changing expression cross-fades | graph | resource |
Vanilla AnimDatabase nodes have isLooped 0: an expression clip plays once and holds | graph; the Mega Pack's override sets it to 1 to loop animated faces | resource |
Clips are found by name among the face_'s animation sets; with duplicate names the first match wins | wiki (custom facial expressions guide); set order within a component is hypothesis | wiki |
| Photo mode menu attribute keys: V expression 28, NPC expression 56 | Photo Mode Pose Selector's Lua | resource |
NPC photo-mode puppets can change expression unless expressionChangingPhotoModePuppet is false for them | photomode.tweak | resource |
What a vanilla expression is
Every vanilla photo-mode expression is a single pose: 2 frames, 0.033 s, all 344 joints at reference and all 414 float tracks stored as constants resource. Fourteen are AdditiveFromRefPose; facial_ is Additive and stores absolute values (envelopes and override weights at 1) instead of deltas resource. Because main poses rest at 0 and the solver clamps weights to 0–1 source, both encodings give the same main-pose weights; they differ only in envelope/override tracks, which saturate hypothesis.
Decoded female clips (photomode_) are sparse control vectors resource:
| Expression | Non-zero controls | Strongest controls |
|---|---|---|
| neutral | 2 | gaze down 0.009 |
| charming | 22 | right sharp corner-up 0.73, right/left corner-up 0.47/0.32, upper lips apart 0.25 |
| happy | 32 | upper lips apart 0.86, right sharp corner-up 0.82, corners up ~0.55, outer squints 0.33 |
| furious | 32 | inner squints 0.9, left snear 0.86, brows lower 0.86, brows lateral 0.84, jaw forward 0.78 |
| scared | 33 | platysma flex 0.98, widen 0.8, inner brow raise 0.65–0.76 |
| surprised | 32 | left widen 0.8, brow raises 0.46–0.62, throat open 0.6 |
| bored | 35 | lips together 0.9, inner brow raise 0.53–0.64, lids 0.18 |
| whistling | 42 | funnel, puff, apart 1.0; gaze out 0.81 |
The expressions are asymmetric by design (charming, disgusted and pissed favour one side), and several hold partly closed lids (bored 0.18, sadness 0.13, whistling ~0.5, singing_01 1.0) resource. Male clips live in photomode_ against the male skeleton; Johnny has his own set resource. The two photomode_ sets attached to V's face rig are empty resource.
4. Photo-mode poses and "idles"
Poses are body clips; faces are separate resource. The full pose chain (lists, records, clip format, the deformation rig and the mod routes) is in poses.
- A pose is a
PhotoModePoserecord (animationName,category,acceptedWeaponConfig,poseStateConfig,lookAtPreset, garment-tag filters,positionOffset,rotation,animationTime,poseSize,allowMoveUpDown), appended tophoto_/mode.character.femalePoses malePosesor a per-NPC list; categories arePhotoModePoseCategoryrecords inposeCategoriesresource source. - The "Idle" category is a pose category, not motion: its vanilla clips (
idle_…stand_ 01 idle_, 133 female clips in_ sniper photomode_) are all 2-frame static poses; the 2.3 "natural" poses are 2–3 frames resource. Photo mode therefore has no body idle loop; the only motion is look-at and the gaze-triggered blinks. Community tools freeze even that with individual time dilation [resource: Photo Mode Pose Selector]._ female_ _ idle.anims - The photo-mode puppet (
player_) runswa_ photomode(_ ep1).ent base\, which carries a workspot slot, a mixer slot,gameplay\ anim_ graphs\ player_ photomode.animgraph AnimFeature_and head/chest rotation features, plus a defaultPhotomodePoseCategory idle_resource. How the engine plays a pose by_ neutral_ _ female_ _ default animationNameis native [hypothesis: through the slot]. - Pose clips carry only 13 body float tracks (body-part visibility, predictive look-at, foot IK) and no face tracks, in vanilla and in every inspected pose pack resource.
5. The character-creator idle
The creator and inventory face graph (player_) selects clips from AnimFeature_, which the preview controller sets from the camera slot resource [source: entityPreviewGameController.script, OnSetCameraSetupEvent]:
| Camera slot | Feature set | Face clip |
|---|---|---|
UI_, UI_ | characterCreation_ | ui_ (loop) |
UI_ | …_, …_ | ui_ once (4.00 s), then ui_ |
UI_ | …_, …_ | ui_ once (5.67 s), then loop |
UI_ | …_, …_ | ui_ once (5.33 s), then loop |
UI_ | …_, …_ | ui_ once (10.00 s), then loop |
UI_ | …_, …_ | ui_ once (5.17 s), then loop |
UI_ | …_, …_ | ui_ (loop) |
UI_ | …_ | ui_ |
| body / other | none of the head flags | ui_, ui_ |
| inventory | inventoryScreen | ui_ once, then ui_ |
The close-up state machine starts in the looping closeup state. Setting a section flag enters that section's one-shot; its end event moves to a second closeup state, which returns to the start only when the flag is false and a 15-second timed condition fires, so a section's showcase clip plays once per visit rather than repeating [resource; the timed condition's exact semantics are a hypothesis]. Transitions blend 0.5 s.
The body graph (player_) loops its own clip per screen: ui_, ui_, the nails loop, gender selection and the inventory's UI_ (body animation §2).
So "the game has one idle" is right for the creator's looping face idle: ui_ (22.07 s, AdditiveFromRefPose, body counterpart 12.33 s in ui_) is the only loop in the close-up view resource. The section clips are Additive one-shot showcases, and the eyes showcase is the strong bilateral brow movement noted in the brow idle gap: it plays when the creator's eyes section is opened [resource; to confirm in game]. They store deltas like the loop (their envelope tracks add 0) resource. The eye camera serves the eyes, eyebrows, eyelash colour and eye makeup rows, and the creator requests a row's camera when the row is hovered or changed, so moving between an eye-area row and any other row can play the showcase again [source; the replay timing is a hypothesis]. Its brows move about 11 times as far as the loop's; the Studio plays it as the Creator close-up, eyes section idle (facial animation §6).
Elsewhere the game has many facial idles, but for NPCs: generic_ holds 20 looping emotion idles (idle_, …joy…, …anger…, …fear… and so on, 21–29 s, AdditiveFromRefPose), used by NPC reactions and by AMM resource. The player's face rig lists these generic sets too resource, but no vanilla graph path was found that loops one on V outside scenes hypothesis.
6. How mods add expressions, poses and idles
| What | Route | Limits | Grade |
|---|---|---|---|
| New photo-mode pose | ArchiveXL animations: entry (entity = scope photomode_ / _ / _ or explicit .ent, set = .anims); TweakXL PhotoModePoses.<id> ($base: PhotoModePoses.idle_) appended to the pose lists, optional category and localisation | Additive and conflict-free; well trodden (45 installed mods use animations:) | resource wiki |
| New photo-mode expression (Photomode Facial Expression Mega Pack) | TweakXL PhotoModeFaces.<id> ($base: facial_, new faceId) appended to faceAnimations; a whole-file replacement of photomode_ with the extra rows; ArchiveXL resource.patch of face_ (and each NPC photo-mode app) re-declaring the PhotomodeAnimations component with the vanilla set plus new sets; whole-file replacements of both photo-mode face graphs to loop animated faces | The CSV and the graphs are single-owner files, so two expression mods conflict; ArchiveXL can merge animation-setup entries and patch entities, apps and meshes, but not 2D arrays or animation graphs; no photo-mode scope covers face apps; 217 rows are shown to work, no list cap found | resource source |
| Replace a vanilla expression | Overwrite a facial_ entry in photomode_ (copy any facial clip and rename it) | Global and exclusive; a fixed set of 12 visible slots | wiki |
| AMM expressions | Runtime: AnimFeature_ applied to the NPC after resetting its reaction manager; clips are the generic NPC facial idles (idle_) | Uses the NPC reaction system, not photo mode | resource |
| AMM poses | Workspot: spawn a collab entity and PlayInDeviceSimple / SendJumpToAnimEnt | AMM-only | resource wiki |
| Creator idle | No mod inspected changes it. Candidate routes: replace ui_, or add a same-named clip at a higher priority through ArchiveXL animations: with component: face_ | Name shadowing by priority is untested | hypothesis |
Adding beside other expression mods. The Mega Pack's patch .app holds V's two photo-mode face appearances, each with one entAnimationSetupExtensionComponent named PhotomodeAnimations (the vanilla component's id), bound to face_ by an entAnimationControlBinding, in the appearance's compiledData package; its menu records use literal displayName strings resource. ArchiveXL merges a patch appearance's components by name and id: a match replaces, anything else is added [source: ArchiveXL 1.27.3 ResourcePatch/ MergeComponents]. So two mods that both re-declare PhotomodeAnimations replace each other's sets, while a component with a new name adds its sets beside theirs; the vanilla appearance already binds two extension components to face_ resource. TweakXL records and !append-once list entries are additive; only the table is single-owner.
ArchiveXL's animations: entries accept entity (path or scope), set, priority, vars and component; entries are appended to the matching entAnimatedComponent's animations.gameplay when it initialises, keyed by the component owner's template path, or by the component name plus that path [source: ArchiveXL 1.27.3 Extensions/, Extension.cpp]. Whether the face rig's owner template is the head item's entity is not established hypothesis.
7. Authoring and export
- An expression exports as a vanilla-shaped clip: one
.animsentry, 2 frames,AdditiveFromRefPose, the face skeleton's 344 joints at reference and 414 constant float tracks carrying the control vector [resource: every vanilla expression has this shape]. An animated expression or idle is the same with keyed tracks at 30 fps [resource: the creator and NPC idles]. Byte layout of a vanilla static face [resource, decoded 28 September]: 1,032 constant joint keys (identical in every static face of a gender's set), then 414 constant track keys in track order, every track but the main poses 0; 19,824 bytes; duration 0.0333333351 s. The Studio writes this layout directly and has WolvenKitdeserializethe set's JSON, since WolvenKit rebuilds a set's data fromanimationDataChunksand each clip'sdataAddressand ignores its own decoded copy on write [source: WolvenKitAnimationReader,animAnimationBufferCompressed]. - WolvenKit can write it.
ModTools.ImportAnimsreads glTF animations withtrackKeys/constTrackKeysextras, keepsanimationType(includingAdditiveFromRefPose), and encodes a compressed buffer by default or SIMD when asked; the format is picked from a.anims.glbfile name [source: WolvenKit 9.0.2 nightlyAnimationTools.cs,ModTools.Types.cs]. It needs the set's rig resolvable from the game archives. Vanilla facial clips use the compressed buffer, so the SIMD re-import caveat in CC idle does not apply to them. Whether the 9.0.1 CLI'simportreaches this path is untested hypothesis. - The Blender add-on round-trips the same
trackKeys/constTrackKeysextras and can solve and preview a facial setup, but has no expression authoring UI and no evidence of a clip being re-imported and played in game source wiki. - Registration follows §6: TweakXL records for the menu, a clip set on the photo-mode face rig through a separately named component, and a CSV row per expression. The table is one file per game: a mod built for the player's own setup carries the installed table's rows; a mod to share can't carry another mod's rows and so conflicts with any other expression mod over the table (export design §6.3).
Nothing in this section has been tried end to end; the first in-game test decides it.
What the Studio's expression editor reads (phase 1)
The expression editor reads the facts above from the player's own files, the way the game resolves them:
- A clip's float tracks sit in its
animAnimationBufferCompresseddata after the joint keys: 8 bytes per key, animated keys asu16normalised time,u16track,f32value, then constant keys asu16track,u16time,f32value; the data is at the clip'sdataAddressin the set'sanimationDataChunks[source: WolvenKitanimAnimationBufferCompressed.ReadBuffer, read and reimplemented]. Decoding the vanilla female set this way reproduces the table in §3 (facial_: upper lips apart 0.86, right sharp corner up 0.82) [offline].happy - The installed expressions on the reference setup: the winning table is the Mega Pack's (217 rows); V's photo-mode face rig and the pack's
resource.patchof it list the animation sets by hash only (ResourcePathstored asuint64in the cooked file), so a reader must look them up by hash; every row's clip is found in an attached set (15 from the base game, 202 from the pack) [offline, 27 September]. - The rig's controls come from the female head's skeleton (
trackNames,referenceTracks) and its facial setup'sinfo.tracksMapping(13 envelopes, 141 main poses, 86 overrides, 33 wrinkles) resource. - Solving one pose with the pinned IO Suite solver takes about 0.7 ms after the setup compiles (about 0.2 s) [offline].
- A change between expressions can play as motion (the drawer's Transitions, design §5.5): the control weights are blended in time before each frame's solve, which is where photo mode's graph blends its tracks, and the default (1 s, linear) is the graph's own
updateFacialPosetransition resource. The Studio solves every frame of the change exactly, so correctives respond as the weights move; whether the game's switch looks the same is open question 9 hypothesis.
8. Natural expressions: FACS on V's rig
What the controls do, measured by solving each one alone with the pinned solver and posing the face skeleton, and checked in the Studio's live preview (natural expressions, experiment 026). All of it is preview evidence on the female head's own facial setup; none is from the game.
Most FACS action units have a counterpart among the main-pose controls: AU1
eye_, AU2[lr]_ brows_ raise_ in …raise_, AU4out …brows_withlower …brows_(which draws the brow toward the nose), AU5lateral …widen, AU6eye_(cheek and lower lid up) with some[lr]_ oculi_ squint_ outer_ lower …outer_(outer brow down), AU7upper …squint_, AU9inner nose_, AU10[lr]_ snear lips_and[lr]_ upper_ raise lips_, AU11[lr]_ pull …nasolabialDeepener, AU12…corner_, AU13up …corner_, AU14sharp_ up …corner_, AU15wide …corner_, AU16dn lips_with[lr]_ lower_ raise lips_, AU17apart_ dn lips_, AU18chin_ raise …purse, AU20…corner_, AU22stretch …funnel, AU25lips_, AU26/27apart_ * jaw_, AU28mid_ open lips_, AU61–64suck_ * eye_[observed] [offline]. The full table, with measured motion, is in the research note.[lr]_ dir_ * Names mislead in places.
nose_flares the nostril and[lr]_ breathe_ in …breathe_narrows it;out lips_lowers that side of the lower lip;[lr]_ lower_ raise lips_seal an open mouth (ARKit'stogether_ * mouthClose) and do nothing on closed lips [offline] [observed].Seven controls move no joint on their own:
lips_,tighten_ up lips_,tighten_ dn jaw_,mid_ clench lips_,corner_ sticky eye_and[lr]_ pupil_ narrow neck_;throat_ adamsApple_ up jaw_only cancelsmid_ close jaw_. Four are modifiers of a partner control (mid_ open lips_change the same lip's seal or puff,tighten_ * jaw_changesmid_ clench jaw_,mid_ close …adamsApple_works againstup …adamsApple_);dn lips_and bothcorner_ sticky …pupil_move nothing in any combination, in the female and the male player setup alike, and none of the seven feeds a wrinkle output [offline]. The Studio's host finds such controls with the solver and the drawer doesn't offer them.narrow The neck and head turn and tilt controls don't move the head.
neck_,[lr]_ turn neck_,up/ dn_ turn neck_,[lr]_ tilt head_andneck_ up/ dn_ turn head_deform neck and jaw-line skin by up to 24 mm and leave the nose and brow in place: they are correctives for head motion the body skeleton drives [offline] [observed].neck_ [lr]_ tilt Ranges differ by an order of magnitude, so a weight means nothing until multiplied by its control's range: at 1,
lips_moves the mouth corner 21 mm and[lr]_ corner_ up lips_the lips 17 mm, while[lr]_ purse …squint_moves the lower lid 1.7 mm andinner …corner_the corner 2.6 mm. Most controls are exactly linear in weight; a few (outer-lower squint, funnel, purse, suck, jaw open) bend by 10 to 22 % [offline].sharp_ up Why vanilla faces look fake, measured: the vanilla smiles keep the eyes 85 to 100 % open (
facial_: lower lid up 0.8 mm, corners up 5.5 to 8.2 mm), so the smile never reaches the eyes; a Duchenne smile with the same mouth closes them to about 63 % (lower lid up 2.4 mm). Several faces drive many controls near their limits at once (happy facial_10 at 0.7 or more,furious facial_19), mix action units that belong to other expressions (surprise with lip purse, funnel and cheek suck; disgust with an open jaw), use controls that move nothing in a still face, or lift one mouth corner more than twice the other (whistling facial_,charming facial_), which reads as deliberate [offline]. The 33 wrinkle outputs are not rendered in the preview, so crow's feet and nose wrinkles are missing there; whether the game renders them for photo-mode faces is open hypothesis.pleased Cheek range (natural expressions §9). At weight 1 the cheek raiser (AU6,
…squint_) lifts the malar cheek 2.6 mm and moves it 4.5 mm, mostly forward; the sneer lifts it 5.6 mm, the smile 3.9, the nasolabial deepener 2.8. Controls add up exactly unless they share a corrective: AU6, AU12, AU11 and AU9 all at 1 lift it 9.5 mm, 2.8 mm less than the sum. Weights clamp at 1. These figures are the female head's setup; the male player setup the game uses lifts the malar cheek more under a smile (1.69 against 1.32 mm at 1) and under the cheek raiser (2.33 against 1.91 mm) but moves it less forward (experiment 031) [offline]. Real smiles move the cheek 4.5 to 7.9 mm at 51 to 59° upward (Fishman et al. 2022) [literature], so the rig's reach is enough;outer_ lower facial_lifts the cheek 3.4 mm under a mouth that on a real face comes with about 4.4 to 5.6 [offline].happy Wrinkle regions. The skin shader's wrinkle rectangles are
engine\: 33 regions named exactly after the 33 wrinkle outputs, each stretch or squash. Crow's feet (materials\ defaults\ defaultfaceregions.regionset …squint_), the nasolabial fold (outer_ lower/ upper lips_), nose lines (*_ corner_ up nose_), forehead and glabella, mouth, chin and neck are covered; the lower lid and infraorbital bulge are not resource. The preview draws none of them, which is much of why its smiles look stiff; whether the engine drives them for photo-mode faces is open (question 8).*_ snear Symmetry and opposing pairs (natural expressions §10). Gaze is anatomical per eye:
eye_andl_ dir_ in eye_are mirror images (both toward the nose), so "both eyes look left" is the left eye'sr_ dir_ in outwith the right eye'sin(both pupils move 4.2 to 4.3 mm toward V's left at 0.5); bothincross the eyes. Every left/right skin pair is an exact mirror image (cosine 1.00). Opposing pairs, proposed by name and confirmed by solving (displacement cosine −0.57 to −1.00; rejected proposals −0.20 or above) [offline]:Axis Ends (negative ↔ positive) Gaze, each eye left ↔ right (left eye dir_↔out dir_, right eyein dir_↔in dir_); down ↔ upout Nostril, each side in ↔ out ( breathe_↔out breathe_, the flare)in Jaw left ↔ right; back ↔ forward Mouth ( lips_)mid_ shift_ * left ↔ right; down ↔ up Face gravity left ↔ right; back ↔ forward Neck turn, neck tilt, head turn and tilt (neck skin) left ↔ right; down ↔ up Tongue base, tongue tip left ↔ right; down ↔ up; base back ↔ front Not opposing (stay separate): brow raise inner/outer, mouth corner up/down, lip suck, puff and part up/down, tongue twist and base forward. The Studio's host confirms the pairs on the setup it solves with and the drawer shows each as one −100 to 100 % control, keeping both raw weights of a mixed pair until it is moved.
Five natural samples (warm smile, confusion, disgust, mild surprise, thinking) are FACS recipes at low to moderate intensity, committed as expression presets in
data/.expression-samples/ MediaPipe's 52 ARKit-named blendshapes can drive V through a mapping onto these controls (7 to 12 ms detection plus a 6 to 8 ms solve per frame). On V's renders they recover gaze, blinks, brow raises and smiles well but miss brow lowering, the nose wrinkle, the upper-lip raise and one-sided mouth movements. On unmirrored frames MediaPipe's Left is the subject's left.
@mediapipe/uploads usage metrics to Google every minute unless the page blocks it [offline] source.tasks-vision
How game expressions read in photo mode (session 4)
At face framing in game [runtime, the maintainer's judgement, 28 September]:
- Expressions look better in the Studio's preview than in game, where they read more comical, and the game's lighting makes a large difference to how well a face renders.
- The Studio's render quality is something the game reaches only under near-perfect lighting.
- Photo-mode expressions usually read as unrealistic and undercut a photo's gravity, unless frozen at a very subtle intensity.
- The cheek bulge beside the nose on smiling is a consistent trait of the game's rig at every framing. The default photo-mode face framing, about 66° at about 35 cm (photo mode §4), exaggerates it, but a portrait lens doesn't remove it (experiment 029).
So the value of authored expressions lies in subtle, low-intensity faces; exporting at a chosen intensity is banked in the backlog.
Open questions
Questions 1 and 2 were answered in session 4 (§1, §3): photo mode's live face rig is on the stand-in and solves with the male player setup, and faceId is the table index, applied only to the stand-in, while the menu's option value is a list position. What remains of them:
- Do the creator and the gameplay head use the male setup too? Their face rig
.appfiles name it resource, and the Studio's idle follows it;face.rig.readin the creator and in gameplay answers it. So does a read with the Mega Pack disabled, which tells which sets are the pack's. - Can table indices be sparse (the database looking rows up by the Index column rather than by position)? That still needs a test table (brief R5).
- Does ArchiveXL
animations:withcomponent: face_reach the photo-mode face rig, and does a higher-priority set shadow a vanilla clip name? (Export no longer needs this: it attaches through a resource patch, §6.)rig - Does a WolvenKit-imported 2-frame
AdditiveFromRefPosefloat-track clip play in photo mode exactly as the preview solves it? - What does the paperdoll graph play on V's face outside the creator, and can a scene or reaction feature drive a looping facial idle on V?
- Can a photo-mode pose clip with many frames animate while photo mode is open, or does photo mode's time freeze it? (The Mega Pack says its animated faces loop, which suggests the face at least keeps time.)
- Do the expression mods' baked blinks stack with the look-at blink additives?
- Does the engine feed the facial solver's wrinkle outputs through
defaultfaceregions.regionsetto the head's skin shader in photo mode and the creator (crow's feet on a close-up offacial_)?happy - Does photo mode's switch between two expressions look like a steady 1 s blend of the two faces (the graph's linear transition on the tracks before the solve), and what does a second switch during a blend start from? Filming a switch from neutral to
facial_beside the Studio's transition at 1 s Linear answers the first part.happy
Related pages
Natural expressions · CC idle · Brow idle gap · Idle controls design · Idle guide · Runtime access · Mod loading · CC file chain · Expressions and idles brief