Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hbmmods/hbm-s-nuclear-tech-git/llms.txt

Use this file to discover all available pages before exploring further.

NTM’s weapon animation system — contributed by MellowArpeggiation — stores all weapon animations as JSON files that are loaded alongside OBJ models at runtime. This approach keeps file sizes small while supporting full skeletal-style animation with per-part keyframes, Bezier and easing curves, parent–child hierarchies, and rest-pose offsets. The Blender addons in the tools/ directory let you author animations visually in Blender and export them directly to the JSON format that NTM reads, or import existing animation files back into Blender for editing. This page explains the file format, the addon workflow, and where everything lives in the repository.

Animation File Format

Each animation JSON file sits next to its corresponding OBJ model inside:
src/main/resources/assets/hbm/models/weapons/animations/
├── am180.json
├── congolake.json
├── flamethrower.json
├── lag.json
├── spas12.json
└── stg77.json
A single file can contain multiple named animation clips (e.g., Fire, Reload, Inspect, Jammed). Each clip drives one or more named parts (mesh objects), and each part carries keyframe data for location and rotation_euler channels on the x, y, and z axes. Keyframe tuples encode the value, the timestamp in milliseconds, the interpolation mode (e.g., BEZIER, EXPO, CONSTANT), optional easing, and Bezier handle positions where applicable. The top-level structure of a file looks like this:
{
  "anim": {
    "AnimationName": {
      "PartName": {
        "location":       { "x": [...], "y": [...], "z": [...] },
        "rotation_euler": { "x": [...], "y": [...], "z": [...] }
      }
    }
  },
  "offset": {
    "PartName": [x, y, z]
  },
  "hierarchy": {
    "ChildPart": "ParentPart"
  },
  "rotmode": {
    "PartName": "YZX"
  }
}
KeyPurpose
animAll animation clips, keyed by clip name, then by part name
offsetRest-pose world-space position of each part (set from frame 0)
hierarchyParent–child relationships between parts
rotmodeEuler rotation order per part (default YZX for best in-game accuracy)
The runtime loader lives in com.hbm.animloader and is driven by AnimationController, AnimatedModel, Animation, and AnimationWrapper. The controller interpolates between keyframe pairs each render frame and applies the resulting transforms as OpenGL matrix operations.
Axes are swizzled on export: Blender’s +Y (up) maps to NTM’s +Z, and +Z (Blender forward) maps to +Y. The export scripts handle this automatically so you do not need to rotate your Blender scene.

Blender Addons

Available versions

The tools/ directory contains three Python addon scripts, one per supported Blender version:
FileBlender version
tools/export-json-animation-2_79.pyBlender 2.79
tools/export-json-animation-3_2.pyBlender 3.2
tools/export-json-animation-4_0.pyBlender 4.0
Newer Blender versions (4.1, 4.2, etc.) should work reasonably well with the 4.0 addon since Blender’s Python API is stable across minor releases in the 4.x series. Each script registers two operators — Export NTM .json and Import NTM .json — and adds them to Blender’s File → Export and File → Import menus respectively.
Check the comment block at the top of each script for version-specific usage notes. The header comments are the authoritative source of truth for that script’s quirks and requirements.

Installing the addon

1

Open Blender Preferences

In Blender, go to Edit → Preferences (or File → User Preferences in 2.79).
2

Navigate to the Add-ons tab

Click the Add-ons tab in the left sidebar of the Preferences window.
3

Install from file

Click Install… (Blender 3.x / 4.x) or Install Add-on from File… (Blender 2.79). Navigate to the tools/ directory in the NTM repository and select the .py file that matches your Blender version.
4

Enable the addon

After installation, search for “Export JSON Animation” in the addon list and tick the checkbox to enable it. The operators will now appear under File → Export → Export NTM .json and File → Import → Import NTM .json.

Export Workflow

This workflow takes you from a rigged and animated Blender scene to a .json file ready to drop into the repository.
1

Set up your action names

Every action in your Blender file must follow the naming convention AnimationName.PartName. For example, an action named Reload.Gun will export as the Reload animation clip driving the Gun part. Actions that do not contain exactly one . separator are silently skipped.
Reload.Gun
Reload.Mag
Reload.Bolt
Fire.Gun
Fire.Trigger
2

Start all actions at frame 0

Every action must begin at frame 0. The exporter reads offsets from frame 0, so parts must be in their rest poses on that frame. If you get unexpected offset issues in-game, verify that the model is in its rest pose at frame 0 before exporting.
3

Set rotation mode to YZX Euler

Select each animated mesh object, open the Object Properties panel, and set Rotation Mode to YZX Euler. This ensures rotations match what NTM expects at runtime.
Object Properties → Transform → Rotation Mode → YZX Euler
4

Run the export

Go to File → Export → Export NTM .json. Choose a destination filename — by convention, use the weapon’s registry name in lowercase (e.g., spas12.json). Click Export NTM .json to write the file.
5

Place the file in the repository

Copy the exported .json file to:
src/main/resources/assets/hbm/models/weapons/animations/
The animation loader references files by this path at runtime.

Import Workflow

Importing lets you load an existing .json animation file back into Blender to inspect or modify it.
1

Open the import dialog

Go to File → Import → Import NTM .json and navigate to the .json animation file you want to open.
2

Select the file and import

Click Import NTM .json. The addon will:
  • Create Blender Actions from the anim data, naming each action AnimationName.PartName.
  • Apply rest-pose offsets from the offset block by moving each mesh object’s origin.
  • Reconstruct parent–child relationships from the hierarchy block.
  • Restore per-object rotation modes from the rotmode block.
3

Assign actions to objects in the Action Editor

Imported actions are stored in bpy.data.actions but are not automatically assigned to the objects in your scene. Open the Action Editor (or NLA Editor) and assign each AnimationName.PartName action to the corresponding mesh object to preview and edit it.

Runtime Integration

The Java-side animation system in com.hbm.animloader works as follows:
ClassRole
AnimationData container: keyframe count, total length, per-part Transform[] arrays
TransformA single interpolated transform snapshot (position + rotation)
AnimationWrapperWraps an Animation with playback state: start time, speed scale, loop/end behavior
AnimationControllerAttached to an AnimatedModel; drives the active AnimationWrapper each frame
AnimatedModelRenderable node in a model hierarchy; applies the controller’s transform via GL11 matrix calls
ColladaLoaderLegacy COLLADA (.dae) loader kept alongside the JSON system
To play an animation from mod code, obtain the AnimationController for the weapon’s AnimatedModel and call the appropriate start method with the animation name and desired EndResult (e.g., END, REPEAT, STAY).
The AnimatedModel.renderAnimated(long sysTime) method drives interpolation using System.currentTimeMillis() as the time source, so animation speed is frame-rate independent.

Build docs developers (and LLMs) love