foitin/STUDY.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

164 lines
8.5 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 — Digitized Fighting Game: Source Study & Assessment
*Study of Bikini Karate Babes 1 (4 ISOs) + BKB2: Warriors of Elysia (installed copy), cross-referenced
with the "Digitized Fighting Game Tech Report" PDF. Goal: build our own original digitized-style
fighter with MODELBEAST-generated assets, architected so new characters drop in as data.*
---
## 1. How the original games actually work (reverse-engineered from BKB2 data)
**Engine:** Custom C++ on Gamebryo/NetImmerse (`.nif` scene files), Bink video (`binkw32.dll`),
Miles Sound System (`mss32.dll`). 2011-era `game.exe` is only 1.4MB — the game is almost
entirely **data**, which is why it worked as a formula.
**The core architecture — one video clip per move:**
```
Data/<Character>/ ← one folder per fighter (12 in BKB2, ~75-83 moves each)
bik/<move>.bik ← 512×512 Bink video @ 30fps, actor pre-keyed onto white
zon/<move>.zon ← "BKB!ZONE": per-frame collision boxes (9 zones × 8 ints/frame)
geo/<move>.geo ← "BKB!GEOM": per-frame root-motion / ground-offset track
me2/<move>.me2 ← "BKB!DAT2": move properties (frame windows, damage, links)
csd/ fpd/ off/ ← cancel/sound/offset sidecar data
world.nif ← stage scene
```
Verified numbers (Venus):
- **81 moves**, each its own clip: idle `stand` (19f loop), jab `handa` (53f), punches `handa-e`,
kicks `kicka-…`, specials `spec1/2`, blocks, ducks, hit reactions (`bhit`, `lhit`, `bfall`,
`bkfal`…), throws, wins. ~202MB/character.
- `handa.zon`: magic `BKB!ZONE`, 53 frames, **9 collision zones per frame**, each zone
8 big-endian ints (type, shape, …, x, y, w, h, flag). Hitboxes AND hurtboxes are hand-placed
**per frame** — this was the labor bomb of the 90s pipeline.
- `handa.geo`: magic `BKB!GEOM`, 53 ints — per-frame X root position (~413px scale), i.e. baked
root motion so the character slides correctly during lunging moves.
- The full-roster inventory: **3,461 .bik clips** across the game (fights, UI slices, VS screens —
even menu elements are positioned video slices named `name-x360-y90-w256-h128.bik`).
**BKB1 discs:** Discs 13 are InstallShield cabs (extractable with `unshield` if we ever want
BKB1's 19-character data), Disc 4 carries the v1.08 patched `BKB.exe`. Not needed — BKB2's
installed data is the better, complete reference.
**What the formula gets right (why it's worth cloning):**
1. Character = folder of clips + frame-indexed metadata. Adding a fighter = adding data, zero code.
2. Frame-indexed everything: collision, root motion, damage windows all keyed to video frame N.
3. Uniform base mechanics (the Mortal Kombat doctrine): shared move vocabulary across the roster
(`handa`…`hande`, `kicka`…, `bhit`, `bfall`…) means the engine treats every character identically.
**What it gets wrong (what we fix):**
- 30fps and a 53-frame jab (1.77s!) — floaty, non-competitive feel. Modern standard: 60fps ticks,
jab = 4-8f startup.
- White-keyed 512×512 video → halo edges, no lighting interaction, fixed camera scale.
- Hand-drawn hitboxes per frame — thousands of hours of labor we can automate.
---
## 2. Level of detail needed (the real answer)
### Per-character clip budget — the minimum viable move set is ~30 clips, not 80
| Category | Clips | Notes |
|---|---|---|
| Locomotion | 6 | idle loop, walk fwd/back, jump (up/fwd/back can share), duck |
| Defense | 3 | stand block, crouch block, block-stun |
| Normals | 8 | 4 punches + 4 kicks (standing/crouching mix) |
| Specials | 34 | the character's identity moves |
| Reactions | 6 | head hit, body hit, low hit, knockdown fall, ground, get-up |
| Throw | 2 | throw + being-thrown |
| Ceremony | 3 | intro, win, dizzy |
| **Total** | **~3032** | BKB's ~75 includes redundant variants + mirrored versions |
At 60fps with modern pacing, average clip ≈ 3060 frames → **~1,2001,800 unique frames per
character**. That's the asset bill per fighter.
### Per-move metadata (one JSON per move, replaces .zon/.geo/.me2)
```json
{
"name": "jab", "input": "LP", "damage": 30,
"startup": 5, "active": [5, 8], "recovery": 14,
"cancels": ["special", "super"], "onBlock": -2, "onHit": 3,
"rootMotion": [0, 0, 2, 4, 4, 2, 0],
"boxes": { "auto": true, "hitFrames": {"5-8": [{"bone": "handR", "r": 28}]} }
}
```
### The one big modernization: **auto-hitboxing**
Run DWPose/RTMPose skeleton estimation over every rendered frame → generate per-frame capsule
hurtboxes from joint positions automatically. Hand-author only the *hit* boxes (active frames of
attacks), which is ~4 frames per attack. This deletes 95% of the 90s labor. It's also the same
DWPose stack the MODELBEAST gen pipeline already uses for pose conditioning — one skeleton pass
serves both generation and collision.
---
## 3. Recommended architecture for FOITIN
### Asset strategy: 3D-first, rendered to digitized sprites ("3D digitized")
Instead of filming actors (BKB) or pure image-to-image chains (fragile identity), build each
fighter as a **textured 3D character** and *render* the digitized look:
```
MODELBEAST pipeline per character:
1. FLUX + character LoRA → master identity portrait(s)
2. Hunyuan3D-2.1 / TRELLIS → textured, rigged-ready 3D mesh (GLB)
3. Auto-rig + mocap clips → the SHARED move library (30 clips, retargeted per character)
4. Fixed orthographic camera → render 60fps PNG frames + normal-map pass + depth pass
5. DWPose over renders → auto hurtbox capsules per frame
6. Pack: WebP/basis atlas + JSON → drop-in character folder
```
Why this beats video capture *and* beats pure 2D generation:
- **One mocap library, every character.** Retarget the same 30 clips to each new rig —
a new fighter costs one mesh + one retarget + one render batch (hours on MODELBEAST, not weeks).
- Perfect frame consistency, perfect alpha (no chroma halo), free normal maps → dynamic stage
lighting on sprites (the 2.5D look the tech report describes).
- The 3D source stays in the vault: cinematic camera moves for supers, restyling, re-rendering at
any resolution later. Character-specific signature moves are just extra clips in that
character's folder.
### Engine: Godot 4.x
Matches the tech report's recommendation and our needs: deterministic fixed-tick
`_physics_process`, AnimatedSprite2D + normal maps + canvas shaders, exports to desktop AND
HTML5/WASM (partly.party-friendly). Combat core = finite state machine + input-buffer reading
numpad-notation motions, fixed 60Hz tick decoupled from render. Design it
deterministic-from-inputs on day one so rollback netcode stays possible.
### Character folder spec (the BKB idea, modernized)
```
characters/<name>/
manifest.json ← display name, stats, move list, palette variants
portrait.png select.webm
moves/<move>/
frames.atlas.webp ← packed sprite frames (+ normals.webp, optional)
data.json ← frame windows, damage, boxes, root motion
audio/ ← per-move whoosh/hit/voice
source/<name>/ ← (not shipped) GLB mesh, LoRA, mocap retargets, render scenes
```
Engine scans `characters/*` at boot → roster builds itself. **That is the "add characters as I
make them" requirement solved** — same as BKB's per-character folders, but self-describing.
---
## 4. Effort assessment
| Phase | Work | Scale |
|---|---|---|
| 1. Combat core | FSM, input buffer, fixed tick, box collision, training-mode hitbox viewer | the hard *code*; small but must be exact |
| 2. Shared move library | ~30 mocap/hand-keyed clips, named vocabulary (BKB-style) | one-time cost, reused forever |
| 3. Pipeline scripts | mesh→rig→retarget→render→pose→pack, one command per character | MODELBEAST jobs |
| 4. First 2 fighters + 1 stage | proves the loop end-to-end | the real milestone |
| 5. Roster growth | new character = new mesh through the pipeline | marginal cost ≈ hours |
**Verdict: very buildable.** The genre's whole trick is that the engine is small and dumb while
the data is rich — a 1.4MB exe ran BKB2. Our advantages over 2002: free auto-hitboxing via pose
estimation, free asset generation via MODELBEAST, 60fps with no ROM limits, and a 3D source of
truth the originals never had. The two things that will make or break it are **feel** (frame
data tuning — steal MK's uniform-mechanics doctrine and modern startup timings, not BKB's) and
**identity consistency** (solved by going through 3D rather than per-frame image generation).
*Original assets only — BKB data stays as reference for formats/mechanics study, nothing ships.*