# Head, face, and hair builder

`objects/people/face-builder.js` exports `createHead(api, options)` and the alias `createFace`. It has no imports. It requires the injected `api.THREE` supplied by the portable engine; geometry, materials, animation state, and disposal belong to the returned head object.

The head faces local +Z. Its origin is the anatomical head centre, with an approximately 0.21 m wide, 0.28 m high adult skull before `headScale`. The nose extends the front profile. The Person model attaches `head.root` to its head bone at local `[0, .055, 0]`, where the rest head-bone height is 1.535 m, giving a head centre of 1.590 m. The body module omits its legacy head geometry for this mode and owns the head-bone pose. Whole-person stature scaling remains on the Person's skinned mesh.

```js
const head = createHead(api, {
  seed: 12,
  skin: 0xd6a27e,
  hair: 0x493024,
  hairStyle: 'swept',
  ageGroup: 'adult',
  headScale: 1
});
headBone.add(head.root);
head.root.position.set(0, .055, 0);

head.setExpression('happy');
head.setGaze({yaw: .20, pitch: -.08});
head.update(dt, time);
// Called before destroying the body/skeleton:
head.dispose();
```

## Options and controls

Options include `seed`, `skin`, `hair`, `female`, `ageGroup`, `headScale`, `hairStyle`, `expression`, `sunglasses`, `sunHat`, and `hatColor`. Skin/hair accept Three.js color inputs. `headScale` must be positive. Its default is 1 for adults and 1.12 for children, applied before whole-person scaling.

`hairStyle` accepts `bald`, `short`, `swept`, `curls`, `bob`, or `ponytail`. Integer styles map into that order modulo six, supporting existing seeded descriptions. `setHair(style)` replaces and disposes the previous hairstyle without rebuilding facial geometry. It is an occasional editing operation.

`setExpression(name, intensity=1)` accepts `neutral`, `happy`/`smile`, `sad`, `concerned`, `focused`, `surprised`, or `talking`. Alternatively pass numeric controls: `{smile, anger, sadness, surprise, mouthOpen, browRaise, talking}`. Values are clamped to 0–1 and interpolated over subsequent updates. Expression intensity must be finite. Talking provides procedural mouth motion; it is not speech recognition or phoneme synchronization.

`setGaze({yaw,pitch})` controls the eyes in radians, independently of the head bone. Positive yaw looks toward local +X; positive pitch looks down, matching Person's convention. Gaze is clamped to ±0.55 rad horizontally and ±0.35 rad vertically. `blink()` requests an immediate blink on the next update; deterministic automatic blinking also runs at varied intervals. Blinks close the almond apertures and clip/hide iris and pupil geometry accordingly.

`update(dt,time)` advances expression interpolation, gaze, and blinking. `properties` provides appearance/preset metadata; `getState()` returns current interpolated controls and gaze. `dispose()` releases all owned geometry and materials, removes the root from its parent, and is idempotent. Call it before body disposal; the body integration already does this.

## Geometry and rendering

The skull, jaw, nose bridge, nose tip, alae, cheek volumes, eye sockets, and chin share a continuous sculpted skin surface. The nose is not assembled from separate ellipsoids. Small nostril openings and ear contours provide secondary detail. Eye whites form narrow almond apertures with upper/lower lids; irises and pupils sit within those apertures. Mouth geometry includes a cupid bow, lower lip, mouth opening, and visible upper teeth when open. Expressions also raise cheek vertices and move the lower jaw surface.

Hair has an irregular anatomical hairline and directional tapered locks. The styles differ in silhouette and construction: short fine tufts, swept locks, curved curls, a face-opening bob, a gathered ponytail, or no hair. These are procedural, stylized character assets. They are not scanned heads or strand-based physically simulated hair.

Skin, ears, eyelids, eyebrows, lips, and mouth are batched into one vertex-colored mesh. Both eyes are a second batch, and hair is a third. A bald head therefore uses two draw calls; ordinary hairstyles use three. Optional hats/glasses add separate accessory meshes. Source attributes are cached: unchanged neutral expressions do not rewrite the skull, and partial GPU update ranges keep eye-only updates from uploading skull vertices.

Measured seed-3 geometry budgets:

| Style | Render meshes | Triangles |
| --- | ---: | ---: |
| Bald | 2 | 16,232 |
| Short | 3 | 29,984 |
| Swept | 3 | 37,504 |
| Curls | 3 | 60,344 |
| Bob | 3 | 24,904 |
| Ponytail | 3 | 22,964 |

## Verification and limits

`tests/face-object.html` provides isolated front/three-quarter/side views and a solo-head selector, expression buttons, gaze, blink, and hairstyle replacement. The implementation was inspected in the confirmed Chrome instance. Observed corrections included exposing the face beneath the initial bob, widening an over-tapered jaw, tapering visible lock roots, reducing short-hair tuft size, and reducing the four-head fixture from 107 draw calls to 11. Smile, surprise, gaze, blinking, and differing hair silhouettes were visible. Browser diagnostics reported no errors or warnings. The temporary inspection tab was closed after testing.

Node checks passed for finite geometry, neutral skull caching, actual gaze displacement, eyelid closure, expression morphing, repeated hairstyle replacement, and exact-once geometry/material disposal. These checks cover the module; full-body poses, head/neck attachment appearance, and beach-scene performance are verified by the body and shell integration tasks.

The face remains a procedural game-character approximation. There is no facial scan, skin-pore normal map, subsurface-scattering skin shader, phoneme solver, or strand-level hair simulation. Mouth depth is represented by layered geometry. Skull normals are recomputed when jaw/cheek deformation changes; neutral updates retain cached geometry. Lip/lid strip normals are recomputed when their geometry changes. The builder does not animate the head bone or own body pose logic.


## Current contour and surface refinement

The current skull profile uses monotone interpolation across jaw, cheek and cranial sections, with orbital sockets, brow relief and an integrated nose. Sclera strips have vertical subdivisions so their curvature does not occlude the iris/pupil. Iris color varies radially; the upper and lower lid contours differ. Ears use shaped helix/concha surfaces. Lip/jaw movement changes the face silhouette as expressions open the mouth.

Swept locks are anchored to the skull rather than forming a floating roof. Hair geometry retains UVs for a generated strand-groove bump texture. Generated skin bump and roughness maps add small surface variation. Skin/lip/lid winding and shadow-side handling were corrected after direct inspection exposed a jagged shadow under the lower lip. These textures and the replacement hairstyles are owned and disposed by the head controller.

Close front and three-quarter checks at the current revision showed neutral, smile and surprise changes without the earlier terraced skull profile, pupil occlusion or jagged under-lip shadow. The complexion remains relatively uniform and the hair reads as molded bundles, particularly curls. The layered mouth cavity and tooth strip also remain visible simplifications. The measured triangle budgets above include the current finer hair; curls are the most expensive style. These observations do not demonstrate near-photorealistic visual acceptance.
