1. Wiki
  2. /Animations
  3. /Render controllers

Render controllers

Choose a mob's model, materials and texture in Minecraft Bedrock with render controllers: arrays, texture variants, part_visibility and colors.

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

Resource pack
RP/
  entity/
    ruby_golem.entity.json
  render_controllers/
    ruby_golem.render_controllers.json
  textures/
    entity/
      ruby_golem/
        red.png
        pink.png
        dark.png

Do 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 entityIn 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:

RP/render_controllers/ruby_golem.render_controllers.json
{
  "format_version": "1.8.0",
  "render_controllers": {
    "controller.render.ruby_golem": {
      "geometry": "geometry.default",
      "materials": [{ "*": "material.default" }],
      "textures": ["texture.red"]
    }
  }
}

The three main parts:

FieldWhat it holds
geometryOne model. A single value, not a list.
materialsA list that matches bones to materials. * means every bone.
texturesA list of textures. Most mobs only need one.

The name must start with controller.render.. Then list it in the client entity:

RP/entity/ruby_golem.entity.json
"render_controllers": ["controller.render.ruby_golem"]

Step 2: three gem colors

Now the fun part. First, list all three textures in the client entity:

RP/entity/ruby_golem.entity.json
"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:

RP/render_controllers/ruby_golem.render_controllers.json
{
  "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:

BP/entities/ruby_golem.json (parts)
"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 arraysHoldsExample item
texturesTexturestexture.red
materialsMaterialsmaterial.default
geometriesModelsgeometry.default

You do not always need an array. A simple choice between two things can use a Molang ternary:

Pick a model without an array
"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:

RP/render_controllers/ruby_golem.render_controllers.json
"part_visibility": [
  { "*": true },
  { "crown": "query.is_tamed" }
]
  • Each entry is a bone name and a value. true or anything that is not 0 shows it, false or 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_*" matches gem_left, gem_right and so on.

The materials list works the same way: start with { "*": ... } for everything, then override single bones after it.

A glowing core
"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:

FieldWhat it does
colorTints the mob. Needs a material that supports tinting.
overlay_colorPaints a color over the whole mob, with a as strength
is_hurt_colorThe flash when the mob takes damage. Vanilla is red.
on_fire_colorThe tint while burning
ignore_lightingtrue draws the mob at full brightness, even at night
uv_animSlides 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:

Flash white when shouting
"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:

RP/entity/ruby_golem.entity.json
"render_controllers": [
  "controller.render.ruby_golem",
  { "controller.render.ruby_golem_shine": "query.is_powered" }
]

When something goes wrong

What you seeMost likely cause
The mob is invisibleThe render controller name in the client entity has a typo, or the file is not in render_controllers
Black and purple checkersThe texture short name or its path is wrong, or the path ends in .png
Every golem is redThe behavior pack never sets minecraft:variant, so query.variant is 0
A hidden part still showsA later part_visibility entry turns it back on, like a * placed last
The color tint does nothingThe material does not support tinting. Try a vanilla material made for it

More help is in Troubleshooting.

What next

Animations: Guides

We use cookies to improve your experience and analyse site traffic. Learn more