-
Notifications
You must be signed in to change notification settings - Fork 0
Item Models
The Item Models API provides a version-independent way to create modern Minecraft item model definitions and item model graphs.
The API is intentionally split into two layers:
-
Resource Layer (
resource.items.*) — mirrors Mojang's JSON structure. -
API Layer (
api.items.*) — convenience builders and helpers.
This design allows advanced users to work directly with the underlying model graph while still providing easy-to-use presets for common item types.
Most items use one of Minecraft's built-in parents.
Used for regular items such as gems, ingots, food, and materials.
ItemModelDefinition ruby =
Models.generated()
.texture(
"layer0",
"pantheon:item/ruby"
)
.build();Equivalent to:
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "pantheon:item/ruby"
}
}Used for swords, tools, and weapons.
ItemModelDefinition sword =
Models.handheld()
.texture(
"layer0",
"pantheon:item/steel_sword"
)
.build();Equivalent to:
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "pantheon:item/steel_sword"
}
}Used for fishing rods and rod-like items.
ItemModelDefinition rod =
Models.handheldRod()
.texture(
"layer0",
"pantheon:item/magic_rod"
)
.build();Minecraft 1.21+ item models are represented as a graph of nodes.
A graph always starts with a root node.
ItemModels model =
Models.model()
.root(
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/ruby"
)
)
)
.build();ModelNode node =
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/ruby"
)
);EmptyNode node =
Nodes.empty();Equivalent to:
{
"type": "minecraft:empty"
}Tints can be applied directly to model nodes.
ModelNode node =
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/ruby"
),
Tints.constant(0xFF0000)
);ModelNode node =
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/armor"
),
Tints.dye(0xFFFFFF),
Tints.team(0xFFFFFF)
);Composite nodes render multiple models together.
CompositeNode composite =
Nodes.composite(
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/base"
)
),
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/overlay"
)
)
);Equivalent to:
{
"type": "minecraft:composite",
"models": [
{},
{}
]
}Condition nodes select one of two models.
ConditionNode node =
Nodes.condition(
"minecraft:selected",
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/selected"
)
),
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/default"
)
)
);Select nodes allow switching between multiple values.
SelectNode node =
Selects.select(
"minecraft:charge_type",
Nodes.empty(),
Selects.when(
"rocket",
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/rocket_launcher"
)
)
),
Selects.when(
"shell",
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/shotgun"
)
)
)
);Range dispatch selects a model based on a numeric value.
RangeDispatchNode node =
Ranges.range(
"minecraft:damage",
Ranges.entry(
0.25f,
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/damage_1"
)
)
),
Ranges.entry(
0.75f,
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/damage_2"
)
)
)
);Nodes can be nested indefinitely.
Example:
- Select by charge type
- Then check if selected
- Then render multiple overlays
ItemModelNode root =
Selects.select(
"minecraft:charge_type",
Nodes.empty(),
Selects.when(
"rocket",
Nodes.condition(
"minecraft:selected",
Nodes.composite(
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/rocket"
)
),
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/glow"
)
)
),
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/rocket"
)
)
)
)
);Models are registered into a ResourcePackItems container.
ResourcePackItems items =
new ResourcePackItems();
items.register(
ResourceLocation.fromString(
"pantheon:ruby"
),
Models.model()
.root(
Nodes.model(
ResourceLocation.fromString(
"pantheon:item/ruby"
)
)
)
.build()
);The API layer is entirely optional.
Advanced users may construct nodes directly.
new SelectNode(
property,
cases,
fallback
);new CompositeNode(
models
);new RangeDispatchNode(
property,
entries
);The API helpers exist only to reduce boilerplate and improve readability. The underlying resource model classes remain fully accessible.