5.7 KiB
5.7 KiB
Asset Contract Reference
This is a working summary. The authoritative sources remain
docs/blender-assets.md, docs/asset-tooling.md, ADR-0013, the tests in
src/test/tests/ and the constants in tools/blender_assets.py /
tools/npc_pipeline.py.
Library inventory
- Character variants (8):
npc_casual,npc_jacket,npc_coat,npc_vest,npc_dress,npc_hoodie,npc_firefighter,npc_guard. - Frozen fallback:
npc_base/assets/models/generated/npc_base.glb. - Gear: 18 attach-space pieces covering head, back, chest and hand items.
- Library props: 20 Blender-authored props plus 6 generated props.
- Venues: procedural venues in
src/game/world_builder.gd; Blender venue geometry follows the same budgets and collision/provenance rules.
Skeleton and geometry
The contract skeleton has 13 bones:
Head, Spine, Neck,
HipL, HipR,
KneeL, KneeR,
ShoulderL, ShoulderR,
ElbowL, ElbowR,
HandL, HandR
Requirements:
npc_basemesh node exists and is skinned underRig.- Limb node names stay stable for
NpcAvatarand tests. - Front is Blender −Y / Godot +Z.
- Feet are grounded at approximately y = 0; no floating origin.
- Units are metres; character height is approximately 1.8 m.
- No zero-area/duplicate degenerate faces in the exported mesh.
- Every character has UVs in [0,1] unless a planned UDIM/atlas change is explicitly accepted.
Material slots
Exactly these five tint slots:
skin, cloth, pants, accessory, hair
- Neutral albedo is authored in Blender; runtime tinting is authoritative.
- Slot names are contract values; do not rename or add a sixth slot casually.
- The procedural fallback (
NpcAvatar._build_body) must keep working when the GLB is missing.
Budgets
| Asset | Limit |
|---|---|
| Library character | 8,000 triangles / 8,000 glTF vertices |
npc_base fallback |
6,000 triangles / 4,000 vertices |
| Gear piece | 1,500 triangles |
| Prop | 4,000 triangles |
| Library prop/venue total | must stay inside the venue tests and library budget |
CHAR_MAX_TRIS, CHAR_MAX_VERTS, GEAR_MAX_TRIS, PROP_MAX_TRIS and related
constants live in tools/blender_assets.py. The budget is per character, not an
average. Measure after every mesh change. Do not lower the cap to make a diff
pass.
Gear and hand items
- Gear is authored in the attach-point space documented by
GEAR/GEAR_ATTACH/ATTACH_BLENDER. blender_assets.py fitmeasures gear boxes against the character's head band, clothing radius and back clearance.- Runtime offsets are intentional:
NpcAvatar.GEAR_OFFSETS = {"lanyard": Vector3(0,0,0.04), "firefighter_helmet": Vector3(0,0.03,0)}NpcAvatar.HAND_ITEM_FORWARD = Vector3(0,0,0.04)
- An offset is not an authored-asset change; do not bake it into the GLB without a separate contract decision.
- Open-palm grip (no finger-curl rig) is the accepted stylized limit.
Textures and AO
- NPC maps are 256² albedo + normal + packed ORM.
TEX_SIZE = 256intools/npc_pipeline.py.- Fabric UV scale is
Materials.NPC_FABRIC_UV_SCALE = Vector3(4,4,1). - Cloth/pants skip the per-character baked AO; skin/hair/gear keep it. This avoids the large blotchy magnification that appeared at 256².
- Gear/props may have their own AO maps;
tools/bake_ao.pywrites<name>_ao.pngnext to the GLB and Godot wires it into the AO channel. - Never overwrite an existing committed image; use a new
-vNcandidate and promote only after review. - Run
python3 tools/asset_pipeline.py audit <path>and the relevantnpc_pipeline.py auditbefore committing map changes.
File map
| Path | Role |
|---|---|
tools/blender_assets.py |
Catalogue, builders, audit/fit/inspect/texels/sheet. |
tools/npc_pipeline.py |
npc_base builder, texture preparation and audit. |
tools/bake_ao.py |
Blender AO bake into <name>_ao.png. |
tools/npc_proportions.py |
Exported-GLB proportion audit (no Blender). |
tools/npc_baseline.py |
Contact sheets/comparisons (no Blender). |
assets/models/blender/manifest.json |
Generated asset manifest. |
assets/models/blender/**/*.glb |
Committed library assets. |
assets/models/generated/npc_base.glb |
Frozen NPC fallback. |
assets/textures/npc/*_{albedo,normal,orm}.png |
Committed NPC maps. |
src/test/capture_npc_baseline.gd |
48-frame neutral baseline. |
src/test/capture_npc_review.gd |
96-frame final-context review. |
Provenance and source rules
- Procedural Blender assets are project-owned.
- External/CC assets need ADR-0015 clearance: CC0 preferred, CC-BY only with
attribution in
CREDITS.md; no service assets with redistribution limits. - Editable
.blendfiles underassets/models/blender_src/are gitignored; only exported.glb, AO maps, manifests and committed preview sheets ship. - AI-generated source images are development inputs, not shipped assets. Keep raw generations under gitignored paths until picked, checked and credited.
- Do not copy a downloaded/Street View/AI reference into a committed asset without the licence and provenance review.
Verification invariants
The asset pass is not complete unless:
python3 tools/blender_assets.py auditexits 0.python3 tools/blender_assets.py fitexits 0 and the report is reviewed.python3 tools/npc_proportions.py reportpasses the stylized guide.python3 tools/npc_pipeline.py auditpasses when the base/textures changed.- The 48-frame baseline and 96-frame final-context review are captured, with no blank frames.
- The 24-NPC budget smoke is inside its frame budget.
- The full Godot suite and Python tooling tests pass.
- No runtime contract, renderer or dependency changed except the rebuilt assets and their generated metadata.