The DS3 Codex
Chapter III

Characters & items

The Knight is no single model. A skeleton, four armour pieces, a sword and a shield come together at dummy polys. A thousand-odd spline-compressed clips move him, and a hundred and eighty thousand timed events tell the game what each frame of them means.

Armour of an unnamed knight. Its plates are rigged to the same hundred and ten bones as every other Unkindled. Only the dummy polys know where the sword is held.Codex · Knight Set, hd/bd/am/lg_m_1950

In short
  • Models are FLVER2: meshes, materials, bones and dummy polys, the named points where weapons attach, hits are measured and effects spawn.
  • One enemy FLVER holds every weapon and outfit of its type. Display masks from NpcParam pick which meshes are drawn.
  • Animations are Havok spline-compressed clips with root motion. TAE event lists turn them into gameplay: invincibility, cancel windows, attacks, sounds, effects.
  • Equipment and items are mostly params. The Estus Flask is an item row that points at a status effect that heals 250 HP.
  • Every character carries a Havok ragdoll, whose capsules double as hurtboxes. Some, like Gundyr, carry Havok Cloth that drives bones and rewrites vertices.

1Assembling the Knight

Skeletonchr/c0000.anibnd → Skeleton.HKX: an hkaSkeleton "Master" of 110 bones, reference pose as hkQsTransforms
Bodyparts/hd_m_1950 (helm), bd_ (chest), am_ (gauntlets), lg_ (leggings) .partsbnd: a FLVER and a TPF each, skinned to the same bones. The full set covers the body, so no bare body is drawn.
Weaponswp_a_0201 Longsword, wp_a_2104 Knight Shield. EquipParamWeapon.wepAbsorpPosId → WepAbsorpPosParam gives the body's dummy poly for each hand: Longsword 20 (on R_Weapon), Knight Shield 23 (on L_Weapon)
Base modelchr/c0000.chrbnd → c0000.flver: no mesh you see, but the dummy polys (901 the right hand, where the Estus Flask appears) and the ragdoll

A dummy poly's matrix is built XNA-style, CreateWorld(0, forward, upward) × its position × its parent node's bind, and it follows its attach bone. Each weapon model is first turned 180° about its own Y (DSAnimStudio's WeaponFlipSideways, true for both hands in DS3). Without that the shield's face points at the arm.

Faithful

DS3's skeleton, parts and weapon placement, matched bone by bone: every bone an armour piece skins to has exactly the skeleton's bind pose (the importer checks).

2FLVER: the model format

FLVER2 (version 0x20014 on map pieces) holds meshes, materials, nodes (bones) and dummy polys data. Things that were easy to get wrong:

Display masks: one model, many enemies

A Cemetery hollow's c1430.flver holds every weapon and outfit its kind can wear. A mesh belongs to mask NN when its material's name starts #NN#. Unnamed meshes always draw, and NpcParam's ModelDispMask0-31 turn masks on data. For c1430: mask 0 a blade, 1 and 2 other weapons, 3 a broken straight sword, 4 a longsword, 5 and 6 shields, 14 a lantern. Gundyr's masks are his halberd (2), the pus (1) and two sets of arms (4, 5). His transformation swaps them with TAE event 233 (Enemies).

3Textures

Textures come in TPF binders as DDS: BC1 and BC7 for colour, BC4 and BC5 for masks, BC6H for the HDR probe cubemaps. The suffix says the role:

Map materials also carry a _s "shininess" texture. Following DSAnimStudio, gloss comes from the normal map's blue and _s is ignored guess. Engine placeholders like SYSTEX_Dummy* mean "no texture", and SYSTEX_DummyBurn_* slots are burn and damage overlays. Lightmaps, probes and the sky's layers are on the Renderer page.

4Skeletons and animations

Clips

  • One hkaSplineCompressedAnimation per clip, named aXXX_YYYYYY. XXX is the motion category: 000 for the common moves, 023 for longsword moves, 048 for the small shield.
  • Clips spread over several anibnds: idle in c0000_a00_lo, locomotion in _a00_hi, Longsword attacks in _a2x.
  • Root motion is separate: an hkaDefaultAnimatedReferenceFrame, samples of (x, y, z, yaw) at 30 Hz. It's what moves the character (Movement).
  • Some TAE entries have no clip of their own and borrow another's motion (LandLow a000_004290 ← a000_004200).

Clips

Our animation reader, a port of the community SoulsAssetPipeline's decoder (and the riskiest part of the importer), decodes every frame at 30 Hz into .anim: per-bone TRS keys, the root track, and the clip's TAE events. The engine only interpolates neighbours, blends (1-D by speed, directional by picking one of four clips as DS3 does) and layers an upper-body clip by the behaviour graph's half-blend weights. GPU skinning, all bone palettes in one storage buffer.

Faithful

DS3's clips, decoded exactly. In a RenderDoc capture, Gundyr's kneel matches DS3's own bone matrices to 0.1° and 4 mm.

5TAE: what every frame means

Each clip has a list of timed events (.tae, 186,508 of them for the player). They're the game's switchboard:

EventName (DSAnimStudio)What it does
0ChrActionFlagA flag on for the span: 8 invincible, 7 no turning, 11 stick may cancel, 4/26 attack/dodge may cancel, 19 no map collision, 27 no gravity, 3 guarding, 50 no push…
1AttackBehaviorThe active window of an attack, and which param row it uses (Combat)
2BulletFire a projectile from a dummy poly (the crossbow hollow)
16BlendCrossfade time into the clip
65 / 66ConsumeCurrentGoods / SetSpEffectUse the item (the Estus heal) / apply a status effect (Gundyr's phase change)
96SpawnOneShotFFXPlay an effect on a dummy poly (Effects)
128-132PlaySound_*Sounds, including footsteps whose name depends on the floor (Sound)
224 / 225SetTurnSpeed / SetSPRegenRatePercentTurn rate for the span / stamina regen (0 % through every Longsword attack)
228RagdollReviveTimeAn enemy goes limp
231 / 233event message / ChangeChrDrawMaskTalk to the event script / show and hide display masks
236 / 237RootMotionReduction / SpawnAISoundScale root motion / make a noise enemies hear
300ActivateJumpTableEarlyInterpolate a value: jump table 27 is the gravity multiplier
710 / 792 / 795HideEquippedWeapon / FootSfx / DS3PoiseHide weapons (drinking, pulling the sword) / a special footstep effect / a hyper-armour window

A small tool of ours, built on the community's SoulsFormats library, lists every event, and the importer copies them unchanged into our .anim files. The engine knows which event types and arguments it reads. One importer bug is worth recording: TAE files were once matched to clips by their first two digits, so a234.tae's events landed on the Longsword's a023_* clips.

6Equipment and items are params

The Longsword · EquipParamWeapon 2010000

atkBasePhysics 110, atkBaseStamina 45, weight 3.0, behaviorVariationId 2300 (its attack rows), wepmotionCategory 23 (its clips, a023_*), attackBaseRepel 66, saWeaponDamage (poise damage), scaling correctStrength / Agility, wepAbsorpPosId (where it's held).

The Knight Shield · 2104

physGuardCutRate 100 (blocks all physical damage), staminaGuardDef 48 (stability), guardBaseRepel 50 (flick power), swordArtId 91 → "Parry", motion category 48.

The Knight set · EquipParamProtector

Absorption is stored as the share let through (0.947 …): the four pieces multiply to 72.1 %. The Poise field is the share of poise damage that counts (product 75.1 %; the menu shows 100 × (1 − rate)). defenseMaterial picks the armour's rattle on every step.

The class · CharaInitParam 3000

The Knight's stats (Vigor 12 → 454 HP through CalcCorrectGraph 100; Attunement 10 → 93 FP), equipment, and Item_01 151 "Estus Flask" × 3.

The Estus Flask

EquipParamGoods 151goodsUseAnim 10 (a drink), isConsume, maxNum 20, refId1 → SpEffect 2000 "Item - Estus Flask": subHpPoint −250
the player script's ExecItem
Clipsa000_050110 start (no cancels: committed) → 050111 the gulp, whose TAE 65 at 0.267 s uses the charge → 050112 end; 050114 shaking an empty flask
TAE 96
Effectsthe flask itself is effect 301000, a model particle on dummy 901 (the hand); the heal's glow is 301002 on dummy 8 (the chest)

7Ragdolls

Every chrbnd's cXXXX.HKX holds an hknpRagdollData data: capsule bodies on the bones (18 for the player, 90 kg; 19 for the hollow, 101 kg; 46 for Gundyr, 25 of them the pus) with DS3's mass, inertia, damping, friction and speed caps. They're joined by twist-cone-plane ragdoll joints and limited hinges (feet, hands). Each body's collision filter ignores its joint's parent. The motors are present but disabled.

Going limp

An enemy's death clip carries TAE 228: the hollow falls backwards, lands at 1.77 s and goes limp from 1.93 s. None of the player's 186k events have it, and none of Gundyr's. NpcParam.UseRagdoll is not the death switch: it says whether the living ragdoll blocks the player (big characters only).

Going limp

Jolt bodies with DS3's mass properties and SixDOFConstraints. Havok's round cone becomes a pyramid stand-in. At event 228 each body takes its pose and the velocity the clip gave it, so the fall carries on. The bodies drive the bones from then on, two collision steps a tick. Walking through a corpse kicks it ours.

Which way an asymmetric limit turns isn't in the data. Tested against DS3's own clips: reading the limits as the parent relative to the child fits the thighs (99 % / 95 % of frames) and the feet. The arms fit the other reading better, so that's still open.

8Cloth

Gundyr's c5110_c.hkx is Havok Cloth: five cloths (loincloth, apron, waist armour, shoulders, the pus's arm), each a small program of operators run every frame:

Skin a small sim mesh from the bones→ Pin the fixed particles→ Simulate: verlet, gravity, damping; local range, links, capsule collisions→ Set 10 cloth bones from sim triangles→ Rewrite mesh vertices on the CPU

Gravity is tuned per piece (−15 m/s² on the loincloth, −100 on the apron). The local range keeps each shoulder particle within 3 cm of its skinned place. The hollow's lantern and cape run the same way.

Close

DS3's operators and numbers, run by our own solver (Havok's code isn't read). Compared with three RenderDoc captures of the fight, the cloth bones turn out rigid in DS3, and ours, orthonormalised the way that fits best, sit a median 2-4 cm from DS3's over 34 attack poses.

9Our .chr

A .chr ties it together: the .skel, skinned parts (each with its display mask), rigid attachments on bones (weapons, with their hand slot), clips, dummies (on an attachment, on a bone, or fixed in model space like Gundyr's dummy 100), hurt capsules (the ragdoll's bodies), and the upper-body weights for half blends. Enemies get one part per display mask and borrow the clips of the character normalChangeAnimChrId names (Enemies).