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

8.5 KiB
Raw Permalink Blame History

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 (handahande, 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)

{
  "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.


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.