Files/Mobs -- creature model tables
==================================

One `<model>.json` per creature, plus one PNG beside it with the same base name. Referenced from
`data/mobs.json` by the `model` and `texture` fields (docs/ENTITIES_AND_WEAPONS.md section 3.3), and
read by `BoxRig` -- the class extracted from `SkinRig` at S12 -- through `FileAccess` with an
absolute OS path from `ModPaths`. NEVER through `load()`, `preload()` or `ResourceLoader`: global
rule R8 forbids the resource pipeline under the content root, and the nearest-filter /
no-VRAM-compression reason `SkinRig.load_skin()` already documents applies identically here (S3TC
destroys 16 px pixel-art edges).

THE SCHEMA (docs/ENTITIES_AND_WEAPONS.md section 5.1)
----------------------------------------------------

    {
      "format": 1,
      "id": "gobot:cave_crawler",        // the mobs.json row this belongs to
      "texture": "cave_crawler.png",     // beside this file
      "texture_size": [64, 64],          // the PNG's own size, for UV normalisation
      "texel_scale": 1.0,                // metres per texel = texel_scale / 16
      "pack_texture": "entity/zombie/zombie",   // OPTIONAL, see THE TEXTURE HOP below
      "alpha_scissor": true,             // OPTIONAL, for a sheet with real holes in it
      "placeholder": "humanoid",         // OPTIONAL, generated stand-in instead of the checker
      "placeholder_tint": "#4E7A4A",     // what colour to generate it in
      "parts": [
        { "name": "body",
          "parent": "",                  // "" = a root part
          "pivot": [0, 6, 0],            // texels, in the PARENT part's space
          "role": "body",                // what the animator does with it, see below
          "rot_deg": [82, 0, 0],         // OPTIONAL rest pose. POSITIVE X IS FORWARD -- see below
          "boxes": [
            { "origin": [-3, -2, -5],    // texels, the box's MIN corner relative to this pivot
              "size":   [6, 5, 10],      // texels
              "uv":     [0, 0],          // top-left of the box's cross in the texture
              "mirror": false,           // OPTIONAL, read the cross with U reversed, X swapped
              "inflate": 0.0 }           // OPTIONAL, grow the box by N texels on every axis
          ] }
      ]
    }

WHICH WAY IS FORWARD
--------------------
`-Z` is forward and `+X` is the creature's RIGHT. That is not a convention someone picked; it falls
out of `BoxRig._box_face_rect`, which maps `FACE_NZ` to the vanilla front rectangle at `(u+d, v+d)`
-- the one with the face on it -- and `FACE_PX` to `(u, v+d)`, the region a Minecraft skin puts the
right side of the head in. `+Y` is up and the model's feet sit at `y = 0`.

So in `rot_deg`, a POSITIVE rotation about X swings a limb FORWARD: a limb hangs at `-Y` from its
pivot, and rotating `-Y` by `+theta` about X carries it toward `-Z`. The first build of
`zombie.json` used `-82` and photographed as a creature with its arms thrown backwards over its
shoulders. No headless assertion can tell you this. The screenshot can.

THE TEXTURE HOP
---------------
`BoxRig.texture_for_model()` resolves a creature sheet in this order, first hit wins:

    1. Files/Mobs/<texture>.png          the user's own art. Always wins.
    2. Files/Skins/<texture>.png         so a humanoid mob can simply wear a player skin.
    3. the ACTIVE PACK's assets/<ns>/textures/<pack_texture>.png
    4. the table's "placeholder", generated in "placeholder_tint"
    5. the magenta/black checker

Step 3 is why `zombie.json` and `skeleton.json` have faces on a fresh checkout and the other five
tables do not. The dev pack carries the whole vanilla `entity/` tree, and COPYING ONE OF THOSE PNGs
INTO THIS FOLDER WOULD BE REDISTRIBUTING IT -- `Files/Pack/base-texture.zip` is Quadral, commercial,
all rights reserved, local development only (DECISIONS.md). Reading it through `PackStack` at run
time redistributes nothing and follows whatever pack the player actually mounted. A ship pack with
no `entity/zombie/zombie.png` falls through to step 4 and gets a plain generated humanoid, which is
a missing texture a player can live with; a magenta checker on a mob is a bug report.

MIRRORED LIMBS, AND WHY BOTH NEW TABLES USE THEM
------------------------------------------------
A modern 64x64 entity sheet gives the left arm and left leg their own regions at `(32,48)` and
`(16,48)`. A legacy 64x32 sheet does not: the left limbs re-read the right ones with `mirror: true`.
THE SHIPPED PACK IS LEGACY FOR BOTH OF THESE CREATURES -- measured, not assumed: `zombie.png` is a
64x64 canvas whose bottom half is 0/256 opaque, and `skeleton.png` is a true 64x32. Mirroring is
also the SAFE choice for a pack nobody has seen: a modern sheet still carries the right-limb
regions, so a mirrored table degrades to a symmetric creature, while a table pointing at `(32,48)`
renders two invisible limbs on any legacy sheet.

`texture_size` is the PNG's CANVAS, never its layout. `zombie.json` says `[64, 64]` and
`skeleton.json` says `[64, 32]` although the two use the identical offsets -- UV normalisation
divides by the canvas, and getting this wrong puts every V at half height.

ALPHA
-----
`BoxRig`'s base surface is opaque, which is right for the player: a skin's base layer is opaque by
definition. It is wrong for a creature with real holes in it. Set `"alpha_scissor": true` and the
base becomes `ALPHA_SCISSOR` + two-sided, so you see the inside of the far wall rather than
straight through to the world. The shipped skeleton needs it: its skull measures 304 of 384 face
texels opaque and its ribcage 190 of 352.

`tools/verify_mob_models.gd` checks every face rect of both new tables against the pack PNG's own
alpha, which is what catches a UV offset that landed on plausible-looking WRONG art.

Everything is in TEXELS at 1/16 m, which is the project's own unit -- the same one `SkinRig.TEXEL`
uses and the same one `ItemMesher` extrudes item sprites at. `texel_scale` exists for the boss,
which is 9 m tall: at 4.0 its 36-texel model is 144 texels of world, so its UVs still fit a sane
sheet instead of needing a 576 px one.

Box UV layout is the Minecraft cross: at `uv = [u, v]` and a box of `w x h x d`, the six faces sit
at `(u+d, v)` top, `(u+d+w, v)` bottom, `(u, v+d)` -X, `(u+d, v+d)` +Z, `(u+d+w, v+d)` +X,
`(u+d+w+d, v+d)` -Z. That is what Blockbench writes, so a box authored there lands here unchanged.

ROLES
-----
`role` is the only thing the procedural animator reads. Unknown roles are static, which is the
correct failure: a part that does not animate is a part that does not animate.

    body        breathe bob, yaw lean
    head        look-at, breathe bob
    jaw         opens on the attack windup
    arm_l arm_r biped swing, antiphase
    leg_l leg_r biped gait, antiphase
    leg_fl leg_fr leg_bl leg_br   quadruped gait: FL/BR in phase, FR/BL in antiphase
    wing_l wing_r                 flap off the gait accumulator, much faster
    tail        lags the body yaw
    static      never moves -- declared, and deliberately never driven

AUTHORING
---------
Blockbench, in its **Generic / free-form** format, never the Minecraft Entity format -- the vanilla
box layout is the Mojang-derivative part, and the geometry you draw yourself is your own work
(decision D17, docs/ENTITIES_AND_WEAPONS.md section 6.1). Blockbench itself is GPL-3.0; the licence
covers the editor, not the art made in it.

THE PNGs ARE NOT IN THIS REPOSITORY, AND TWO TABLES NO LONGER NEED THEM.
Every table here ships without its texture, on purpose: a creature PNG is art the user authors, and
a missing texture shows the magenta/checker fallback rather than crashing (the house rule). Until
they land, a mob reads as its `body_color` tint from `data/mobs.json`, which is what
docs/ENTITIES_AND_WEAPONS.md section 3.3 redefines that field to be -- the per-instance MultiMesh
tint, not a placeholder green box.

`zombie.json` and `skeleton.json` are the exception: both declare `pack_texture` and wear the active
pack's own vanilla entity art, so they are the only two creatures here that are textured today.
`scenes/dev/mob_lab.tscn` shows all seven side by side and prints, per creature, exactly which of
the five resolution steps above it landed on.

AND THE THING NONE OF THIS FIXES
--------------------------------
There is no mob renderer. `MobBody` owns no mesh on purpose (section 7.1: one MultiMesh per
species, limbs animated in the vertex shader, `src/mobs/mob_renderer.gd`) and that file has never
been written -- nothing under `src/` constructs a `BoxRig` at all. `MobScheduler` and
`SpawnDirector` ARE mounted in `scenes/match.tscn`, so these creatures spawn in real caves, walk,
chase, swing and die; they are simply invisible while doing it. Every table in this folder is art
waiting on section 7.4 step 4.
