Wolfenstein Modloader Buy me a coffeeKaffee spendieren

Wiki / Latest research roundsNeueste Forschungsrunden

Animation Decode: the Geist System Behind the Bind-Pose Puzzle

OpenOffen Original page in the GitHub wikiOriginalseite im GitHub-Wiki

In plain wordsIn einfachen Worten

This report continues the effort to decode Wolfenstein II: The New Colossus's compressed .md6anim animations and to explain why the soldier's skeleton does not pose correctly while a pistol's does. It found that two suspected decoder functions belong to a separate animation system called Geist, identified from the game's own debug text. The soldier has a Geist identity file and no weapon does, which may explain the mismatch, but this is inferred, and a full animation decode is still not achieved; everything is static research.

  • Rotation compression ('smallest three' quaternions) is solved and round-trips 86/86 samples.
  • Geist is large: 2,818 .geistanim and 66 .geistidentity files, including one for the soldier, none for weapons.
  • The md6anim and Geist code never call each other, apart from two shared rotation helpers.
  • The 10-number pose record after the animation header is decoded: position, rotation and scale.
  • Nothing new for modders yet: new animations still cannot be made or decoded.

Dieser Bericht setzt die Entschlüsselung der komprimierten .md6anim-Animationen von Wolfenstein II: The New Colossus fort und sucht nach dem Grund, warum das Skelett des Soldaten nicht korrekt posiert, das einer Pistole aber schon. Er fand heraus, dass zwei verdächtige Decoder-Funktionen zu einem eigenen Animationssystem namens Geist gehören, erkannt an den eigenen Debug-Texten des Spiels. Der Soldat hat eine Geist-Identitätsdatei, keine Waffe hat eine, was die Abweichung erklären könnte; das ist aber nur gefolgert, und eine vollständige Entschlüsselung der Animationen gelingt noch nicht. Alles ist statische Forschung.

  • Die Rotationskompression („Smallest Three“-Quaternionen) ist gelöst und übersteht 86/86 Proben im Round Trip.
  • Geist ist groß: 2.818 .geistanim- und 66 .geistidentity-Dateien, darunter eine für den Soldaten, keine für Waffen.
  • Der md6anim- und der Geist-Code rufen sich nie gegenseitig auf, außer zwei gemeinsamen Rotations-Hilfsfunktionen.
  • Der 10-Zahlen-Posendatensatz nach dem Animations-Header ist entschlüsselt: Position, Rotation und Skalierung.
  • Für Modder noch nichts Neues: Neue Animationen lassen sich weiterhin weder erstellen noch entschlüsseln.

Technical detailsTechnische Details

Der technische Teil ist auf Englisch – so, wie er im Wiki steht. Unterstrichene Begriffe haben eine Erklärung auf Deutsch.

This research continues a multi-pass effort to decode TNC's compressed .md6anim animation format, and to explain why the soldier model's skeleton does not pose correctly from the already-proven formula while a pistol's does. This pass found that two "candidate decoder" functions flagged by an earlier reviewer belong to a completely separate, independently-shipped animation system called "Geist" (identified directly from the game's own embedded debug strings, not guessed), not to .md6anim itself. No weapon in the game has a Geist identity file, but the soldier does, which plausibly explains the bind-pose mismatch without yet fixing it. Rotation (quaternion) compression was solved in an earlier pass and remains confirmed; a full byte-for-byte decode of a .md6anim animation is still not achieved. Everything here is static disassembly/format research — no game launch was involved and there is nothing to test in-game yet.

Proven

  • Rotation ("smallest three" quaternion) compression: fully solved, round-trips 86/86 samples. Dequantizer at .text 0x54bfa0, quantizer at 0x54bdd0.
  • 0x1169530 is idCompressedRigAnimation::Compress, part of C++ namespace Geist050::Mercury (source file .../geist/lib/core/compiler/animation/riganimationcompressed.cpp) — identified from its own embedded debug strings (source path, log tags, a Linear/Scalar/Quat2/Quat4 channel-type enum), not inferred from structure.
  • Zero code calls in either direction between the .md6anim cluster (0x549e70-0x552210) and the Geist cluster (0x1168000-0x116f000), except two shared low-level quaternion primitives (0x54bdd0/0x54bfa0). The two systems are siblings, not one wrapping the other.
  • 0x116d212, the strongest "separate decoder" candidate an earlier pass found, has zero static callers anywhere in .text, no RTTI vtable slot, and shares its only two internal helper calls exclusively with Compress itself — more likely part of the compiler's own machinery (e.g. a keyframe-fidelity check) than a standalone runtime decoder.
  • Geist is a large, independently-shipped system in the retail content: 2,818 .geistanim files, 66 .geistidentity files (including geist/identity/soldier.identity). No weapon has a .geistidentity (0/66 checked) — weapons stay entirely in the plain .md6skl/.md6anim world.
  • The 10-float TRS record right after .md6anim's outer header is now precisely decoded: translation (3 floats) + quaternion xyzw (4) + scale (3).
  • The "_FRAMESET_" tag occurs twice per file, not once as earlier passes assumed.

Inferred, not proven

  • The likely explanation for the bind-pose puzzle: Geist (not idMD6Anim) builds the soldier's actual runtime skin pose, while .md6skl/.md6anim may serve the humanoid rig for something else (attachment points, a ragdoll proxy, a distant-LOD fallback) where literal bone-length reproduction isn't expected. Motivated by the code separation above but not proven — Geist's own bind-pose/skin-matrix construction code was not found or disassembled.
  • 0x116d212's 4-mode dispatch likely corresponds to Compress's own Linear/Scalar/Quat2/Quat4 channel types, with mode 3 (Quat4) being the one that touches quaternion data — a clean structural match, not confirmed by a trace.

Open / not decoded

  • Where inside the (now precisely located) "_FRAMESET_" regions the per-joint rotation data actually sits. Two sample files have substantial non-zero payload there (75–92% non-zero bytes) and are better decode targets than the "none_additive" sample earlier passes used, which turned out to be a near-empty additive placeholder.
  • Which function dequantizes translation.
  • .md6settings, a resource path pattern (md6/geist/<name>/face.md6settings) referenced by Compress's only known caller, is not among the 174 resource types that actually ship in the retail archive index — possibly unused/cut content, not resolved further.

For modders

Nothing here changes what's achievable in a mod today: reusing an existing weapon's full animation set still works (see the weapon-decl report), but no new .md6anim content can be authored or decoded yet. This is pure format research with no mod-facing recipe of its own.