Models and files
The formats, where each file lives, and how to point Strut somewhere else.
The formats
| Extension | Holds |
|---|---|
.strutmodel | Geometry: cubes, free-form meshes, bone groups and armatures with skinning weights. |
.strutanim | Animation clips: keyframes for bones and armature bones, plus event keyframes (sounds, particles, custom instructions). |
Both are compact binary files. The Blockbench plugin in this repository (plugin/strut_toolkit) reads and writes them directly, so there is no separate export step. The formats are versioned, and a reader refuses a file it does not understand instead of guessing.
Legacy JSON
Bedrock-style .geo.json and .animation.json files can still be loaded when you name them explicitly. New features are built for the binary formats only: the folder conventions, typed events and server-side timelines all read .strutanim.
Folder conventions
For a registry id namespace:path and a kind, Strut looks for:
| Kind | Model | Texture | Animations |
|---|---|---|---|
| entity | strut/models/entity/path.strutmodel | textures/entity/path.png | strut/animations/entity/path.strutanim |
| item | strut/models/item/path.strutmodel | textures/item/path.png | strut/animations/item/path.strutanim |
| block | strut/models/block/path.strutmodel | textures/block/path.png | strut/animations/block/path.strutanim |
| armor | strut/models/armor/path.strutmodel | textures/armor/path.png | strut/animations/armor/path.strutanim |
All under assets/namespace/. The model folder is strut/models/ rather than models/ because models/ is where vanilla keeps its own json models.
Choosing files
You can ask for a conventional model directly, and change one part of it:
| Call | Gives |
|---|---|
StrutModel.entity(id) | The entity convention above. |
StrutModel.item(id) | The item convention. |
StrutModel.block(id) | The block convention. |
StrutModel.armor(id) | The armor convention. |
.withAltModel(id), .withAltTexture(id), .withAltAnimations(id) | The same, with that one part taken from another id (with the same folder convention applied to it). |
When the files do not follow the convention, build the model from ids or from functions of the animatable. The functions run every time the game asks, so the model can depend on the entity's state or variant (an enchanted and a forested model, for instance):
return StrutModel.<HeroEntity>builder()
.model(creature -> Identifier.of("mymod", "strut/models/forested/" + creature.getName().getString() + ".strutmodel"))
.texture(creature -> Identifier.of("mymod", "textures/entities/" + creature.getName().getString() + ".png"))
.animation(Identifier.of("mymod", "strut/animations/creature.strutanim"))
.build();
Anything the builder does not cover (turning a head bone, custom bone handling, animation fallbacks) is still a subclass of StrutModel: override getModelResource, getTextureResource and getAnimationResource, plus whatever else you need.
How loading works
- Models and animations are loaded when resources load, from every resource pack, in pack order.
- Assets delivered by asset sync appear as one more resource pack on top, so they load through the same path.