Maturity: Draft. Consolidated from the installed 2.31 facial rig, facial setups, morph targets and face animation sets, read offline with WolvenKit and the Cyberpunk Blender Add-on's facial solver on 23 to 27 September 2026; §1 revised on 28 September from the clean-room reading of that solver, and §1 and §5 again the same day when XF Studio's own solver replaced it in the app. Nothing here has runtime evidence of its own except the report in §7. Evidence grades follow the knowledge rules: source engine, framework or tool source, resource extracted game or mod resources, wiki Modding Docs, runtime running game, hypothesis not yet established. Measurements, hashes and commands are in the game's blink and character-creator idle.
This page answers how V's face is animated, and in particular how a blink closes the eyes, and what the Studio reproduces.
1. From control values to moving bones
Clip (float tracks over time) → added to the rig's referenceTracks → 414 control values → .facialsetup (envelopes, limits, influences, inbetweens, main poses, correctives) → solver → local rotation and translation per joint → .rig (344 joints) → skinning of the head, eye, brows, lashes and face decals.
- A face clip animates controls, not bones: float tracks such as
eye_(track 21),l_ blink eye_(22),r_ blink eye_(114) orl_ dir_ dn jaw_. The female head rig has 414 tracks and 344 joints resource.mid_ open - Face clips are mostly
AdditiveFromRefPose: their values add to the rig'sreferenceTracksresource. Of the 13 envelope tracks,faceEnvelope,upperFace,lowerFace, the left and right lipsync envelopes and the two JALI strengths rest at 1;antiStretch,lipSyncEnvelopeand the four muzzles rest at 0 resource. Playing such a clip as bone animation gives a static face resource. - The
.facialsetupturns controls into joint motion in three parts solved in turn (tongue, eyes, face), each in stages: envelopes (muzzles mute the eye, brow and gaze groups), speech limits, influences between poses, upper/lower-face scaling, lipsync overrides, added lipsync poses, influences again, in-betweens, correctives that fire on combinations of poses and in-betweens, corrective influences, pose blending, then wrinkle outputs. Poses are local rotation/translation deltas applied after each joint's rest: translations add, rotations are post-multiplied, each scaled toward identity by normalised lerp. Every joint a pose moves on the female head has an identity rest rotation and unit scale [resource, reference: the IO Suite solver]. The full behaviour, with the data fields and edge cases, is the facial solver specification. - At rest
lipSyncEnvelopeis 0, which switches the speech limits and lipsync overrides off entirely; a limit also needsmuzzleLipsraised to pull a weight down [reference]. - The IO Suite does not read
faceEnvelope,antiStretchor the left/right lipsync envelopes, ignores the setup's scale poses (the pupil narrow and wide poses scale the pupil joint; one tongue pose scales too), and treats a corrective-entry flag as a minimum LOD, so three lip correctives (lips_and the twotogether_ dn_ _ Corr jaw_) never fire at full detail. The ignored pupil scales are why the Studio's inert-control check finds that bothmid_ open0_ _ lips_ together_ *_ _ Corr …pupil_controls move nothing. Whether the game does the same is open in each case (specification §7) [resource, reference; game behaviour a hypothesis].narrow - The Studio solves the face itself. XF Studio's own MIT solver (
src/), written from the clean-room specification, matches the add-on's pinned solver, run as a black box, on all 2,558 parity cases (3,456 frames: every pose, in-between, influence, corrective, muzzle and lip-sync case, the blink, the creator idle, the vanilla expressions, 1,300 random vectors and the male setup) within 1.6 × 10⁻⁶ rad, 1.6 × 10⁻⁸ m and 1.6 × 10⁻⁷ on the wrinkle and processed tracks; a solve takes 0.003 to 0.09 ms (specification §10) source. The app reads the rig and setup with its own reader (archive formats §13) and needs neither Python nor WolvenKit for the face. The add-on's code is never copied into the app (it is GPL-3.0-or-later); its solver remains a developer's parity oracle source.engines/ facial-rig/ solver.ts
2. How a blink closes the eye
| Fact | Detail | Grade |
|---|---|---|
| Controls | eye_ / eye_, one per eye; 0 open, 1 closed | resource |
| Main poses | Face part poses 8 and 9, a single inbetween at 1.0 (the weight is the control value), envelope muzzleEyes (LOD 1), no limit, not scaled by upper/lower face; each suppresses its side's eye_ | resource |
| What moves | 30 joints per side: the upper and lower lid roots, upper rows A–D, lower rows A–B, the inner corner, three eye_, the eye's wetness root, three nasolabial joints. The lid roots sit exactly on the eye joint, so the lids turn about the eye centre: about 37° at the upper root, up to 58° at an upper row | resource |
| Lashes | The eye_ joints hang under the lid rows and have no pose of their own: they follow the lid through the hierarchy | resource |
| Correctives | 38 face correctives name a blink. eye_ fires with every blink but carries no transforms in the female setup; the rest combine the blink with gaze, squints or brows and act only when those move too | resource |
| Timing, gameplay | generic_ holds additive_ (0.33 to 0.57 s) and eyes-closed clips. The normal blink reaches 1.0 at 0.10 s and is open again by about 0.33 s, adding a little outer squint, brow lower, widen, gaze down and pupil dilation | resource |
| When they play | The creator and photo-mode face graphs have no periodic blink; the additive blink clips play when the gaze moves (facial expressions §2) | resource |
| Creator idle | The close-up idle's face clip has nine blinks of its own (peaks 0.51 to 0.97, about 0.4 s each, both eyes identical), on average 2.45 s apart | resource |
3. Which facial setup V uses
The female face-rig entity names the male player setup (h0_), while a female setup (h0_) sits beside the female skeleton resource. Both have the same structure (121 face main poses, 255 correctives, the same limits, influences and in-betweens) but different pose data: the male blink turns the upper lid less (upper root 33.6° against 37.0°) resource. Solved on the female head offline, the female setup closes the neutral eye completely and the male one leaves 2 to 6 % of it in view [resource, measured offline]. Photo mode solves the female V with the male setup [runtime, session 4] (facial expressions §1); the creator's and gameplay's face rigs name it too resource. The Studio solves with the setup the face rig names (design D1, since 29 September): the male player setup on the base game, the female head's own only as a fallback or a developer's comparison (XFS_). The expression, blink and idle all use it; experiment 031 measures what changed. In the creator's close-up loop it parts the lips about 18 % less at the two breaths (2.75–2.91 mm at the midline lip joints against 3.36–3.51 mm) with the same jaw turn [offline] (experiment 034); the creator's own use of the setup is still unread in game.
4. Eye shapes move the joints too
Each morph target carries its own joint binds (
boneRigMatrices) beside its vertex offsets. They belong to a preset head: the five region targets of one number (h091_,eyes h092_, …) share them resource.nose The facial setup's
JointRegionsassigns every joint a region: 0 eyes (132 joints: lids, brows, eye joints), 1 nose, 2 mouth, 3 jaw, 4 ear, 255 none resource.The 21 eye shapes translate the eye region's skinned joints without turning them; the eye joint moves 0.9 to 3.9 mm resource. The unskinned lid roots, which carry the blink's big turn, are listed by no target resource.
A community fix, the Facial Customisation Rig Fix, renames six ear joints in every morph target to stop eye clipping, which only makes sense if the engine uses these binds at runtime [resource; runtime effect a hypothesis].
Reading adopted by the Studio hypothesis: an eye shape re-seats the eye-region joints on its binds, the facial poses act about the moved pivots, and the unskinned lid roots follow the eye joint. Nothing in the game files or at runtime confirms it; it was chosen because it closes the four measured shapes best on the whole, not on every shape. Measured offline at full closure (share of the open eye in view from the front, left / right, the game's blink) [measured offline]:
- the base shape closes completely either way;
h211closes completely, where turning about the base centre leaves 16 / 18 %;h091keeps a slit about 1 mm high (7.5 / 4.8 %), where turning about the base centre leaves 22 / 17 %;h011gets worse: 10.2 / 5.5 % re-seated against 3.6 / 0 % about the base centre.
h111was not measured offline; the slit on it was seen only in the browser [observed in the browser]. How the engine blends five region targets' binds, what it does with joints no target lists, and whether the game's own blink closes these shapes fully are open.
5. The Studio's blink
- Source. The host solves the game's
additive_clip with the setup V's face rig names (§3), with XF Studio's own solver, when the page first asks (_ blink_ normal_ _ 01 GET /, facial-host.ts). The Closure slider scrubs that clip's closing half (0 to 0.10 s, 21 solved steps); Play blink plays the whole clip at its own speed (60 Hz), repeating every 2.45 s (the idle's average spacing, a Studio choice). Closure 0 is the exact editing pose; the clip's first frame looks about 1° down. It is made from the player's game files and never shipped; it records the rig and facial setup it was solved with, and the Studio refuses it, in plain words, when it can't be read, is damaged, or was made for a head whose joints sit more than 0.1 mm from the preview head's. Solved with the female head's setup, it equals the developer bake the Studio used before (api/ facial/ blink tools/through the IO Suite): every joint within 1.1 × 10⁻⁵ mm and 1.2 × 10⁻⁵° at every key, and the 21 eye shapes' 126 joint seats each within 9 × 10⁻⁶ mm (bake_ game_ blink.py tools/) source.facial-bake-oracle.ts - Eye shapes. The blink re-seats its rig on the shown eye shape's joint binds, the hypothesis in §4, with its
h011regression. The idle still turns the lids about the base centres. A modded eye shape the bake has no binds for keeps the base seat source. - Everything follows the lids. The solved rig drives every bone of the same name: the core head, the eye plate and each resolved detail's own skeleton copy (brows, lashes of any mod, the eye). Offline on the real head at full closure, the upper-lash roots stay within about 0.6 mm (median) of the lid skin, where the retired synthetic study left them about 6 mm behind; the plate stays exactly on the skin [source, measured offline].
- A lash mesh follows the joints it is weighted to, not the lid it sits on. A mod's lashes close with the lid only when their roots are weighted like the lid skin under them. The CCXL "Lush Manga Eyelashes" (icxrus) mesh uses the head's own joint binds exactly (every shared joint within 0 mm and 0°) and carries only the 21 eye-shape targets (no blink or corrective shapes; the engine animates the face through joints alone), but its upper lashes are weighted mostly to the outer-corner row
eye_and the row above the margin,lid_ up_ rowA_ 3 eye_, where the vanilla lashes use the margin rows A_0–A_2 and theirlid_ up_ rowB_ 0 eye_children. Measured offline on the reference install: the median share of an upper lash root's weights on the same joints as the head vertex under it (lash joints folded into their lid) is 0.82 for the vanilla lashes and 0.22 for these; at full closure their roots leave the lid by 1.42 mm (median) where the vanilla ones stay within 1 mm, and in the browser the outer lashes kink upward off the closed lid. Linear skinning with the same weights and joints does the same in any renderer, so the game is expected to show it too [hypothesis until test ask 4]; it is not a mechanism the preview lacks.lid_ lashes_ * tools/reports the agreement per lash mesh (verify_ blink.ts upperLashRootSkinAgreement), and the blink test holds a lash mesh to the drift limit only when its agreement reaches 0.5, naming one below it as the mesh's own rigging [resource; source]. - No push-through. The retired study drove the upper lid 3.4 mm through the lower one; the solved lids meet with about half a millimetre of overlap [measured offline].
- The idle. The idle blinks by itself and the facial solve is not additive, so the blink controls are off while the idle plays; turning the idle on returns the blink to the editing pose source. The idle's body and face clips are read natively and the face is solved on the host by XF Studio's own solver when an idle is first chosen (
GET /: about 0.2 s for the close-up's 663 frames, then cached), on the desktop too. Each idle plays the creator puppet's face clip of its own name (the inventory the close-up's) fromapi/ idles?face=<id> ui_; the eyes section playsfemale_ face.anims ui_blended in and out over 0.5 s before the loop. Solved with the female head's setup (the bakes' choice), the faces equal the developer bakes within 2 × 10⁻⁴ mm and 1.5 × 10⁻³° source. Where the face can't be read, the body still moves and the Motion panel says why (body animation §2).closeup_ shot_ eyes - A mod can replace the creator's face set. On the reference MO2 route an Appearance Menu Mod archive (
PinkyDude_) winsANIM_ FacialExpressions_ FemaleV.archive base\with a set of 78 expression clips and none of the creator'sanimations\ ui\ female\ ui_ female_ face.anims ui_clips resource. Whether the game's creator face then holds still or finds the clips elsewhere is untested; the Studio reads the next copy of the set that holds* ui_(the base game's) and logs it [hypothesis; in-game test ask 6].closeup_ shot - Makeup coverage on closed lids. On save B's eye shape (
h111) a strip of the upper lid that hides under the crease while the eye is open comes into view when it closes and shows bare skin inside the drawn makeup: it appears to lie outside the eye plate's footprint [observed in the browser; cause a hypothesis]. If the game deforms the lid the same way, exported makeup has the same gap on closed eyes.
6. The idle's upper face
Why the creator shows movement above V's eyes that the Studio's close-up idle barely shows. Scripts and numbers: brow idle gap, 27 September.
| Fact | Detail | Grade |
|---|---|---|
| The close-up loop barely moves the brows | ui_: brow raises at most 0.0012 (inner) and 0.086 (right outer only, 10.4–10.9 s); brows_ a constant 0.41; lateral, widen and inner squint 0. Solved, the brow joints swing at most 0.55 mm and 0.7° over the loop; their largest offset from rest (1.9 mm) is that constant lowered pose, not motion | resource [measured offline] |
| Its squint is small | Outer lower squint 0–0.30 (left) and 0–0.35 (right), peaking near 2, 4, 11 and 14 s, moves the cheek and lower lid joints up to 1.7 mm; the upper lids move with the nine blinks | resource [measured offline] |
| Nothing mutes them | The muzzle tracks rest at 0 and the clip adds 0; a muzzle scales its poses by 1 − muzzle; the envelopes rest at 1; brows_ is limited only by the outer raise, too small here to matter. At full weight brows_ moves brows_ 4.4 mm and the outer lower squint moves eye_ 4.5 mm (two in-betweens) | resource source [measured offline] |
| The Studio plays it faithfully | The baked close-up face matches the pinned solver to 6 × 10⁻⁶ mm per joint; every moving upper-face joint exists and carries weights in the prepared head, and all 26 moving brow joints in the brows mesh (the head lacks only the unskinned lid roots); the brow cards move 0.08–1.13 mm | [measured offline] |
| The setup choice doesn't explain it | Solved with the male player setup V's face rig names, the loop's brows swing 0.80 mm | [measured offline] |
| The face graph adds no brow motion | No node writes brow or squint tracks; EyesTracksLookAt sets the gaze tracks from the look-at target (gaze down at 1 lowers the upper lid 7.9 mm, at 0.13 about 1 mm); gaze-change blinks add brows_ 0.049 and outer squint 0.076 | resource |
| The eyes section moves the brows | The eye camera (UI_) serves the eyes, eyebrows, eyelash colour and eye makeup rows and sets the eyes flag; the graph then plays ui_ once (4.00 s): brow raises about 0.7, brows_ 0.12–0.32, outer squint about 0.30 around 1.5–2.25 s, with a blink. Solved, the brows swing about 5.8 mm, 11 times the loop. Hovering or changing a row requests its camera and any other row (an XF Eye Artistry row included) asks for the head camera, so moving between rows can play it again, subject to the graph's 15-second timed return (facial expressions §5, photo mode) | resource source [measured offline]; replays hypothesis |
| Wrinkles | At the squint moments the solver's wrinkle outputs reach 0.51 and 0.58 (left, right); the preview doesn't render wrinkle shading, which in game would make a 1–2 mm squint read more strongly | [measured offline] for the signal; its look hypothesis |
Reading adopted by the Studio [hypothesis until test ask 5]: the brow lowering and lid narrowing seen in game are mostly the eyes-section showcase, with wrinkle shading and live gaze as further contributors. The Motion panel offers Creator close-up, eyes section: the close-up body with the showcase once and then the close-up loop, blended as CC idle describes. The close-up stays the default idle; the showcase is never labelled or looped as the idle.
7. Why smiles bunch beside the nose
A smile made with the mouth-corner controls forms a sharp lump beside the nose and upper lip, and the cheek under the eye barely lifts. The same lump shows in game [runtime, report of 28 September]. It is the facial setup's data, not the preview: the preview solves with the pinned solver itself, and replaying its stages one at a time reproduces the solve exactly [offline]. Numbers, the setup entries behind them and what a retune would change are in facial correctives tuning.
| Fact | Detail | Grade |
|---|---|---|
| The cause | The main pose lips_ (one in-between, linear) lifts the fold line beside the nose and lip (jaw_, mug_) about 10.6 mm at weight 1, the row just outside it 2.5 mm and the malar cheek (eye_) 1.3 mm. The gap between the first two rows closes by 31 % at 0.3, 56 % at 0.7 and 46 % at 1: the skin folds into a ridge | resource [offline] |
| The cheek raiser doesn't round it | eye_ moves the malar cheek mostly forward (3.7 mm at 1, 1.9 mm up) and never reaches the fold line; smile plus raise still closes the gap 54 % | [offline] |
| No corrective for it | None of the 255 face correctives combines a mouth control with the cheek raiser, sneer or nasolabial deepener; the two-corner smile corrective only turns lip joints | resource |
| Influences hide the fill | lips_ is capped at 1 − corner_, and corner_ by corner up, mid shift, jaw open and stretch together: in the reported expression the deepener set at 100 % solves at 26 % | resource [offline] |
| Limits don't apply | The global limits act only while lipSyncEnvelope is above 0; it rests at 0 | resource source |
tools/ reports, for any saved expression, each stage's effect on the control weights, the in-betweens and correctives that fire, and how far each one moves chosen joints (by switching it off and solving again). A retune, in the preview and as an optional in-game override, is banked as a later feature (backlog); the in-game comparison ran in session 4 (N13 results) runtime. The lump shows in game at the same place as in the preview. It reads milder at a portrait lens, but the lens, the light and the facial setup differ, so its size isn't settled. The cheek raiser doesn't visibly round the cheek there, as offline. From long photo-mode experience the bulge on smiling is a consistent trait of the game's rig at every framing; the default photo-mode face lens (about 66° at 35 cm) exaggerates it.
Open questions
Which facial setup does the engine solve V's face with?Answered for photo mode (session 4): the male player setup, on the photo-mode stand-in'sface_(facial expressions §1); the preview follows it since 29 September. The creator and gameplay faces aren't read yet.rig - How does the engine combine the joint binds of V's five region targets, and what happens to joints no target lists (the lid roots)?
- Does the game's blink close every eye shape completely, or does it leave the slit the preview shows on
h091andh011(measured offline) andh111(seen in the browser)? Doesh011close fully in game, as it does about the base centre? - What counts as a gaze change for the look-at controller's blinks, and what drives blinks in gameplay outside the creator and photo-mode graphs? (Those graphs play the additive blink clips on gaze changes, with minimum intervals, and have no periodic blink: facial expressions §2.)
- Does the closed lid on deep-set shapes uncover skin outside the eye plate in game?
- Do lashes rigged to other lid joints than the lid skin under them (the "Lush Manga Eyelashes" mesh) leave the closed lid in game as they do in the preview (§5)?
- Is the brow and lid movement seen above V's eyes in the creator the eyes-section showcase (§6), and how much do wrinkle shading and live gaze add?
- Where does the game's solver differ from the IO Suite's reading: pupil scale poses,
faceEnvelope, the lips muzzle, the corrective-entry flag, the double influence pass (specification §7)? Each is a compile option of XF Studio's solver, so a runtime comparison can switch one at a time. - With a mod that replaces
ui_without the creator's clips (§5), does the creator's face hold still in game?female_ face.anims - The game's smile lump sits where the preview's does (session 4); is it as large now that the preview solves with the male setup at a matched lens and light, and does wrinkle shading change how it reads (§7)?
In-game test asks
Batch into one prepared session; record the game version and the face-rig and morph mods installed.
- Blink closure on four eye shapes. In the creator (or photo mode with eyes closed), capture frontal close-ups of a fully closed blink for eye shapes 01 (base), 10 (
h091), 12 (h111) and the shape whose morph ish011: is any eye visible between the lids? Compare with the Studio at Closure 100 %.h011decides between the per-shape seat and the base centre. - Lashes on closed lids. Same captures: do the upper lashes lie along the closed lid line as in the Studio?
- Makeup on closed lids. With an XF Eye Artistry look covering the upper lid, close the eyes on eye shape 12: does bare skin show between the crease and the lashes?
- Mod lashes on closed lids. With the CCXL "Lush Manga Eyelashes" chosen, photo mode, eyes closed, one frontal and one three-quarter close-up of the left eye; then the same with vanilla lashes. If the outer lashes kink upward off the lid as in the preview (
evidence/, private), the mod's rigging does it in game too.screenshots/ head-fixes/ lashes-compare.png - The eyes section's brows (§6). A fixed camera on the creator's head: 25 s hovering only a head-camera row (skin), then 25 s moving back and forth between an XF Eye Artistry row and the eyebrows row. Do the brows lower and the lids narrow only in the second? Compare with the Studio's Creator close-up and Creator close-up, eyes section idles (
evidence/, private). The runtime bridge can read the active clip and the paperdoll flags meanwhile.screenshots/ idle-brows/ - A replaced creator face set (§5). With Appearance Menu Mod's female facial expressions installed, open the creator's head camera and watch V's face for 25 s: does it blink and move as the close-up idle does, or hold still?
Smile lump (§7).Run in session 4 (N13 results); the preview now solves with the male setup (the smile bunches less with it: experiment 031); the size comparison waits for a matched lens and light.
Related pages
Facial expressions and idles · Facial correctives tuning · Facial solver specification · Character-creator idle · The game's blink · Brow idle gap · CC file chain · Eye rendering · Brows · Tooling