Guidefor modders4 min read
Armor textures to equipment JSON: why worn armor breaks in 1.21.2+
Armor rendering moved off plain layer_1/layer_2 PNGs and onto a separate equipment JSON system in 1.21.2 through 1.21.4. Updating the item icon does not fix the worn texture. What changed, where the new files live, and how to migrate.
Two changes, one version window, not the same system
Minecraft overhauled how items look and how armor renders in the same stretch of versions, and the two changes get merged into one confused bug report constantly. They are not the same system.
item_model and custom_model_data control what an item looks like as an inventory icon and in hand. That is the item side.
This guide covers how armor renders on the entity actually wearing it. That is a separate rendering path, with its own file locations, that changed on its own track across 1.21.2 through 1.21.4.
A complete armor set resource pack commonly needs both changes applied: item_model so the piece looks right in the inventory and in hand, and the equipment JSON system below so it looks right worn. Doing one without the other is the single most common state a broken armor pack is found in, which is exactly what the next section covers.
The mistake that causes almost every report
Pack creators update assets/minecraft/textures/item/<armor piece>.png, see the inventory icon
looks correct, and conclude the armor is fixed.
That file has zero bearing on how the armor will look when rendered on your character.
The item texture and the worn texture are two different files with two different rendering paths that happen to both be called "the armor texture" in casual conversation. Fixing one does nothing to the other. This is why threads like "Mizuno's armor not showing up" and "texture pack armor not working" keep surfacing on packs whose inventory icons are already correct: the reporter fixed the half of the system that was visible in their hand and never touched the half that renders on the body.
If your item icon is right and the worn armor is still wrong, you have not touched the equipment system at all yet.
Old system: plain PNGs, no JSON
Before 1.21.2, armor rendering had no JSON layer. The game's armor-rendering code was hardcoded to look for two specific files per material:
assets/minecraft/textures/models/armor/<material>_layer_1.png
assets/minecraft/textures/models/armor/<material>_layer_2.png
_layer_1 covers helmet, chestplate, and boots. _layer_2 covers leggings, which render at a
different scale and so needed a separate texture. Dropping a correctly named PNG in this folder
was the entire system. No file declared that the texture existed or how it should be applied;
the game just looked for it by convention.
Armor trims worked as a further overlay on top of this, applied by the game separately from the base material texture.
New system: equipment JSON plus a moved texture path
From 1.21.2 through 1.21.4, this became a component-driven system. Armor rendering now goes through a JSON file that defines the equipment model:
assets/minecraft/equipment/<name>.json
That file references textures at a new location, split the same way as before but moved and renamed:
assets/minecraft/textures/entity/equipment/humanoid/<name>.png
assets/minecraft/textures/entity/equipment/humanoid_leggings/<name>.png
Trim materials are folded into this same structure rather than remaining a separate overlay system. A pack that used to ship custom trim handling as its own layer now defines that behavior inside the equipment JSON alongside the base armor model, not as a standalone file set next to it.
None of the old paths are read anymore on a client running 1.21.4 or later. A pack that only
updates the item texture, or that still ships _layer_1/_layer_2 PNGs and nothing else, will
show a correct icon and no worn armor, or the vanilla default worn armor, depending on what the
client falls back to.
Migrating a pack
1. Find the old textures. Locate every
assets/minecraft/textures/models/armor/<material>_layer_1.png and _layer_2.png your pack
ships, including any for materials added by mods rather than vanilla.
2. Create the equipment JSON. For each material, add
assets/minecraft/equipment/<name>.json defining the equipment model. This file is new; there
is no old-system equivalent to copy forward, since the old system needed no JSON at all.
3. Move and rename the textures. Move _layer_1.png content to
assets/minecraft/textures/entity/equipment/humanoid/<name>.png and _layer_2.png content to
assets/minecraft/textures/entity/equipment/humanoid_leggings/<name>.png. The image content
itself does not need to change, only its location and how it is referenced.
4. Migrate trims if the pack touches them. Fold any trim customization into the equipment JSON structure rather than keeping it as a separate overlay. A trim system left in the old overlay shape will not connect to the new rendering path.
5. Do the item side too. If the pack also customizes inventory icons or held appearance for these pieces, apply the item_model and custom_model_data migration as well. It is a separate file set and a separate change, not something the equipment JSON migration includes.
Community tooling
BrilliantTeam's Minecraft-ResourcePack-Migrator, also listed on SpigotMC, is a third-party tool built specifically to convert old armor packs into this new structure. For a large existing pack, running the conversion first and then checking the output is faster than doing every material by hand.
It is a shortcut, not a substitute for understanding the structure above. Trim handling, non-standard materials, and any custom layering the original pack used are the parts most worth checking manually after running a converter, since those are exactly the cases a general-purpose migration tool is most likely to get only partly right.
Version note
This is a 1.21.2 through 1.21.4 change, the same window as the item_model overhaul but on an independent track. Check pack_format and supported_formats if you need one pack to serve both older and newer clients, since the old layer PNGs and the new equipment JSON cannot both be read as alternatives by the same client. Whichever system a given version expects is the only one it reads.

