Models and files

The formats, where each file lives, and how to point Strut somewhere else.

The formats

ExtensionHolds
.strutmodelGeometry: cubes, free-form meshes, bone groups and armatures with skinning weights.
.strutanimAnimation 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:

KindModelTextureAnimations
entitystrut/models/entity/path.strutmodeltextures/entity/path.pngstrut/animations/entity/path.strutanim
itemstrut/models/item/path.strutmodeltextures/item/path.pngstrut/animations/item/path.strutanim
blockstrut/models/block/path.strutmodeltextures/block/path.pngstrut/animations/block/path.strutanim
armorstrut/models/armor/path.strutmodeltextures/armor/path.pngstrut/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:

CallGives
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