agentleFS
willy92winswilly92wins/DayZ-Modding-Knowledge-Pack/skills/dayz-characters/SKILL.md

dayz-characters

Skill20 starsChanged 42 days agoMITView on GitHub

Import and author DayZ humanoids: infected/zombies, survivors and human NPCs on vanilla character bases. Covers retopo and rigging to OFP2_ManSkeleton, bind pose, weights, baked scale, UV/normal bake/textures, character LODs, config.cpp/model.cfg inheritance and in-game deformation. Use for custom zombie/infected/survivor/NPC, ragdoll, sandstorm PPE, "rig to OFP2_ManSkeleton", mesh explodes or stretches, spiky/pinched vertices, all weights on Pelvis, missing bone, giant infected, see-through body holes, foot sliding, wrong facing or animations not playing. Always invoke before rigging/configuring a DayZ humanoid. Compose with ai-3d-to-dayz, dayz-model-pipeline, dayz-animation-pipeline, dayz-pbo-build and dayz-test-ingame; use dayz-vehicles/dayz-aviation for those domains.

The file

We split this skill into the rules it gives an agent

7 rules. About 0 are common, 4 are distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    GOTCHA that silently ruins the bind: before Blender bone-heat auto-weights, you MUST bake the scale into the armature …

    line 71
  2. Distinctive:

    Implication for a custom infected: if your mesh carries weights on bones the zed bind lacks (face, fingers, IK), the engine resolves them …

    line 131
  3. Very specific:

    The real root cause behind ~8 sessions of "arm bind" pain: After making model.cfg's OFP2_ManSkeleton byte-match a vanilla zombie's (159 …

    line 177
  4. Distinctive:

    THE WALL: only one mod that modifies player/creature animations can be loaded at a time — loading two crashes the client/server (Enfusion …

    line 268
  5. Very specific:

    Geometry (collision): must be closed and convex ([BI Validating Geometries]).

    line 276
  6. Distinctive:

    Next (decided with user): STOP iterating against the rig FBX.

    line 471
  7. Distinctive:

    ONLY armbands carry camoMale_big_a/b + small_a/b complexion variants), empty Geometry LOD with autocenter=0 is the vanilla worn pattern.

    line 570

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

DayZ Humanoid Character Modding

Custom humanoid characters in DayZ — infected (zombies), survivors, human NPCs — are built by reusing the vanilla character chain, not from EntityAI. The hierarchy (DZ_LightAI → DayZInfected → ZombieBase → ZombieMaleBase / ZombieFemaleBase → variants) gives you the skeleton OFP2_ManSkeleton, every infected animation, and the AI driver for free through inherited config — so the only thing you author is a new mesh. The real cost of the whole project is one step: rigging that custom mesh to OFP2_ManSkeleton. Everything else is generic pipeline work delegated to the skills below.

This skill is the character-specific layer on top of dayz-model-pipeline (generic geometry / LODs), dayz-texture-pipeline (textures), dayz-animation-pipeline (the skeleton/anim deep-dive), and ai-3d-to-dayz / hunyuan3d-local / rodin3d-skill (mesh generation). It is the humanoid counterpart to dayz-vehicles (wheeled) and dayz-aviation (flight).

Scope: anything that walks on the player skeleton — infected, survivors, NPCs — generated by AI, modeled from scratch, or imported from another game. (desde 1.30 Exp: female military ZmbF_SoldierNormal_Base / ZmbF_ArmyOfficer / ZmbF_eastSoldier_Base and Nasdara Zmb*_taki* — references/dayz-1-30-characters.md.)

PREFLIGHT

Gate real build work on /dayz-preflight (P:\ mounted, AddonBuilder, P:\Mods junction), per _shared/dayz-conventions.md. Authoring config / rigging / baking offline does not need it; packing does.

Before rigging a zombie/infected: its canonical bind is the 95-bone hermit_newbindpose.xob, a SUBSET of the player skeleton — NOT OFP2's full player bone list. Read THE CANONICAL-BIND INVARIANT (ZED bind) first. (desde 1.30 Exp: that zed bind is unchanged; global bone indices are name-derived, not XML index values. [CHANGELOG] See references/character-rigging.md.)

THE PIPELINE (who owns each stage)

StageOwnerNotes
Generate / model the meshai-3d-to-dayz, hunyuan3d-local, rodin3d-skillmulti-view + A/T-pose helps the rig; see CASE LOG
Retopo to low-poly manifoldai-3d-to-dayz / dayz-model-pipelineAI retopo leaves non-manifold — clean it
RIG to OFP2_ManSkeletonTHIS skillthe expensive, character-specific step → references/character-rigging.md
UV-unwrap + normal/AO bake (high→low→_nohq)THIS skill + dayz-texture-pipelinecharacter-specific gotchas (conform misalignment, AI-high normals) → references/character-uv-bake.md
Texture _co / _nohq / _smdidayz-texture-pipelineSubstanceToArma preset
Character LODs (Visual / Geometry / Fire / Memory / View)THIS skill + dayz-model-pipelinesee CHARACTER LODs
config.cpp inheritance + model.cfgTHIS skillinherit ZombieMaleBase → skeleton+anims+AI free
PBO / binarizedayz-pbo-build
In-game testdayz-test-ingame (+ dayz-mcp-verify)anims / foot-slide / collision / hit / spawn

RIGGING TO OFP2_ManSkeleton (the core — read references/character-rigging.md)

The single hardest step. Summary of the verified workflow ([LFInfectedBig ✓] 2026-06-24):

  • Skeleton = OFP2_ManSkeleton (player + infected share it). The mesh MUST use the exact bone / selection names. In DayZ a "bone" in model.cfg is a named vertex selection weighted per-vertex; there is no shipped armature — model.cfg defines the skeleton, the .p3d carries selections+weights.
  • Armature source = the official rig FBX animation_rig_character.fbx from BohemiaInteractive/DayZ-Misc → "Rig and Animations". Blender-native FBX: armature with 114 bones (exact OFP2_ManSkeleton names) + a weighted reference body Male_body in the canonical bind A-pose. Units are centimetres. Helpers (*_Dummy, Weapon_*, EntityPosition) import as EMPTIES, not bones → ignore them for body deform.
  • GOTCHA that silently ruins the bind: before Blender bone-heat auto-weights, you MUST bake the scale into the armature (transform_apply(scale=True)). Scaling only the object/parent runs bone-heat at the rig's native scale against your differently-scaled mesh → every vertex collapses onto Pelvis and the rest of the bones get zero verts. Symptom: posing any limb does nothing.
  • Bind pose: the mesh MUST ship in the canonical A-pose (anims are relative to that rest). If your mesh's limbs sit at a different angle, conform them to the rig (see reference) — a per-region rotation masked by the auto-weight value gives a crease-free shoulder.
  • Cleanup: limit total influences to ≤4 per vertex + normalize; target 0 zero-weight verts (zero-weight → pinched/spiky verts in-game). Disable deform on face/finger/eye bones for a body rig.
  • Blender deform-check = gross-motion sanity ONLY (does a limb move at all; cross-midline weight bleed). It is a FALSE GATE for real deform — the engine skins against the real OFP2_ManSkeleton, not your rig-FBX armature (see the FALSE GATE section below). The deform gate is in-game/Buldozer. Bone-name mismatch → RPT logs Bone X doesn't exist in skeleton OFP2_ManSkeleton and that bone silently does not animate; a stray unnamed selection not in skeletonBones[] makes the mesh explode.

Bone catalog by zone lives in dayz-animation-pipeline → references/player-skeleton.md.

THE CANONICAL-BIND INVARIANT — why a rig that looks fine at rest deforms under anims

[✓ in-game, LFInfectedBig S7 2026-06-24] The engine skins the mesh against the canonical OFP2_ManSkeleton bind (the shared rig's bone positions), NOT a bind derived from your mesh. So the inherited vanilla anims deform correctly only if your mesh matches that canonical bind in three ways:

  • Scale — at ~vanilla size (the rig's Male_body ≈ 1.8 m). A mesh baked oversize (LFInfectedBig was 2.277 m ≈ 1.27×) is bound against the 1.8 m canonical positions → limbs swing from the wrong pivots → gross deform under anims (not just foot-slide). Rescaling to ~1.8 m removed the catastrophic deform.
  • Orientation and handedness — facing the same way as the rig, and not mirrored. A 180°-about-vertical error makes the character face / walk backward AND deform; a mirror makes limbs fling (next section). The (x,z,−y) transform shipped backward; (−x,z,y) turned it round but mirrored it. Both are det +1. The map that gets facing and side right is the det −1 (x,z,y) of dayz-model-pipeline Rule 12 (corrected 2026-10-01; derivation in references/character-rigging.md §6).
  • Proportions / joint positions — the mesh's anatomical elbow/knee/shoulder/wrist must sit at the canonical bone positions. An AI mesh has its OWN proportions; a UNIFORM-scale fit (character-rigging.md §1) preserves canonical proportions but cannot match a differently-proportioned mesh → bones land off the anatomy → limbs overextend / stretch under anims. Needs a proportion conform (§3), not just the arm-angle conform.

The tell: fine at rest, breaks only when animating. At the bind pose the skinned output equals the rest mesh regardless of weights, so "looks right standing" proves nothing about the bind — only an anim (or a deform-test posing real bone transforms, character-rigging.md §5) exposes a scale/orientation/proportion mismatch.

Diagnostic (offline, no in-game): per bone, distance from the bone head to the weighted centroid of its verts; large distances (LFInfectedBig: LeftUpLeg 0.33 m vs 0.22 bone-len, hands 0.20 vs 0.06) = the bone doesn't sit on the anatomy it drives → that limb will deform. (_export/diag_bind_mismatch.py.)

py3d transmits the per-vertex weights faithfully (the cross-side fix and the S7 fixes all propagated in-game) → Object Builder is not required for the export encoding itself.

⚠️ A ZED'S canonical bind is hermit_newbindpose.xob (95-bone SUBSET), NOT the player skeleton [✓ verified vanilla 2026-06-28]

Infected do NOT skin against the player rig. ZombieBase (and thus ZombieMaleBase, which your custom infected inherits) carries an enfanimsys block — verified DZ\characters\zombies\config.cpp:71-77: graphname=…\infected\infected_main\infected.agr, defaultinstance=…infected_main.asi, skeletonName="hermit_newbindpose.xob", meshObject="…\z_hermit_m.xob". hermit_newbindpose.xob is the zed's bind pose, and it is a reduced subset. Counting <bone> in DZ\anims\cfg\skeletons.anim.xml (method: grep -c): hermit_newbindpose.xob = 95 bones; player_testing.xob = 172 bones. The 77-bone delta the zed OMITS = the entire face rig (~40 face_*, eyeleft/right, lids, lips, tongue), the finger bones (pinky/ring), IK helpers (*handik, *forearmdirection*, righthandik_helper), and all weapon bones (weapon_bone_01..06, magazine, trigger, bolt, holsters, cameras).

  • Implication for a custom infected: if your mesh carries weights on bones the zed bind lacks (face, fingers, IK), the engine resolves them wrong at runtime → deform, including at idle (the infected graph's default pose ≠ your A-pose). Conform/weight the mesh to the 95-bone hermit_newbindpose set, or override enfanimsys skeletonName/meshObject to player_testing.xob to restore the missing bones (the community fix for headgear/face stretch on zeds — Hoxdolum, DayZ Modders Discord 2024, mechanism confirmed vanilla).
  • Three bone catalogs — do NOT conflate: the Enfusion enfanimsys .xob bind pose (zed 95 / player 172) is a DIFFERENT layer from the RV model.cfg OFP2_ManSkeleton (vanilla zombie ~159 bones, below). "Match the canonical bind" means the .xob the engine actually binds (hermit_newbindpose), not just the model.cfg skeleton. A mesh weighted to OFP2's full player bone list can still deform on a zed for this reason alone. (desde 1.30 Exp: infected.agr remains the workspace index but is now Enfusion AnimSrcGraph text listing .agf subgraphs. Re-verified enfanimsys at exp/characters_zombies/DZ/characters/zombies/config.cpp:50-57 (digest/skill :71-77 was DeRap-shifted). Custom infected graphs: re-save the workspace in Workbench 1.30. Bone-index rule: references/character-rigging.md.)

⚠️⚠️ The Blender deform-test is a FALSE GATE — only in-game (or Buldozer) validates deform [LFInfectedBig S8 2026-06-24]

The single most expensive lesson of this project. Posing your imported rig-FBX armature in Blender and measuring edge-stretch does NOT reproduce the engine's deform. S8 drove the Blender edge-stretch from 34× → 6× across THREE rebuilds (re-weight, TPS conform, depth-preserving conform) while the in-game deform stayed unchanged and broken (user: "sigue igual" — weird at idle AND animating) — a 3× false green. Do NOT trust the Blender armature pose-test as the deform gate; it cost ~12 offline iterations that produced zero in-game improvement.

  • Why it lies: the engine skins against the REAL OFP2_ManSkeleton from DZ_Characters (its bind / inverse-bind matrices + the skeleton your model.cfg declares), NOT the rig-FBX armature you posed in Blender. If your model.cfg skeleton hierarchy or the mesh's authored rest pose diverges from vanilla even slightly, the engine deforms wrong no matter how clean the Blender pose-test renders.
  • "Weird at REST / idle too" (not only walking) ⇒ bind / skeleton mismatch, NOT weights. At the true bind pose LBS returns the rest mesh regardless of weights; if it looks wrong while barely moving, the engine's bind ≠ your mesh (model.cfg skeleton wrong, or rest pose ≠ engine bind). Re-weighting will NOT fix it.
  • Ground truth = a debinarized VANILLA character (DZ\characters\zombies\*.p3d → external ODOL→MLOD converter). Its mesh IS authored in the exact engine bind pose, with the exact selection structure and a model.cfg that the engine accepts. Copy its model.cfg skeleton verbatim and conform/weight your mesh against ITS bind — do NOT hand-author a 114-bone hierarchy and assume it matches OFP2 (it didn't, here). (Scope: the debinarized vanilla is reliable for skeleton, named selections, model.cfg wiring and weights — NOT for visual-LOD vertex POSITIONS, which ODOL→MLOD conversion corrupts for character bodies; for positions use the Male_body of the rig FBX — see the addendum below / SP-034.)
  • Valid deform gates, in order: (1) in-game spawn — the real one; (2) Buldozer (BI model viewer, real engine skinning). The Blender armature pose-test is good only for gross "does a limb move at all" sanity.
  • What DID hold up offline (so the offline work isn't all waste): the winding gate check_dayz_winding.py (it held for the winding of the det +1 builds of that time, which in game turn out lit inverted; rewritten 2026-10-02 for Rule 12, it now fails those builds on their normals, see OFFLINE GATE below and references/character-rigging.md Stage B), scale (f from armature span), orientation (T2), and always LOOK at the REST SIDE/depth render — a TPS conform to near-coplanar bone-midpoint targets flattened the mesh to paper (2D in-game); the flat side-view was in the render folder a whole build cycle before it was noticed.

⚠️ The mesh can be left/right MIRRORED vs the canonical skeleton — anims fling a limb back/up [LFInfectedBig S9 2026-06-25]

The real root cause behind ~8 sessions of "arm bind" pain. After making model.cfg's OFP2_ManSkeleton byte-match a vanilla zombie's (159 bones, isDiscrete=0, exact parents/order — which restored the leg leftupleg→propthighleft→leftleg chain), the legs walked but the arms still flung back/up, equal at idle and animating. The rest arms were a sane A-pose, so it was not pose/proportion — the whole mesh was reflected in X relative to the skeleton's left/right convention: a left* selection's geometry sat where the canonical right* bone lives, so the inherited anim drove it about a pivot ~2× a limb-width away → big lever → the limb swings off even under tiny idle motion. AI/GLB meshes that went through a reflection (then had winding reversed to render right-side-out) are prone to this, and a 180°-about-Y orientation fix can leave a residual reflection. Root cause, found 2026-10-01: the reflection was the export map itself. Blender is right-handed and DayZ left-handed, so every det +1 map ((x,z,−y), (−x,z,y)) mirrors the mesh, and the face reversal it then needs hides the mirror (dayz-model-pipeline Rule 12; references/character-rigging.md §6).

The test (offline, decisive): debinarize a vanilla male (external ODOL→MLOD converter), read the embedded Skeleton bones + the visual LOD's per-vertex vertex_bone_ref, and compute each bone's vert-X relative to the spine center. Vanilla puts left* on +X, right* on −X, consistent across shoulder/hip/arm (use large-n bones; pelvis/hand centroids are noisy). Opposite side ⇒ mirrored. The conversion adds only boundingCenter and reverses winding — it does NOT negate an axis — so ODOL-X == model-X and the comparison is valid. (Gotcha: vanilla ODOL named_selections carry bone NAMES but EMPTY selected_vertices; real membership is vertex_bone_ref pairs → sub_skeletons_to_skeleton → skeleton bone index.)

The fix (two options; prefer the second):

  • Swap L↔R selection names in every LOD (leftarm↔rightarm, all sub-bones + fingers + the l*/r* memory points). Geometry/winding/normals stay byte-identical (confirmed-good rendering is untouched); only which bone each side binds to changes. Lowest risk, reversible. Leaves the mesh visually mirrored — fine for a symmetric humanoid; an off-center detail (a chest hole) lands on the mirror side (cosmetic).
  • Un-reflect the geometry: negate X on all verts + reverse winding (and drop the swap). Makes the mesh properly handed. Bigger change (re-verify the winding gate + facing) but it can also clear a reflection side effect: single-sided faces culled from grazing angles the upright anim never reaches — e.g. a ragdoll corpse going invisible from one angle. Swap alone leaves the reflection, so that culling can persist; un-reflect fixes both at once. On a (−x,z,y) export with reversed faces, un-reflecting gives the Rule 12 positions and face order: (x,z,y) with the faces back in Blender order (Rule 12 also negates the normals). When the Blender source exists, re-export it that way instead of patching the p3d. The Rule 12 export this leads to was checked in game on a character (2026-10-02, references/character-rigging.md §6); the patch was not.

UV + NORMAL/AO BAKE (read references/character-uv-bake.md)

Unwrapping the low and baking the high-poly detail into a tangent _nohq + AO is generic texture work, but a rigged character adds gotchas that each cost an iteration ([LFInfectedBig ✓] 2026-06-25):

  • Bake from a PRE-conform proxy, not the conformed low. The rig conforms the limbs (character-rigging.md §3); the high was never conformed → after rigging low.dims ≠ high.dims in those regions and a direct high→low bake is garbage there. Bake onto a proxy = shipped low's topology+UV with the pre-conform retopo positions (which align with the high); a tangent normal is pose-invariant so it applies to the conformed shipped low. Verify proxy.dims == high.dims first.
  • Do NOT normals_make_consistent the AI high-poly (non-watertight → flips shells inward → black blotches). Use its original normals + shade_smooth.
  • Pre-fill the bake image with neutral (0.5,0.5,1.0) and use_clear=False so misses stay flat, not black (a (0,0,0) texel decodes to an inward normal → renders black).
  • AO: hide every mesh except the target (the coincident high self-occludes → dark AO) AND clear custom split normals + normals_make_consistent on the target.
  • _nohq is DirectX Y- → green-invert the OpenGL bake (dayz-texture-pipeline). Triangulate before baking and ship triangulated so bake tangents == in-game tangents.
  • Internal decorative geometry (ribcage): bone-heat fails on thin self-intersecting meshes → weight procedurally by height to the spine chain (or DATA_TRANSFER from the body, but strip arm/shoulder leakage).

The gate is a lit preview of the low+normal vs the high, plus numeric checks (UV stretch spread, % black pixels = 0, AO surface mean ~200). Render and look (blender-visual-review).

SCALING — runtime is broken, bake it into the mesh

"Make it bigger/smaller" has no config or script path: SetScale/GetScale are broken on entities (T140705) and the collision box does not follow; the Object-Spawner scale is static-objects-only. The only route is to bake the size into the mesh on the same OFP2_ManSkeleton. Geometry + collision LODs scale together. BUT the engine binds against the canonical ~1.8 m bind (see THE CANONICAL-BIND INVARIANT), so baked oversize scale does more than foot-slide — it DEFORMS the mesh under anims: LFInfectedBig at ~1.27× deformed grossly; rescaling to ~1.8 m removed the catastrophic deform [✓ in-game S7]. Small departures (≤~1.1×) may pass with only foot-slide / IK drift; a genuinely BIGGER animated character that still deforms cleanly is unsolved here — it would need a custom skeleton with a scaled bind, not baked mesh scale. Verify foot-contact / melee reach / door clipping / AI pathing in-game; if limbs distort under anims, the size is fighting the bind.

CONFIG INHERITANCE BY CHARACTER TYPE

Inherit the right base and the skeleton + anims + AI come for free via the inherited enfanimsys block. Minimal infected pattern (verified vanilla, full detail in dayz-custom-infected.md §1):

class CfgVehicles {
    class ZombieMaleBase;
    class MyZ_Base: ZombieMaleBase { scope=0; model="\MyMod\infected\myz.p3d"; hiddenSelectionsMaterials[]={...}; };
    class MyZ: MyZ_Base { scope=2; hiddenSelectionsTextures[]={"MyMod\data\myz_co.paa"}; };
};
Character typeInheritGivesNotes
Infected (male)ZombieMaleBaseOFP2_ManSkeleton + infected anim graph + AI[recipe ✓] community rule (PvZmoD): inherit ZombieBase, never AnimalBase
Infected (female)ZombieFemaleBasesame, female proportions
Survivor / human NPCSurvivorBase / player chainOFP2_ManSkeleton + player anims[TBD-verify] — not yet built here; verify the base + clothing/proxy slots vs vanilla
Infected (female military, 1.30)ZmbF_SoldierNormal_Basefemale soldier AIZmbF_SoldierNormal, ZmbF_ArmyOfficer; ZmbF_eastSoldier_Base config-inherits ZmbF_usSoldier_normal_Base (zombies/config.cpp:10376)

THE WALL: only one mod that modifies player/creature animations can be loaded at a time — loading two crashes the client/server (Enfusion limit). A character that ships new animations conflicts with every other anim mod on the server. A pure reskin that inherits the vanilla enfanimsys does NOT hit this wall. Warn the user whenever a plan ships custom character anims. (dayz-animation-pipeline anchor 3.)

CHARACTER LODs

  • Visual: the rendered mesh (with the hole/detail).
  • Geometry (collision): must be closed and convex (BI Validating Geometries). A holed/concave torso is not convex → either convex-decompose into numbered ComponentXX, or (simple) keep collision solid and ignore the visual hole. Collision need not match Visual. Mass ≥ 10.
  • FireGeometry: solid unless you want shots-through. With solid collision, bullets crossing a visual hole still hit — a design choice.
  • Memory / View / LandContact: per dayz-model-pipeline. Use DayZ LOD resolutions, not Arma 3 (_shared/dayz-conventions.md LOD table — ViewGeo 6e15, FireGeo 7e15).

QUICK TRIAGE

SymptomLikely causeWhere
Posing the rig moves nothing / mesh won't deformarmature scale not applied before bone-heat → weights collapsed to Pelvisreferences/character-rigging.md GOTCHA
Whole mesh explodes in-gamea named selection not in skeletonBones[], or wrong skeleton nameRIGGING; check model.cfg skeleton
Spiky / pinched verticeszero-weight verts or a selection with no weightcleanup: normalize, fill weights
Bone X doesn't exist in skeleton OFP2_ManSkeleton (RPT)bone-name typo (casing/underscore)bone catalog in dayz-animation-pipeline
Limbs lag / float during animsmesh not in canonical bind A-pose, or baked-scale driftRIGGING bind-pose; SCALING
Anims don't play at allnot inheriting ZombieMaleBase/enfanimsys, or new-anim wallCONFIG INHERITANCE
Bigger character, collision wrongscaled at runtime instead of bakedSCALING
Character faces / walks BACKWARD in-gamedet +1 export (x,z,−y): it sends the rig front (−Y) to +Z; the bind faces −Zre-export with (x,z,y) (Rule 12), not (−x,z,y), which turns it round but mirrors it. references/character-rigging.md §6; THE CANONICAL-BIND INVARIANT
Limbs overextend / stretch under anims, fine at restmesh scale or proportions ≠ canonical bindTHE CANONICAL-BIND INVARIANT; proportion conform character-rigging.md §3
Deforms wrong in-game but the Blender deform-test looked cleanthe Blender armature ≠ engine skeleton — the pose-test is a FALSE GATETHE CANONICAL-BIND INVARIANT (FALSE GATE); debinarize vanilla + gate in-game/Buldozer
Looks wrong at REST / idle, not only walkingbind / skeleton mismatch (model.cfg ≠ vanilla, or rest pose ≠ engine bind) — NOT weightsdebinarize a vanilla zombie, copy its model.cfg skeleton + match its bind
Skeleton now matches vanilla but a limb flings back/up (idle AND animating), rest pose is a sane A-posemesh is left/right mirrored vs the canonical skeleton — left* geometry sits where the right* bone isdebinarize a vanilla male, compare bone vert-X to spine center (vanilla left*=+X); cause = a det +1 export map; fix = re-export with (x,z,y) (Rule 12) or un-reflect (negate X + reverse winding, same result); swapping L↔R selection names only relabels the mirror. See THE CANONICAL-BIND INVARIANT (MIRROR)
Custom infected/zombie deforms even at idle; mesh was rigged to the full player skeletona zed binds to the 95-bone hermit_newbindpose.xob SUBSET (no face/finger/IK bones), not the player rigconform/weight to the 95-bone set OR override enfanimsys skeletonName. See THE CANONICAL-BIND INVARIANT (ZED bind)
Corpse/ragdoll goes invisible from a specific anglesingle-sided faces of a reflected mesh culled at grazing angles the upright anim never reachesun-reflect the mesh (negate X + reverse winding; with the Blender source, re-export with (x,z,y), Rule 12); a pure L/R selection swap leaves the reflection so the culling persists
Whole mesh renders flat / paper / 2D in-gamea conform/warp collapsed depth (Y) — e.g. TPS to near-coplanar bone-midpoint targetsconform in X/Z only, preserve Y; ALWAYS check the REST SIDE render, not just front
In-game diffuse = "camo" / black-grey facet noise, persists without _nohqcorrupt high→low bake (mis-aligned high/low) — the noise is in the _co DIFFUSE, not the normal mapopen and LOOK at the baked _co PNG; references/character-uv-bake.md pre-conform proxy
Green/grey/brown "camo" patches that SURVIVE replacing the _co entirely (uniform _co too) AND disabling _nohqan ENVIRONMENT/terrain texture in an rvmat stage with uvSource="tex" projects that texture onto the body UV. [LFInfectedBig S10] dz\data\data\env_land_co.paa (a landscape photo = DayZ env map) was in Stage7 with uvSource="tex" → painted the landscape over the mesh; survived 6 _co iterations because the fix is the rvmat, not the diffuseAudit EVERY rvmat stage — an env/macro/detail map must be uvSource="none" (sampled by reflection), never "tex". ImageToPAA in.paa out.png to LOOK at each stage's texture. The _co+normal Blender preview HIDES rvmat stages = FALSE GATE. First prove the mesh is clean with the CLAY-TEST (render .p3d geometry, NO textures)
Solid, but dark on the sunlit side and lit in the shade (inverted lighting)first suspect: shading normals stored OUTWARD, as in the det +1 recipe (LFInfectedBig as shipped) or a Rule 12 export with its normals re-negated (base shading measured in game 2026-10-02 on an untextured client); rule out the material and _nohq toocheck the stored sign with dayz-p3d-audit's absolute check (agreement near 0 % = normals against the winding); if they point outward, store them inward: Rule 12 / py3d.blender_to_dayz() negates them
Textures on the INTERIOR / model see-through from outside (inside-out)the faces are not in the MLOD inward order: a det +1 map without face reversal (LFInfectedBig S6), or a det −1 map with one. Blender/Three.js previews are double-sided and HIDE thisexport with Rule 12: (x,z,y), faces in Blender order, normals negated. Reversing every face is right only under a det +1 map, and that map mirrors the mesh. See references/character-rigging.md §6

OFFLINE GATE — run before EVERY PBO (catches the inside-out bug without an in-game cycle)

python references/check_dayz_winding.py <source_mlod.p3d>

A double-sided preview never shows DayZ's single-sided culling, so an inside-out model (textures on the interior) only surfaces in game, losing a test cycle, and normals stored the wrong way only as inverted lighting. Run the gate after building the .p3d and before AddonBuilder. It reads every visual LOD in the MLOD convention of dayz-model-pipeline Rule 12, which py3d.blender_to_dayz() writes: the vertex-order cross product and the stored normals both point into the material.

  • Winding, per closed shell (points welded, faces linked only through edges that exactly two faces share, proxy:* faces left out): the signed volume by winding must be negative, the production sign of dayz-p3d-audit "Absolute winding check". A positive shell is inside-out: face.vertices.reverse() on every face of it, the whole LOD when every shell reads positive. Never decide on the sum over the LOD, which can hide an inverted part. A shell whose faces disagree with their neighbours is made coherent first.
  • Normals, per shell and corner by corner, read as that reversal leaves them: each corner normal against its face's vector area (the fan sum, right on a non-convex quad too); within 5° of the face plane it has no clear sign and is not read. A shell agrees above 90 % of its corners, a tolerance rather than proof of every corner: smooth-shaded exports carry corners against their face. Below 10 % in every shell they disagree, which with the winding right means normals stored outward: negate the normal pool and keep the faces, never reverse them on that reading; the gate counts the corners that agree now and that fix turns too, and withholds it when part of the LOD is not read. Anything else lists the shells, to read part by part, never a corner on its own sign: in a shell that reads cleanly, negate the normals of the faces that read against their winding and keep the rest; leave any other shell as it is, to inspect (py3d README, "Winding", step 3). A corner normal smoothed across a sharp fold can point against a face wound right. py3d _pct_normal_agreement, the absolute check's count, reads only each face's first corner; the gate prints it alongside, over every face of the LOD. (Changed 2026-10-03: this read "Anything else lists the shells to fix corner by corner.", and the gate's fix negated each corner against its face; a flat tetrahedron wound right, with one area-weighted normal per point, has 6 of its 12 corners against their faces.)
  • Not scored: an open part (a sheet, an open tube) or a flat one (welded twins) has no volume sign; its faces are counted as not scored, for dayz-p3d-audit's visibility battery. A visual LOD with no closed shell is not measurable.
  • Exit 0 PASS, 1 defect, 2 invalid input, ODOL or not measurable. A PASS with faces not scored says so on its own line. A PASS cannot see a mirror: the det +1 export with reversed faces and negated normals passes too; check chirality on an asymmetric feature (Rule 12, references/character-rigging.md §6).

[OFFLINE MEASURED 2026-10-02] references/winding_fixtures/ holds the three MLODs of the Rule 12 in-game probe byte for byte (make_fixtures.py rewrites them with py3d 1.8.0) and the correct one with its normals negated; tests/test_check_dayz_winding.py holds the expected verdicts. The gate passes the correct export and the mirrored one, both solid in game, and fails the inside-out one (reverse every face, then negate the pool) and the outward-normal one (negate the pool). On the three LFInfectedBig builds of the chiral check it passes the Rule 12 build (48 closed shells negative; 99.8 % of its 131,278 corner normals with a clear sign agree, 99.5 % in the body, its lowest shell, with 219 against their face and 200 within 5° of it; the open ribcage tubes, 63.5 % of the faces, not scored) and fails the two with outward normals on their normals (0.2 % of their corners agree, every shell below 10 %). Measured on a skinned character too (LFInfectedBig, in game 2026-10-02, chiral check in references/character-rigging.md): the Rule 12 build is solid and lit like vanilla; the builds with normals stored outward, which the gate passed before this rewrite, are lit inverted (base shading, untextured client), and the shipped one is also mirrored. (claim: CLAIM-CHAR-NORMALS-INWARD-SKILL) (Rewritten 2026-10-02. The gate encoded the LFInfectedBig det +1 build, normals stored OUTWARD and cross·normal < 0, and exited 1 on all three MLODs of the Rule 12 probe, including the one that renders solid and reads correctly (cross.normal_positive=1.00, normals_outward=0.00), with fix hints that would turn it inside-out; until then this section sent inward-normal builds to the absolute check. S6 confirmed that build's winding only.) Detail + why (incl. why NOT to compare against a debinarized vanilla) in references/character-rigging.md §6.

SP-290 (measured 2026-08-17): exit 0 is not "safe to ship." The gate fails only on relative winding (cross.normal_positive / cn<=0.30). It measures global inversion — it prints normals_outward[info]=0.00 and NOTE normals look INWARD too (separate lighting issue): negate stored normals — but does not fail for it. Three fixtures from one source (Crate\models\Crate_Wooden.p3d, 9 LODs), gate run as shipped: intact (A) → exit 0, cross.normal_positive=0.00; winding inverted, 784 faces (B) → exit 1, cross.normal_positive=1.00 (the named case — the gate DOES catch it); winding AND stored normals inverted, 784 faces + 488 normals (C) → exit 0 PASS. That C state is internally coherent, globally inside-out — the silent Blender Z-up → Y-up ship (DZ-R Rule 13; WallLamp, Crate_Wooden). Do not ship on PASS; read the [info] line. Required of references/check_dayz_winding.py: (1) normals_outward == 0 (or below a threshold) MUST fail, not annotate — combined with inverted winding this is the state the gate exists to block, not "a separate lighting issue" (2026-10-01: implemented as NORMALS_OUTWARD_MIN = 0.35, but it contradicted the MLOD convention measured since: shading normals stored inward, dayz-p3d-audit "Absolute winding check" (engine verdict 2026-09-07) and Rule 12 (in-game 2026-10-01), and it failed every correct Rule 12 export. 2026-10-02: replaced. The gate reads the direction from the signed volume of each closed shell and fails stored normals that disagree with the winding; C's state, winding and normals turned together, fails on its volume where its shells are closed (the probe's mirror_c, inside-out in game: +0.1086). See OFFLINE GATE above); (2) three exit codes, not two — today exit 1 is both "defect found" and "invalid input". An ODOL .p3d (a6\LMGs\M249\m249_new.p3d) raises a bare AssertionError and exits 1, indistinguishable from inside-out. Need: 0 PASS, 1 defect, 2 invalid/non-MLOD with an explicit "this file is ODOL, debinarize first"; (3) keep the three fixtures next to the check (f0_fixtures/crate_{A_intacto,B_solo_winding,C_winding_y_normales}.p3d, regenerable with f0_winding_v2.py). Fixture C inverts stored normals to reach the internally-coherent globally-inside-out state; it does not byte-reproduce an exporter that also mirrors coordinates. (2026-10-02: the fixtures next to the check are the Rule 12 probe's, references/winding_fixtures/; the crate fixtures are not in the Pack.)

CITE-THEN-VERIFY

Character config and bone names are easy to half-remember. Before writing a class name, base, property or named selection, grep vanilla (P:\dz\characters\, DZ\characters\zombies\) or the cited reference, and keep provenance labels ([LFInfectedBig ✓], [recipe ✓], [TBD-verify]). The bone names MUST match OFP2_ManSkeleton exactly — verify against the rig FBX or player-skeleton.md, never from memory.

REFERENCES

  • references/character-rigging.md — the full verified rig workflow (armature source, scale gotcha, auto-weights, conform-to-bind, cleanup, deform-test) with the Blender-headless script patterns.
  • references/character-uv-bake.md — UV-unwrap + high→low normal/AO bake: the pre-conform-proxy alignment fix, AI-high normal handling, neutral-prefill misses, AO occluder isolation, internal-mesh weighting, with Blender-headless script patterns.
  • dayz-custom-infected.md (vault 20_Knowledge) — the infected recipe: config inheritance, scaling, the see-through hole, LODs, with primary-source citations. Deep config detail lives here.
  • dayz-animation-pipeline → references/player-skeleton.md — the OFP2_ManSkeleton bone catalog by zone.
  • references/character-ragdoll.md — 1.30 human.ragdoll (RagdollDef) on SurvivorBase.
  • references/dayz-1-30-characters.md — 1.30 Exp humanoid delta (variants, agr/agf, PPE, skinning, surrender).

CASE LOG (append one entry per real import)

LFInfectedBig — giant infected with a see-through torso hole (2026-06-23 → ongoing)

First character imported. ~1.2× infected, pass-through chest hole (ribs+spine), reskin of ZombieMaleBase.

  • Mesh: AI-generated (Rodin v2.5 multi-view + TAPose recovers an A-pose from arms-down refs) → scripted ribcage cavity → retopo 14k manifold (hole open) → high-poly 1M kept for the bake.
  • Rig [✓ 2026-06-24]: auto-weights from the BI DayZ-Misc FBX; the armature-scale-apply GOTCHA cost an intermediate failure (all weights → Pelvis) before it was caught; arms were 28°/34° narrower than canonical → conformed via weight-masked rotation; cleanup to max-4 influences, 0 zero-weight; deform-test passed (6961/7000 verts move, smooth, cavity follows the torso).
  • UV + bake [✓ 2026-06-25]: Smart UV + rotating pack (uniform density, bbox 96.8%, triangulated 14k). Normal high 1M→low baked via a pre-conform proxy (the S4 conform had opened the arms ~8 cm → low≠high); the rainbow/black-blotch/dark-AO failures all traced to alignment, AI-high make_consistent flips, black-cleared misses, and coincident-high AO self-occlusion — all fixed (references/character-uv-bake.md). Maps in the NEW UV. Ribcage decimated 95k→15.8k + spine-height weights (bone-heat failed on the thin geometry); deform-test dot 0.823. pose_position ships REST=bind; set 'POSE' for the deform-test.
  • Export rig→.p3d + texture + LODs + config + PBO [✓ 2026-06-25]: gate R15 closed. Export = py3d direct (now verified in §6, no longer [TBD-verify]): fractional per-vertex bone-weight selections (lowercase), transform (x,z,−y) det+1 DERIVED from the armature matrix, validated against a debinarized vanilla zombie (ground truth for selection names + Y-up frame + character LOD anatomy). (2026-10-01: that derivation missed the handedness change; the map is (x,z,y), Rule 12. See references/character-rigging.md §6.) _co baked DIFFUSE high→pre-conform-proxy onto the new UV; Super rvmat (Stage4 AS uvSource="tex", not "none"). 6 LODs: Geometry hull class='man' (not skinned), FireGeo skinned-to-bones + dmgzone_spine + meatbones.rvmat, ViewGeo, LandContact, Memory (points from bone positions). model.cfg = full OFP2_ManSkeleton hierarchy, self-contained. binarize + CfgConvert + AddonBuilder → 6.4 MB PBO, all offline-verified.
  • Inside-out winding fix [2026-06-25, deployed + offline-verified; in-game re-confirm pending]: first in-game build rendered inside-out (textures on interior) — the AI/GLB+retopo source ships glTF-CCW winding that DayZ back-faces despite the det+1 transform. Fix = reverse every visual face. Built references/check_dayz_winding.py (FAILs the inside-out build, PASSes the fixed one) and wired it as a pre-PBO gate so this never costs an in-game cycle again. Corrected §6 (it wrongly said "no flip"). (2026-10-03: the inside-out render came from the det=+1 map, not from the source's winding. From Blender any det=+1 map mirrors the mesh, and reversing every visual face then hides the mirror (references/character-rigging.md §6; LFInfectedBig S6). In game on 2026-10-02 the shipped build, det=+1 with its faces reversed, read its chiral marker mirrored and lit inverted; the Rule 12 build, (x,z,y) with the faces in their order and the normals negated, read it correctly and lit like a vanilla zombie. §6's "no flip", which this entry called wrong, holds under Rule 12's det=-1 map, and check_dayz_winding.py, rewritten for Rule 12 the same day, passes the Rule 12 build and fails the shipped one on its normals.)
  • Scale + orientation fixed, residual = proportions [✓ in-game S7 2026-06-24]: the deep investigation diagnosed the S6 breakage offline. Texture "camo" = a corrupt high→low bake (noise in the _co DIFFUSE, not _nohq; body UV was clean) → replaced with a clean procedural flesh. Deform had two systemic causes, both confirmed in-game: (a) scale — the 2.277 m (1.27×) mesh fought the canonical ~1.8 m bind → uniform rescale f=0.7901; (b) orientation — the (x,z,−y) transform was 180° about vertical → faced/walked backward → fix (−x,z,y) (also det +1: it fixed the facing and kept the mirror that S9 found). Both landed (faces forward, vanilla-sized, camo gone). py3d weights transmit fine (Object Builder not needed). See THE CANONICAL-BIND INVARIANT. (_export/{rescale_1x.py,build_full_p3d_1x_t2.py,diag_bind_mismatch.py}.)
  • S8 — re-rig attempt + the FALSE-GATE wall [2026-06-24, deform still broken in-game]: tried to fix the proportion deform offline. Diagnosed the shipped deform: asymmetric auto-weights (LeftUpLeg 37 vs RightUpLeg 166 verts) + 19% cross-midline, and clean_cross_side AMPLIFIED it to 21–34× (it keeps the dominant side per vert; on bled asymmetric weights it reassigns whole regions to the OPPOSITE limb). Replaced the bind with envelope weighting (distance-to-bone-segment + sidedness fade + a Pelvis→crotch column) — robust for the see-through cavity (data-transfer from a solid Male_body mis-weighted the tunnel interior → 100× spikes). A TPS proportion conform to bone-midpoint targets flattened the mesh to 2D (targets near- coplanar in Y); fixed with an X/Z-only conform preserving Y. Blender edge-stretch fell 34×→6× over 3 rebuilds. BUT all 3 in-game builds deformed the same (user: weird at idle AND animating) → the Blender deform-test is a FALSE GATE (see THE CANONICAL-BIND INVARIANT). Root cause now scoped to a bind/skeleton mismatch (model.cfg skeleton or authored rest ≠ vanilla OFP2). Confirmed in-game still-good: scale, orientation, winding, 3D volume (X/Z conform). Reusable: envelope weighting, the _conform/ diagnostics.
  • Next (decided with user): STOP iterating against the rig FBX. Debinarize a vanilla zombie, copy its model.cfg skeleton + match its bind/selection structure, re-author the custom mesh against THAT, gate on in-game/Buldozer only. Brief LFInfectedBig_dev\reviews\2026-06-24-prompt-vanilla-zombie-reproduce.md.
  • Detail: 30_Sessions\2026-06-24-LFInfectedBig-s8-offline-gate-false-green.md, 2026-06-24-LFInfectedBig-scale-orient-fixed.md, LFInfectedBig_dev\HANDOFF.md (live state).

(added 2026-06-28) Custom character deforms ONLY under animation = proportion, and the vanilla-body escape

Case LFInfectedBig (AI zombie ~1.2x): correct shape at rest, limbs over-extend when animated ("Vietnam flashback" at shoulders/arms). Verified diagnosis chain:

  1. A ZED's bind is hermit_newbindpose.xob (95 bones), not the player's — enfanimsys block of ZombieBase (DZ\characters\zombies\config.cpp:71-78). Quick triage: diff the mesh's WEIGHTED bones against those 95 (parse DZ\anims\cfg\skeletons.anim.xml). BUT 0% weight outside the 95 does NOT mean the deform is solved: LFInfectedBig had all 42 weighted bones inside → the deform was NOT missing bones nor Hoxdolum's facial fix, it was mesh-vs-skeleton proportion (bone heads 0.10-0.22 m off the anatomy). diff script pattern: see _judge\diff_zed_skeleton.py.
  2. When the mesh doesn't match the skeleton, conform/re-weight has a ceiling — it attenuates the deform (~30-45%) but never removes it; the geometry stays far from the pivots. Robust exit = Camino C: rebuild on a VANILLA well-rigged body (zero deform by construction) and graft only the distinctive bits (torso hole, look/texture, baked scale). Use this when conform/re-weight stalls.
  3. To get an EDITABLE vanilla body with positions AND weights: use the Male_body of the rig FBX animation_rig_character.fbx (Blender), NOT the ODOL->MLOD converter. The conversion (ODOL->MLOD) CORRUPTS visual-LOD positions of character bodies (non-human bbox, span ~2.5x height); the ODOL vertex_bone_ref carries the weights but the positions are garbage. The FBX gives correct human positions + clean vertex groups (verified: Male_body 7499v, bbox 1.4x0.28x1.8, 0 unweighted, <=4 infl). Extract: import_scene.fbx -> mesh whose name contains 'body' -> matrix_world@v.co + v.groups; bone heads from the armature (bone.head_local). See _judge\extract_fbx_rig.py.
  4. py3d: to READ selection weights from an MLOD use the constructor py3d.P3D(open(p,'rb')), NOT m=P3D(); m.read(f) — only the constructor populates selection.points = {Point: weight}. An old debinarized MLOD may keep selection NAMES but with .points empty (weights lost).
  5. Offline deform judge (canonical LBS) — useful but with a hard limit. A hierarchical FK with bind = bone-head positions reproduces a mis-proportioned mesh's deform (validated against in-game) and, with a negative control of capsules centered on the bones, discriminates good/bad. BUT it assumes identity-rotation bind; it is NOT faithful to a rig with real bone orientations in the bind (a vanilla body) -> the FK chain explodes (edge-stretch 400x+). To validate a well-rigged body offline: FK with FULL bind matrices, or deform in Blender with the native armature (reconcile the bind-matrix after FBX import, which otherwise explodes). The faithful deform gate is in-game. Cross-ref: SP-030 (judge method + silhouette 2nd axis), SP-034 (converter gap), LL-169.

(added 2026-07-14) Offline deform judge = hierarchical LBS with CANONICAL bind, not the Blender armature (SP-030)

The deform-under-animation of a mesh rigged to OFP2_ManSkeleton CAN be judged OFFLINE - no in-game build, no real RTM - with a CANONICAL hierarchical LBS: v' = sum(wi * Gi * Bi^-1 * v), where the bind Bi = T(head_i) uses the REAL bone heads (the ones the engine uses: Memory-LOD pivots / a bones_*.json derived from the rig) and Gi is FK over the REAL model.cfg hierarchy (skeletonBones[]), rotating each bone about ITS head and propagating to children. This reproduces the real over-extension (bones far from the anatomy -> long arcs when rotated) that an in-game build takes ~hours to reveal.

This does NOT contradict the FALSE GATE section above: the Blender armature / Blender deform-test / single-pivot rotation ARE false gates (they re-bind to non-canonical positions). Two reliable gates and one not:

  • FALSE: Blender armature / Blender deform-test / single-pivot rotation (e.g. inv_hunch_test.py).
  • OK: hierarchical LBS with bind = canonical heads + model.cfg hierarchy.
  • OK: mandatory synthetic negative control - a capsule dummy centered EXACTLY on each bone segment, weighted 100% to that bone. Under the same pose it must bend clean; if the judge also breaks it, the judge over-reports and is useless. Turns "reproduces the deform" into "discriminates good vs bad".

Second axis (from the head-to-head round): a conform judge needs TWO axes reported together - (1) reduced over-extension under anim (edge-stretch), (2) rest-pose silhouette preservation (mean radius of a region's verts to its dominant bone's head->tail axis, original vs conform). Optimizing only (1) lets silhouette distortion pass: in a blind A/B the user's eye caught an arm-thickness diff (orig 0.140 m -> A 0.124 vs B 0.113) that all three offline metrics missed.

CAVEAT (why this is doc-applied, not "verified"): this is an offline PREFILTER validated to DISCRIMINATE (negative control + the S8 false-green case), NOT quantitatively validated against the engine; the final fidelity gate is still the user's eye in-game, and the LFInfectedBig case that produced it is not yet in-game-confirmed. Reference impl: LFInfectedBig\_judge\judge_lbs.py + judge_control.py + judge_compare.py / judge_metric.py. Origin: 2026-06-28 deform gate.

(added 2026-08-03, ArmorHneck, IN-GAME VERIFIED) WORN CLOTHING binds via skeleton name "DayzTemporarySkeleton" — NOT OFP2_ManSkeleton

The single fact that makes custom worn clothing (ClothingTypes m/f) work. A worn p3d whose model.cfg declares skeletonName="OFP2_ManSkeleton" renders as a RIGID block anchored above the player (floating ~1 m, rotated, not animating) — the engine treats it as a model with its own skeleton and never re-binds it to the wearer. ALL vanilla worn clothing (verified: armbend_dynamic_m, chainmail_m via ODOL model_info.skeleton.name) compiles with the skeleton named DayzTemporarySkeleton — same 159 bones, same hierarchy/order as OFP2, only the NAME differs (a placeholder the engine substitutes with the wearer's skeleton). Fix = rename the CfgSkeletons class + every skeletonName= in the clothing model.cfg to DayzTemporarySkeleton and rebinarize. The community 114-bone OFP2 template fails TWICE for clothing: wrong bone count AND wrong name.

Worn-clothing canonical frame (measured on chainmail_m/hoodie_m, anatomical components — a global Z histogram is TOO COARSE and false-negatives a 180° flip): -Z = chest/front (hoodie front drawstrings at Z -0.14..-0.07; chainmail pelvis/spine centroids Z -0.04/-0.08), +X = anatomical left, +Y up, origin at feet. A mesh built facing +Z disperses into "exploded" rigid pieces when worn (each plate transformed by its bone from a flipped frame). Fix = R_y(180°) (det=+1, do NOT touch winding) + swap left*/right* selection PAIRS in every LOD.

Handedness of that fix (added 2026-10-01). Not touching the winding is right: R_y(180°) is a rotation. The swap it needs shows that the received mesh was a mirror, though: it faced +Z with left* on +X. ArmorHneck's received p3d was the det +1 map (x, z, −y) of the artist's Blender coordinates, and the shipped one is (−x, z, y) of them (ArmorHneck_dev\CLAUDE.md, artist alignment 2026-08-04). Rotation + swap fixes the binding and keeps the mirror, which symmetric plates hide; text, logos, buckles and one-sided straps come out reversed. With the Blender source, re-export it with (x, z, y), Rule 12, and no swap. With only the p3d, the reflection depends on its state: the received (x, z, −y) p3d takes z → −z; the shipped (−x, z, y) one takes x → −x with the L/R swap undone, as "un-reflect" in THE CANONICAL-BIND INVARIANT (z → −z on it would face +Z again). Either one moves every point (memory points included), reverses every face and reflects the normals the same way. Decide on an asymmetric feature in game: chiral check in dayz-clothing, CANONICAL WORN FRAME.

Diagnosis ladder that isolated this (reusable, each step in-game-cheap):

  1. Cross-matrix bisection: {armband class + vanilla worn p3d} vs {vanilla top class + custom p3d} — separates config-side from p3d-side in ONE config-only rebuild.
  2. Compare ODOL.model_info.skeleton.name custom vs vanilla worn (the tell: vanilla has NO "ofp2_manskeleton" string anywhere; a compliant clothing ODOL says DayzTemporarySkeleton).
  3. Structure parity checklist custom-vs-vanilla worn: skeleton 159 bones, per-vertex weight sums (vanilla = raw bytes summing 255), sub_skeletons palette, sections (tops use camomale alone; ONLY armbands carry camoMale_big_a/b + small_a/b complexion variants), empty Geometry LOD with autocenter=0 is the vanilla worn pattern.
  4. The registration gate is a live spawn (unknown_type = config not loaded — also caught here: config.bin from CfgConvert did not register at all; pack clothing PBOs with config.cpp as TEXT).

Origin: ArmorHneck 2026-08-03 (third-party RAR, ~6 in-game cycles to isolate; dual research Claude+Codex on debinarized vanilla). Full case: ArmorHneck_dev\CLAUDE.md + research workspace REPORT.md (armorhneck_research_ws).

DayZ 1.30 Exp (build 1.30.164014)

What changes: SurvivorBase binds ragdoll = "DZ/characters/bodies/human.ragdoll"; infected .agr is an Enfusion index over .agf; new female military + Nasdara infected classes; MINDSTATE_COWER; human Skinning drops Lard; sandstorm PPE via DEF_DUST_PARTICLE_BREATH / DEF_DUST_PARTICLE_EYES. What breaks: 1.29 custom infected animation workspaces; EmoteManager.ForceSurrenderState (use PlayerBase.SetSurrenderState / IsSurrendered); recipes expecting human Lard. Migration: keep inheriting ZombieMaleBase/ZombieFemaleBase (or a 1.30 female-soldier base); re-save infected .aw in Workbench 1.30; if you replace a survivor body, keep/override the ragdoll path; do not author correlative bone index values in skeletons.anim.xml. Checklist: [ ] workspace re-saved [ ] ragdoll path on survivors [ ] no Lard in human Skinning [ ] PPE constants if the character wears masks/eyewear [ ] MINDSTATE_COWER if you patch infected AI. Detail: references/character-ragdoll.md, references/dayz-1-30-characters.md, references/character-rigging.md.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.