/** * AgentAvatarHair — procedural hair geometry + body+hair mesh combiner, as PURE DATA. * * Hair is card-strips seeded over a scalp dome above the head bone. EVERY hair vertex is * pinned to the 'head' palette index with weight 1.0, so the body's joint-matrix palette * (`computeJointPalette`) skins the hair through forward kinematics with zero extra wiring — * the hair rides the head bone for free. Each vertex carries a REAL strand tangent (xyz) + * strandT (w, 0 root → 1 tip) for the Kajiya-Kay hair shader (fixing HairRenderer.tsx:97's * hardcoded placeholder tangent). * * `buildCharacterMesh` concatenates the body (skin) + hair into ONE SkinnedMeshData and * reports the two index ranges, so the renderer draws body=skin-SSS / hair=marschner as two * material groups over a single shared vertex buffer + skin palette. No GPU, no Three.js. * * @module character-render */ import type { HairCoverageProfile, SkinnedMeshData } from '../native-render/draw-spec'; import { type AgentAvatarMeshData, type AgentAvatarMeshOptions } from './AgentAvatarMesh'; import { type AgentAvatarGarmentGeometryReceipt, type SovereignGarmentStyle, type SovereignMantleStyle } from './AgentAvatarGarment'; export interface HairMeshData { positions: Float32Array; normals: Float32Array; /** 4 floats/vertex: xyz strand-flow tangent + w strandT (0 root → 1 tip). */ tangents: Float32Array; /** 2 floats/vertex. Hair cards use u=0/1 across width; scalp-cap v stays negative. */ uvs?: Float32Array; indices: Uint32Array; jointIndices: Uint32Array; jointWeights: Float32Array; vertexCount: number; /** Derived evidence for the operative native groom geometry, when requested. */ groom?: AgentAvatarGroomGeometryReceipt; } export declare const AGENT_AVATAR_OCULAR_PROFILES: readonly ["legacy-composite-v1", "layered-ocular-v1", "layered-ocular-tearfilm-v2", "layered-ocular-calibrated-v3"]; export type AgentAvatarOcularProfile = (typeof AGENT_AVATAR_OCULAR_PROFILES)[number]; export type AgentAvatarOcularRegion = 'sclera' | 'iris' | 'pupil' | 'cornea'; export interface OcularMeshData extends HairMeshData { /** Radial UVs used by the native iris material; non-iris regions stay deterministic. */ uvs: Float32Array; /** Per-eye contiguous index ranges, ordered left then right for each authored region. */ regionRanges: Record>; receipt?: AgentAvatarOcularGeometryReceipt; } export interface AgentAvatarOcularGeometryReceipt { schemaVersion: 'holoscript.agent-avatar-ocular-geometry.v1' | 'holoscript.agent-avatar-ocular-geometry.v2' | 'holoscript.agent-avatar-ocular-geometry.v3'; profile: AgentAvatarOcularProfile; eyeCount: 2; regionCount: 4; /** H3Z independently indexed lower-cornea wetline. */ tearMeniscusProfile?: 'lower-cornea-meniscus-v1'; tearMeniscusIndexCount?: number; /** H4A proportions shared with the source-authored lid and wetline response. */ calibrationProfile?: 'portrait-ocular-balance-v1'; irisScale?: number; pupilScale?: number; lidOpening?: number; corneaRadiusScale?: number; } export declare const AGENT_AVATAR_HAIR_STYLES: readonly ["short", "medium_wavy", "long", "swept_ridge", "cropped_coils", "structured_updo", "weathered_waves", "braided_crown", "silver_curls", "asymmetric_crop", "high_bun"]; export type AgentAvatarHairStyle = (typeof AGENT_AVATAR_HAIR_STYLES)[number]; export declare const AGENT_AVATAR_GROOM_PROFILES: readonly ["radial-cards-v1", "scalp-flow-v1", "scalp-flow-containment-v2", "scalp-flow-breakup-v3", "scalp-flow-portrait-v4", "scalp-flow-volume-v5", "scalp-flow-density-v6"]; export type AgentAvatarGroomProfile = (typeof AGENT_AVATAR_GROOM_PROFILES)[number]; export declare const AGENT_AVATAR_HAIR_COVERAGE_PROFILES: readonly ["opaque-v1", "alpha-to-coverage-v1"]; export interface AgentAvatarHairMaterialReceipt { schemaVersion: 'holoscript.agent-avatar-hair-material.v1' | 'holoscript.agent-avatar-hair-material.v2' | 'holoscript.agent-avatar-hair-material.v3'; shadingModel: 'marschner-hair'; /** Exact source-authored 0xRRGGBB hair chroma when the v2 material path is active. */ sourceColor?: number; /** Bounded source-chroma contribution; omission preserves the v1 melanin-only response. */ sourceColorWeight?: number; coverageProfile: HairCoverageProfile; strandCoverage: number; edgeSoftness: number; anisotropyStrength: number; longitudinalShift: number; primaryExponent: number; secondaryExponent: number; tangentAttribute: 'strand-flow'; cardUvAttribute: 'card-width'; alphaToCoverageRequested: boolean; /** H4J layered opacity and root-occlusion response over the A2C card path. */ densityProfile?: 'layered-card-density-v1'; densityStrength?: number; rootShadowStrength?: number; } export interface AgentAvatarGroomGeometryReceipt { schemaVersion: 'holoscript.agent-avatar-groom-geometry.v1' | 'holoscript.agent-avatar-groom-geometry.v2' | 'holoscript.agent-avatar-groom-geometry.v3' | 'holoscript.agent-avatar-groom-geometry.v4' | 'holoscript.agent-avatar-groom-geometry.v5' | 'holoscript.agent-avatar-groom-geometry.v6'; profile: AgentAvatarGroomProfile; rootLift: number; tipTaper: number; hairlineBias: number; /** Signed crown-flow rotation around the scalp normal (-1..1). */ crownWhorl: number; /** Optional source-authored angular cluster count. Omitted preserves legacy root seeding. */ clusterCount?: number; /** Optional within-cluster angular spread (0.08..1). */ clusterSpread?: number; requestedGuideCount: number; emittedGuideCount: number; cardCount: number; scalpSurface: 'legacy-sphere' | 'neutral-anatomical-ellipsoid'; scalpCapVertexCount: number; scalpCapTriangleCount: number; vertexCount: number; triangleCount: number; /** p95 absolute dot(root tangent, scalp normal); lower means less radial card eruption. */ rootTangentRadialDotP95: number; /** Hair vertices inside a deterministic upper-face prism in bind space. */ frontalOcclusionVertexCount: number; /** H3Y exterior projection used to keep cards and guides outside the authored scalp. */ containmentProfile?: 'ellipsoidal-scalp-exterior-v1'; /** Vertices projected outward because their authored position crossed the scalp surface. */ containmentAdjustedVertexCount?: number; /** Final vertices remaining inside the scalp ellipsoid after containment. */ scalpPenetrationVertexCount?: number; /** H3Z deterministic, scalp-contained silhouette breakup. */ breakupProfile?: 'contained-flyaway-breakup-v1'; flyawayGuideCount?: number; flyawayCardCount?: number; /** H4A hair-material facial framing emitted with the scalp groom. */ facialFramingProfile?: 'portrait-brow-lash-ribbons-v1'; browCardCount?: number; lashCardCount?: number; facialFramingVertexCount?: number; /** H4I deterministic scalp-volume and broad-lock silhouette treatment. */ silhouetteProfile?: 'massed-silhouette-clumps-v1'; massGuideCount?: number; massCardCount?: number; /** Maximum source-independent cap lift in metres after build scaling is removed. */ scalpCapMaxLift?: number; /** H4J three-axis undercoat cards added below the broad silhouette locks. */ densityLayerProfile?: 'cross-card-undercoat-v1'; densityLayerCardCount?: number; /** Art-directed silhouette feature that must alter emitted geometry, not only metadata. */ styleFeatureProfile?: 'stacked-updo-mass-v1' | 'weathered-wave-beard-v1' | 'braided-crown-loop-v1' | 'silver-curl-clusters-v1' | 'asymmetric-length-field-v1' | 'high-bun-mass-v1'; styleFeatureVertexCount?: number; styleFeatureTriangleCount?: number; /** Source-derived native shading/coverage contract joined by CharacterHost. */ material?: AgentAvatarHairMaterialReceipt; } /** Resolve author-facing aliases without silently accepting an unknown geometry style. */ export declare function resolveAgentAvatarHairStyle(style: string): AgentAvatarHairStyle | undefined; /** Resolve source spellings without relabelling an unknown groom implementation. */ export declare function resolveAgentAvatarGroomProfile(profile: string): AgentAvatarGroomProfile | undefined; /** Resolve source spellings without silently accepting an unknown coverage implementation. */ export declare function resolveAgentAvatarHairCoverageProfile(profile: string): HairCoverageProfile | undefined; export interface HairOptions { buildScale?: number; heightScale?: number; /** Face topology whose scalp surface the opt-in groom follows. */ faceTopology?: AgentAvatarMeshOptions['faceTopology']; /** Neutral-head width multiplier used to align the scalp and eyes. */ faceWidth?: AgentAvatarMeshOptions['faceWidth']; /** Neutral-head length multiplier used to align the scalp shell. */ faceLength?: AgentAvatarMeshOptions['faceLength']; /** Deterministic source-authored geometry profile (default `medium_wavy`). */ style?: AgentAvatarHairStyle; /** Scalp guide roots (default comes from the selected style profile). */ guides?: number; /** Cards per guide for volume (default comes from the selected style profile). */ cardsPerGuide?: number; /** Points per guide curve (default comes from the selected style profile). */ segments?: number; /** Card width in metres (default comes from the selected style profile). */ cardWidth?: number; /** Tip length in metres (default comes from the selected style profile). */ length?: number; /** Native root-flow/card-orientation algorithm. Compatibility default is `radial-cards-v1`. */ groomProfile?: AgentAvatarGroomProfile; /** Extra shell offset in metres for the scalp-flow root. */ rootLift?: number; /** Tip width divided by root width, clamped to 0.02..1. */ tipTaper?: number; /** Additional front-hairline retraction, clamped to 0..0.3. */ hairlineBias?: number; /** Signed crown-flow rotation around the scalp normal, clamped to -1..1. */ crownWhorl?: number; /** Angular groom clusters. Values below 2 disable clustering and preserve legacy geometry. */ clusterCount?: number; /** Fraction of each cluster sector occupied by roots (0.08..1). */ clusterSpread?: number; } /** * Build procedural hair as card-strips over the scalp dome. Deterministic (golden-angle * Fibonacci seeding — no RNG). All vertices skin to the head bone. */ export declare function buildAgentAvatarHair(o?: HairOptions): HairMeshData; /** * Two eyeball spheres at the front of the head, weighted to the head bone (so they ride the * head). Emits the same 6-array format as hair; rendered with the refractive-eye material. */ export declare function buildAgentAvatarEyes(o?: { buildScale?: number; heightScale?: number; faceTopology?: AgentAvatarMeshOptions['faceTopology']; orbitalProfile?: AgentAvatarMeshOptions['orbitalProfile']; eyeRecess?: number; eyeScale?: number; eyeSpacing?: AgentAvatarMeshOptions['eyeSpacing']; faceWidth?: AgentAvatarMeshOptions['faceWidth']; }): HairMeshData; /** * Build source-selectable layered ocular geometry. * * Each eye is emitted as four actual mesh regions (sclera sphere, iris disc, pupil disc, and * transparent cornea cap). The left eye is fully emitted before the right eye so the existing * native blink channel can continue splitting the aggregate eye vertex range in half. */ export declare function buildAgentAvatarOcularRegions(o?: { buildScale?: number; heightScale?: number; faceTopology?: AgentAvatarMeshOptions['faceTopology']; orbitalProfile?: AgentAvatarMeshOptions['orbitalProfile']; eyeRecess?: number; eyeScale?: number; eyeSpacing?: AgentAvatarMeshOptions['eyeSpacing']; faceWidth?: AgentAvatarMeshOptions['faceWidth']; irisScale?: number; pupilScale?: number; lidOpening?: number; ocularProfile?: AgentAvatarOcularProfile; }): OcularMeshData; export interface CharacterMeshData { mesh: SkinnedMeshData; groom?: AgentAvatarGroomGeometryReceipt; anatomy: AgentAvatarMeshData['anatomy']; jointDeformation?: AgentAvatarMeshData['jointDeformation']; handSurface?: AgentAvatarMeshData['handSurface']; facialLandmarks?: AgentAvatarMeshData['facialLandmarks']; garment?: AgentAvatarGarmentGeometryReceipt; ocular?: AgentAvatarOcularGeometryReceipt; ocularProfile: AgentAvatarOcularProfile; orbital: AgentAvatarMeshData['orbital']; /** H4J analytic body/head UV atlas receipt, present only when explicitly authored. */ skinUv?: AgentAvatarSkinUvReceipt; bodyVertexRange: { vertexStart: number; vertexCount: number; }; hairVertexRange: { vertexStart: number; vertexCount: number; }; eyeVertexRange: { vertexStart: number; vertexCount: number; }; bodyRange: { indexStart: number; indexCount: number; }; /** Body index slices with keratin nail plates removed for the SSS skin draw. */ bodySkinRanges: Array<{ indexStart: number; indexCount: number; }>; /** V3 keratin nail-plate slices, empty for every compatibility profile. */ nailRanges: Array<{ indexStart: number; indexCount: number; }>; hairRange: { indexStart: number; indexCount: number; }; eyeRange: { indexStart: number; indexCount: number; }; ocularRanges: Record>; garmentRange: { indexStart: number; indexCount: number; }; visorRange: { indexStart: number; indexCount: number; }; mantleRange: { indexStart: number; indexCount: number; }; /** One authored mobility value per combined mesh vertex for deterministic cloth dynamics. */ clothSimulationWeights: Float32Array; } export type AgentAvatarSkinUvProfile = 'portrait-atlas-v1'; export interface AgentAvatarSkinUvReceipt { schemaVersion: 'holoscript.agent-avatar-skin-uv.v1'; profile: AgentAvatarSkinUvProfile; vertexCount: number; nonDegenerateVertexCount: number; headIslandVertexCount: number; uRange: [number, number]; vRange: [number, number]; } /** * Build the combined body+hair+eyes mesh as one SkinnedMeshData, with the three index ranges * the renderer slices for the body=skin-SSS / hair=marschner / eyes=refractive material groups. */ export declare function buildCharacterMesh(opts?: AgentAvatarMeshOptions & HairOptions & { garmentStyle?: SovereignGarmentStyle; garmentSegments?: number; mantleStyle?: SovereignMantleStyle; includeHair?: boolean; includeEyes?: boolean; ocularProfile?: AgentAvatarOcularProfile; irisScale?: number; pupilScale?: number; skinUvProfile?: AgentAvatarSkinUvProfile; }): CharacterMeshData; //# sourceMappingURL=AgentAvatarHair.d.ts.map