Privacy
Language: Русский

Dynamic textures

Swap a model part's texture or geometry by what the held item holds: the item a sulfur cube has absorbed, or a bucketed axolotl's variant.

This page has not been translated into Russian yet, so it is shown in English. Read in English

On this page

A dynamic texture is a rule that changes how a model part looks by what the held item carries. Punchy! reads two things for this: the block a sulfur cube has absorbed, and the variant of a bucketed axolotl. This page is for pack makers who already have a model part definition and want a bucket that shows what is inside it.

Before you start

  • Install Punchy! 3.0 or newer, from Modrinth or CurseForge. The keys on this page were checked against Punchy! 3.0 for Fabric on Minecraft 26.3.
  • The sulfur cube source is read in the Punchy! builds for Minecraft 26.2, 26.3 and 26.4, the versions that have the sulfur cube. The axolotl source needs no sulfur cube and works on older versions too, for example 1.21.11.
  • You need a resource pack with a working definition for a bucket. Model part definitions shows how to make one, and Geometry and textures how to build the model.
  • The model needs a bone for the part that changes, such as the contents of the bucket. The texture swap works on one bone at a time.
  • For the check in Punchy! Studio you need Punchy! Studio, from Modrinth or CurseForge.

What the two sources read

Every rule names a source. The source decides which held item it reads and what it gets from it.

sourceThe definition coversWhat the rule getsExamples of what you write in map
sulfur_cube_contentminecraft:sulfur_cube_bucketThe item id of the block the sulfur cube had absorbed when you picked it up.minecraft:tnt, minecraft:oak_log
axol_variantsminecraft:axolotl_bucketThe variant of the axolotl in the bucket, as the game names it.lucy, wild, gold, cyan, blue

Punchy! reads the stack in your hand every frame, so the model changes the moment you swap buckets. Each hand reads its own stack.

When the held item has nothing to report, for example a sulfur cube bucket whose cube absorbed nothing, the rule gets no key. Then only the fallback applies. A rule without a fallback leaves the bone on its base texture when no key matches, so add a fallback when you want a fixed look.

A rule can change one of two things:

  • A texture rule gives one bone another texture. The shape stays. This is the default.
  • A geo rule swaps the whole geometry for another file. Use it only when the shape itself changes.

Make a bucket that shows its contents

You will make a small sulfur cube bucket model. The body keeps its texture. A flat contents layer on top changes by the block the cube absorbed: red for TNT, brown for oak logs, white for everything else.

  1. In your game’s resourcepacks folder, make a folder called Dynamic textures. Inside it, make pack.mcmeta with the text below. The numbers are for Minecraft 26.3. Resource packs has the other versions.

    {
      "pack": {
        "description": "Dynamic textures: sulfur and axolotl buckets",
        "pack_format": 97,
        "min_format": 97,
        "max_format": 97
      }
    }
  2. Next to pack.mcmeta, create the folder assets/minecraft/punchy/model_parts_items/definitions. Beside definitions, create the folders geo and textures.

  3. Save the geometry below as geo/sulfur_bucket.geo.json.

    It has two bones. bucket is the body and contents is a child bone on top. The rule will retexture contents only.

    {
      "format_version": "1.12.0",
      "minecraft:geometry": [
        {
          "description": { "identifier": "geometry.sulfur_bucket", "texture_width": 16, "texture_height": 16 },
          "bones": [
            {
              "name": "bucket",
              "pivot": [0, 0, 0],
              "cubes": [
                {
                  "origin": [-3, 0, -3],
                  "size": [6, 5, 6],
                  "uv": {
                    "north": { "uv": [0, 0], "uv_size": [16, 16] },
                    "south": { "uv": [0, 0], "uv_size": [16, 16] },
                    "east": { "uv": [0, 0], "uv_size": [16, 16] },
                    "west": { "uv": [0, 0], "uv_size": [16, 16] },
                    "up": { "uv": [0, 0], "uv_size": [16, 16] },
                    "down": { "uv": [0, 0], "uv_size": [16, 16] }
                  }
                }
              ]
            },
            {
              "name": "contents",
              "parent": "bucket",
              "pivot": [0, 5, 0],
              "cubes": [
                {
                  "origin": [-2, 5, -2],
                  "size": [4, 2, 4],
                  "uv": {
                    "north": { "uv": [0, 0], "uv_size": [16, 16] },
                    "south": { "uv": [0, 0], "uv_size": [16, 16] },
                    "east": { "uv": [0, 0], "uv_size": [16, 16] },
                    "west": { "uv": [0, 0], "uv_size": [16, 16] },
                    "up": { "uv": [0, 0], "uv_size": [16, 16] },
                    "down": { "uv": [0, 0], "uv_size": [16, 16] }
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  4. In any paint program, make four PNG files, each 16 by 16 pixels and filled with one flat color, and put them in textures/. Flat colors are enough to see the result.

    • sulfur_bucket.png, a grey square, for the body.
    • sulfur_tnt.png, a red square.
    • sulfur_oak_log.png, a brown square.
    • sulfur_other.png, a white square.
  5. Save the definition below as definitions/sulfur_bucket.json.

    {
      "items": ["minecraft:sulfur_cube_bucket"],
      "geo": "minecraft:punchy/model_parts_items/geo/sulfur_bucket.geo.json",
      "texture": "minecraft:punchy/model_parts_items/textures/sulfur_bucket",
      "dynamic_bone_textures": [
        {
          "type": "texture",
          "bone": "contents",
          "source": "sulfur_cube_content",
          "fallback": "minecraft:punchy/model_parts_items/textures/sulfur_other",
          "map": {
            "minecraft:tnt": "minecraft:punchy/model_parts_items/textures/sulfur_tnt",
            "minecraft:oak_log": "minecraft:punchy/model_parts_items/textures/sulfur_oak_log"
          }
        }
      ]
    }
  6. Turn the pack on under Options, then Resource Packs…, and press Done. If a world is open, press F3+T to reload the resources.

  7. Get a sulfur cube bucket whose cube had absorbed a block: pick the cube up with a bucket. Hold the bucket and switch to first person.

  8. Pick up another cube that holds a different block and compare. The top layer takes the color of its block. A cube that holds a block the map does not list, and a bucket with nothing, show the white fallback.

Video coming soon

One definition, three buckets: the top layer follows the absorbed block.

To check the fallback without catching a cube, run /give @s sulfur_cube_bucket. It has no content, so the top layer is white.

What each part of the rule does:

  • type is texture, so one bone changes. It is also the default.
  • bone names the bone to retexture. Without it, a texture rule is thrown away.
  • source says to read the sulfur cube content. It is also the default when you leave source out.
  • map pairs a block item id with the texture to use. Write the id with its namespace, as minecraft:tnt.
  • fallback is the texture for every other case.

The same rule for an axolotl bucket

An axolotl bucket keeps the variant of the axolotl in it. Use axol_variants as the source and write each map key as the variant’s name exactly as the game spells it: lucy, wild, gold, cyan and blue. Punchy! passes the name through unchanged, so the spelling has to match.

This example has one bone, axolotl, and a texture for each variant.

{
  "format_version": "1.12.0",
  "minecraft:geometry": [
    {
      "description": { "identifier": "geometry.axolotl_bucket", "texture_width": 16, "texture_height": 16 },
      "bones": [
        {
          "name": "axolotl",
          "pivot": [0, 0, 0],
          "cubes": [
            {
              "origin": [-3, 0, -5],
              "size": [6, 3, 10],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "west": { "uv": [0, 0], "uv_size": [16, 16] },
                "up": { "uv": [0, 0], "uv_size": [16, 16] },
                "down": { "uv": [0, 0], "uv_size": [16, 16] }
              }
            }
          ]
        }
      ]
    }
  ]
}

Save it as geo/axolotl_bucket.geo.json. In textures/, make five PNG files, each 16 by 16 pixels and filled with one flat color, so the variants are easy to tell apart:

  • axolotl_lucy.png, pink.
  • axolotl_wild.png, brown.
  • axolotl_gold.png, yellow.
  • axolotl_cyan.png, light blue green.
  • axolotl_blue.png, blue.

Then save this as definitions/axolotl_bucket.json.

{
  "items": ["minecraft:axolotl_bucket"],
  "geo": "minecraft:punchy/model_parts_items/geo/axolotl_bucket.geo.json",
  "texture": "minecraft:punchy/model_parts_items/textures/axolotl_lucy",
  "dynamic_bone_textures": {
    "type": "texture",
    "bone": "axolotl",
    "source": "axol_variants",
    "fallback": "minecraft:punchy/model_parts_items/textures/axolotl_lucy",
    "map": {
      "lucy": "minecraft:punchy/model_parts_items/textures/axolotl_lucy",
      "wild": "minecraft:punchy/model_parts_items/textures/axolotl_wild",
      "gold": "minecraft:punchy/model_parts_items/textures/axolotl_gold",
      "cyan": "minecraft:punchy/model_parts_items/textures/axolotl_cyan",
      "blue": "minecraft:punchy/model_parts_items/textures/axolotl_blue"
    }
  }
}

Here dynamic_bone_textures is one object, not a list. Both forms work. To get a bucket of a given variant, run /give @s axolotl_bucket[axolotl/variant="blue"], or catch an axolotl with a bucket.

Video coming soon

Each variant shows its own texture on the same model.

Swap the whole geometry

Use a geo rule when the shape changes: a bucket that is full of TNT looks different from an empty one, not only recolored. A geo rule needs no bone.

Make two more geometry files next to geo/sulfur_bucket.geo.json. Keep the same bone names in all of them, because the texture, glow and texture animation rules find a bone by its name.

  1. Copy geo/sulfur_bucket.geo.json to geo/sulfur_bucket_plain.geo.json. Change its identifier to geometry.sulfur_bucket_plain and leave the rest as it is.
  2. Copy it again as geo/sulfur_bucket_tnt.geo.json. Change its identifier to geometry.sulfur_bucket_tnt. In the contents bone, change "size": [4, 2, 4] to "size": [4, 4, 4], so the top layer is twice as tall.

Then write the rule. Save it as definitions/sulfur_bucket.json in place of the first definition, or copy its rule into the dynamic_bone_textures list of that file, after the texture rule. If you replaced the file, the whole model uses textures/sulfur_bucket.png, because no texture rule is left. Hold a sulfur cube bucket whose cube absorbed TNT and the top layer is taller; with any other content, or none, you see the plain shape.

{
  "items": ["minecraft:sulfur_cube_bucket"],
  "geo": "minecraft:punchy/model_parts_items/geo/sulfur_bucket.geo.json",
  "texture": "minecraft:punchy/model_parts_items/textures/sulfur_bucket",
  "dynamic_bone_textures": [
    {
      "type": "geo",
      "source": "sulfur_cube_content",
      "fallback": "minecraft:punchy/model_parts_items/geo/sulfur_bucket_plain",
      "map": {
        "minecraft:tnt": "minecraft:punchy/model_parts_items/geo/sulfur_bucket_tnt"
      }
    }
  ]
}

The top level geo is still needed. It is the model Punchy! draws when no geo rule picks one. With a fallback, a geo rule always picks one, so the top level geo only has to exist.

A geo rule changes the shape only. The main texture and your other bone rules stay, so you can combine a geo rule with texture rules in the same list. The geo ids are written differently from the top level geo:

You writePunchy! loads
minecraft:punchy/model_parts_items/geo/sulfur_bucket_tntassets/minecraft/punchy/model_parts_items/geo/sulfur_bucket_tnt.geo.json
minecraft:punchy/model_parts_items/geo/sulfur_bucket_tnt.geo.jsonthe same file
minecraft:punchy/model_parts_items/geo/sulfur_bucket_tnt.jsonthe same file, with .json turned into .geo.json
minecraft:sulfur_bucket_tntassets/minecraft/geo/sulfur_bucket_tnt.geo.json, because geo/ is put in front

Write the full .geo.json path in the top level geo. Only the geo rules add the ending for you.

The files you end up with

Here is the whole pack from this page. The two sulfur_bucket_plain and sulfur_bucket_tnt files are for the geo rule only.

Dynamic textures/
  pack.mcmeta
  assets/minecraft/punchy/model_parts_items/
    definitions/
      sulfur_bucket.json
      axolotl_bucket.json
    geo/
      sulfur_bucket.geo.json
      sulfur_bucket_plain.geo.json
      sulfur_bucket_tnt.geo.json
      axolotl_bucket.geo.json
    textures/
      sulfur_bucket.png
      sulfur_tnt.png
      sulfur_oak_log.png
      sulfur_other.png
      axolotl_lucy.png
      axolotl_wild.png
      axolotl_gold.png
      axolotl_cyan.png
      axolotl_blue.png

How to write the texture ids

The texture ids in fallback and map follow the same rule as the top level texture.

You writePunchy! loads
minecraft:punchy/model_parts_items/textures/sulfur_tntassets/minecraft/punchy/model_parts_items/textures/sulfur_tnt.png
mypack:punchy/model_parts_items/textures/sulfur_tnt.pngassets/mypack/punchy/model_parts_items/textures/sulfur_tnt.png
minecraft:block/tnt_sideassets/minecraft/textures/block/tnt_side.png, a texture the game already has

The ending .png is added when it is missing. A path that does not start with punchy/model_parts_items/textures/ gets textures/ put in front, and a path that already starts with textures/ is kept as it is. Ids use lower case letters, digits, _, -, . and /. An id with a capital letter or a space is not valid, and Punchy! skips that entry.

Give every texture in one rule the same layout as the main texture. The faces of the geometry read the same UV rectangles whichever PNG is on the bone.

How Punchy! applies the rules

  • The rules are read in the order you wrote them. A texture rule for a bone that already has a texture from bone_textures replaces it. Two texture rules for the same bone: the later one wins, as long as it resolves to a texture.
  • For one rule, Punchy! looks up the key in map. The match is exact and case sensitive, so blue matches blue and not Blue. Spaces around a key in map are trimmed. When map has no entry, the fallback is used. When there is no fallback either, the bone keeps the texture it had.
  • Child bones use their parent’s texture unless they have a texture of their own. A rule on bucket in the example above would retexture contents too, until contents has a rule or a bone_textures entry.
  • The bone name is found by its exact spelling first, then without regard to case.
  • Geo rules: the last rule that picks a geometry wins. A rule picks one when its map has the key, or when it has a fallback.
  • The swapped texture is the one the bone’s glow and texture animation use. A bone with bone_emission glows with the new texture. A bone with bone_texture_anim needs every texture in its map to be exactly frames times the frame height tall (frame_height, or the geometry’s texture height when it is not set), or that texture stays still.
  • Glow and per-bone texture animation match the bone’s own name only. A child bone that takes its texture from a parent does not glow from the parent’s bone_emission. The whole-model texture_anim also applies to a swapped texture unless the bone has its own bone_texture_anim entry, so the same height rule applies.
  • The type and source words are not case sensitive. Any type other than geo counts as texture.

Check it in Punchy! Studio

Punchy! Studio does not edit dynamic rules. It keeps them when you import a model part and export it again, shows each one in a list, and its live link shows what the real bucket in your hand picks.

  1. Put your pack on, join a world, hold your bucket and switch to first person. Press F6 to open the editor. If it opens in the Third Person perspective, pick First Person with the switch between the menus and the workspace tabs. Then choose the Model workspace.
  2. Choose File > Open Model Part… (Ctrl+O). In the Model Parts Library, pick Resource Packs, select your definition and press Open.
  3. Open the Material tab. Under Dynamic Textures each rule is listed as its type, its bone and its source, for example texture contents sulfur_cube_content.
  4. Choose View > Live Link with Punchy (Ctrl+L). Punchy! now draws the model in your hand through its own loader, so swapping the bucket in your hand swaps the texture.
  5. Choose File > Export Model Part… (Ctrl+E), type the name of the pack in Pack and press Export. The rules are written back with the model part.

The stage on the left does not hold a bucket. It shows the fallback of every texture rule and does not swap geometry. Trust the live link for what the bucket in your hand will look like.

Video coming soon

The Dynamic Textures list on the Material tab, and the live link following the bucket in your hand.

Keys of a dynamic rule

dynamic_bone_textures sits at the root of the definition. It is one rule object or a list of them. The alias dynamicBoneTextures is read only when dynamic_bone_textures is missing.

Keys of a dynamic rule
KeyTypeDefaultWhat it doesExample
typestringtexturetexture gives one bone another texture. geo swaps the whole geometry. Case does not matter, and any other value counts as texture.geo
bonestringThe bone to retexture. Required for texture: a texture rule without it is thrown away. Ignored for geo.contents
sourcestringsulfur_cube_contentWhat the rule reads. sulfur_cube_content reads the block a sulfur cube absorbed. axol_variants reads the variant of a bucketed axolotl. Case does not matter. A missing or blank value means sulfur_cube_content. Any other value matches nothing, so only the fallback applies.axol_variants
mapobjectemptyMaps what the source reports to a texture id, or a geometry id for geo. Keys match exactly, with case. A map that is not an object counts as empty. Entries with a value that is not valid text or not a valid id are skipped, and the rest of the rule still works.{ "minecraft:tnt": "minecraft:punchy/model_parts_items/textures/sulfur_tnt" }
fallbackresource idUsed when the map has no entry for the key, and when the held item reports nothing. A texture id for texture, a geometry id for geo.minecraft:punchy/model_parts_items/textures/sulfur_other
What each source reports
KeyTypeWhat it doesExample
sulfur_cube_contentitem idThe registry id of the block item the cube had absorbed, written with its namespace. A bucket whose cube absorbed nothing reports nothing.minecraft:tnt
axol_variantstextThe variant name of the axolotl, as the game spells it: lucy, wild, gold, cyan or blue. Punchy! passes the name through unchanged, so match the spelling exactly.blue

Things that drop a rule

A rule that is not usable is thrown away without a message. The other rules of the definition still work, and so does the rest of the definition.

What is wrongExample
A texture rule with no bone."type": "texture" and no "bone".
A rule with no usable fallback and no usable map entry.A fallback with a capital letter and no map entries. A map that is not an object and no fallback.
A map entry whose id is not valid."minecraft:tnt": "Sulfur Tnt". Only that entry is skipped, and the rest of the rule still works.
dynamic_bone_textures that is neither an object nor a list of objects."dynamic_bone_textures": "sulfur_cube_content"
A bone that is not text on a texture rule."bone": ["contents"]

Why my bucket does not change

  • The mapped texture never shows. The source is misspelled, for example axolotl_variants. Any value other than the two names matches nothing, so only the fallback shows.
  • Only the fallback shows. The map key does not match. For sulfur cubes, write the full id: minecraft:tnt, not tnt. For axolotls, write lower case: blue, not Blue. Keys match exactly.
  • A bucket from /give shows the fallback. A bucket with no content or no variant reports nothing. Catch a cube or an axolotl with a bucket, or give the variant with /give @s axolotl_bucket[axolotl/variant="gold"].
  • The bone keeps its old texture. The bone name is not in the geometry, so check its spelling against the geometry. Or a later texture rule for the same bone replaces yours, because the later rule wins when it resolves to a texture. Check the order of the rules in the list.
  • The bone does not show the texture you expect. The file is not at the id you wrote, or the id points at another namespace. Punchy! reads the size of each texture when it loads the definition and says nothing when a file is missing.
  • Punchy! draws nothing for the bucket. A geometry in a geo rule is missing or broken. Punchy! then leaves the model out and the vanilla bucket shows. Check every geo id in map and fallback.
  • A texture animation stands still. The swapped PNG is not exactly frames times the frame height tall.
  • Nothing happened after an edit. Press F3+T to reload the resources.
  • The model is not drawn while you use the bucket. While you use an item, Punchy! lets the vanilla model draw it, unless the definition has an entry of a use or consume type or a using state model. See Model part definitions for the entry types.
  • Another definition covers the bucket. Among definitions with no customName, the one whose id sorts first wins. A definition with a customName wins over those when the held stack carries that name. See Which definition covers an item.

Last checked against the mod on 29 October 2026.