docs(artist-guide): update for Full/FullHead conventions, custom bones, frame 0 behavior, validation tools
This commit is contained in:
@@ -96,16 +96,17 @@ PlayerArmature ← armature root object (never keyframe this)
|
|||||||
**Never animate:** `PlayerArmature` — it's the armature root object, not a bone.
|
**Never animate:** `PlayerArmature` — it's the armature root object, not a bone.
|
||||||
|
|
||||||
**Everything else follows this rule:**
|
**Everything else follows this rule:**
|
||||||
- Your item **always** controls bones in its declared regions.
|
- **Standard animations** (`Idle`, `Struggle`, `Walk`): your item controls ONLY bones in its declared regions. Keyframes on other bones are ignored.
|
||||||
- Your item **can also** animate free bones (not owned by any other equipped item).
|
- **`Full` animations** (`FullIdle`, `FullStruggle`, `FullWalk`): your item also controls free bones (body, legs — not owned by another item). See [Full-Body Animations](#full-body-animations-naming-convention).
|
||||||
|
- **Head is protected by default**: vanilla head tracking is preserved unless your item owns a head region (HEAD, EYES, EARS, MOUTH). In `Full` animations, head stays protected. Use `FullHead` prefix (e.g., `FullHeadStruggle`) to explicitly opt into head animation as a free bone.
|
||||||
- Your item **cannot** override bones owned by another equipped item.
|
- Your item **cannot** override bones owned by another equipped item.
|
||||||
|
|
||||||
| Bone | Who Controls It |
|
| Bone | Who Controls It |
|
||||||
|------|----------------|
|
|------|----------------|
|
||||||
| `body` / `torso` | Context layer by default. Your item if it owns TORSO or WAIST, or if `body` is free. |
|
| `body` / `torso` | Context layer by default. Your item if it owns TORSO or WAIST. Also available as a free bone in `Full` animations. |
|
||||||
| `head` | Vanilla head tracking by default. Your item if it owns HEAD, EYES, EARS, or MOUTH. |
|
| `head` | **Vanilla head tracking by default.** Your item if it owns HEAD, EYES, EARS, or MOUTH. Available as a free bone ONLY in `FullHead` animations (e.g., `FullHeadStruggle`). |
|
||||||
| Arms (`*UpperArm`, `*LowerArm`) | Vanilla by default. Your item if it owns ARMS or HANDS. |
|
| Arms (`*UpperArm`, `*LowerArm`) | Vanilla by default. Your item if it owns ARMS or HANDS. Also available as free bones in `Full` animations. |
|
||||||
| Legs (`*UpperLeg`, `*LowerLeg`) | Context layer by default. Your item if it owns LEGS or FEET. |
|
| Legs (`*UpperLeg`, `*LowerLeg`) | Context layer by default. Your item if it owns LEGS or FEET. Also available as free bones in `Full` animations. |
|
||||||
|
|
||||||
**Note:** `torso` and `body` both map to the same internal part. Prefer animating `body` — using `torso` produces the same result but is less intuitive.
|
**Note:** `torso` and `body` both map to the same internal part. Prefer animating `body` — using `torso` produces the same result but is less intuitive.
|
||||||
|
|
||||||
@@ -160,7 +161,7 @@ Three regions are **global** — they encompass sub-regions:
|
|||||||
|
|
||||||
Use the **TiedUp! Blender Template** (provided with the mod). It contains:
|
Use the **TiedUp! Blender Template** (provided with the mod). It contains:
|
||||||
- The correct `PlayerArmature` skeleton with all 11 bones
|
- The correct `PlayerArmature` skeleton with all 11 bones
|
||||||
- A reference player mesh (Steve + Alex) for scale — toggle visibility as needed
|
- A reference player mesh (Slime model) for scale — toggle visibility as needed
|
||||||
- Pre-named Action slots
|
- Pre-named Action slots
|
||||||
|
|
||||||
### Guidelines
|
### Guidelines
|
||||||
@@ -260,9 +261,6 @@ Declare default colors per channel in your item JSON:
|
|||||||
"tintable_1": "#FF0000",
|
"tintable_1": "#FF0000",
|
||||||
"tintable_2": "#C0C0C0"
|
"tintable_2": "#C0C0C0"
|
||||||
},
|
},
|
||||||
"animation_bones": {
|
|
||||||
"idle": []
|
|
||||||
},
|
|
||||||
"pose_priority": 10,
|
"pose_priority": 10,
|
||||||
"escape_difficulty": 3
|
"escape_difficulty": 3
|
||||||
}
|
}
|
||||||
@@ -311,19 +309,19 @@ The `PlayerArmature|` prefix is Blender's convention for armature-scoped actions
|
|||||||
| Gag (MOUTH) | *(none)* | No pose change — mesh only |
|
| Gag (MOUTH) | *(none)* | No pose change — mesh only |
|
||||||
| Straitjacket (ARMS+TORSO) | Arms + body (+ legs if free) | Arms crossed, slight forward lean, optional waddle |
|
| Straitjacket (ARMS+TORSO) | Arms + body (+ legs if free) | Arms crossed, slight forward lean, optional waddle |
|
||||||
|
|
||||||
**Why only your bones?** The mod's 2-layer system activates your keyframes for bones in your declared regions. But there's a nuance: **free bones** (bones not owned by any equipped item) can also be animated by your item.
|
**Why only your bones?** In standard animations (`Idle`, `Struggle`), the mod only uses keyframes for bones in your declared regions. Keyframes on other bones are ignored — safe to leave them in your GLB.
|
||||||
|
|
||||||
For example: if a player wears only a straitjacket (ARMS+TORSO), the legs are "free" — no item claims them. If your straitjacket's GLB has leg keyframes (e.g., a waddle walk), the mod will use them. But if the player also wears ankle cuffs (LEGS), those leg keyframes are ignored — the ankle cuffs take over.
|
To animate free bones (body, legs not owned by another item), use the `Full` prefix — see [Full-Body Animations](#full-body-animations-naming-convention). For example, a straitjacket's `FullWalk` can animate legs for a waddle, but only if no ankle cuffs are equipped.
|
||||||
|
|
||||||
**The rule:** Your item always controls its own bones. It can also animate free bones if your GLB has keyframes for them. It can never override another item's bones.
|
**The rule:** Standard animations = owned bones only. `Full` animations = owned + free bones. `FullHead` animations = owned + free + head. Your item can never override another item's bones.
|
||||||
|
|
||||||
### Idle is a Single-Frame Pose
|
### Animation Frames
|
||||||
|
|
||||||
`Idle` should be a **static pose** — one keyframe at frame 0. The mod loops it as a held position.
|
**Frame 0 is the base pose** — the minimum every animation must have. The mod always has a valid pose to display from frame 0.
|
||||||
|
|
||||||
```
|
**Multi-frame animations** (loops, transitions) are supported by the GLB parser — all frames are parsed and stored. However, **multi-frame playback is not yet implemented** in the item animation converter (`GltfPoseConverter`). Currently only frame 0 is read at runtime. Multi-frame playback is a high-priority feature — see `docs/TODO.md`.
|
||||||
Frame 0: Pose all owned bones → done.
|
|
||||||
```
|
**What this means for artists now:** Design your animations with full multi-frame loops (struggle thrashing, walk cycles, breathing idles). Put the most representative pose at frame 0. When multi-frame playback ships, your animations will work immediately without re-exporting.
|
||||||
|
|
||||||
### Optional Animations
|
### Optional Animations
|
||||||
|
|
||||||
@@ -331,13 +329,13 @@ Beyond `Idle`, you can provide animations for specific contexts. All are optiona
|
|||||||
|
|
||||||
| Animation Name | Context | Notes |
|
| Animation Name | Context | Notes |
|
||||||
|----------------|---------|-------|
|
|----------------|---------|-------|
|
||||||
| `Idle` | Standing still | **Required.** Single-frame pose. |
|
| `Idle` | Standing still | **Required.** Single-frame or looped. Frame 0 = base pose. |
|
||||||
| `Struggle` | Player is struggling | Multi-frame loop. 20-40 frames recommended. |
|
| `Struggle` | Player is struggling | Multi-frame loop recommended. 20-40 frames. |
|
||||||
| `Walk` | Player is walking | Multi-frame loop synced to walk speed. |
|
| `Walk` | Player is walking | Multi-frame loop synced to walk speed. |
|
||||||
| `Sneak` | Player is sneaking | Single-frame or short loop. |
|
| `Sneak` | Player is sneaking | Single-frame or short loop. |
|
||||||
| `SitIdle` | Sitting (chair, minecart) | Single-frame pose. |
|
| `SitIdle` | Sitting (chair, minecart) | Single-frame or looped. |
|
||||||
| `SitStruggle` | Sitting + struggling | Multi-frame loop. |
|
| `SitStruggle` | Sitting + struggling | Multi-frame loop. |
|
||||||
| `KneelIdle` | Kneeling | Single-frame pose. |
|
| `KneelIdle` | Kneeling | Single-frame or looped. |
|
||||||
| `KneelStruggle` | Kneeling + struggling | Multi-frame loop. |
|
| `KneelStruggle` | Kneeling + struggling | Multi-frame loop. |
|
||||||
| `Crawl` | Crawling (dog pose) | Multi-frame loop. |
|
| `Crawl` | Crawling (dog pose) | Multi-frame loop. |
|
||||||
|
|
||||||
@@ -352,21 +350,27 @@ If an animation doesn't exist in your GLB, the mod looks for alternatives. At ea
|
|||||||
|
|
||||||
```
|
```
|
||||||
SIT + STRUGGLE:
|
SIT + STRUGGLE:
|
||||||
FullSitStruggle → SitStruggle → FullStruggle → Struggle
|
FullHeadSitStruggle → FullSitStruggle → SitStruggle
|
||||||
→ FullSit → Sit → FullStruggle → Struggle → FullIdle → Idle
|
→ FullHeadStruggle → FullStruggle → Struggle
|
||||||
|
→ FullHeadSit → FullSit → Sit
|
||||||
|
→ FullHeadIdle → FullIdle → Idle
|
||||||
|
|
||||||
KNEEL + STRUGGLE:
|
KNEEL + STRUGGLE:
|
||||||
FullKneelStruggle → KneelStruggle → FullStruggle → Struggle
|
FullHeadKneelStruggle → FullKneelStruggle → KneelStruggle
|
||||||
→ FullKneel → Kneel → FullStruggle → Struggle → FullIdle → Idle
|
→ FullHeadStruggle → FullStruggle → Struggle
|
||||||
|
→ FullHeadKneel → FullKneel → Kneel
|
||||||
|
→ FullHeadIdle → FullIdle → Idle
|
||||||
|
|
||||||
SIT + IDLE: FullSitIdle → SitIdle → FullSit → Sit → FullIdle → Idle
|
SIT + IDLE: FullHeadSitIdle → FullSitIdle → SitIdle → ... → FullHeadIdle → FullIdle → Idle
|
||||||
KNEEL + IDLE: FullKneelIdle → KneelIdle → FullKneel → Kneel → FullIdle → Idle
|
KNEEL + IDLE: FullHeadKneelIdle → FullKneelIdle → KneelIdle → ... → FullHeadIdle → FullIdle → Idle
|
||||||
SNEAK: FullSneak → Sneak → FullIdle → Idle
|
SNEAK: FullHeadSneak → FullSneak → Sneak → FullHeadIdle → FullIdle → Idle
|
||||||
WALK: FullWalk → Walk → FullIdle → Idle
|
WALK: FullHeadWalk → FullWalk → Walk → FullHeadIdle → FullIdle → Idle
|
||||||
STAND STRUGGLE: FullStruggle → Struggle → FullIdle → Idle
|
STAND STRUGGLE: FullHeadStruggle → FullStruggle → Struggle → FullHeadIdle → FullIdle → Idle
|
||||||
STAND IDLE: FullIdle → Idle
|
STAND IDLE: FullHeadIdle → FullIdle → Idle
|
||||||
```
|
```
|
||||||
|
|
||||||
|
At each step, `FullHead` is tried first (full body + head), then `Full` (full body, head preserved), then standard (owned bones only).
|
||||||
|
|
||||||
In practice, most items only need `Idle`. Add `FullWalk` or `FullStruggle` when your item changes how the whole body moves.
|
In practice, most items only need `Idle`. Add `FullWalk` or `FullStruggle` when your item changes how the whole body moves.
|
||||||
|
|
||||||
**Practical impact:** If you only provide `Idle`, your item works in every context. The player will hold the Idle pose while sitting, kneeling, sneaking, etc. It won't look perfect, but it will work. Add more animations over time to polish the experience.
|
**Practical impact:** If you only provide `Idle`, your item works in every context. The player will hold the Idle pose while sitting, kneeling, sneaking, etc. It won't look perfect, but it will work. Add more animations over time to polish the experience.
|
||||||
@@ -396,18 +400,19 @@ Some items affect the entire body — not just their declared regions. A straitj
|
|||||||
|
|
||||||
**Convention:** Prefix the animation name with `Full`.
|
**Convention:** Prefix the animation name with `Full`.
|
||||||
|
|
||||||
| Standard Name | Full-Body Name | What Changes |
|
| Standard Name | Full-Body Name | Full + Head | What Changes |
|
||||||
|--------------|---------------|-------------|
|
|--------------|---------------|-------------|-------------|
|
||||||
| `Idle` | `FullIdle` | Owned bones + body lean, leg stance |
|
| `Idle` | `FullIdle` | `FullHeadIdle` | Owned bones + body lean, leg stance (+ head if Head variant) |
|
||||||
| `Walk` | `FullWalk` | Owned bones + leg waddle, body sway |
|
| `Walk` | `FullWalk` | `FullHeadWalk` | Owned bones + leg waddle, body sway (+ head if Head variant) |
|
||||||
| `Struggle` | `FullStruggle` | Owned bones + full-body thrashing |
|
| `Struggle` | `FullStruggle` | `FullHeadStruggle` | Owned bones + full-body thrashing (+ head if Head variant) |
|
||||||
| `Sneak` | `FullSneak` | Owned bones + custom sneak posture |
|
| `Sneak` | `FullSneak` | `FullHeadSneak` | Owned bones + custom sneak posture (+ head if Head variant) |
|
||||||
|
|
||||||
**In Blender:**
|
**In Blender:**
|
||||||
```
|
```
|
||||||
PlayerArmature|Idle ← region-only: just arms for handcuffs
|
PlayerArmature|Idle ← region-only: just arms for handcuffs
|
||||||
PlayerArmature|FullWalk ← full-body: arms + legs waddle + body bob
|
PlayerArmature|FullWalk ← full-body: arms + legs waddle + body bob
|
||||||
PlayerArmature|FullStruggle ← full-body: everything moves
|
PlayerArmature|FullStruggle ← full-body: body + legs thrash (head free)
|
||||||
|
PlayerArmature|FullHeadStruggle ← full-body + head: everything moves including head
|
||||||
```
|
```
|
||||||
|
|
||||||
**How the mod resolves this:**
|
**How the mod resolves this:**
|
||||||
@@ -425,7 +430,9 @@ PlayerArmature|FullStruggle ← full-body: everything moves
|
|||||||
| `Sneak` | Default sneak lean is fine | Your item changes how sneaking looks |
|
| `Sneak` | Default sneak lean is fine | Your item changes how sneaking looks |
|
||||||
|
|
||||||
**Key points:**
|
**Key points:**
|
||||||
- `Full` animations include keyframes for ALL bones you want to control (owned + free).
|
- **Standard animations** (`Idle`, `Struggle`, `Walk`) only animate your item's **owned bones** (from `regions`). Any keyframes on other bones are ignored. This is safe — you can keyframe everything in Blender without worrying about side effects.
|
||||||
|
- **`Full` animations** (`FullIdle`, `FullStruggle`, `FullWalk`) additionally enable **free bones** (body, legs — bones not owned by any other equipped item). This is how you create waddle walks, full-body struggles, etc.
|
||||||
|
- **Head is protected by default.** In `Full` animations, the `head` bone is NOT enabled as a free bone — vanilla head tracking (mouse look) is preserved. To animate the head in a Full animation, add `Head` to the animation name: `FullHeadStruggle`, `FullHeadIdle`, etc. Items that own a head region (HEAD, EYES, EARS, MOUTH) always control head regardless of naming.
|
||||||
- Free bones in `Full` animations are only used when no other item owns them.
|
- Free bones in `Full` animations are only used when no other item owns them.
|
||||||
- You can provide BOTH: `Idle` (region-only) and `FullWalk` (full-body). The mod picks the right one per context.
|
- You can provide BOTH: `Idle` (region-only) and `FullWalk` (full-body). The mod picks the right one per context.
|
||||||
- `FullIdle` is rarely needed — most items only need a full-body version for movement animations.
|
- `FullIdle` is rarely needed — most items only need a full-body version for movement animations.
|
||||||
@@ -651,9 +658,6 @@ Every item needs a JSON file that declares its gameplay properties. The mod scan
|
|||||||
"display_name": "Rope Gag",
|
"display_name": "Rope Gag",
|
||||||
"model": "mycreator:models/gltf/rope_gag.glb",
|
"model": "mycreator:models/gltf/rope_gag.glb",
|
||||||
"regions": ["MOUTH"],
|
"regions": ["MOUTH"],
|
||||||
"animation_bones": {
|
|
||||||
"idle": []
|
|
||||||
},
|
|
||||||
"pose_priority": 10,
|
"pose_priority": 10,
|
||||||
"escape_difficulty": 2,
|
"escape_difficulty": 2,
|
||||||
"lockable": false
|
"lockable": false
|
||||||
@@ -762,7 +766,6 @@ The `movement_style` changes how the player physically moves — slower speed, d
|
|||||||
| `supports_color` | bool | No | Whether this item has tintable zones. Default: `false` |
|
| `supports_color` | bool | No | Whether this item has tintable zones. Default: `false` |
|
||||||
| `tint_channels` | object | No | Default colors per tintable zone: `{"tintable_1": "#FF0000"}` |
|
| `tint_channels` | object | No | Default colors per tintable zone: `{"tintable_1": "#FF0000"}` |
|
||||||
| `icon` | string | No | Inventory sprite model (see [Inventory Icons](#inventory-icons) below) |
|
| `icon` | string | No | Inventory sprite model (see [Inventory Icons](#inventory-icons) below) |
|
||||||
| `animations` | string/object | No | `"auto"` (default) or explicit name mapping |
|
|
||||||
| `movement_style` | string | No | Movement restriction: `"waddle"`, `"shuffle"`, `"hop"`, or `"crawl"` |
|
| `movement_style` | string | No | Movement restriction: `"waddle"`, `"shuffle"`, `"hop"`, or `"crawl"` |
|
||||||
| `movement_modifier` | object | No | Override speed/jump for the movement style (requires `movement_style`) |
|
| `movement_modifier` | object | No | Override speed/jump for the movement style (requires `movement_style`) |
|
||||||
| `creator` | string | No | Author/creator name, shown in the item tooltip |
|
| `creator` | string | No | Author/creator name, shown in the item tooltip |
|
||||||
@@ -828,9 +831,6 @@ Items without the `"components"` field work normally — components are entirely
|
|||||||
"display_name": "GPS Shock Collar",
|
"display_name": "GPS Shock Collar",
|
||||||
"model": "mycreator:models/gltf/gps_shock_collar.glb",
|
"model": "mycreator:models/gltf/gps_shock_collar.glb",
|
||||||
"regions": ["NECK"],
|
"regions": ["NECK"],
|
||||||
"animation_bones": {
|
|
||||||
"idle": []
|
|
||||||
},
|
|
||||||
"pose_priority": 10,
|
"pose_priority": 10,
|
||||||
"escape_difficulty": 5,
|
"escape_difficulty": 5,
|
||||||
"components": {
|
"components": {
|
||||||
@@ -1047,7 +1047,7 @@ If your GLB contains multiple meshes, name your item mesh `Item` in Blender. The
|
|||||||
|
|
||||||
| Mistake | Symptom | Fix |
|
| Mistake | Symptom | Fix |
|
||||||
|---------|---------|-----|
|
|---------|---------|-----|
|
||||||
| Bone name typo (`RightUpperArm` instead of `rightUpperArm`) | Warning in log: "did you mean 'rightUpperArm'?" — bone treated as custom | Names are **camelCase**, not PascalCase. Check exact spelling. Run `/tiedup validate` to see warnings. |
|
| Bone name typo (`RightUpperArm` instead of `rightUpperArm`) | WARN in log with suggestion: "did you mean 'rightUpperArm'?" — bone treated as custom | Names are **camelCase**, not PascalCase. Check exact spelling. Run `/tiedup validate` to see warnings. |
|
||||||
| Extra bones in the armature | Custom bones follow their parent in rest pose | Intentional custom bones are fine (chains, decorations). Unintentional ones add file size — delete them. |
|
| Extra bones in the armature | Custom bones follow their parent in rest pose | Intentional custom bones are fine (chains, decorations). Unintentional ones add file size — delete them. |
|
||||||
| Missing `PlayerArmature` root | Mesh renders at wrong position | Rename your armature root to `PlayerArmature` |
|
| Missing `PlayerArmature` root | Mesh renders at wrong position | Rename your armature root to `PlayerArmature` |
|
||||||
| Animating `body` bone without TORSO region | Body keyframes used only if `body` is free (no other item owns it) | Declare TORSO/WAIST region if you always want to control body, or use `Full` animations for free-bone effects |
|
| Animating `body` bone without TORSO region | Body keyframes used only if `body` is free (no other item owns it) | Declare TORSO/WAIST region if you always want to control body, or use `Full` animations for free-bone effects |
|
||||||
@@ -1060,7 +1060,7 @@ If your GLB contains multiple meshes, name your item mesh `Item` in Blender. The
|
|||||||
| Wrong case (`idle` instead of `Idle`) | Animation not found | Use exact PascalCase: `Idle`, `SitIdle`, `KneelStruggle` |
|
| Wrong case (`idle` instead of `Idle`) | Animation not found | Use exact PascalCase: `Idle`, `SitIdle`, `KneelStruggle` |
|
||||||
| Variant gap (`.1`, `.2`, `.4` — missing `.3`) | Only .1 and .2 are used | Number sequentially with no gaps |
|
| Variant gap (`.1`, `.2`, `.4` — missing `.3`) | Only .1 and .2 are used | Number sequentially with no gaps |
|
||||||
| Animating bones outside your regions | Keyframes silently ignored | Only animate bones in your declared regions |
|
| Animating bones outside your regions | Keyframes silently ignored | Only animate bones in your declared regions |
|
||||||
| Multi-frame Idle | Works but wastes resources | Idle should be a single keyframe at frame 0 |
|
| Multi-frame animations play as static pose | Multi-frame playback not yet implemented — only frame 0 is used | Design full animations now (they'll work when playback ships). Ensure frame 0 is a good base pose. |
|
||||||
|
|
||||||
### Weight Painting Issues
|
### Weight Painting Issues
|
||||||
|
|
||||||
@@ -1100,9 +1100,6 @@ A collar sits on the neck. It doesn't change the player's pose.
|
|||||||
"display_name": "Leather Collar",
|
"display_name": "Leather Collar",
|
||||||
"model": "mycreator:models/gltf/leather_collar.glb",
|
"model": "mycreator:models/gltf/leather_collar.glb",
|
||||||
"regions": ["NECK"],
|
"regions": ["NECK"],
|
||||||
"animation_bones": {
|
|
||||||
"idle": []
|
|
||||||
},
|
|
||||||
"pose_priority": 5,
|
"pose_priority": 5,
|
||||||
"escape_difficulty": 3,
|
"escape_difficulty": 3,
|
||||||
"lockable": true
|
"lockable": true
|
||||||
@@ -1578,7 +1575,8 @@ GOOD TO KNOW:
|
|||||||
→ animation_bones is optional. Omit it and all owned bones work for all animations.
|
→ animation_bones is optional. Omit it and all owned bones work for all animations.
|
||||||
→ Templates let you skip animation entirely.
|
→ Templates let you skip animation entirely.
|
||||||
→ Custom bones are supported — add chain/ribbon/twist bones parented to standard bones.
|
→ Custom bones are supported — add chain/ribbon/twist bones parented to standard bones.
|
||||||
→ Free bones (not owned by any item) CAN be animated by your GLB.
|
→ Free bones (body, legs) can be animated using Full-prefixed animations (FullWalk, FullStruggle).
|
||||||
|
→ Head is protected — use FullHead prefix (FullHeadStruggle) to also animate the head.
|
||||||
→ Bones owned by another equipped item are always ignored.
|
→ Bones owned by another equipped item are always ignored.
|
||||||
→ The mod handles sitting, sneaking, walking — you don't have to.
|
→ The mod handles sitting, sneaking, walking — you don't have to.
|
||||||
→ Context GLBs in tiedup_contexts/ replace default postures.
|
→ Context GLBs in tiedup_contexts/ replace default postures.
|
||||||
|
|||||||
Reference in New Issue
Block a user