@bitmagic/cli 0.1.66-dev.1 → 0.1.66-dev.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +37 -1
  2. package/assets/blender-level/find_blender.py +3 -1
  3. package/assets/character-rigging/SKILL.md +80 -0
  4. package/assets/character-rigging/references/articulation.md +55 -0
  5. package/assets/character-rigging/references/new-rig.md +51 -0
  6. package/assets/character-rigging/references/repairs.md +44 -0
  7. package/assets/character-rigging/references/verification.md +49 -0
  8. package/assets/character-rigging/scripts/rig_tool.py +197 -0
  9. package/assets/character-skin-authoring/SKILL.md +43 -0
  10. package/assets/character-skin-authoring/references/exporters.md +134 -0
  11. package/assets/character-skin-authoring/references/eyes.md +215 -0
  12. package/assets/character-skin-authoring/references/materials.md +115 -0
  13. package/assets/character-skin-authoring/references/playground.md +78 -0
  14. package/assets/character-skin-authoring/references/profiles.md +97 -0
  15. package/assets/character-skin-authoring/references/projection.md +190 -0
  16. package/assets/character-skin-authoring/references/regional-detail.md +72 -0
  17. package/assets/character-skin-authoring/scripts/assemble_character.py +205 -0
  18. package/assets/character-skin-authoring/scripts/authored_detail.py +47 -0
  19. package/assets/character-skin-authoring/scripts/authored_surface_patch.py +83 -0
  20. package/assets/character-skin-authoring/scripts/brow_groom.py +62 -0
  21. package/assets/character-skin-authoring/scripts/build_face_detail.py +107 -0
  22. package/assets/character-skin-authoring/scripts/build_surface_candidate.py +28 -0
  23. package/assets/character-skin-authoring/scripts/canthus_wall.py +57 -0
  24. package/assets/character-skin-authoring/scripts/character_build.py +54 -0
  25. package/assets/character-skin-authoring/scripts/eye_assets.py +333 -0
  26. package/assets/character-skin-authoring/scripts/eye_opening.py +114 -0
  27. package/assets/character-skin-authoring/scripts/eye_texture.py +35 -0
  28. package/assets/character-skin-authoring/scripts/eyelid_detail.py +34 -0
  29. package/assets/character-skin-authoring/scripts/eyelid_morph.py +171 -0
  30. package/assets/character-skin-authoring/scripts/eyelid_patch.py +173 -0
  31. package/assets/character-skin-authoring/scripts/face_atlas.py +51 -0
  32. package/assets/character-skin-authoring/scripts/geometry_repair.py +112 -0
  33. package/assets/character-skin-authoring/scripts/glb_arrays.py +13 -0
  34. package/assets/character-skin-authoring/scripts/glb_output.py +21 -0
  35. package/assets/character-skin-authoring/scripts/inspect_skin_point.py +66 -0
  36. package/assets/character-skin-authoring/scripts/normal_patch_height.py +38 -0
  37. package/assets/character-skin-authoring/scripts/prepare_face_reference.py +23 -0
  38. package/assets/character-skin-authoring/scripts/regional_atlas.py +51 -0
  39. package/assets/character-skin-authoring/scripts/select_preview.py +90 -0
  40. package/assets/character-skin-authoring/scripts/skin_views.py +267 -0
  41. package/assets/character-skin-authoring/scripts/surface_pbr_maps.py +46 -0
  42. package/assets/character-skin-authoring/scripts/texture_repair.py +98 -0
  43. package/assets/character-skin-authoring/scripts/vertex_detail_support.py +80 -0
  44. package/assets/character-skin-authoring/scripts/vision_blend_materials.py +74 -0
  45. package/assets/character-skin-authoring/scripts/vision_materials.py +276 -0
  46. package/assets/character-skin-authoring/scripts/workspace_paths.py +18 -0
  47. package/assets/metahuman/src/work/metahuman/MetaHumanActor.ts +580 -0
  48. package/assets/metahuman/src/work/metahuman/MetaHumanLabHooks.ts +122 -0
  49. package/assets/metahuman/src/work/metahuman/MetaHumanMaterials.ts +500 -0
  50. package/assets/metahuman/src/work/metahuman/MetaHumanSpeech.ts +242 -0
  51. package/assets/metahuman/src/work/metahuman/StudioEnvironment.ts +142 -0
  52. package/assets/metahuman/tools/lipsync/make_line.py +181 -0
  53. package/assets/metahuman/tools/metahuman/README.md +21 -0
  54. package/assets/metahuman/tools/metahuman/e2e/eval.mjs +34 -0
  55. package/assets/metahuman/tools/metahuman/e2e/probes/arm-pose-check.js +32 -0
  56. package/assets/metahuman/tools/metahuman/e2e/probes/bone-displacement.js +26 -0
  57. package/assets/metahuman/tools/metahuman/e2e/probes/clip-shoulder.js +41 -0
  58. package/assets/metahuman/tools/metahuman/e2e/probes/grafted-bones.js +11 -0
  59. package/assets/metahuman/tools/metahuman/e2e/probes/helper-follow-descent.js +38 -0
  60. package/assets/metahuman/tools/metahuman/e2e/probes/helper-follow-sweep.js +31 -0
  61. package/assets/metahuman/tools/metahuman/e2e/probes/helper-joints-inspect.js +10 -0
  62. package/assets/metahuman/tools/metahuman/e2e/probes/outfit-bad-vertices.js +26 -0
  63. package/assets/metahuman/tools/metahuman/e2e/probes/outfit-body-material.js +7 -0
  64. package/assets/metahuman/tools/metahuman/e2e/probes/outfit-own-skeleton.js +8 -0
  65. package/assets/metahuman/tools/metahuman/e2e/probes/shirt-bone-ownership.js +25 -0
  66. package/assets/metahuman/tools/metahuman/e2e/probes/shirt-edge-stretch.js +26 -0
  67. package/assets/metahuman/tools/metahuman/e2e/probes/shirt-long-edges.js +23 -0
  68. package/assets/metahuman/tools/metahuman/e2e/probes/walk-sampler.js +105 -0
  69. package/assets/metahuman/tools/metahuman/e2e/shot.mjs +125 -0
  70. package/assets/metahuman/tools/metahuman/e2e/walk-probe.mjs +43 -0
  71. package/assets/metahuman/tools/metahuman/merge-skeletons.mjs +69 -0
  72. package/assets/metahuman/tools/metahuman/package.json +13 -0
  73. package/assets/metahuman/tools/metahuman/prepare.sh +25 -0
  74. package/assets/metahuman/tools/metahuman/reorder-body-first.mjs +20 -0
  75. package/assets/metahuman/tools/metahuman/smooth-outfit-weights.mjs +48 -0
  76. package/assets/metahuman/tools/metahuman/strip-draco.mjs +32 -0
  77. package/assets/metahuman/tools/metahuman/transfer-skin-weights.mjs +90 -0
  78. package/dist/assets/voxelize-glb.d.ts +5 -1
  79. package/dist/assets/voxelize-glb.js +1 -0
  80. package/dist/assets/voxelize-glb.js.map +1 -1
  81. package/dist/assets/vxl-summary.js +2 -2
  82. package/dist/commands/forge.js +3 -1
  83. package/dist/commands/forge.js.map +1 -1
  84. package/dist/commands/generate.d.ts +62 -0
  85. package/dist/commands/generate.js +241 -2
  86. package/dist/commands/generate.js.map +1 -1
  87. package/dist/commands/init.js +2 -1
  88. package/dist/commands/init.js.map +1 -1
  89. package/dist/commands/judge.js +5 -0
  90. package/dist/commands/judge.js.map +1 -1
  91. package/dist/commands/verify.js +7 -0
  92. package/dist/commands/verify.js.map +1 -1
  93. package/dist/editor/asset-viewer.js +10 -5
  94. package/dist/editor/asset-viewer.js.map +1 -1
  95. package/dist/generate/audio-file.d.ts +6 -0
  96. package/dist/generate/audio-file.js +42 -0
  97. package/dist/generate/audio-file.js.map +1 -0
  98. package/dist/generate/model.js +3 -3
  99. package/dist/generate/model.js.map +1 -1
  100. package/dist/generate/music.d.ts +4 -3
  101. package/dist/generate/music.js +6 -23
  102. package/dist/generate/music.js.map +1 -1
  103. package/dist/generate/prop.d.ts +19 -1
  104. package/dist/generate/prop.js +34 -6
  105. package/dist/generate/prop.js.map +1 -1
  106. package/dist/generate/stream.d.ts +20 -0
  107. package/dist/generate/stream.js +15 -1
  108. package/dist/generate/stream.js.map +1 -1
  109. package/dist/scaffold/asset-pipeline-skill-files.js +6 -1
  110. package/dist/scaffold/asset-pipeline-skill-files.js.map +1 -1
  111. package/dist/scaffold/character-rigging-skill-files.d.ts +2 -0
  112. package/dist/scaffold/character-rigging-skill-files.js +17 -0
  113. package/dist/scaffold/character-rigging-skill-files.js.map +1 -0
  114. package/dist/scaffold/character-skin-skill-files.d.ts +2 -0
  115. package/dist/scaffold/character-skin-skill-files.js +49 -0
  116. package/dist/scaffold/character-skin-skill-files.js.map +1 -0
  117. package/dist/scaffold/metahuman-skill-files.d.ts +21 -0
  118. package/dist/scaffold/metahuman-skill-files.js +306 -0
  119. package/dist/scaffold/metahuman-skill-files.js.map +1 -0
  120. package/dist/scaffold/project-files.js +28 -19
  121. package/dist/scaffold/project-files.js.map +1 -1
  122. package/dist/scaffold/project.js +6 -0
  123. package/dist/scaffold/project.js.map +1 -1
  124. package/dist/scaffold/skill-files.js +5 -2
  125. package/dist/scaffold/skill-files.js.map +1 -1
  126. package/dist/telemetry/command-context.d.ts +23 -0
  127. package/dist/telemetry/command-context.js +11 -0
  128. package/dist/telemetry/command-context.js.map +1 -1
  129. package/dist/telemetry/report.d.ts +1 -0
  130. package/dist/telemetry/report.js +4 -1
  131. package/dist/telemetry/report.js.map +1 -1
  132. package/dist/tools/bundles.js +8 -0
  133. package/dist/tools/bundles.js.map +1 -1
  134. package/dist/verify/browser.js +25 -0
  135. package/dist/verify/browser.js.map +1 -1
  136. package/dist/verify/categories.d.ts +16 -0
  137. package/dist/verify/categories.js +51 -0
  138. package/dist/verify/categories.js.map +1 -0
  139. package/package.json +10 -7
@@ -0,0 +1,134 @@
1
+ # Installed character exporters
2
+
3
+ The skill now includes the tested offline skin, optical-eye and rig-assembly helpers.
4
+ Run `scripts/character_build.py` with an explicit `--workspace`; character assets live
5
+ outside the skill so refreshes do not erase them. Python needs NumPy, Pillow and SciPy.
6
+ Exact visibility recovery also needs Blender on PATH or `BITMAGIC_BLENDER`. These tools
7
+ perform deterministic assembly of the agent's reviewed inputs, never semantic recognition.
8
+
9
+ The retained workspace convention is:
10
+
11
+ ```text
12
+ characters/ID/high/v1/
13
+ source/hy31pro.glb immutable source (name is a convention)
14
+ output/viewer-profile.json {"height": physical height in metres}
15
+ materials/body-detail-profile.json optional designed regional creases
16
+ materials/surface-patch-profile.json optional licensed regional patches
17
+ materials/repair-profile.json optional separately reviewed source defects
18
+ materials/v2/ registered face inputs and intermediate maps
19
+ materials/v4/ mixed-surface GLB and report
20
+ eyes/v1/ independent fitted optical-eye revision
21
+ output/character.glb optional existing bound body mesh
22
+ rig-report.json optional validated rig provenance
23
+ runtime/v1/ combined surface/eye/body variants
24
+ highquality/materials/faces/ID.json character-specific landmark registration
25
+ highquality/references/ licensed immutable exemplar files
26
+ ```
27
+
28
+ Evidence/masks/eye profiles can be anywhere supplied explicitly. Relative command paths
29
+ are workspace-relative. Keep their source/image hashes and projection receipts intact.
30
+ Paths inside authored JSON retain their documented conventions; relocating evidence may
31
+ require updating its source path without changing source bytes or camera contracts.
32
+
33
+ ## Commands
34
+
35
+ Use [the profile schemas](profiles.md) for independently authored landmarks, exclusions,
36
+ scale and optical dimensions. After preparing the facial profile:
37
+
38
+ ```sh
39
+ python scripts/character_build.py --workspace /path/to/assets --id CHARACTER --stage face
40
+ ```
41
+
42
+ The current face adapter uses the Lee Perry-Smith reference: `LeePerrySmith.glb`,
43
+ `Infinite-Level_02_Disp_NoSmoothUV-4096.jpg` and `Map-COL.jpg` in
44
+ `highquality/references/lee-perry-smith/`. Obtain the licensed originals explicitly and
45
+ retain CC BY 3.0 attribution; the skill does not download them. The adapter writes its
46
+ modification notice and hashes. Its calibrated relief amplitude is an authoring estimate,
47
+ not measured capture scale. It does not transfer donor face geometry.
48
+
49
+ After reviewing the dense semantic bake:
50
+
51
+ ```sh
52
+ python scripts/character_build.py --workspace /path/to/assets --id CHARACTER \
53
+ --evidence evidence/CHARACTER --masks masks/CHARACTER
54
+ ```
55
+
56
+ This preserves source geometry and writes mixed skin/hair/lip/nail materials plus the
57
+ registered detail binding. The adapter currently requires one source mesh primitive,
58
+ embedded textures, normals and non-overlapping anatomical UV ownership. It fails unsupported
59
+ layouts rather than flattening them automatically. Multiple-material adapters remain work.
60
+ `--check` validates required input presence without building; full geometry/hash contracts
61
+ are checked by the exporters themselves. Neither check is visual acceptance.
62
+
63
+ For eyes, first follow [the eye fitting workflow](eyes.md), then:
64
+
65
+ ```sh
66
+ python scripts/character_build.py --workspace /path/to/assets --id CHARACTER \
67
+ --stage eyes --eyes-profile profiles/CHARACTER-eyes.json
68
+ ```
69
+
70
+ The current optical texture adapter uses `blue_eye.png` and `LICENSE.md` from the CC0
71
+ MakeHuman eye reference in `highquality/references/makehuman-eyes/`. Its source registration
72
+ is specific to that donor atlas. Character opening contours, dimensions and fitting remain
73
+ individually authored. Existing skinned cut edges/full facial rigs are not supported by
74
+ this prototype; preserve them and use a suitable topology adapter.
75
+
76
+ For a previously validated body binding:
77
+
78
+ ```sh
79
+ python scripts/character_build.py --workspace /path/to/assets --id CHARACTER \
80
+ --stage assemble --input eyes/v1/character.glb --variant eyes
81
+ ```
82
+
83
+ The assembler consumes the existing bound mesh and `rig-report.json`, verifies the output
84
+ hash and negligible geometry displacement, then retains materials and eye layers while
85
+ adding the body skin. It does not invent bones, fit a skeleton or simulate cloth. The
86
+ playground's shared Blender rig fitting remains separate from this installed exporter.
87
+ Use the project's existing rigging workflow to produce compatible inputs.
88
+
89
+ A surfaces run can also take `--eyes-profile` and `--assemble` to execute the same stages
90
+ in order. Each stage stops on failure and leaves a review candidate, never `viewerReady`.
91
+ Review every changed region and both rendering backends before selecting a local preview.
92
+
93
+ ## Detail-binding seams
94
+
95
+ Unused UV texels are not reliable vertex visibility samples at split seams. The exporter
96
+ uses exact source-geometry rays for those vertices, then samples the same reviewed image
97
+ annotations. It leaves occupied unknown/conflicted samples untouched and never changes
98
+ fragment coverage. Geometric caches include source, cameras, positions, normals and
99
+ algorithm version; annotation labels are re-read. Adjacent zero-weight triangle corners
100
+ still receive coherent patch coordinates so interpolation cannot sample another atlas
101
+ region. If an artifact persists, inspect coverage, geometry normals and source color
102
+ separately before changing skin strength.
103
+
104
+ Eye rest fitting retains `_BIND_SOURCE_POSITION` before moving source eyelid vertices.
105
+ The assembly exporter consumes this authoring attribute for weight correspondence and
106
+ removes it from the runtime attributes. Original vertices use their exact bound match;
107
+ clipped vertices use a verified rigid-head field or closest-triangle barycentric weights.
108
+ Points outside the bound surface tolerance fail rather than inheriting a nearby limb.
109
+ The rendered fitted positions and morphs retain their shape during this transfer.
110
+
111
+ Local preview selection now copies the exact reviewed GLB, render receipt, visual
112
+ verdict and inspected images into a content-addressed `.previews` snapshot beside
113
+ the candidate. An atomic `*.selected.json` pointer names that snapshot. Rebuilding
114
+ the candidate or its review images does not mutate the selected preview. A failed
115
+ review leaves the previous pointer intact. Engine consumers should resolve the
116
+ selected snapshot for ordinary preview and use explicit candidate paths for QA.
117
+ These snapshots remain local previews with recorded issues, not whole-character
118
+ acceptance or a publication step.
119
+
120
+ An explicitly authored `materials/geometry-repair-profile.json` can correct a local
121
+ source defect during the mixed surface build. Select the defect center and clean
122
+ support annulus from the exact evidence view; supply a bounded depth interval and
123
+ maximum displacement. The quadratic patch follows surrounding curvature and feathers
124
+ into unchanged geometry. Never infer that a painted marking should be removed:
125
+ record the user's intent and preserve the source. Optional clean skin color donors
126
+ and a painted dot replace the source's baked bump shading. Evidence UVs use Blender's
127
+ bottom-left convention; decoded texture rows use top-left. The exporter converts
128
+ this explicitly and pads only adjacent unused UV gutters.
129
+
130
+ The repair keeps topology, UVs and `_BIND_SOURCE_POSITION`; subsequent eye fitting
131
+ must preserve that attribute, and assembly uses it for the original rig weights.
132
+ Rebuild both eyes and runtime assemblies after a repair. Inspect front and oblique
133
+ views and both renderer backends before selecting the new snapshots. A displacement
134
+ receipt alone does not prove that old normal-map or pigment shading is gone.
@@ -0,0 +1,215 @@
1
+ # Optical eyes after reviewed ocular exclusions
2
+
3
+ This is an independent, opt-in asset revision. A working eye pilot does not certify the
4
+ skin maps or body rig. Preserve the source, material revision and existing animation.
5
+ The current adapter supports a single, unskinned source mesh and two eyes; it refuses
6
+ existing facial morphs and skinned cut edges. Do not silently flatten a rig to bypass it.
7
+
8
+ ## Availability
9
+
10
+ The [installed exporter runner](exporters.md) now includes the optical-eye builder and
11
+ its dependencies. Supply an explicit workspace and independently authored fit; exemplar
12
+ textures remain external licensed inputs. The playground browser review harness is still
13
+ separate. Confirm the installed engine supports the optical-eye contract before adoption.
14
+
15
+ ## Vision fit
16
+
17
+ Prepare exact close front and both oblique source views with `skin_views.py prepare`.
18
+ Use enough pixels to distinguish the iris, visible eye opening, inner corner and lids.
19
+ Record each iris center/radius, an ordered convex opening contour and the lower contour
20
+ indices on the original image. Record anatomical left/right explicitly; image orientation
21
+ is not a side label. Do not reuse another character's target pixels or eye centers.
22
+
23
+ Write a profile following `highquality/materials/eyes/b3843.json`. Source and evidence
24
+ hashes are mandatory. Globe radius, corneal bulge, pupil ratio, pigment and depth offset
25
+ are authored estimates in metres. Verify those estimates against side views and physical
26
+ character height. An opening wider than the globe requires corner tissue; moving the
27
+ eyeball forward until it fills the hole is not a valid substitute.
28
+
29
+ Run `python highquality/src/eye_assets.py --profile PROFILE`. The builder ray-fits each
30
+ eye against source geometry and writes `characters/ID/high/v1/eyes/v1/`. It clips openings
31
+ at the reviewed contour with barycentric attribute interpolation. It creates separate
32
+ sclera, recessed iris, pupil, cornea, orbital mucosa, lid contact and tear meniscus surfaces.
33
+ It adds actual eyelid position/normal morphs and gaze/blink clips. Inspect the closed lids:
34
+ the builder's deformation is a starting fit, not an anatomically validated universal rig.
35
+
36
+ ## Shared rendering and control contract
37
+
38
+ - Eye nodes have `extras.characterEye=true` and `forwardAxis=+Z`; local +Y is up.
39
+ - `CharacterEyeController` applies local yaw/pitch relative to the authored rest fit and
40
+ drives `eyeBlinkLeft`/`eyeBlinkRight`. It never scales the eyeballs or changes body bones.
41
+ Give these channels one owner: either this controller or an AnimationMixer clip.
42
+ - Corneal transmission/IOR use standard glTF physical-material extensions on both backends.
43
+ Source ocular textures are not a replacement for a clear cornea and recessed iris.
44
+ - The MakeHuman eye source is CC0; retain its license, immutable source hash and adaptation
45
+ record. The current texture uses reviewed planar atlas registration and authored pigment.
46
+ It is not a captured iris of the generated character and has finite source resolution.
47
+
48
+ ## Review gate
49
+
50
+ Use the viewer's **Optical eyes · fit preview** option; toggling must preserve the camera.
51
+ Inspect front, both three-quarter views and profile; then gaze in both directions, half
52
+ blink, independent winks and full closure. Play the exported clip as well as testing sliders.
53
+ Check upper-lid contact, inner/outer corners, tear edge, iris parallax, refraction, texture
54
+ orientation, eyeball penetration and closed-lid normals. Check WebGL and WebGPU.
55
+
56
+ `highquality/tests/eye_fit_smoke.mjs` exercises the local viewer and writes screenshots.
57
+ Read those images: zero renderer errors does not establish good optical fit. Keep
58
+ `optical_fit_review_required` until visual checks pass. Next production work includes
59
+ regional scleral scattering, richer iris relief, fitting across characters, refined lid shape and composition with a complete facial/body rig. Do not call this MetaHuman
60
+ parity based on the presence of corneal transmission alone.
61
+
62
+ ## Separate source defects from optical defects
63
+
64
+ If a closed eyelid shows bright fragments, hide all generated optical layers temporarily.
65
+ If the fragments remain, inspect the original unlit face and material-region evidence.
66
+ Do not keep moving the eyeball to compensate for source albedo, normals or incorrect lid
67
+ labels. A bright painted streak and a geometric hole require different corrections.
68
+
69
+ A narrowly authored source-albedo defect can use a separate UV selection and
70
+ `texture_repair.py`: harmonic interpolation in linear light changes only selected texels,
71
+ with outside pixels byte-identical. Keep that selection separate from anatomical labels,
72
+ archive its projection evidence and inspect the repair. It does not reconstruct eyelid
73
+ geometry, lashes or missing detail. The djinn trial still requires eyelid surface work.
74
+ Eye profiles explicitly choose `skinRevision` so a later skin build cannot silently change
75
+ an already-reviewed eye fit. The current adapter accepts v2/v3/v4 and keeps output hashes.
76
+
77
+
78
+ Orbital backing must remain behind the recessed iris and pupil at every blink and gaze angle. Do not reuse the corneal-envelope eyelid deformation for backing tissue: even a small inset can still place it ahead of the iris. Validate partial blinks and isolate optical layers when diagnosing occlusion. Current prototype keeps its dense backing head-fixed. Continue its recessed depth envelope beyond the globe at the canthi too; retaining source-surface depth outside the globe can leave a visible triangle ahead of the closing lid.
79
+
80
+
81
+ Before generating blink targets, inspect the neutral lid/globe intersection. The playground
82
+ can opt into `conformOpenLids` to push intersecting tissue outside the explicitly fitted
83
+ globe. This is geometry fitting around authored landmarks, not automatic anatomical
84
+ recognition. Do not pull the surrounding orbital skin inward merely to follow a sphere;
85
+ keep a smooth support band and stationary canthi. Inspect partial and full closure anew.
86
+
87
+
88
+ The playground now exports gaze-follow lid targets as well as blink targets. The engine
89
+ uses `eyeLidLookUpLeft/Right` and `eyeLidLookDownLeft/Right` at ±0.35 radians pitch;
90
+ full closure suppresses gaze follow independently for each eye. Inspect both directions,
91
+ partial blinks and winks. A controller test validates channel ownership, not the surface fit.
92
+
93
+
94
+ ## Reconstructed lid bands (experimental playground option)
95
+
96
+ When the source eye margin is damaged, explicitly author a paired `outerLidPx` contour
97
+ around the existing `openingPx`. The outer contour must contain the aperture. The builder
98
+ ray-samples the original boundary and reconstructs only the intervening strip, preserving
99
+ its outer position/normal and following the fitted optical envelope at its inner edge.
100
+ This is designed topology and needs neutral, oblique, partial and full-blink inspection.
101
+ It does not recover missing anatomy automatically.
102
+
103
+ Source albedo can contain painted eye shadows or highlights. Stretching those into a
104
+ closed lid is a source-color defect. Optional `lidSkinSamplesPx` records at least three
105
+ explicitly reviewed clean skin donors in the same exact evidence view. Their linear colors
106
+ supply invented inner-lid pigment, blended to the sampled outer edge. Inspect the join;
107
+ never label this as scan-derived detail. The djinn trial still has outer-transition and
108
+ corner limitations. Keep this feature opt-in until its fit is acceptable.
109
+
110
+ For geometry diagnostics, hide cornea, sclera, iris, pupil, contact, tear and lashes, but
111
+ retain reconstructed `eyelid-skin`. Hiding that skin too produces an intentional hole and
112
+ invalidates the closure diagnostic. Inspect unlit albedo separately from geometry normals.
113
+ The playground regression now renders front, both obliques, profile, both yaw directions, and an oblique full blink. Eye review receipts must identify the exact selected output hash, including assembled
114
+ variants; a previous screenshot cannot validate an output rebuilt afterward.
115
+
116
+ ## Authored brow strands (playground option)
117
+
118
+ A painted brow can retain its color but still lack visible strand depth. The optional
119
+ `browGroom` on each fitted eye accepts an independently reviewed `polygonPx`, at least
120
+ two `combGuidesPx` start/end pairs in that same exact view, `strandCount`, `seed`,
121
+ `radiusM`, `lengthRangeM` and `colorLinear`. The local `brow_groom.py` ray-projects roots
122
+ onto the nearest visible source surface and projects the authored comb directions into
123
+ its tangent plane. It constructs tapered short fibers; it performs no hair recognition.
124
+ Do not classify a dark supraorbital shadow as a brow without inspecting the source.
125
+
126
+ Record these as designed hairs, inspect both sides and profile, and preserve the underlying
127
+ source. The strands attach to the head; they do not yet follow expressive brow morphs.
128
+ Fine strands can alias without temporal antialiasing or a filtered hair LOD. This prototype
129
+ is not a replacement for a production groom/simulation system. The b5359 trial uses a
130
+ separate medial-corner tissue surface too; review its fit during closure independently.
131
+ A reconstructed lid-band trial on b5359 was rejected because its pale angular transition
132
+ looked worse. Do not assume that enabling every optional reconstruction improves a fit.
133
+
134
+ ## Corner lining
135
+
136
+ A deep backing disk can leave a dark gap between the globe and the medial lid opening.
137
+ The optional `canthusWalls` profile lists explicit upper/corner/lower `contourIndices`
138
+ and a designed `colorLinear`. The narrow lining joins those reviewed source-lid points
139
+ to a recessed globe rim. Only the lid edge follows blink/gaze targets; the globe edge stays
140
+ fixed, outside the iris envelope over the reviewed ±0.35 radian gaze range. Do not apply
141
+ the corneal closure deformation to the whole socket. Inspect partial closure and both
142
+ obliques after fitting; source corners and dimensions differ between characters.
143
+ This is designed lining, not transferred scan anatomy. The CC0 MakeHuman topology was
144
+ visually inspected as an anatomical reference; no donor mesh is embedded by this option.
145
+ When a reconstructed lid band replaces the source margin, set its lining's
146
+ `contactMethod: "reconstructed-lid-v1"` to use the same aperture depth calculation.
147
+ Otherwise the lining can follow a removed source surface and protrude below the new
148
+ lid. This joins the support consistently; it does not supply a realistic caruncle or
149
+ make an oversized authored corner anatomical. Inspect those separately.
150
+
151
+ If a source has no separately classified ocular material, inspect the exact eye views
152
+ and explicitly set `openingAuthority: "reviewed-contours"`. The adapter then uses the
153
+ authored contours to remove the source surface. It still verifies source/image hashes
154
+ and rejects a cut that removes no interior triangles. Never infer the opening from
155
+ skin color or copy another character's contour; narrow hooded lids need their own fit.
156
+
157
+ Eyelid normal targets transport the imported shading normals with the shortest rotation
158
+ between the rest and deformed geometric normals. This preserves the imported normal's
159
+ angle to the surface while the lid moves. The neutral mesh retains its authored normals;
160
+ unused vertices keep their original normals. Inspect both the neutral and fully closed
161
+ pose after changing a fit, since valid normals cannot correct a poor anatomical shape.
162
+
163
+ Review each eye at eye-sized framing as well as face-sized framing. Inspect a neutral
164
+ eye and an oblique fully closed eye separately. A smooth globe can hide a polygonal
165
+ opening at face scale; a successful blink protocol does not establish anatomical quality.
166
+ In the playground, `CLOSE_EYES=1` adds these views and `REVIEW_SUFFIX` keeps experiments
167
+ separate. Use `SELECTED_EYES=1` to compare with the reviewed snapshot, rather than the
168
+ latest candidate. Explicitly unset `BACKEND` for a complete two-backend review.
169
+
170
+ An optional `contourRefinement` with `method: "convex-quadratic-v1"` and
171
+ `samplesPerLandmark: 8` rounds the segments between reviewed landmarks, staying inside
172
+ the original convex opening and preserving the two shared upper/lower eye corners.
173
+ For a reconstructed band, set `outerBoundary: "preserve-authored"` to retain every
174
+ segment of the reviewed outer source cut. Rounding that cut inward can leave pieces of
175
+ the damaged original eye margin behind. Paired outer points are then subdivided without
176
+ changing the cut; only the visible inner aperture is rounded. The older `rounded` outer
177
+ mode remains available for reproducibility, and requires its own review.
178
+ Indexed tissue chains are refined together. The fitted output
179
+ records the original points and maximum inset; it is safe to rebuild without applying
180
+ the refinement twice. This is a geometric interpolation of the agent's landmarks, not
181
+ an inferred anatomical contour. Inspect the result before selecting it: rounding alone
182
+ does not fix tissue depth, color, contact or deformation.
183
+
184
+ `outerEdgeSampling: "source-intersections-v1"` on an eye adds the original triangle-edge
185
+ crossings to the paired lid-band sampling. Its outer rim then follows the piecewise
186
+ source surface rather than bridging over small source ridges between uniform samples.
187
+ It preserves the authored cut and adds no anatomical selection. Keep checking the
188
+ closed pose: normal continuity and an actual eyelid fold need their own review.
189
+
190
+ If a designed `caruncle` is hidden behind an authored lining, its optional
191
+ `support: "corner-lining-v1"` positions it on the corresponding lining depth. It must
192
+ reference a corner in exactly one `canthusWalls` chain. The helper rejects centers
193
+ outside that lining's supported interval and rejects a tissue footprint that intersects
194
+ the iris envelope over the reviewed gaze range. Medial tissue may overlap peripheral
195
+ sclera; forcing it behind the entire sphere would hide it again and distort its shape.
196
+ The dimensions, placement and color remain explicit authored choices. This construction
197
+ is a prototype anatomical insert, not a scanned tear duct or a proof of eye realism.
198
+
199
+ For a reconstructed band that produces radial fan creases, `fairLidDepth: true`
200
+ uses harmonic depth fairing across the whole projected strip mesh. Both authored
201
+ rims remain fixed; projected columns interpolate the paired contours directly,
202
+ preventing independent Hermite tangents from bunching them at the canthi. The
203
+ result is refitted outside the optical envelope before computing normals and
204
+ blink targets. This is geometry repair, not a wrinkle texture filter. It does not
205
+ resolve an incorrect boundary shape or source pigment automatically. Inspect both
206
+ corners, neutral and full closure, obliques and gaze before selecting the asset.
207
+
208
+ A front silhouette alone cannot establish corner depth. `cornerDepths` optionally
209
+ records explicitly reviewed `pixel`, `depthM` (relative to the globe center, positive
210
+ forward), and `radiusM` for a corner. Local source support fades toward that depth;
211
+ the reconstructed lid and lining share a smooth tangent continuation from 85% of
212
+ the globe radius toward the corner. The curve stays outside the globe. Its angular
213
+ influence has a full-strength central half-width and smooth outer falloff. Inspect
214
+ both close lateral views (`SIDE_EYES=1`) and closure. Never assign these corrections
215
+ across characters without independently reviewing their actual depth and silhouette.
@@ -0,0 +1,115 @@
1
+ # Applying reviewed skin maps
2
+
3
+ The projection helper creates evidence and labels. It does not generate a body rig or
4
+ reconstruct missing anatomical detail. Keep source models immutable and store character
5
+ work outside this shipped skill, because GDK upgrades refresh the skill files.
6
+
7
+ ## Prepare the material revision
8
+
9
+ Use the project's existing character loader and material pipeline. In the Bitmagic engine,
10
+ read `agent-docs/character-surfaces.md` and use `RealisticCharacter.create(root, options)`
11
+ when that API is available. Do not assume a published engine version already contains it:
12
+ inspect the installed engine declarations first. Preserve working standard glTF materials
13
+ when the specialized adapter is unavailable and report that rendering integration remains.
14
+ Do not silently upgrade the engine or edit unrelated existing character types.
15
+
16
+ Author maps from licensed skin exemplars or the creator's own assets. Register the exemplar
17
+ to this character's reviewed facial landmarks and physical scale; never reuse another
18
+ character's target coordinates. Keep donor identity, tattoos, beard and complexion out of
19
+ relief transfer. Use anatomically appropriate detail for hands, palms, feet and body areas.
20
+ A generic repeated face tile is a preview fallback, not a finished regional detail library.
21
+ Retain attribution, source hashes, transformations and the authored physical amplitude.
22
+ For visible regional creases, the agent may author curves in exact evidence-image
23
+ coordinates and bake physically scaled relief onto independently labelled visible skin.
24
+ Record these as designed enhancements, not captured measurements. Keep glabrous palm
25
+ detail separate from facial follicles, and inspect the result at hand-sized framing.
26
+ The [regional detail helpers](regional-detail.md) evaluate authored crease curves and
27
+ licensed roughness patches without making anatomical decisions.
28
+
29
+ The source UV label map is top-left image data. Convert to the exporter/runtime's UV
30
+ convention exactly once. Bake source albedo as sRGB; roughness, metalness, masks, normals
31
+ and packed detail as linear data. Confirm with a known neutral patch and a source-material
32
+ comparison under identical lighting. A global saturation adjustment cannot diagnose a
33
+ color-space conversion bug.
34
+
35
+ ## Specialized engine contract
36
+
37
+ Explicit material extras opt into the character adapter. Untagged materials remain native.
38
+ For mixed skin/clothing primitives, `skinSurfaceBlend: true` uses atlas alpha as per-pixel
39
+ skin coverage. The packed linear RGBA atlas stores signed height around .5, roughness,
40
+ chromatic residual around .5 and coverage. `skinAtlasHeightRangeM` sets physical height.
41
+ `skinAtlasTexture` and optional `skinExpressionTexture` refer to embedded glTF texture
42
+ indices. `_FACE_UV` supplies atlas coordinates; `_FACE_WEIGHT` supplies coverage weighting.
43
+ `_SCATTER` is a fallback transmission attribute. Read the installed engine contract for
44
+ exact current fields rather than guessing their implementation.
45
+
46
+ Check physical texel density before increasing relief strength: a 4K full-body texture
47
+ can still sample the face at roughly half a millimetre per texel. In engines supporting
48
+ `skinFacialAtlasTexture`, retain the registered facial detail separately from body coverage.
49
+ The `skinFacialAtlasLayout: "detail-expression-halves-v1"` contract packs facial detail in
50
+ the left half and facial expression in the right half of one linear texture; its detail
51
+ height uses the same physical range as the body atlas. `_FACIAL_DETAIL` packs independently registered UV in XY and geometry-verified projection
52
+ visibility in Z, retaining the WebGPU vertex-buffer budget on skinned meshes.
53
+ This layer replaces facial detail baked into the body atlas, not skin coverage. Body
54
+ expression must be neutral for this layout. Packing replaces its shader sampler rather
55
+ than adding samplers beyond WebGL's budget. Compare the actual backends, preserve physical
56
+ filter widths when changing resolution, and check that coverage remains byte-identical.
57
+
58
+ The same packed texture can reserve additional rows for independently reviewed body
59
+ patches while keeping the original face texels. `skinFacialAtlasRegion` then records the
60
+ face rectangle within the detail half, and each vertex's `_FACIAL_DETAIL` coordinates
61
+ already address its assigned region. Reconstructed eyelids must use that rectangle too.
62
+ Keep patch alpha as detail blending only: the body atlas still owns skin coverage. This
63
+ retains the sampler and vertex-buffer budget instead of adding one material per patch.
64
+
65
+ Resolve embedded textures through the engine GLTF loader parser. Keep the scene diffusion
66
+ and transmission passes and the body AnimationMixer caller-owned. The adapter exposes
67
+ independent eye controls, preserves source materials on disposal, and does not create a
68
+ missing skeleton. Keep specular reflection outside diffuse scattering. A blurred beauty
69
+ image is not subsurface diffusion. Author channel diffusion ratios in asset metadata;
70
+ never infer skin type from character ID, race, height or RGB thresholds.
71
+
72
+ At a known skin/hair/lip boundary, material weights must sum to one; independent fades
73
+ expose the native response as a glossy line. Fill filtering gutters in UNUSED UV atlas
74
+ space from the nearest occupied texel, but never grow labels into unseen surface regions.
75
+ Check the actual zero-coverage and full-coverage endpoints against the native and skin
76
+ materials. Preserve armor, cloth, hair and optical surfaces during skin changes.
77
+
78
+ ## Source defects and acceptance
79
+
80
+ Separate source pigment spill, baked lighting, UV seams, normal errors, geometric creases
81
+ and missing coverage. Inspect unlit source, material labels and shaded results independently.
82
+ Color repair needs a separate authored selection. When a defect crosses UV islands, use
83
+ reviewed clean swatches in surface space; atlas-space harmonic fill may retain contaminated
84
+ island boundaries. A color repair cannot reconstruct missing hand geometry or eyelids.
85
+
86
+ Review all exposed regions and fixed-camera detail on both supported rendering backends.
87
+ Store region verdicts, current output hashes and review images beside the character. A
88
+ successful export or low conflict count is not visual acceptance. Keep incomplete regions
89
+ explicit and continue gathering views or authoring detail rather than calling a face-only
90
+ pass a complete character.
91
+
92
+ When a project uses the `viewerReady` metadata convention, `scripts/select_preview.py`
93
+ can validate the mechanical handoff. Supply `--asset`, `--metadata`, `--render-report`
94
+ and `--visual-verdict`. The render report is an array containing both `webgl` and
95
+ `webgpu` receipts with matching `actual`, empty `errors`, and the current `outputSha256`.
96
+ For combined runtime reports use `--variant eyes` or `--variant surfaces` to read
97
+ `assetHashes` instead. The agent-written verdict must identify the same output hash,
98
+ use `status: "local_preview_with_known_issues"` and `wholeCharacterAccepted: false`,
99
+ and list actually inspected images as `visuallyInspected: [{file, sha256}]`, relative
100
+ to that verdict. The helper checks current image bytes before selecting the preview.
101
+ It does not inspect those images, publish an asset, or declare the character finished.
102
+
103
+ Use the [installed exporters](exporters.md) to build these authored inputs into GLBs.
104
+ [The playground example](playground.md) records the tested asset layout and review harness;
105
+ its browser review commands still require that separate checkout.
106
+
107
+
108
+ ### Regional height composition
109
+
110
+ Independently registered body patches may declare `skinRegionalAtlasHeightMode: "additive-v1"` with `skinFacialAtlasRegion: [0, 0, 1, faceEndV]`, where `0 < faceEndV < 1`. The face occupies the atlas's top rows; body patches occupy rows below it. In those body rows, patch relief adds to the underlying body height rather than replacing authored palm creases or other regional folds. Facial relief retains replacement behavior, and body coverage is unchanged. Roughness still blends to the authored patch value. Assets without this explicit mode retain their previous replacement behavior.
111
+
112
+ This uses the existing packed texture and VEC3 binding on WebGL and WebGPU; it adds no sampler or vertex attribute. Do not compensate for erased crease layers by increasing microdetail strength. Check the composition with the patch enabled and disabled at the same camera, and retain the physical amplitude of each layer.
113
+
114
+
115
+ Regional bindings need coherent UV coordinates at every corner of a triangle touching the patch, including corners with zero detail weight. A zero-weight corner still participates in UV interpolation. Leaving its old facial coordinates in place can make the triangle sample unrelated atlas texels. Extend coordinate support by adjacent triangles while keeping their detail weight zero and semantic coverage unchanged; reject overlapping active patch bindings or split the geometry explicitly.
@@ -0,0 +1,78 @@
1
+ # Applying the reviewed maps in the character-forger playground
2
+
3
+ The maintained helpers are in `highquality/src/` at the character-forger repository root.
4
+ They are not standalone engine binaries. Use the project's Python with NumPy, Pillow and
5
+ SciPy, and Blender for projection. Keep this adapter's single mesh/primitive limitation
6
+ explicit; do not silently flatten a rigged or instanced scene to make it pass.
7
+
8
+ 1. Prepare and annotate exact views; dense-bake with `--surface-data --triangle-labels`.
9
+ 2. Author `highquality/materials/faces/ID.json` from this character's face view. The target
10
+ bounds describe normalized body X/Z in Blender world space. Pixel dimensions belong to
11
+ their respective source and target views. Reusing donor correspondence is valid; reusing
12
+ another character's target landmarks is not. Hair surrounding a face is an enclosure,
13
+ not one filled exclusion polygon covering the face.
14
+ 3. Run `python highquality/src/build_face_detail.py --id ID`. It registers band-limited
15
+ licensed scan relief and emits attribution. The amplitude is an authoring estimate,
16
+ not measured displacement. Empty coverage is an error requiring a profile correction.
17
+ 4. Run `python highquality/src/vision_materials.py --id ID --masks MASK_REVISION --evidence EVIDENCE`.
18
+ The adapter writes `characters/ID/high/v1/materials/v2/character.glb` and a report. It
19
+ preserves source geometry/buffer bytes, nodes, existing skin data and animation data.
20
+ This does not add a missing body rig. Inputs are currently the immutable HY source.
21
+ 5. Rebuild the viewer with `node hero/viewer/build.mjs`. Run
22
+ `CHARACTER_ID=ID node highquality/tests/vision_skin_smoke.mjs` on both renderers, then
23
+ inspect the screenshots. Tests check loading and camera stability, not anatomical truth.
24
+
25
+ The detail atlas uses source UVs and includes all explicitly observed skin. Face detail is
26
+ registered from a licensed scan; other follicular skin currently uses reduced scan relief.
27
+ Palms/soles use authored nonfollicular ridges. This is not a library of captured regional
28
+ hand/foot exemplars. Source geometry retains its existing larger creases. The report keeps
29
+ unresolved labels and texture defects visible.
30
+
31
+ Engine contract: explicitly tagged skin/hair materials opt into `createCharacterSurfaceMaterial`.
32
+ RGBA detail stores signed height around .5, roughness, chromatic residual and coverage.
33
+ `_FACE_UV` supplies coordinates, `_FACE_WEIGHT` coverage, `_SCATTER` the fallback transmission
34
+ attribute. Atlas data is linear; albedo is sRGB. The helper excludes defective HY normals on
35
+ labelled skin, keeps native materials elsewhere, and performs geometry-corresponding skin
36
+ UV seam colour equalization. It cannot remove arbitrary baked lighting or interior texture
37
+ stitches merely by correcting normal maps.
38
+
39
+ Material reports remain `shaded_review_required` until actual exposed regions and rendered
40
+ maps have been reviewed. Do not convert low conflict counts into a whole-character quality
41
+ claim. The b3658 scalp albedo stitch, ambiguous nails and b3843 palm colour spill are examples
42
+ of asset defects that require separate correction.
43
+
44
+ ## Per-pixel material boundaries
45
+
46
+ After the v2 evidence build, `python highquality/src/vision_blend_materials.py --id ID`
47
+ creates an opt-in v3 revision. `--all-surfaces` creates v4 with hair/lip/nail PBR maps
48
+ as well. Both preserve geometry. They currently require one shared source material/UV
49
+ layout; unsupported native specular or fiber maps fail rather than being overwritten.
50
+
51
+ `skinSurfaceBlend: true` makes the engine use atlas alpha for skin response, including
52
+ diffusion and thin-skin transmission. Zero coverage retains the native response. Coverage
53
+ must have UV gutters: copy nearest occupied texels into unused atlas space, never into
54
+ unobserved surface regions. This distinction fixes false seams without inventing anatomy.
55
+ At skin/hair/lip boundaries, known material weights must sum to one. Independently fading
56
+ both sides to zero exposes the source material as a bright halo.
57
+
58
+ V4 expresses fiber and lip response through standard glTF ORM/specular/anisotropy/sheen
59
+ maps. The current fiber direction is provisional; author a comb-flow field before calling
60
+ hair finished. Its skin inspector shows actual skin coverage (white), not an entire mixed
61
+ primitive falsely labelled as skin. `viewerReady` only selects a tested local preview;
62
+ it is not the region-level semantic or final character quality approval.
63
+
64
+ ## Runtime adoption
65
+
66
+ The engine now provides `RealisticCharacter.create(root, options)` for the loaded GLTF.
67
+ Use the engine's `createGltfLoader()` and resolve embedded atlas indices through its parser.
68
+ The adapter validates UV attributes, retains native untagged materials, preserves coverage
69
+ when detail is disabled, and exposes independent eye controls. It commits material changes
70
+ only after texture resolution succeeds. Scene postprocessing and the body mixer remain
71
+ caller-owned. See the GDK engine document `agent-docs/character-surfaces.md` for ownership
72
+ and pass ordering; do not copy the lab's former material-loading loops into each game.
73
+
74
+ For a rigged playground derivative, use `highquality/src/assemble_character.py` after
75
+ shared Blender binding. It converts refined geometry to canonical bind coordinates and
76
+ keeps canonical inverse-bind matrices; exercise pose reset and body motion, not only a
77
+ rest-position comparison. Unrigged material/eye previews can coexist with a rigged body
78
+ variant. Determine normalization from the loaded asset, not a catalog-wide rigging flag.
@@ -0,0 +1,97 @@
1
+ # Face and eye profile authoring
2
+
3
+ These schemas describe authored inputs to the installed exporters. Values that locate
4
+ anatomy must come from images of this character. Keep the physical dimensions and source
5
+ hashes beside the profile; never copy another character's target coordinates.
6
+
7
+ ## Facial detail registration
8
+
9
+ Write `highquality/materials/faces/ID.json` with:
10
+
11
+ - `version: 2`, `id`, `sourceSha256`, `evidenceImage` (workspace-relative), and
12
+ `evidenceImageSha256` identifying the exact source and reviewed frontal image.
13
+ - `annotationImageSize`: the square target image's actual pixel dimension.
14
+ - `bounds: [minX, minZ, maxX, maxZ]`: the target image rectangle in normalized body
15
+ coordinates. The current adapter requires a frontal view with direction `[0,1,0]`
16
+ and up `[0,0,1]`; align an arbitrarily oriented source explicitly before preparing
17
+ evidence. Normalized X is `(worldX - boundsCenterX) / bodyHeight`; normalized Z is
18
+ `(worldZ - boundsCenterZ) / bodyHeight + .5`. For a frontal evidence camera, its
19
+ `targetOffset` and `span` give this rectangle directly:
20
+ `[offsetX-span/2, .5+offsetZ-span/2, offsetX+span/2, .5+offsetZ+span/2]`.
21
+ - `sourceBounds` and `sourceAnnotationImageSize`: the donor registration view's
22
+ rectangle and pixel size. Generate and inspect it with the helper below.
23
+ - `landmarkNames`, `sourcePixels`, `targetPixels`: equal-length ordered arrays of
24
+ corresponding points. Use a well-spread non-collinear set spanning forehead,
25
+ temples, cheek/jaw/chin boundary, eye corners, nose and mouth. These define the
26
+ correspondence and its supported hull; points outside the hull receive no face detail.
27
+ - `regions: {"eyes": [...], "brows": [...], "lips": [...]}`: each list contains polygons
28
+ of target image pixels. These exclude those regions from ordinary facial detail.
29
+ Include facial-hair exclusions in the exclusion polygons too. Empty lists are valid
30
+ only when that exclusion is actually absent in the selected patch.
31
+ - `atlasSize`: 2048 or 4096. `independentFacialDetail: true` retains the full facial
32
+ resolution in the packed runtime atlas.
33
+ - `detailHeightRangeM`: full signed encoding range in metres (zero is .5).
34
+ `detailAmplitudeM`: authored donor-band calibration, not measured scan amplitude.
35
+ Compare the resulting relief at face-sized framing under side light; do not compensate
36
+ for missing texel density by increasing amplitude.
37
+ - `diffusionProfile`: three positive authored channel falloff ratios, such as the
38
+ renderer's human-skin default `[1,.55,.3]`. Fantasy skin ratios are appearance choices.
39
+
40
+ Generate the fixed licensed donor's reference image without a playground checkout:
41
+
42
+ ```sh
43
+ python scripts/prepare_face_reference.py --workspace /path/to/assets \
44
+ --out /path/to/assets/evidence/donor --size 900
45
+ ```
46
+
47
+ Use `donor-front.png` and `registration-view.json` to author `sourcePixels`. Pixel origin
48
+ is top-left for both source and target. The helper uses the same donor projection and
49
+ UV convention as the atlas builder; choosing points from a differently framed photo
50
+ will misregister the relief. It renders the existing licensed files and downloads nothing.
51
+
52
+ ## Optical eye fit
53
+
54
+ An eye profile has `id`, `sourceSha256`, `evidence` (absolute prepared-view folder),
55
+ `skinRevision: "v4"`, and exactly two entries in `eyes`. Each entry requires:
56
+
57
+ - `name`, `anatomicalSide: "left" | "right"`, and `view`, matching a manifest view.
58
+ - `irisCenterPx: [x,y]`, `irisRadiusPx`, and `openingPx`: an ordered convex aperture
59
+ polygon in that exact view. Inspect both obliques before choosing the final depth.
60
+ - `upperContourIndices` and `lowerContourIndices`: ordered indices along the corresponding
61
+ aperture edges, including their corners. These guide contacts, lashes and closure.
62
+ - `globeRadiusM`, `corneaBulgeM`, `frontOffsetM`, `pupilRatio`, `irisColorLinear` (RGB).
63
+ These are designed optical dimensions and pigment. The iris must fit inside the globe;
64
+ confirm against the character's physical height and side views.
65
+
66
+ Use `openingAuthority: "reviewed-contours"` only after explicitly inspecting the aperture
67
+ when the source has no separately classified ocular primitive. `conformOpenLids: true`
68
+ pushes intersecting source lid tissue outside the fitted globe; inspect its effect.
69
+ Optional `lashes` uses `upperCount`, `lowerCount`, `upperLengthM`, `lowerLengthM`,
70
+ `radiusM` and an authoring note. Reconstructed bands (`outerLidPx`, `lidSkinSamplesPx`),
71
+ corner lining (`canthusWalls`), medial tissue (`caruncle`) and brow strands (`browGroom`)
72
+ are described in [eyes.md](eyes.md). Start with the source-preserving fit; optional
73
+ reconstruction is not automatically an improvement, as the rejected elf trial showed.
74
+
75
+ The current blink is a fitted geometric morph, not a biomechanical eyelid simulation.
76
+ Preserve source folds unless an independently reviewed correction improves the result.
77
+ Simple smoothing of the closed support band was rejected because it created visible
78
+ rings. Treat any future smoothing as a new fit experiment requiring matched neutral
79
+ and closed-eye review.
80
+
81
+ ### Several independent source-color repairs
82
+
83
+ `materials/repair-profile.json` may retain the single-operation form or contain
84
+ `{"repairs": [operation, ...]}`. Each operation has its own `mask`, `purpose`,
85
+ optional `cleanSwatches`, `blendWidthM` and optional `evidence` workspace path.
86
+ The latter permits fresh, color-faithful swatch views without invalidating a
87
+ separate anatomical bake whose camera/geometry evidence is unchanged. Source,
88
+ image and correspondence hashes are checked. Every donor must still land on
89
+ independently classified skin. Operations run in order and report separately;
90
+ use disjoint selections unless the overlap is explicitly intentional.
91
+
92
+ Baked illumination in a generated albedo can make a correctly lit surface dark
93
+ or plastic. Inspect the unlit runtime albedo and color-faithful evidence first.
94
+ A swatch-based correction is an art-directed reconstruction, not measured
95
+ reflectance recovery. Do not globally brighten skin or infer defects from RGB.
96
+ Review the selected region, donor color, transitions and the final relit result;
97
+ retain the original and the rejected candidates.