systems/GROOM_STAGE_SPEC.md
What this is. The build spec for GROOM as a standing stage of the character factory chain, per
Josh's factory-enhancement roster item 3: *"GROOM as a standing stage: per-age hair states carrying
the ruled color curve, with physics/wind — not a one-off for the protagonist."*
(docs/spine/DECISIONS_PENDING_JOSH.md L4710-4711, THE FACTORY ENHANCEMENT ROSTER.) The emphasis in
that line is the whole point: one head has a groom today, and a factory that stamps every living
asset needs a stage.
Authority. PROPOSAL-TIER, and it rules nothing. Canon, the CVD and Josh's rulings bind every
line. Where this spec and canon disagree, canon wins and this spec is the defect. It says HOW hair
gets built; the colour curve, the keystone ages, and the ear-visibility law were already ruled and
this spec quotes them rather than restating them.
Honest tier. Everything below about current state is a measured read off a landed record. **No
groom asset in this project is graded acceptable.** The stage-map verdict for grooms and cloth is
PARTIAL / MISSING (docs/pipeline_review/AAA_WORKFLOW_CORRESPONDENCE_2026-08-06.md L58), and this
spec inherits that register unchanged.
---
**This section originally read "nothing in this spec executes yet / every execution step below is
BLOCKED" behind two blockers. Blocker 1 is DISCHARGED BY EVENTS; blocker 2 stands. Execution has in
fact landed, and it went FURTHER than this spec's card-atlas route:** the card cap is RETIRED and
REPLACED by a 68,000-strand Alembic groom on the V2.1 head — a UE5 Groom asset with 6,800 guides,
ShadingModel = Hair, measured passes on crown root coverage (1.0000 within 4 mm), eye clearance,
and strand definition (build/3d/best_a14/groom/GROOM_REBUILD_RECORD.md, landed canon 49e97ae8 /
game 0542b95; charter S11 row). What remains OWED on that landed groom — the GroomBinding async-build crash, the exposure
control that never takes, and the colour bar behind it — is charter S11's register and is a claimed
in-flight wave tonight (bee8d8d5), not this spec's blocker. A doc still reading "blocked" while a
strand groom is landed is the drift class the living-source law exists to kill; hence this
supersession. The card-atlas harness below remains valid as the per-LOD CARD representation route
(cards vs strands is a per-LOD choice, CRAFT_TEXTURE_LOOKDEV_GROOM.md:363-368).
build/3d/cage/CAGE_PICK.jsonPICK = S2 numpy landmark-NRICP) and its blend-proof release blocker closed as an
instrument-reference defect, proven by four controls
(build/3d/cage/blend_fix/BLEND_G4_REFERENCE_FINDING.json, landed 869ba32f). The original
scalp-partition caution is preserved as history below and needs no further observance.
chain has not proven first (prep/reads exempt)"*
(docs/HANDOFF_2026-08-05_ACCOUNT_SWITCH.md L1003-1005). The groom stage proves itself on
CHAR_0001 at the graded keystone ages, then cascades.
A third, softer dependency, named honestly: the per-age COLOUR VALUES (§4.3) come from the
graded keystone plates. The keystones currently read FAIL on every age
(build/3d/characters/CHAR_0001_AGE_KEYSTONES.json /keystones/*/verdict). This spec therefore
carries the colour curve's shape and its ruled words as data, and refuses to invent the numbers.
What is NOT blocked, and is what this wave landed: this spec, the card-atlas bake harness
running on a synthetic strand fixture (GAME:Tools/groom/card_atlas_bake.py), the per-age hair
state data file (GAME:Tools/groom/hair_age_states.json), and their proofs. **None of them
generate a character.**
## 0. THE UNBLOCK TRIGGER — nothing in this spec executes yet
**This spec is SCAFFOLDING. Every execution step below is BLOCKED until both of the following
land, in this order.**
- BLOCKER 1 — THE CAGE VERDICT. The groom's roots live on the cage's scalp. The cage-source
bake-off is the standing chain's stage-2 gate and the next architecture verdict due
(docs/spine/DECISIONS_PENDING_JOSH.md L4642-4644), and the ratified architecture is ONE BARE
MESH PARTITIONED into anatomical regions, *"each region with its own proportions, physical
values …, record, UV block, and material slot"* (L4630-4633). **The scalp is one of those
regions and the hairline is its boundary.** The groom stage consumes the winning cage's head
partition — scalp region extent, its UV block, and its material slot — and must not presume
which cage wins. The bench deciding it is build/3d/cage/CAGE_BENCH_SPEC.md (READ-ONLY to this
lane).
---
The teacher's own number sizes the debt. Square Enix's lead character artist Dai Suzuki on *FFVII
Remake* Cloud: his hair *"was an extremely high-priority element and in fact accounted for half of
the total polygon count for the whole model"*
(docs/pipeline_review/AAA_WORKFLOW_CORRESPONDENCE_2026-08-06.md L181-183, citing the GamesRadar
report of Suzuki's remarks). Against the published model numbers — 1997 Cloud ≈ 900 polygons,
*Remake* Cloud ≈ 110,000, *Rebirth* Cloud ≈ 220,000 (dossier L178-180) — that is roughly 55,000
polygons of hair on the model whose appeal is our ruled bar.
The dossier draws the conclusion this spec is built on: the FF7R hair figure *"makes converting the
pivot's 2,558 strand shells to cards a budget-legitimate priority rather than an extravagance, and
makes 73 bald creature rows a larger deficit than their triangle count suggests"* (dossier L233-235).
And its groom verdict is blunter still: *"The groom hole is the AAAAA-blocking one"* (dossier L517).
THE BUDGET LINE ITSELF IS NOT DECLARED HERE. Roster item 5 arms per-asset triangle and material
budgets as gate teeth this same wave (DECISIONS_PENDING_JOSH.md L4715-4717), and the sibling Lane
B owns that declaration (docs/HANDOFF_2026-08-05_ACCOUNT_SWITCH.md L1032-1037). This spec states
its cost by spec-class name only — steam_deck_minimum / mid_range_pc / high_end_pc /
ultra (_source/01_Tier_1_Foundation/T1_Build_Pipeline_Contracts [ACTIVE v1.0].md §1.7, L166 and
L185-188) — and its obligation is to declare per-LOD counts INTO Lane B's gate, never to mint a
parallel number beside it.
---
One head carries a real card groom, and its record is specific: 1,488 cards, 262 excluded by the
ear window, 192 whorl-fill cards roofing the crown gap, a scalp cap under them, 29,760 verts /
26,784 tris total (build/3d/characters/CHAR_0001_HEAD_AUTHORED_RECORD.json /geometry/hair and
/geometry/counts/hair). The emitter is build/3d/characters/char_head_author.py L882-1036, and it
already encodes four hard-won corrections that this stage inherits rather than rediscovers:
tangent × world-up, which for a strand running down the back of a head is a horizontal plane, and
*"the check render printed flat plates lying across the skull like shelves."* The binormal is now
tangent × SURFACE NORMAL, sampled at the root and carried along the strand (L890-895).
3.4 mm root lift was *"a visible gap at portrait distance"* (L897-899).
produced *"a flat-topped slab protruding from the crown with a straight top edge and hard vertical
sides"* — a card seen edge-on, standing proud of the skull. Whorl cards now run 1.52× width at
0.34× lift (L942-951).
finding was *"THE HAIR IS A CAP, NOT A HAIRSTYLE"*; the fix was a real parting lane at
PART_ANG = 0.42 rad with two deliberately unequal lobes, plus length variance widened to roughly
±34% *"so a few strands always overshoot the mass"* (L954-963, L1000-1004).
ear the single elven marker; hair that hides it deletes the marker."* The card field carries an
explicit angular exclusion around the ear, and the exclusion is a counted number in the record
(262) rather than an intention (L901-905). §6.3 is where this collides with the hood, and the
collision is designed rather than accidental.
The atlas emitter is equally real. build/3d/characters/char_head_textures.py L442-527 (hair_atlas)
authors six strand clumps across U with real alpha, a normalised root/mid/tip ramp, darkening-only
strand separation, and baked root occlusion. Its own numbers on the landed atlas: `opaque_texels
363,585, clipped_fraction 0.0, value_separation_p90_minus_p10 0.3084`
(CHAR_0001_HEAD_AUTHORED_RECORD.json /textures/hair_atlas_stats). **The clipped-fraction figure
is the stage's most transferable lesson** and §2.3 makes it a gate.
Also reused unchanged: T_HAIR_FLOW (tangent flow so the anisotropic highlight runs *along* the
strand rather than across it), the MI_CHAR_0001_Hair and MI_CHAR_0001_Scalp material slots, and
the importer's masked-material handling — BLEND_MASKED, alpha wired to MP_OPACITY_MASK,
two_sided True, because *"hair cards without an opacity mask are opaque rectangles, which is the
single loudest tell that hair is a texture"* (GAME:Tools/char/import_char_0001_headasm.py
L203-208).
instead of cards, and converting them is *"the highest-value next step by a wide margin"* —
closing three measured ceilings at once: the LOD floor (LOD2 = LOD3 = 51,492 tris, cause proven by
a topology-free control at 51,282), the texture hole (~19.3% unobserved, concentrated on the back
of the head where strand mass occludes the six views), and the appeal gap against the floor sheet
(docs/pipeline_review/AAAAA_IMPROVEMENT_REGISTER_2026-08-06.md L86, register row 13, scored 2.5).
This is the stage's first execution step.
hard-coded root bands with literal constants. A factory stage needs the style to be data, so
the same emitter can stamp a different hairstyle for a different character or a different age
without a code edit. §3.3 makes the band table a file.
HAIR_PRESET = "silver_white" is a module constant (char_head_textures.py L125). The ruled curve is a function of age (§4), so colour becomes a
looked-up per-age value.
*"Hair, everything else: zero. A grep for groom|fur|hair card|xgen|fibermesh across harness/,
build/3d/schema/ and the game repo's Tools/ returns only the CHAR_0001 head's cards and the
rubric's lens list — re-derived at HEAD this sitting. **73 creature rows (62 QUADRUPED + 11
ARBOREAL_PRIMATE) cannot reach the bar as bald shells no matter how good the rig is**"* (dossier
L501-505; register row 47 at AAAAA_IMPROVEMENT_REGISTER_2026-08-06.md L130). This spec is written
so the coat stage is the same stage with a different band table, not a second pipeline.
And the engine end is already built and waiting. Unreal's groom pipeline is Alembic-schema
driven with strand/card/mesh LODs and a Groom Binding Asset, *"which means a creature-coat stage
does not need a new engine capability, only an authoring stage that emits conforming .abc"*
(dossier L519-522).
---
Four steps. **The stage is defined so that step 1 can be swapped — for a real strand groomer, for a
generated strand field, for a hand-authored curve set — without touching steps 2 through 4.** That
is what makes it a stage rather than a script.
Input to the bake is a strand set: N polylines in scalp-local space, each with a root position,
a root tangent, a per-vertex width taper, and a clump id. Three producers are legal and the stage
does not care which ran:
what the landed head used and what the synthetic fixture in card_atlas_bake.py --self-test
exercises.
row 13 takes for the pivot head's 2,558 shells.
schema (groups for head hair, vellus, beard, eyelashes, eyebrows; width and color attributes;
guide curves flagged for interpolation and simulation — dossier L459-467). **Tool freedom
applies**: *"survey and adopt whatever model/open-source tool does age progression (or any task)
BEST"* (DECISIONS_PENDING_JOSH.md L4439-4442). If a better groomer exists, it feeds this step.
The strand set becomes an atlas plus a card library. This is the step the scaffolding tool in
this wave implements end-to-end on a synthetic fixture.
vertical strip of the atlas. The incumbent uses K = 6 with strips assigned by card index modulo 6
(char_head_author.py L1018-1022 sets strip = (i % 6) / 6.0). The bake generalises this: strip
count is a parameter, strip assignment is by measured clump shape rather than by index, and the
layout is emitted as data so placement can look up which strip a card belongs to.
_BCA — base colour + alpha. The colour ramp along V (root → tip) and the strand alpha.Alpha is geometry-bearing (§2.1).
_D — depth. Per-texel distance from the card plane to the strand mass it stands for. Thisis what lets a flat card catch light like a rounded clump instead of a ribbon, and the incumbent
does not have it. Consumed as a normal-derivation input plus a parallax term at LOD0.
_ID — clump id. A per-clump index, so the material can jitter hue/value per clump at runtime rather than baking the jitter in. The incumbent bakes it (clump term,
char_head_textures.py L500-501); moving it to runtime is what lets one atlas serve many
characters.
_RT — root-to-tip gradient. A normalised 0→1 along the strand, so root occlusion, colourramp position, and physics stiffness all read one authoritative gradient instead of each
re-deriving V.
clipped_fraction — the share of opaque texels pinned at 1.0 in any channel — and
value_separation_p90_minus_p10. The history is the reason: silver-white measured 0.3146
clipped against ash-blond's 0.0000, because a ramp whose three basis weights summed to 1.511
was a 1.5× multiply masquerading as an interpolation, and *"the root-to-tip separation the strands
are drawn by vanished, and the render printed a flat white cap"* (char_head_textures.py
L446-458). **A light preset cannot blow out on a normalised ramp, and the gate proves it did not
rather than assuming it.** Threshold: clipped_fraction == 0.0 and
value_separation >= 0.20. Both are asserted by card_atlas_bake.py.
no headroom on a light preset; one that darkens has all the headroom there is. It is also the
truthful model — blond and silver hair are read by the SHADOWS between the strands, not by
highlights on them"* (char_head_textures.py L460-464). Every per-clump and per-strand modulation
in the bake multiplies downward. This matters more here than anywhere else in the factory because
the ruled curve's age-7 end is silver-blonde — the lightest hair the project will ever author.
Placement is where the band table lives, and the band table is the file that makes a hairstyle.
height (u0) rule, travel (du_total), length, width multiplier, lift multiplier, and the atlas
V-window the band samples. The incumbent's five bands become five rows: whorl fill (0.00-0.11,
golden spiral, V-window 0.42-0.92, width ×1.52, lift ×0.34), fringe (0.11-0.34, parted at 0.42
rad with unequal lobes), side/temple sweep (0.34-0.60), crown (0.60-0.92, golden-increment spiral
so *"no radial line of bald scalp can survive between them"*), nape (0.92-1.00) —
char_head_author.py L920-999.
it is counted, never assumed (§2.1). Additional exclusions arrive per character and per equipped
state (§6.3).
show skin-coloured skull, which the check render printed"*
(CHAR_0001_HEAD_AUTHORED_RECORD.json /geometry/hair/scalp_cap_reason). The cap is a dark
light-blocker under the cards on its own material slot (MI_CHAR_0001_Scalp), sitting at a
measured 0.2361 cm standoff at the crown.
partition region with its own UV block (DECISIONS_PENDING_JOSH.md L4630-4633), a placement
expressed in scalp-region UV **transfers to every age morph and every character sharing the cage
topology for free.** This is the single largest reason the groom stage waits for the cage verdict
rather than proceeding around it.
| LOD | Representation | Mechanism |
|---|---|---|
| 0 | full card field | every card, depth map consumed as parallax + derived normal |
| 1 | reduced card field | thin the field by clump; widen survivors to hold coverage — never raise lift |
| 2 | coarse cards | one card per clump type per band; depth map as normal only |
| 3 | helmet / scalp bake | the card field baked to a fitted shell over the scalp with the silhouette's outer strands preserved as a fringe strip |
coverage bought with lift produces a slab in silhouette (§2.1). A thinning pass that widens
survivors keeps the mass; one that lifts them makes a helmet.
Prioritize* as the silhouette lever (dossier L872-875); a card field's equivalent is the
overshooting-strand tail (the ±34% length variance with a 6% long tail,
char_head_author.py L1000-1004). The reduction must keep the outliers and thin the mass, which
is the opposite of what a naive decimator does.
cause proven to be the shell count by a topology-free control at 51,282 (register row 13). Cards
are the fix; the ladder above is where the fix is measured.
---
Josh, and this is the operative shape of the curve — recorded against his own reference panels:
HAIR CURVE REVISED BY THE FLOORS THEMSELVES: silver-blonde (fairy realm, age 7)
-> visibly warm sandy-blond BY 11 -> dirty blonde through 14-18; the earlier
crown-holds-silver-through-13 proposal is SUPERSEDED by Joshs own panels.
(docs/spine/DECISIONS_PENDING_JOSH.md L4599-4601, THE AGE-11 AND AGE-14 FLOORS LAND.)
And the end-state, ruled in the same sitting:
THE HAIR END-STATE REFINED (updates the progression ruling): the ladder runs
SILVER-BLONDE (fairy realm child) -> DIRTY BLONDE at age 18 - not golden/clear
gold; the curves end-state is dirty blonde, with the transition still massed in
Adolescence 14-17 per the standing curve unless Josh re-shapes it.
(docs/spine/DECISIONS_PENDING_JOSH.md L4582-4585, JOSH GRADES ITERATION-2 IN FLIGHT.)
The origin ruling both of these update:
The hair as a child the silver white and as progression on the earthly realm turns
to golden blonde as ages to young adult
(docs/spine/DECISIONS_PENDING_JOSH.md L3875-3876, THE HAIR IS A PROGRESSION. Its end-state
"golden blonde" is superseded by L4583-4584's "not golden/clear gold … dirty blonde".)
The canon line under all of it, which does not move: the Elven King's *"hair is silver-white. His
eyes are the same color as the protagonist's but deeper"*
(_source/03_Tier_3_Characters/T3_Core_Characters [ACTIVE v1.0].md L563). The eye colour is the
canon-shared quantity; the hair colour is a curve.
L4584-4585 says the transition is *"still massed in Adolescence 14-17"*. L4599-4601, written later
in the same sitting and explicitly *"REVISED BY THE FLOORS THEMSELVES"*, places **visibly warm
sandy-blond BY 11** — which means the transition has substantially begun before 14. The two readings
cannot both shape the curve.
This spec implements the LATER entry (warm sandy-blond by 11), on the ground that it is the one
that says it is revising, and that it is grounded in Josh's own landed floor panel — the director's
sighted read of that panel records *"the 11 already wears warm sandy-blond hair with the freckle
dusting and full child charm"* (L4595-4597). **This is recorded as a finding for the director, not
as a ruling by this lane.** If it is wrong, the fix is one field in one data file.
The keystone ages are ruled: *"anchor ages 7 (the pick), 11, 14, 18 FIRST — built as the LARGEST
jumps first … then interpolate between keystones for the gradual steps. Fill ages derive from graded
keystones, never the reverse"* (DECISIONS_PENDING_JOSH.md L4435-4438). The groom stage carries
exactly those four as declared states and interpolates 8-17 between them.
| Age | Colour, in the ruling's own words | RGB root/mid/tip | Length + style state |
|---|---|---|---|
| 7 | silver-blonde (fairy realm) | MEASURED AND LANDED — (0.520,0.523,0.536) / (0.762,0.768,0.786) / (0.940,0.946,0.962) | the landed card field: fringe with the 0.42-rad parting, crown spiral, nape, ear window open |
| 11 | visibly warm sandy-blond | AWAITING THE GRADED KEYSTONE | awaiting |
| 14 | dirty blonde (transition through) | AWAITING THE GRADED KEYSTONE | awaiting |
| 18 | dirty blonde (the end-state) | AWAITING THE GRADED KEYSTONE | awaiting |
**Three of the four rows read AWAITING and that is the correct state of this stage today, not a
gap in it.** The age-7 values are on disk because the age-7 plate was picked and the atlas that
renders it was measured (char_head_textures.py L88-107;
CHAR_0001_HEAD_AUTHORED_RECORD.json /textures/colour_canon/hair_rgb_root_mid_tip). The other
three keystones currently read FAIL on every axis
(CHAR_0001_AGE_KEYSTONES.json /keystones/11|14|18/verdict), so there is no graded plate to
measure a colour off. Inventing three RGB triples here would be exactly the defect the
proposals-are-HOW-never-WHAT rule exists to prevent.
The mechanism is therefore built and the values are left null. GAME:Tools/groom/hair_age_states.json
carries the four keystones with rgb_root_mid_tip: null on three of them, the ruled colour NAME as
a quoted string with its citation, and a status of AWAITING_GRADED_KEYSTONE. The interpolator in
card_atlas_bake.py refuses loudly when asked for an age whose bracketing keystones are not
both resolved, rather than silently returning grey — and the self-test proves that refusal fires.
ash_blond is explicitly NOT the end-state. It is the retired lane default kept only as the
ladder's comparator (char_head_textures.py L112-124), and the ruling names the end-state as
*"dirty blonde — not golden/clear gold"* (L4583-4584). Anyone reaching for ash_blond as the 18 has
misread the curve.
A per-age hair state is not a colour. It carries:
who has fallen into another world and an 18-year-old who has lived eleven years in it do not wear
the same head of hair, and **the physique ladder's own principle applies: the body at every age
shows what the spine's lived history has earned by that chapter** (DECISIONS_PENDING_JOSH.md
L4751-4755, THE TRAINING CLOCK). Hair follows the same clock.
Ages 8-10, 12-13, and 15-17 are derived by interpolation between the bracketing keystones, in
line with the keystone-order ruling. The interpolation is on the data, so it is reproducible and it
costs no generation.
For completeness against the standing minor-age ruling: *"MINOR-AGE ASSETS (the child/teen ages
under 18): generated imagery keeps the tasteful-minimal register permanently — not an
over-restriction but a hard line — and loses NOTHING by it, because mesh completeness for every age
comes from the parametric CAGE (complete by construction), never from generated imagery"*
(DECISIONS_PENDING_JOSH.md L4768-4772). **Nothing in the groom stage generates imagery of a
person.** It bakes hair atlases from strand geometry and places cards on a scalp. The register
binds the plate lanes; it is stated here only so the boundary is on the record and no future reader
has to re-derive it.
Related and equally binding on any lane that does author prompts: register language is removed from
prompt text entirely and lives instead in framing defaults and sighted post-checks, because
restriction language *"steals attention from identity and fidelity"* (DECISIONS_PENDING_JOSH.md
L4776-4789). The groom stage writes no prompts.
---
time and flagged in the placement data) becomes a guide chain of bones; the rest interpolate their
transform from the nearest guides. This is the same guide/interpolated split Unreal's Alembic
groom schema already expresses with its guide curve flag (dossier L461-463), which means the
card route and a future strand route share one concept.
_RT map baked in §3.2 is theauthoritative gradient: stiff at the root, loose at the tip, monotonic. One gradient, three
consumers (occlusion, colour ramp, physics), which is what keeps them from disagreeing.
rigid-body count at roughly 1,000 live physics objects across the whole scene (dossier
L488-490). A groom that spends 200 of them on one NPC's hair is a groom that cannot ship in a
crowd. Guide count per LOD is therefore a declared number in the placement data, and it drops
with LOD alongside the card count.
per-clump phase offset from the _ID map so the mass does not move as one board. Amplitude scales
with the length multiplier from the age state (§4.4), so a longer 18-year-old's hair moves more
than a 7-year-old's without a second tuning pass.
fitted to the partition regions rather than to a per-character mesh. Because the partition is
shared topology, one proxy set serves every character and every age morph — the same
transfer property that makes placement free (§3.3).
simulation tell there is, and the review ceremony is a motion test precisely because *"a static
groom that reads well can still explode on a run cycle"* (dossier L490-492).
the same arithmetic discipline the creature rig used to place joints — solved and recorded, not
eyeballed (dossier L567-571).
This is where the groom stage meets the 16-slot equipment law, and it is a named gate rather than a
hope. **The swap gauntlet requires the full equip/unequip cycle in-engine across all 16 slots, their
combinations, and every age state, with garment inner surfaces showing ZERO penetration of visible
body, measured rather than eyeballed** (DECISIONS_PENDING_JOSH.md L4692-4699). Hair is the hardest
case in that gauntlet because it is the only body-adjacent surface that moves.
SLOT_0001 (helmet), layer order 11, and the ruled 16 are Josh's own enumeration (registries/T0_Equip_Slot_Registry [DRAFT v0.1]/Sheet1.csv, SLOT_0001; the ruling
quoted in that row's ruled_by field). The hood is the helmet-slot cloth class — the first
human-realm pickup, *"whose function is concealing the tipped ears and other fairy-elf signs …
the PHYSICAL LAYER of FIRST_CONCEALMENT"* (DECISIONS_PENDING_JOSH.md L3735-3739).
which BANDS of the band table it suppresses and which it leaves. A hood suppresses crown and
nape and leaves the fringe; a full helmet suppresses everything but the fringe and adds a short
under-band. **This is the per-region suppression model the partition architecture already
ratified** (DECISIONS_PENDING_JOSH.md L4630-4633), applied one level down to hair bands. It
costs no extra mesh and it cannot desynchronise from the equipment state, because the equipment
state is what drives it.
DESIGN.** The card field must never cover the ear, because the ear is the elven marker
(§2.1). The hood must cover the ear, because concealing it is the hood's entire gameplay
function (L3735-3739). These do not conflict — they compose: hair leaves the marker visible so
the player and the world can read it, and the hood is what the player equips to hide it. The
groom's ear exclusion is therefore *preserved* under a hood rather than relaxed, and the hood's
own geometry does the concealing. A design that let hair creep over the ear would quietly delete
the mechanic the hood exists to serve.
every age state, imaged per the every-pass law. This rides the existing swap gauntlet rather than
minting a parallel gate.
(DECISIONS_PENDING_JOSH.md L4524-4529), which has no head-slot component, so hair returns to its
unsuppressed state — a testable assertion, not an assumption.
---
boundary against the forehead region IS the hairline. Because the partition is shared topology,
a hairline authored once is the same hairline on every character and every age — and moving it
for a character is a region-boundary edit, which is a data change rather than a re-author.
MI_CHAR_0001_Scalp exists, is a dark light-blocker at (0.072, 0.062, 0.048) roughness 0.62, carries used_with_skeletal_mesh: True,
and survived an engine import (GAME:Tools/char/import_char_0001_headasm.py L89-90;
CHAR_0001_HEAD_AUTHORED_RECORD.json /engine_import/materials). The stage fills it; it does not
mint a new one.
material slot come from the cage verdict. Until that lands, the band table's u0 values are
expressed in the incumbent head's own parameterisation and will need re-expressing in the cage's.
**That re-expression is one of the first execution steps (§8), and pretending otherwise would
hide a real cost.**
The incumbent already builds lashes and brows as geometry with real alpha
(char_head_author.py L1187-1249; T_LASH_BCA), on MI_CHAR_0001_LashBrow. They are folded into
the band table as two additional bands rather than kept as a separate script.
---
No groom claim counts unless it was made under the calibrated light, per roster item 4
(DECISIONS_PENDING_JOSH.md L4712-4714). The W-LOOK standard is being built this same wave by the
sibling lane (docs/HANDOFF_2026-08-05_ACCOUNT_SWITCH.md L1025-1031) and landed as
docs/LOOKDEV_STANDARD.md — THE CALIBRATED LOOKDEV STANDARD — while this spec was being written;
the groom stage consumes it and does not restate it. If that path ever moves, find it by its
DOC_MAP row.
Groom-specific ceremony on top:
and a wind gust — because a static groom that reads well can still explode on a run cycle
(dossier L490-492). A groom reviewed only on a bust is un-reviewed.
the frame that catches the slab defect (§2.1) and the frame the whorl-fill regression was found in.
clipped_fraction and value_separation printed onthe sheet beside the atlas, because "silver-white now renders" is a number and was measured as one.
reference for that age, and *"a sheet without the references inline is un-DONE"*
(DECISIONS_PENDING_JOSH.md L4649-4653).
---
1. Read the cage verdict; re-express the band table's root positions in the winning cage's scalp
region UV, and fit the collision proxies to its head/shoulder regions.
2. Convert the pivot head's 2,558 strand shells to cards through the bake — register row 13,
scored 2.5, the highest-value next step by a wide margin.
3. Land the four bake maps (_BCA, _D, _ID, _RT) with the clipping gate armed.
4. Resolve the three AWAITING colour keystones off the graded 11/14/18 plates the moment they
grade, and fill hair_age_states.json. Ages 8-17 then derive with no generation.
5. Build the LOD ladder and declare per-LOD card/guide counts into Lane B's budget gate.
6. Wire physics: guide chains, cage-fitted collision, wind with per-clump phase.
7. Run the swap gauntlet's hair leg — every head-slot item against every age state, penetration
measured, imaged.
8. Run the review ceremony under W-LOOK: motion test, silhouette frame, atlas sheet, side-by-side.
9. Cascade to the creature coat — the same stage with a different band table, closing the 73
bald rows (register row 47).
the tool refuses to interpolate across them.
ages are ruled, and the band table is the landed head's own.