Animations move a mob. A render controller decides what the mob is drawn with: which model, which texture and which material. It can also hide parts of the model. In this guide our Ruby golem gets three gem colors and a crown it only wears sometimes.
Render controllers live in the resource pack. Like animations, they only change how a mob looks.
The files
RP/
entity/
ruby_golem.entity.json
render_controllers/
ruby_golem.render_controllers.json
textures/
entity/
ruby_golem/
red.png
pink.png
dark.pngDo you even need one?
Many mobs have one model and one skin. For those, use the vanilla controller controller.render.default. It draws the geometry, texture and material that are all called default in your client entity, and you do not have to write any file. Your first custom mob does exactly that.
You need your own render controller when:
- the mob has several textures to choose from, like colors or skins,
- the mob changes model, like a sheep that loses its wool,
- parts of the model should appear or vanish, like a saddle or armor,
- the mob should be tinted a color.
Short names come from the client entity
A render controller never uses file paths. It uses the short names you gave things in the client entity, with a prefix in front:
| In the client entity | In the render controller |
|---|---|
"geometry": { "default": "geometry.wiki.ruby_golem" } | geometry.default |
"textures": { "red": "textures/entity/ruby_golem/red" } | texture.red |
"materials": { "default": "entity_alphatest" } | material.default |
So texture.red means "the texture I called red in the client entity".
Step 1: the simplest controller
Render controller files go in the render_controllers folder:
{
"format_version": "1.8.0",
"render_controllers": {
"controller.render.ruby_golem": {
"geometry": "geometry.default",
"materials": [{ "*": "material.default" }],
"textures": ["texture.red"]
}
}
}The three main parts:
| Field | What it holds |
|---|---|
geometry | One model. A single value, not a list. |
materials | A list that matches bones to materials. * means every bone. |
textures | A list of textures. Most mobs only need one. |
The name must start with controller.render.. Then list it in the client entity:
"render_controllers": ["controller.render.ruby_golem"]Step 2: three gem colors
Now the fun part. First, list all three textures in the client entity:
"textures": {
"red": "textures/entity/ruby_golem/red",
"pink": "textures/entity/ruby_golem/pink",
"dark": "textures/entity/ruby_golem/dark"
}Then put them in an array in the render controller and pick one with Molang:
{
"format_version": "1.8.0",
"render_controllers": {
"controller.render.ruby_golem": {
"arrays": {
"textures": {
"array.gem_colors": [
"texture.red",
"texture.pink",
"texture.dark"
]
}
},
"geometry": "geometry.default",
"materials": [{ "*": "material.default" }],
"textures": ["array.gem_colors[query.variant]"]
}
}
}array.gem_colors[query.variant] means "take item number query.variant from the list". Counting starts at 0, so variant 0 is red, 1 is pink and 2 is dark.
Where does query.variant come from?
From the behavior pack. The minecraft:variant component stores a number on the mob, and query.variant reads it. Here each golem picks a random color when it spawns:
"component_groups": {
"wiki:color_red": { "minecraft:variant": { "value": 0 } },
"wiki:color_pink": { "minecraft:variant": { "value": 1 } },
"wiki:color_dark": { "minecraft:variant": { "value": 2 } }
},
"events": {
"minecraft:entity_spawned": {
"randomize": [
{ "weight": 2, "add": { "component_groups": ["wiki:color_red"] } },
{ "weight": 1, "add": { "component_groups": ["wiki:color_pink"] } },
{ "weight": 1, "add": { "component_groups": ["wiki:color_dark"] } }
]
}
}Red has weight 2, so it shows up twice as often as each of the others.
Out of range is not an error
If the number is bigger than the list, it wraps around: in a list of 3, number 3 picks item 0 again. Negative numbers pick item 0. So a wrong variant shows the wrong color, not a crash.
Arrays for models and materials too
arrays can hold three kinds of lists. Each list may only hold one kind of thing:
| Key inside arrays | Holds | Example item |
|---|---|---|
textures | Textures | texture.red |
materials | Materials | material.default |
geometries | Models | geometry.default |
You do not always need an array. A simple choice between two things can use a Molang ternary:
"geometry": "query.is_baby ? geometry.small : geometry.default"Step 3: hide and show parts
part_visibility turns bones on and off. Our golem has a crown bone that it only shows when it is tamed:
"part_visibility": [
{ "*": true },
{ "crown": "query.is_tamed" }
]- Each entry is a bone name and a value.
trueor anything that is not 0 shows it,falseor 0 hides it. - Hiding a bone hides its children too.
- Entries are applied in order, so later ones win. Here everything is shown first, then the crown is set by the query.
*works as a wildcard:"gem_*"matchesgem_left,gem_rightand so on.
The materials list works the same way: start with { "*": ... } for everything, then override single bones after it.
"materials": [
{ "*": "material.default" },
{ "core": "material.glow" }
]For this to work, glow must be a short name in the client entity's materials, pointing at a real material that glows, like entity_emissive_alpha.
Colors and effects
A render controller can also change colors. All of these are optional:
| Field | What it does |
|---|---|
color | Tints the mob. Needs a material that supports tinting. |
overlay_color | Paints a color over the whole mob, with a as strength |
is_hurt_color | The flash when the mob takes damage. Vanilla is red. |
on_fire_color | The tint while burning |
ignore_lighting | true draws the mob at full brightness, even at night |
uv_anim | Slides the texture over time with offset and scale, for flowing effects |
Each color has r, g, b and a from 0 to 1, and each can be Molang:
"overlay_color": {
"r": 1.0,
"g": 1.0,
"b": 1.0,
"a": "variable.is_shouting ? 0.5 : 0.0"
}More than one controller
render_controllers in the client entity is a list. Each controller draws the mob once with its own model, so you can stack them. Vanilla uses this for layers like armor or glowing eyes.
You can also add a condition so a controller only draws sometimes:
"render_controllers": [
"controller.render.ruby_golem",
{ "controller.render.ruby_golem_shine": "query.is_powered" }
]When something goes wrong
| What you see | Most likely cause |
|---|---|
| The mob is invisible | The render controller name in the client entity has a typo, or the file is not in render_controllers |
| Black and purple checkers | The texture short name or its path is wrong, or the path ends in .png |
| Every golem is red | The behavior pack never sets minecraft:variant, so query.variant is 0 |
| A hidden part still shows | A later part_visibility entry turns it back on, like a * placed last |
| The color tint does nothing | The material does not support tinting. Try a vanilla material made for it |
More help is in Troubleshooting.
What next
- Make the mob move with Entity animations.
- Play sounds and particles from animations with Animation events.
- Paint better skins with Pixel textures.