foitin/characters/_spec/CHARACTER_SPEC.md
m3ultra b067bf7f0b Scaffold: deterministic 60Hz combat core, drop-in character format, MODELBEAST pipeline
- Godot 4.7 project; fixed-tick FSM fighter, facing-relative input buffer
  with numpad motion parsing, box collision, training-mode hitbox overlay
- characters/ = self-describing drop-in folders (spec in _spec/); two
  generated placeholder fighters (alpha, beta)
- pipeline/: pack_character.py + autohitbox.py (pose/silhouette hurtboxes)
- STUDY.md: reverse-engineering study of the BKB reference games

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 18:45:44 +10:00

98 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# FOITIN character folder spec (v1)
A character is a **self-describing folder** under `characters/`. The engine scans
`characters/*` at boot (folders starting with `_` or `.` are skipped) — dropping a
valid folder in IS shipping a character. This is the BKB per-character-folder idea
(`Data/Venus/{bik,zon,geo,me2}`) modernized: PNG/WebP frames instead of Bink video,
one JSON per move instead of the binary `BKB!ZONE/GEOM/DAT2` sidecars.
```
characters/<id>/
manifest.json identity, stats, move bindings
portrait.png select-screen / HUD portrait
moves/<move>/
data.json frame data (timing, boxes, damage, root motion)
frames/0000.png ... sprite sequence, alphabetical order
```
## Conventions
- **Timing is in 60Hz ticks.** Sprite frames are spread evenly across a move's
`total` ticks, so art frame-rate is decoupled from game logic (render at 15, 20,
30 or 60fps — the engine doesn't care).
- **Boxes are fighter-local, right-facing**: origin at the ground pivot (feet
centre), +x forward, y up. Rects are `[x, y, w, h]` (y usually negative).
The engine mirrors everything when facing left.
- Frames must share one canvas size with the ground pivot at bottom-centre
(the BKB `.geo` lesson: bake a consistent pivot or sprites jitter).
## manifest.json
```json
{
"id": "alpha",
"name": "ALPHA",
"health": 1000,
"walk_speed": 3.2,
"back_speed": 2.6,
"jump_velocity": -13.5,
"color": "#3ec6a8",
"normals": { "P": "jab", "6P": "straight", "K": "kick" },
"command_moves": [
{ "motion": [2, 3, 6], "button": "P", "move": "rush_palm" }
]
}
```
- `normals`: button → move. Optional numpad-direction prefix (`6P` = forward+P,
`2K` = crouching K). Plain button is the fallback.
- `command_moves`: checked before normals; `motion` is numpad notation
(`[2,3,6]` = quarter-circle-forward), completed within 14 ticks.
## moves/<move>/data.json
```json
{
"name": "jab",
"total": 22,
"loop": false,
"startup": 5,
"active": [6, 8],
"damage": 30,
"hitstun": 14,
"blockstun": 8,
"pushback": 7,
"knockdown": false,
"cancels": [],
"root_motion": [0, 0, 1.5, 3, 3, 1.5],
"hurtboxes": {
"default": [[-22, -305, 44, 50], [-30, -255, 60, 105], [-26, -150, 52, 150]],
"frames": { "6-8": [[-22, -305, 44, 50], [-30, -255, 90, 105], [-26, -150, 52, 150]] }
},
"hitboxes": { "6-8": [[30, -272, 78, 34]] }
}
```
- `active`: `[first, last]` tick (inclusive) the move can hit. One hit per move
execution (no multi-hit yet).
- `hitboxes` / `hurtboxes.frames`: keys are a tick or tick-range string
(`"6"`, `"6-8"`) → list of rects. `hurtboxes.default` covers unlisted ticks.
- `root_motion`: per-tick forward displacement in px, optional, truncates to 0.
- `cancels`: reserved for the cancel system (not enforced yet).
## Required move names
The FSM binds these animation names — every character must provide them:
`idle` `walk_f` `walk_b` `crouch` `jump` `block` `hit` `knockdown` `getup`
plus whatever attack moves the manifest binds. Recommended full set and budget:
see STUDY.md §2 (~30 clips).
## Where assets come from
Placeholder: `tools/gen_placeholder_char.py`. Production: the MODELBEAST
pipeline (`pipeline/README.md`) renders a rigged 3D character to frames, then
`pipeline/autohitbox.py` generates hurtboxes from pose estimation and
`pipeline/pack_character.py` assembles this folder.