Privacy
Language: Suomi

Recreate a 3D bucket pack

Build a 3D bucket pack with a model and textures of your own: a model part for every bucket, item clips, an in-water condition, sloshing liquid, glowing lava and particles.

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

On this page

This tutorial builds a whole 3D bucket pack from an empty folder. Every bucket gets its own model part: the empty bucket, the water, lava and milk buckets, and the fish buckets. The model and every texture are built here from numbers and flat colors.

It is inspired by the example pack provided by patovskiz, Refined Buckets, and uses the same techniques: contents that change with the item, clips that react to water, liquid that sloshes, lava that glows and particles that fit the moment. It is for pack makers who want to see a full set of model parts built in one go. Choose Blockbench or Punchy! Studio in the tool chooser, and every step shows your tool.

What you will build

One geometry, one clip file and nine definitions. Each definition is one bucket state.

BucketItemWhat showsWhat it does
Emptyminecraft:bucketA steel pail with a handleAir bubbles rise from the opening while you touch water
Waterminecraft:water_bucketAnimated waterThe surface sloshes when you turn or move, and splashes when you jump or land
Lavaminecraft:lava_bucketAnimated, glowing lavaA smaller, tighter slosh, embers in the air, and the embers stop in water
Milkminecraft:milk_bucketMilkSloshes, puffs when you jump or land, and tilts when you drink
Cod, salmon, tropical fish, pufferfishminecraft:cod_bucket and the other threeA fish at the surface of the waterThe fish swims, blows bubbles and reacts when you jump or land
Axolotlminecraft:axolotl_bucketThe same fish in the color of the axolotlThe color follows the variant of the axolotl inside

Video coming soon

The finished pack, bucket by bucket.

Before you start

  • Punchy! 3.0 or newer. The files and numbers on this page are written for Fabric on Minecraft 26.3.
  • Blockbench 5 or Punchy! Studio. The tool chooser follows your choice on every page.
  • A plain text editor for the definitions, if you use Blockbench. Studio writes them for you.
  • Python 3 is optional. A short script makes every texture in one go.
  • A rough idea of what a definition is. The model parts overview and Model part definitions explain it, and this page links to the deeper pages as it goes.

How the pack fits together

All nine buckets share one geometry. It holds the pail and everything that can sit in it: a block of liquid and a fish. Each definition then decides what shows with bone_textures. A bone drawn with a completely transparent texture is invisible, so the empty bucket hides the liquid and the fish, the water bucket shows the liquid, and a fish bucket shows both.

Three more choices keep the pack small:

  • Flat colors. Every texture is one color over the whole picture, so it does not matter where a face’s UV points, as long as it stays inside the picture. You never place a UV by hand.
  • One clip file. All the clips move bones by name, and a definition only uses the clips it names.
  • One definition per state. The item decides which definition applies, so the pack needs no switching of its own. When an empty bucket scoops water, Minecraft hands you a water bucket and Punchy! draws that definition.

The geometry has eight bones. Pixels are model pixels, and 16 of them make one block. The model is centered on the middle, with its base on the floor.

BoneParentPivotCubeOriginSize
bodynone0, 5, 0north wall-5, 1, -510, 9, 1
south wall-5, 1, 410, 9, 1
west wall-5, 1, -41, 9, 8
east wall4, 1, -41, 9, 8
footbody0, 0, 0base-5, 0, -510, 1, 10
handlebody0, 9, 0left post-6, 9, -0.51, 3, 1
right post5, 9, -0.51, 3, 1
bar-6, 12, -0.512, 1, 1
liquidbody0, 1, 0liquid-4, 1, -48, 6, 8
surfacebody0, 7.5, 0surface-3.5, 7, -3.57, 1, 7
fishbody0, 8, 0fish body-1.5, 6.5, -33, 3, 6
eyesfish0, 8.6, -2.1left eye-1.7, 8.2, -2.50.4, 0.8, 0.8
right eye1.3, 8.2, -2.50.4, 0.8, 0.8
tailfish0, 8, 3tail-0.5, 6.5, 31, 3, 1

Why these shapes:

  • The four walls and the base make a hollow pail. The walls are 1 pixel thick, so you can look down into it.
  • liquid fills the pail up to 3 pixels below the rim. surface is a thin slab on top of it, so its top sits 2 pixels below the rim. Because it is its own bone, it can tilt on its own, and that is the slosh.
  • The handle pivots at the middle of the pail, one pixel below the top of the walls, so it swings forward and back around the middle of the rim.
  • The fish floats at the surface, half in the liquid, so you see its back. Its eyes and tail are bones of their own, so the tail can wag.

The files end up in this layout. Studio writes its own copy of the geometry and textures for every state, named after the state, so its folders hold more files. They work the same way.

Bucket pack/
  pack.mcmeta
  assets/bucketpack/punchy/model_parts_items/
    definitions/    bucket_empty.json, bucket_water.json, bucket_lava.json, bucket_milk.json,
                    bucket_cod.json, bucket_salmon.json, bucket_tropical_fish.json,
                    bucket_pufferfish.json, bucket_axolotl.json
    geo/            bucket.geo.json
    animations/     bucket.animation.json
    textures/       steel.png, iron.png, clear.png, water.png, lava.png, milk.png, fish_*.png, axolotl_*.png
    shading.json    optional, next to the folders: lights the lava bucket in the dark

The namespace bucketpack is yours to choose. A namespace other than minecraft keeps your files apart from the game’s.

Set up the pack folder

Studio makes the pack folder and its pack.mcmeta the first time you export, so skip this section if you use Studio.

  1. In your game folder, open resourcepacks and make a folder called Bucket pack.

  2. Inside it, make pack.mcmeta with the text below. The numbers are for Minecraft 26.3. Resource packs has the other versions.

    {
      "pack": {
        "description": "A 3D bucket pack",
        "pack_format": 97,
        "min_format": 97,
        "max_format": 97
      }
    }
  3. Make these four folders, next to each other: assets/bucketpack/punchy/model_parts_items/definitions, geo, animations and textures.

Model the bucket

The model is the table above: eight bones and fourteen cubes. Build it once. Origins are the file’s corner with the smallest numbers, in pixels.

Tool

In Blockbench

Blockbench makes the geometry file. You write the definitions by hand later.

  1. Choose File > New > Bedrock Entity. Do not pick Bedrock Legacy Model: it writes the old layout that Punchy! cannot read.
  2. Choose File > Project…. Set Default UV Mode to Per-face UV and Texture Size to 16 and 16, then press Confirm.
  3. Use Add Group and name the group body. Every group becomes a bone, and its name is how the definitions refer to it. Set its Pivot Point to 0, 5, 0.
  4. With the group selected, use Add Cube. Set its Position and Size to the north wall row of the table. Add the other three walls the same way.
  5. Use Add Group for the next bone, foot, and set its Pivot Point. Drag it onto body in the Outliner so it becomes a child. Select it and use Add Cube for its cube.
  6. Do the same for handle (three cubes), liquid, surface and fish, each a child of body. Then add eyes (two cubes) and tail and drag them onto fish.
  7. Check the Outliner. Every parent sits above its children, as in the table. Punchy! attaches a bone that the file lists before its parent to the model’s root instead of to the parent, and the complete geometry file below lists every parent first, so compare your export with it.
  8. Choose File > Export > Export Bedrock Geometry and save the file as bucket.geo.json in the pack’s geo folder.

Video coming soon

A Bedrock Entity project set to Per-face UV, and the first group and cube.

Video coming soon

Eight groups, fourteen cubes, and the export.

Two things to know about Blockbench:

  • It mirrors the X axis when it writes a file: a cube at Position X 5 is written with an origin of -6. Every cube here is centered or comes in a left and right pair, so place both cubes of a pair and the file comes out right.
  • You do not need to touch a UV. Blockbench gives each face one, and the exported numbers will not match the file below. That is fine, because every texture is a flat color. Leave the UVs as Blockbench makes them: they stay inside the 16 by 16 picture you set in the project.

You can also skip the modeling: save the file from the next section and open it with File > Open Model.

In Punchy! Studio

Studio builds the geometry in the Model workspace and shows it in your hand while you work. This first model part is the empty bucket. You will reuse it for the other states later.

  1. Join a world, hold a bucket, switch to first person and press F6. If the editor opens in the Third Person perspective, pick First Person with the Perspective switch between the menus and the workspace tabs.
  2. Open the Model workspace and choose File > New Model Part (Ctrl+N).
  3. Type bucket_empty in Name and minecraft:bucket in Held Item, then press Create. The part starts with one bone called root and one cube.
  4. Open the Definition tab. In the Project panel, set File Name to bucket_empty and Namespace to bucketpack.
  5. Select root in the Outliner. In the Bone tab, type body in Name and 0, 5, 0 in Pivot.
  6. Select its cube. In the Cube tab, set Origin and Size to the north wall row of the table.
  7. Select body again and press Add Cube in the Bone Actions panel. Set Origin and Size to the next wall. Repeat until body has its four walls.
  8. For each other bone, select its parent and press Add Child Bone. In the Bone tab set Name and Pivot, then press Add Cube for each cube of that bone and set its Origin and Size. eyes and tail are children of fish, so select fish first.
  9. Choose View > Live Link with Punchy (Ctrl+L) and hold the bucket. Punchy! now draws your unsaved model in your hand.

Video coming soon

A new model part, the first bone and cube, and the live link.

Video coming soon

The remaining bones and cubes.

Studio leaves the UVs of a new cube as they are, and that is fine here, because every texture is a flat color. Its Lint panel on the Definition tab names anything Punchy! would drop.

The complete geometry file

This is what the model comes to. Save it as geo/bucket.geo.json if you want to skip the modeling or compare your own file. Every face reads the whole 16 by 16 picture.

{
  "format_version": "1.12.0",
  "minecraft:geometry": [
    {
      "description": { "identifier": "geometry.bucket", "texture_width": 16, "texture_height": 16 },
      "bones": [
        {
          "name": "body",
          "pivot": [0, 5, 0],
          "cubes": [
            {
              "origin": [-5, 1, -5],
              "size": [10, 9, 1],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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] }
              }
            },
            {
              "origin": [-5, 1, 4],
              "size": [10, 9, 1],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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] }
              }
            },
            {
              "origin": [-5, 1, -4],
              "size": [1, 9, 8],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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] }
              }
            },
            {
              "origin": [4, 1, -4],
              "size": [1, 9, 8],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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": "foot",
          "parent": "body",
          "pivot": [0, 0, 0],
          "cubes": [
            {
              "origin": [-5, 0, -5],
              "size": [10, 1, 10],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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": "handle",
          "parent": "body",
          "pivot": [0, 9, 0],
          "cubes": [
            {
              "origin": [-6, 9, -0.5],
              "size": [1, 3, 1],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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] }
              }
            },
            {
              "origin": [5, 9, -0.5],
              "size": [1, 3, 1],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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] }
              }
            },
            {
              "origin": [-6, 12, -0.5],
              "size": [12, 1, 1],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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": "liquid",
          "parent": "body",
          "pivot": [0, 1, 0],
          "cubes": [
            {
              "origin": [-4, 1, -4],
              "size": [8, 6, 8],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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": "surface",
          "parent": "body",
          "pivot": [0, 7.5, 0],
          "cubes": [
            {
              "origin": [-3.5, 7, -3.5],
              "size": [7, 1, 7],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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": "fish",
          "parent": "body",
          "pivot": [0, 8, 0],
          "cubes": [
            {
              "origin": [-1.5, 6.5, -3],
              "size": [3, 3, 6],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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": "eyes",
          "parent": "fish",
          "pivot": [0, 8.6, -2.1],
          "cubes": [
            {
              "origin": [-1.7, 8.2, -2.5],
              "size": [0.4, 0.8, 0.8],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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] }
              }
            },
            {
              "origin": [1.3, 8.2, -2.5],
              "size": [0.4, 0.8, 0.8],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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": "tail",
          "parent": "fish",
          "pivot": [0, 8, 3],
          "cubes": [
            {
              "origin": [-0.5, 6.5, 3],
              "size": [1, 3, 1],
              "uv": {
                "north": { "uv": [0, 0], "uv_size": [16, 16] },
                "east": { "uv": [0, 0], "uv_size": [16, 16] },
                "south": { "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] }
              }
            }
          ]
        }
      ]
    }
  ]
}

Make the textures

The pack needs fifteen small PNG files. Each is one flat color over the whole picture.

FileSizeUsed forColor (hex)Red, green, blue
steel.png16 by 16The walls of the pail#B9BFC7185, 191, 199
iron.png16 by 16The base, the handle and the eyes#4A4F5774, 79, 87
clear.png16 by 16Hides a bonenonefully transparent
water.png16 by 64Water, four frames#2F6FE0, #3A7DEC, #2F6FE0, #2563D047, 111, 224; 58, 125, 236; 47, 111, 224; 37, 99, 208
lava.png16 by 64Lava, four frames#E0540A, #F26A10, #FF8A1E, #F26A10224, 84, 10; 242, 106, 16; 255, 138, 30; 242, 106, 16
milk.png16 by 16Milk#F4F4EE244, 244, 238
fish_cod.png16 by 16The cod#A67C52166, 124, 82
fish_salmon.png16 by 16The salmon#D0685C208, 104, 92
fish_tropical.png16 by 16The tropical fish#F58A24245, 138, 36
fish_pufferfish.png16 by 16The pufferfish#E9C13B233, 193, 59
axolotl_lucy.png16 by 16The axolotl variant lucy, also the fallback#F4A6C9244, 166, 201
axolotl_wild.png16 by 16The axolotl variant wild#8A5A3C138, 90, 60
axolotl_gold.png16 by 16The axolotl variant gold#F2C94C242, 201, 76
axolotl_cyan.png16 by 16The axolotl variant cyan#4CC9D676, 201, 214
axolotl_blue.png16 by 16The axolotl variant blue#3B63E059, 99, 224

Two of them have more than one frame. An animated texture stacks its frames one under the other, each as tall as the geometry’s texture grid, which is 16 here. Four frames make a picture 16 pixels wide and 64 tall. clear.png has no color at all: every pixel is fully transparent, which makes a bone invisible.

Tool

In Blockbench

Blockbench only makes the model, so the textures come from somewhere else. Pick one:

  • The script. It writes all fifteen files. Open the next box, save the script as make_textures.py in your resourcepacks folder and run python make_textures.py. The files land in the pack’s textures folder.
  • An image editor. Make each file by hand: a 16 by 16 picture filled with the color in the table, and a 16 by 64 picture for water.png and lava.png with a color of its own in each of the four 16 pixel rows. Save them as PNG, with clear.png fully transparent, in the pack’s textures folder.

In Punchy! Studio

Studio paints the textures in the Model workspace, or takes finished PNG files.

  1. Select the bone that needs a texture, for example body. Open the Paint tab (5 switches the stage to Paint mode) and type the red, green, blue and alpha values from the table in the Color panel. Alpha is 255 for every color except clear.
  2. Choose Image > New Image…. Type the name in Name, set Width and Height from the table, set Fill to Paint Color (or Transparent for clear) and press Create. The image becomes the texture of the selected bone. Studio puts your File Name in front of the image’s name when it writes the file.
  3. To give another bone an image you already made, select the bone and pick the image in the Texture list of its Bone tab.
  4. For water and lava, select the liquid bone and make the image 16 wide and 64 high. In the Bone tab, set Frames to 4 and Frame Time to 10 for water or 6 for lava, under Bone Texture Animation. Then, for each frame, set the Frame field of the image editor, set the color of that frame (the table lists the colors from the top frame down) and paint it with the Pencil set to a Square shape and a Size of 32: a stroke stays inside the chosen frame. Give surface the same image in its Texture list, and the same Frames and Frame Time.

Video coming soon

Image > New Image fills a whole texture with one color.

If you ran the script below, dropping a PNG on the game window is quicker. With a bone selected the PNG becomes that bone’s texture.

The texture script

It needs only Python 3. It writes every texture of the table into the folder named in OUT near the top, so change that line if your pack sits somewhere else.

import os
import struct
import sys
import zlib

# Where the PNG files go. Pass another folder as the first argument to change it.
OUT = sys.argv[1] if len(sys.argv) > 1 else "Bucket pack/assets/bucketpack/punchy/model_parts_items/textures"

def png(path, width, height, rows):
    """Write an 8-bit RGBA PNG. rows is a list of height rows, each a list of (r, g, b, a)."""
    raw = b"".join(b"\x00" + b"".join(bytes(px) for px in row) for row in rows)
    def chunk(kind, data):
        body = kind + data
        return struct.pack(">I", len(data)) + body + struct.pack(">I", zlib.crc32(body) & 0xFFFFFFFF)
    data = b"\x89PNG\r\n\x1a\n"
    data += chunk(b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 6, 0, 0, 0))
    data += chunk(b"IDAT", zlib.compress(raw, 9))
    data += chunk(b"IEND", b"")
    with open(path, "wb") as f:
        f.write(data)

def hexcolor(text):
    text = text.lstrip("#")
    return (int(text[0:2], 16), int(text[2:4], 16), int(text[4:6], 16), 255)

def flat(color):
    return [[color] * 16 for _ in range(16)]

def strip(colors):
    """One 16 by 16 frame per color, one under the other."""
    rows = []
    for color in colors:
        rows += flat(color)
    return rows

os.makedirs(OUT, exist_ok=True)

solid = {
    "steel": "#B9BFC7",
    "iron": "#4A4F57",
    "milk": "#F4F4EE",
    "fish_cod": "#A67C52",
    "fish_salmon": "#D0685C",
    "fish_tropical": "#F58A24",
    "fish_pufferfish": "#E9C13B",
    "axolotl_lucy": "#F4A6C9",
    "axolotl_wild": "#8A5A3C",
    "axolotl_gold": "#F2C94C",
    "axolotl_cyan": "#4CC9D6",
    "axolotl_blue": "#3B63E0",
}
for name, color in solid.items():
    png(os.path.join(OUT, name + ".png"), 16, 16, flat(hexcolor(color)))

# Nothing at all: draws as see-through, which hides a bone.
png(os.path.join(OUT, "clear.png"), 16, 16, flat((0, 0, 0, 0)))

# Animated textures: four frames of 16 by 16 pixels, so the files are 16 by 64.
water = ["#2F6FE0", "#3A7DEC", "#2F6FE0", "#2563D0"]
lava = ["#E0540A", "#F26A10", "#FF8A1E", "#F26A10"]
png(os.path.join(OUT, "water.png"), 16, 64, strip([hexcolor(c) for c in water]))
png(os.path.join(OUT, "lava.png"), 16, 64, strip([hexcolor(c) for c in lava]))

print("Wrote", len(solid) + 3, "textures to", OUT)

Animate the bucket

The pack has five item clips. They move bones by name, so one file serves every definition. Item clips play at 1x unless a clip sets a speed of its own.

ClipWhat it is for
bucket_idleThe handle swings and the pail rises a little, over 3 seconds, on a loop.
bucket_floatA faster bob and roll, for when you touch water. Loops.
bucket_drinkThe pail tilts and comes back, once. For the milk bucket.
fish_idleA handle swing, plus a fish that bobs and turns and a tail that wags. Loops.
fish_floatThe faster version for water. Loops.

These are the keys, as they are written in the clip file and as Studio shows them. Times are in seconds, and each key is three numbers. Between two keys the motion is a straight line. Punchy! reads a clip with the sign of X rotation, Y rotation and X position flipped, which matters when you key in Blockbench (see below).

ClipBoneChannelKeys
bucket_idle, 3 s, loophandleRotation0: 0, 0, 0; 1.5: 6, 0, 0; 3: 0, 0, 0
bucket_idle, 3 s, loopbodyPosition0: 0, 0, 0; 1.5: 0, 0.3, 0; 3: 0, 0, 0
bucket_float, 2.4 s, loopbodyPosition0: 0, 0, 0; 1.2: 0, 0.8, 0; 2.4: 0, 0, 0
bucket_float, 2.4 s, loopbodyRotation0: 0, 0, 0; 0.6: 0, 0, 3; 1.2: 0, 0, 0; 1.8: 0, 0, -3; 2.4: 0, 0, 0
bucket_float, 2.4 s, loophandleRotation0: 0, 0, 0; 0.8: 10, 0, 0; 1.6: -6, 0, 0; 2.4: 0, 0, 0
bucket_drink, 1.6 s, oncebodyRotation0: 0, 0, 0; 0.5: -35, 0, 0; 1.1: -35, 0, 0; 1.6: 0, 0, 0
bucket_drink, 1.6 s, oncebodyPosition0: 0, 0, 0; 0.5: 0, 2, 1; 1.1: 0, 2, 1; 1.6: 0, 0, 0
fish_idle, 1.5 s, loophandleRotation0: 0, 0, 0; 0.75: 5, 0, 0; 1.5: 0, 0, 0
fish_idle, 1.5 s, loopfishPosition0: 0, 0, 0; 0.5: 0, 0.4, 0; 1: 0, -0.3, 0; 1.5: 0, 0, 0
fish_idle, 1.5 s, loopfishRotation0: 0, 0, 0; 0.5: 0, 8, 0; 1: 0, -8, 0; 1.5: 0, 0, 0
fish_idle, 1.5 s, looptailRotation0: 0, 0, 0; 0.375: 0, 25, 0; 0.75: 0, 0, 0; 1.125: 0, -25, 0; 1.5: 0, 0, 0
fish_float, 1.2 s, loopbodyPosition0: 0, 0, 0; 0.6: 0, 0.8, 0; 1.2: 0, 0, 0
fish_float, 1.2 s, loopbodyRotation0: 0, 0, 0; 0.3: 0, 0, 3; 0.6: 0, 0, 0; 0.9: 0, 0, -3; 1.2: 0, 0, 0
fish_float, 1.2 s, loophandleRotation0: 0, 0, 0; 0.6: 10, 0, 0; 1.2: 0, 0, 0
fish_float, 1.2 s, loopfishRotation0: 0, 0, 0; 0.3: 0, 12, 0; 0.9: 0, -12, 0; 1.2: 0, 0, 0
fish_float, 1.2 s, looptailRotation0: 0, 0, 0; 0.3: 0, 30, 0; 0.6: 0, 0, 0; 0.9: 0, -30, 0; 1.2: 0, 0, 0
Tool

In Blockbench

Blockbench animates the bones of the model you just made and exports a Bedrock animation file.

  1. In the same project, press Animate, the mode tab at the top right.
  2. In the Animations panel, press Add Animation. Type bucket_idle in Name, set Loop Mode to Loop and press Confirm. Set Animation Length to 3.
  3. In the Outliner, select handle. In the Timeline panel, click the ruler at 0 and press the + beside Rotation. Type the numbers from the table in the Keyframe panel, with the signs flipped as described below the steps. Add the keys at the other times the same way.
  4. Select body and key its Position the same way.
  5. Add the other four clips with Add Animation. Use Play Once as the Loop Mode for bucket_drink and Loop for the rest, and the lengths from the table’s last key time.
  6. Choose Animation > Export Animations…. In Select Animations to Export, tick all five clips and press Confirm. Save the file as bucket.animation.json in the pack’s animations folder.

Video coming soon

Keying the idle clip and exporting all five.

Blockbench’s Bedrock export flips the sign of X rotation, Y rotation and X position, and Punchy! flips them back when it reads the file, so a motion keyed in Blockbench plays in the game as it looks in Blockbench. The tables hold the numbers as the file has them, so in Blockbench key each rotation with its first two numbers flipped, and each position with its first number flipped. The handle’s -6, 0, 0 is keyed as 6, 0, 0, the fish’s 0, 8, 0 as 0, -8, 0 and the drink tilt’s -35, 0, 0 as 35, 0, 0. A zero stays zero, and the third number keeps its sign. After the export, compare your file with the complete clip file below.

In Punchy! Studio

Studio keys the clips on a timeline, writes the clip file and adds it to the definition.

  1. In the Model workspace, open the Animation tab and press Add Clip. A clip named idle appears under Item Clips in the Outliner.
  2. In the Item Clip panel, type bucket_idle in Name and 3 in Length, and choose Loop on the Loop row. The row offers Once, Loop and Hold.
  3. Select the handle bone in the Outliner and pick its Rotation row in the timeline. Put the playhead on 0 and press I. Set the key’s values in the key column, then add the other keys of the table at their times the same way.
  4. Select body, pick its Position row and key it the same way.
  5. Press Add Clip for each of the other four clips. Use Once for bucket_drink and Loop for the rest. Key each bone and channel of the table.
  6. Press Space to play a clip on the stage.

Video coming soon

Add Clip, name it, key the bones.

Studio keys the numbers exactly as they are written in the clip file, so type the numbers of the table as they are. It plays every item clip key in a straight line, as Punchy! does. Check the tilt of bucket_drink in the live link: if it goes the wrong way, flip the sign of its keys.

The complete clip file

Save it as animations/bucket.animation.json. These are the numbers as the file holds them. Studio writes the same clips into its own file, named after the part.

{
  "format_version": "1.8.0",
  "animations": {
    "bucket_idle": {
      "loop": true,
      "animation_length": 3.0,
      "bones": {
        "handle": { "rotation": { "0.0": [0, 0, 0], "1.5": [6, 0, 0], "3.0": [0, 0, 0] } },
        "body": { "position": { "0.0": [0, 0, 0], "1.5": [0, 0.3, 0], "3.0": [0, 0, 0] } }
      }
    },
    "bucket_float": {
      "loop": true,
      "animation_length": 2.4,
      "bones": {
        "body": {
          "position": { "0.0": [0, 0, 0], "1.2": [0, 0.8, 0], "2.4": [0, 0, 0] },
          "rotation": {
            "0.0": [0, 0, 0],
            "0.6": [0, 0, 3],
            "1.2": [0, 0, 0],
            "1.8": [0, 0, -3],
            "2.4": [0, 0, 0]
          }
        },
        "handle": {
          "rotation": { "0.0": [0, 0, 0], "0.8": [10, 0, 0], "1.6": [-6, 0, 0], "2.4": [0, 0, 0] }
        }
      }
    },
    "bucket_drink": {
      "animation_length": 1.6,
      "bones": {
        "body": {
          "rotation": { "0.0": [0, 0, 0], "0.5": [-35, 0, 0], "1.1": [-35, 0, 0], "1.6": [0, 0, 0] },
          "position": { "0.0": [0, 0, 0], "0.5": [0, 2, 1], "1.1": [0, 2, 1], "1.6": [0, 0, 0] }
        }
      }
    },
    "fish_idle": {
      "loop": true,
      "animation_length": 1.5,
      "bones": {
        "handle": { "rotation": { "0.0": [0, 0, 0], "0.75": [5, 0, 0], "1.5": [0, 0, 0] } },
        "fish": {
          "position": {
            "0.0": [0, 0, 0],
            "0.5": [0, 0.4, 0],
            "1.0": [0, -0.3, 0],
            "1.5": [0, 0, 0]
          },
          "rotation": { "0.0": [0, 0, 0], "0.5": [0, 8, 0], "1.0": [0, -8, 0], "1.5": [0, 0, 0] }
        },
        "tail": {
          "rotation": {
            "0.0": [0, 0, 0],
            "0.375": [0, 25, 0],
            "0.75": [0, 0, 0],
            "1.125": [0, -25, 0],
            "1.5": [0, 0, 0]
          }
        }
      }
    },
    "fish_float": {
      "loop": true,
      "animation_length": 1.2,
      "bones": {
        "body": {
          "position": { "0.0": [0, 0, 0], "0.6": [0, 0.8, 0], "1.2": [0, 0, 0] },
          "rotation": {
            "0.0": [0, 0, 0],
            "0.3": [0, 0, 3],
            "0.6": [0, 0, 0],
            "0.9": [0, 0, -3],
            "1.2": [0, 0, 0]
          }
        },
        "handle": { "rotation": { "0.0": [0, 0, 0], "0.6": [10, 0, 0], "1.2": [0, 0, 0] } },
        "fish": {
          "rotation": { "0.0": [0, 0, 0], "0.3": [0, 12, 0], "0.9": [0, -12, 0], "1.2": [0, 0, 0] }
        },
        "tail": {
          "rotation": {
            "0.0": [0, 0, 0],
            "0.3": [0, 30, 0],
            "0.6": [0, 0, 0],
            "0.9": [0, -30, 0],
            "1.2": [0, 0, 0]
          }
        }
      }
    }
  }
}

The empty bucket

A definition ties the files together. This one covers minecraft:bucket, hides every bit of content and adds one condition: when you touch water, the bucket bobs and blows bubbles.

Tool

In Blockbench

Save the text below as definitions/bucket_empty.json. Every definition in this pack is a file of this kind.

{
  "items": ["minecraft:bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/clear",
      "bones": ["liquid", "surface", "fish", "eyes"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "bucket_idle", "disable_all_particles": true },
    { "type": "idle", "animation": "bucket_float", "in_water": true }
  ],
  "particles": [
    {
      "type": "minecraft:bubble",
      "bone": "body",
      "offset": [0, 0.35, 0],
      "rate": 3,
      "life": 0.9,
      "size": 0.03,
      "spread": [0.08, 0, 0.08],
      "velocity": [0, 0.02, 0]
    }
  ]
}

In Punchy! Studio

Studio writes the definition from the forms of the Model workspace. You already have the geometry. Add the rest in this order.

  1. Make the textures of the empty bucket as in Make the textures: steel for body, iron for foot and handle, and clear for liquid, surface, fish and eyes. tail takes the texture of fish by itself.
  2. Make the five clips of Animate the bucket in this model part. Studio adds them to one clip file.
  3. In the Animation tab, press Add Entry. Set Type to idle and Clip to bucket_idle, and tick No Particles.
  4. Press Add Entry again. Set Type to idle and Clip to bucket_float, and choose Yes on the In Water row.
  5. Choose Add > Add Emitter. In the Particles tab, set Type to minecraft:bubble, Bone to body, Rate to 3, Life to 0.9, Size to 0.03, Spread to 0.08, 0, 0.08, Velocity to 0, 0.02, 0 and Offset to 0, 0.35, 0.
  6. Choose File > Export Model Part… (Ctrl+E). In the Export Model Part window, type Bucket pack in Pack, tick Activate the pack and play it now and press Export.

Video coming soon

Two entries and one emitter for the empty bucket.

Each Studio field has a tooltip that names the JSON key it writes. This table shows where the keys of this page live in the Model workspace.

In the definitionIn Studio
itemsDefinition tab, Items panel, Items
bone_texturesBone tab, Texture list
bone_texture_animBone tab, Bone Texture Animation: Frames and Frame Time
bone_emissionBone tab, Glow Level. Blur Glow is in the Material tab, under Glow Settings
modelPartsAnimationAnimation tab: Add Entry, then Type, Clip, In Water, No Particles
bone_physicsPhysics tab with a bone selected: Mode, Limit, Camera Sensitivity, Gravity, Motion Sensitivity, Creature Feedback
particlesParticles tab: Add Emitter, then Type, Bone, Count, Rate and the trigger switches
dynamic_bone_texturesNot edited in Studio. Studio keeps it when you export

Studio writes the file names itself: the definition, geometry, clips and textures are named after the File Name of the part. With Export First in Order on, the definition goes into a folder called 0_punchy_studio. Punchy! sorts definitions by their full id, so a folder name changes the order among definitions of the same namespace, and this one sorts before other folders of that namespace. Which definition covers an item has the whole rule.

What each part does:

  • items is the item the definition covers. geo is the full id of the geometry, with the folder and the .geo.json ending. texture is the main texture, which any bone without a texture of its own uses. Punchy! adds .png for you.
  • bone_textures lists the exceptions as groups of bones. foot and handle are iron. liquid, surface, fish and eyes get clear, which hides them. tail is a child of fish, so it takes fish’s texture and is hidden with it.
  • animations loads the clip file, with the full id and the .animation.json ending.
  • The first idle entry plays bucket_idle all the time. The second also asks in_water: it passes only while you touch water, and an entry with a condition beats a plain one while it passes. So the bob plays in water and the sway on land. in_water is true on contact with water around you. inside_water is true only while your eyes are under water, and it holds for 4 ticks after you leave the water. Conditions covers these and the other checks: weather, blocks, time of day and biomes.
  • disable_all_particles on the dry entry silences the emitters while it plays. The bubbles therefore appear only in water.
  • The bubble emitter has no triggers, so it runs on its own clock: 3 releases a second. offset lifts it to just above the rim. Distances in a particle are in blocks, so 0.35 is 5.6 pixels.

Press F3+T in a world after a change to reload definitions, clips and particle settings. If you change a texture that a particle uses, restart Minecraft, because particle textures stay cached until then. Try the pack in the game tells you what to look for.

The water bucket

The water bucket shows the animated water and makes it slosh. It also adds a splash that fires when you jump or land.

{
  "items": ["minecraft:water_bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/water",
      "bones": ["liquid", "surface"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/clear",
      "bones": ["fish", "eyes"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "bucket_idle" },
    { "type": "idle", "animation": "bucket_float", "in_water": true }
  ],
  "bone_texture_anim": {
    "liquid": { "frames": 4, "frametime": 10 },
    "surface": { "frames": 4, "frametime": 10 }
  },
  "bone_physics": {
    "surface": {
      "pendulum_mode": "full",
      "limit_deg": 10,
      "camera_sens": 0.5,
      "gravity": 14,
      "motion_sens": 0.4
    }
  },
  "particles": [
    {
      "type": "minecraft:splash",
      "bone": "surface",
      "count": 4,
      "life": 0.5,
      "size": 0.05,
      "spread": [0.06, 0, 0.06],
      "velocity": [0, 0.03, 0],
      "gravity": -0.4,
      "triggers": { "jump": true, "landing": true },
      "trigger_mode": "any"
    }
  ]
}
Tool

In Blockbench

Save the file as definitions/bucket_water.json. From here on the Blockbench path is only saving files: each definition below goes into definitions under the name in the layout above (bucket_lava.json, bucket_milk.json, bucket_cod.json, bucket_pufferfish.json and bucket_axolotl.json; the salmon and tropical fish files are named in their own box), and the geometry and the clips stay as they are.

In Punchy! Studio

Make the water bucket from a part you already have. Every other state works the same way.

  1. Choose File > Open Model Part… (Ctrl+O) to open the Model Parts Library. Pick Resource Packs, select bucket_empty and press Open. Studio copies the definition and its files into a new project. The pack you took it from is not changed.
  2. In the Definition tab, set File Name to bucket_water and untick Keep Original Paths, so the export writes new files and leaves the empty bucket alone. Change Items to minecraft:water_bucket.
  3. Make the water texture as in Make the textures: select liquid, create the 16 by 64 image, set Frames to 4 and Frame Time to 10, and paint the four frames. Select surface and pick the same image in its Texture list, with the same Frames and Frame Time.
  4. Select fish and eyes and keep them on clear.
  5. In the Outliner, select the first entry under Animation Entries. In the Animation tab, untick No Particles.
  6. Select the surface bone and open the Physics tab. Press the Item Pendulum Default preset, which creates the entry. Set Mode to Full, Limit to 10, Camera Sensitivity to 0.5, Gravity to 14 and Motion Sensitivity to 0.4. Studio writes every pendulum setting, the ones you did not change too, at the values Punchy! uses by default.
  7. Choose Add > Add Emitter. Set Type to minecraft:splash, Bone to surface, Count to 4, Life to 0.5, Size to 0.05, Spread to 0.06, 0, 0.06, Velocity to 0, 0.03, 0 and Gravity to -0.4. Turn on Jump and Landing, and set Trigger Logic to Any.
  8. Export with Ctrl+E.

Video coming soon

Open the empty bucket as a new part, then add the water, the slosh and the splash.

For the other states, change what differs and make the project match the definition file of that state on this page: the Items, the bone textures, the entries, the physics and the emitters. Set File Name to the name of that state in the layout (bucket_lava, bucket_milk, bucket_cod, bucket_salmon, bucket_tropical_fish, bucket_pufferfish or bucket_axolotl), and make the textures the state needs as in Make the textures: lava, milk, the color of the fish or the five axolotl pictures. The water is the model; the lava, the milk and the fish buckets only change a few of these.

What is new:

  • bone_textures now gives liquid and surface the water texture. Only fish and eyes stay hidden.
  • bone_texture_anim animates the water. water.png is 16 by 64, so it holds 4 frames, and each frame lasts 10 game ticks, half a second. It is set per bone and by the exact bone name, so both liquid bones need an entry. The picture must be exactly frames times the frame height tall, or the water does not animate and shows the whole picture squeezed onto each face, without a message.
  • bone_physics makes the surface slab slosh. It swings around its pivot like a pendulum, pushed by the way you turn the camera and move. limit_deg caps the swing at 10 degrees. gravity is how hard the slab is pulled back to rest, and 14 is softer than the default of 25. The mode full swings both ways. These numbers are a starting point: raise limit_deg for a wilder slosh and camera_sens for a stronger reaction to the camera.
  • The splash particle belongs to the surface bone. A particle trigger is a pulse, an event that fires once: jump and landing are two pulses that never happen at the same moment, so trigger_mode is any. With the default mode, which needs every trigger at once, it would never fire. count is how many particles one event throws, gravity is negative, which pulls them down gently (particles anchored to the item work in pixels), and velocity throws them up.

Video coming soon

The surface follows the camera, and a jump throws a splash.

The lava bucket

The lava bucket reuses the water recipe with a few changes: the liquid glows, the texture moves faster, the physics are tighter and the embers have their own rule.

{
  "items": ["minecraft:lava_bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/lava",
      "bones": ["liquid", "surface"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/clear",
      "bones": ["fish", "eyes"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "bucket_idle" },
    {
      "type": "idle",
      "animation": "bucket_float",
      "in_water": true,
      "disable_all_particles": true
    }
  ],
  "bone_emission": { "liquid": 100, "surface": 100, "blur": true },
  "bone_texture_anim": {
    "liquid": { "frames": 4, "frametime": 6 },
    "surface": { "frames": 4, "frametime": 6 }
  },
  "bone_physics": {
    "surface": {
      "pendulum_mode": "full",
      "limit_deg": 6,
      "camera_sens": 0.35,
      "gravity": 22,
      "motion_sens": 0.25
    }
  },
  "particles": [
    {
      "type": "minecraft:lava",
      "bone": "surface",
      "rate": 2,
      "life": 0.8,
      "size": 0.03,
      "spread": [0.06, 0, 0.06],
      "velocity": [0, 0.025, 0],
      "gravity": -0.3
    }
  ]
}

What is new:

  • bone_emission makes liquid and surface glow. A level from 1 to 15 sets how bright the glow layer is, and 16 to 100 add bloom, which shows only when blur is on. The glow layer is drawn at full brightness, so the lava stays bright in the dark. blur is a setting of the whole object, not a bone, and so are clamp and strength: a bone with one of those names could not glow.
  • The lava texture changes every 6 ticks. Because the glow is drawn from the same frame, the glow flickers with the lava.
  • The slosh is tighter: limit_deg 6, lower sensitivities and a higher gravity of 22 make the lava swing less and snap back sooner.
  • The minecraft:lava particle uses the picture Punchy! finds for that id. The emitter runs on its own clock, 2 releases a second, and a negative gravity pulls the embers down gently.
  • The in-water entry carries disable_all_particles, so the embers stop while you touch water. The glow stays.

The glow above lights the lava and nothing else. To keep the whole lava bucket bright in the dark, the pail and the handle too, add a shading rule. It is a small file of its own, assets/bucketpack/punchy/model_parts_items/shading.json, next to the definitions folder. Write it in a text editor, whichever tool made the rest of the pack. Studio has no form for it and leaves it alone when you export:

{
  "rules": [
    { "item": "minecraft:lava_bucket", "fullbright": true }
  ]
}

fullbright draws a model part item without the light map, so it stays bright at night. The rule changes only items a pack draws as model parts, and it is the same for every bucket you add a rule for. Press F3+T after you change the file. Shading rules lists the other keys, shading and additive.

Video coming soon

Lava that stays bright in the dark, and goes quiet in water.

The milk bucket

Milk is the only bucket you drink, so its definition adds an entry for the drink moment.

{
  "items": ["minecraft:milk_bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/milk",
      "bones": ["liquid", "surface"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/clear",
      "bones": ["fish", "eyes"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "bucket_idle" },
    { "type": "idle", "animation": "bucket_float", "in_water": true },
    { "type": "useDrink", "animation": "bucket_drink" }
  ],
  "bone_physics": {
    "surface": {
      "pendulum_mode": "full",
      "limit_deg": 8,
      "camera_sens": 0.4,
      "gravity": 18,
      "motion_sens": 0.3
    }
  },
  "particles": [
    {
      "type": "minecraft:cloud",
      "bone": "surface",
      "count": 3,
      "life": 0.6,
      "size": 0.05,
      "spread": [0.06, 0, 0.06],
      "velocity": [0, 0.015, 0],
      "triggers": { "jump": true, "landing": true },
      "trigger_mode": "any"
    }
  ]
}

What is new:

  • While you use an item, Punchy! draws the normal item instead of your model, unless the definition has an entry for that use. The useDrink entry keeps the model in your hand while you drink, and plays bucket_drink: the pail tilts and comes back. Check the direction in the game. If it tilts the wrong way, flip the sign of the X rotation in that clip.
  • The milk texture is a still picture, so there is no bone_texture_anim.
  • A softer slosh: limit_deg 8 sits between water and lava.
  • The cloud particle puffs on a jump or a landing, with the same pulse pair as the water splash.

The fish buckets

A fish bucket shows the water and one fish. The fish sits at the surface and has three of its own bones: the body, the eyes and the tail.

{
  "items": ["minecraft:cod_bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle", "eyes"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/water",
      "bones": ["liquid", "surface"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/fish_cod",
      "bones": ["fish"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "fish_idle" },
    { "type": "idle", "animation": "fish_float", "in_water": true }
  ],
  "bone_texture_anim": {
    "liquid": { "frames": 4, "frametime": 10 },
    "surface": { "frames": 4, "frametime": 10 }
  },
  "bone_physics": {
    "surface": {
      "pendulum_mode": "full",
      "limit_deg": 10,
      "camera_sens": 0.5,
      "gravity": 14,
      "motion_sens": 0.4
    },
    "fish": {
      "enableCreaturePhysics": true,
      "impactInclinationPercent": 50,
      "fallInclinationPercent": 50
    }
  },
  "particles": [
    {
      "type": "minecraft:bubble",
      "bone": "fish",
      "rate": 1.5,
      "life": 0.8,
      "size": 0.025,
      "spread": [0.04, 0, 0.04],
      "velocity": [0, 0.02, 0]
    }
  ]
}

What is new:

  • bone_textures gives the water to liquid and surface, and the fish’s color to fish. eyes joins foot and handle in the iron group, so they are dark. tail follows fish.
  • The entries play the fish clips: fish_idle and, in water, fish_float. Each clip also moves the handle, so the pail still sways.
  • The fish bone has enableCreaturePhysics, the feedback Punchy! gives a pufferfish bucket: the bone tilts and squashes as you jump, fall, land, turn and walk. The two percent keys scale the tilt down to half, because 100 is the default and a cod should not wobble like a pufferfish. A bone spec needs a pendulum mode, creature feedback or slime feedback, or Punchy! drops it, and here the creature feedback keeps it.
  • The bubble emitter belongs to the fish bone and runs all the time, because a fish in a bucket is always in water.

The pufferfish bucket is the same file with a different item and texture, and with the creature feedback at full strength: a pufferfish is the animal that feedback was made for.

{
  "items": ["minecraft:pufferfish_bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle", "eyes"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/water",
      "bones": ["liquid", "surface"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/fish_pufferfish",
      "bones": ["fish"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "fish_idle" },
    { "type": "idle", "animation": "fish_float", "in_water": true }
  ],
  "bone_texture_anim": {
    "liquid": { "frames": 4, "frametime": 10 },
    "surface": { "frames": 4, "frametime": 10 }
  },
  "bone_physics": {
    "surface": {
      "pendulum_mode": "full",
      "limit_deg": 10,
      "camera_sens": 0.5,
      "gravity": 14,
      "motion_sens": 0.4
    },
    "fish": { "enableCreaturePhysics": true }
  },
  "particles": [
    {
      "type": "minecraft:bubble",
      "bone": "fish",
      "rate": 1.5,
      "life": 0.8,
      "size": 0.025,
      "spread": [0.04, 0, 0.04],
      "velocity": [0, 0.02, 0]
    }
  ]
}

The salmon and the tropical fish buckets differ from the cod in two places: the item and the fish texture. Open the box for both files.

The salmon and tropical fish definitions

Save them as definitions/bucket_salmon.json and definitions/bucket_tropical_fish.json.

{
  "items": ["minecraft:salmon_bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle", "eyes"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/water",
      "bones": ["liquid", "surface"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/fish_salmon",
      "bones": ["fish"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "fish_idle" },
    { "type": "idle", "animation": "fish_float", "in_water": true }
  ],
  "bone_texture_anim": {
    "liquid": { "frames": 4, "frametime": 10 },
    "surface": { "frames": 4, "frametime": 10 }
  },
  "bone_physics": {
    "surface": {
      "pendulum_mode": "full",
      "limit_deg": 10,
      "camera_sens": 0.5,
      "gravity": 14,
      "motion_sens": 0.4
    },
    "fish": {
      "enableCreaturePhysics": true,
      "impactInclinationPercent": 50,
      "fallInclinationPercent": 50
    }
  },
  "particles": [
    {
      "type": "minecraft:bubble",
      "bone": "fish",
      "rate": 1.5,
      "life": 0.8,
      "size": 0.025,
      "spread": [0.04, 0, 0.04],
      "velocity": [0, 0.02, 0]
    }
  ]
}
{
  "items": ["minecraft:tropical_fish_bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle", "eyes"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/water",
      "bones": ["liquid", "surface"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/fish_tropical",
      "bones": ["fish"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "fish_idle" },
    { "type": "idle", "animation": "fish_float", "in_water": true }
  ],
  "bone_texture_anim": {
    "liquid": { "frames": 4, "frametime": 10 },
    "surface": { "frames": 4, "frametime": 10 }
  },
  "bone_physics": {
    "surface": {
      "pendulum_mode": "full",
      "limit_deg": 10,
      "camera_sens": 0.5,
      "gravity": 14,
      "motion_sens": 0.4
    },
    "fish": {
      "enableCreaturePhysics": true,
      "impactInclinationPercent": 50,
      "fallInclinationPercent": 50
    }
  },
  "particles": [
    {
      "type": "minecraft:bubble",
      "bone": "fish",
      "rate": 1.5,
      "life": 0.8,
      "size": 0.025,
      "spread": [0.04, 0, 0.04],
      "velocity": [0, 0.02, 0]
    }
  ]
}

Video coming soon

Two fish buckets, one geometry.

The axolotl bucket

An axolotl has five colors, and the bucket remembers which one it holds. A dynamic texture picks the fish’s texture by that color. The rule asks for axol_variants, and each key of its map must be the variant name exactly as the game reports it. The five names used here are lucy, wild, gold, cyan and blue; confirm each one in the game as described in Try the pack in the game. The first, lucy, is the fallback, which is also what a bucket with no variant shows.

{
  "items": ["minecraft:axolotl_bucket"],
  "geo": "bucketpack:punchy/model_parts_items/geo/bucket.geo.json",
  "texture": "bucketpack:punchy/model_parts_items/textures/steel",
  "bone_textures": [
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/iron",
      "bones": ["foot", "handle", "eyes"]
    },
    {
      "texture": "bucketpack:punchy/model_parts_items/textures/water",
      "bones": ["liquid", "surface"]
    }
  ],
  "animations": ["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"],
  "modelPartsAnimation": [
    { "type": "idle", "animation": "fish_idle" },
    { "type": "idle", "animation": "fish_float", "in_water": true }
  ],
  "bone_texture_anim": {
    "liquid": { "frames": 4, "frametime": 10 },
    "surface": { "frames": 4, "frametime": 10 }
  },
  "bone_physics": {
    "surface": {
      "pendulum_mode": "full",
      "limit_deg": 10,
      "camera_sens": 0.5,
      "gravity": 14,
      "motion_sens": 0.4
    },
    "fish": {
      "enableCreaturePhysics": true,
      "impactInclinationPercent": 50,
      "fallInclinationPercent": 50
    }
  },
  "particles": [
    {
      "type": "minecraft:bubble",
      "bone": "fish",
      "rate": 1.5,
      "life": 0.8,
      "size": 0.025,
      "spread": [0.04, 0, 0.04],
      "velocity": [0, 0.02, 0]
    }
  ],
  "dynamic_bone_textures": {
    "type": "texture",
    "bone": "fish",
    "source": "axol_variants",
    "fallback": "bucketpack:punchy/model_parts_items/textures/axolotl_lucy",
    "map": {
      "wild": "bucketpack:punchy/model_parts_items/textures/axolotl_wild",
      "gold": "bucketpack:punchy/model_parts_items/textures/axolotl_gold",
      "cyan": "bucketpack:punchy/model_parts_items/textures/axolotl_cyan",
      "blue": "bucketpack:punchy/model_parts_items/textures/axolotl_blue"
    }
  }
}

What is new:

  • dynamic_bone_textures swaps the texture of one bone, fish, while the game runs. source says what Punchy! asks about the item, map links each answer to a texture, and fallback covers every other case. The answers are matched exactly, so each key has to be spelled as the game spells the variant. Dynamic textures explains the rule and its other source.
  • fish has no entry in bone_textures, because the rule gives it a texture.

Try the pack in the game

  1. Put Bucket pack in your resourcepacks folder. If you ticked Activate the pack and play it now in Studio’s export, it is already on and you can skip the rest of this step. In the game, open Options…, Resource Packs…, move the pack from Available to Selected, and press Done.
  2. Join a creative world and switch to first person. Press F3+T after a later change to reload definitions, clips and particle settings. Restart Minecraft after changing a texture a particle uses.
  3. Give yourself the buckets one at a time, for example /give @s water_bucket. The ids are bucket, water_bucket, lava_bucket, milk_bucket, cod_bucket, salmon_bucket, tropical_fish_bucket, pufferfish_bucket and axolotl_bucket. Hold each one in your main hand.
  4. Check each row of the table below. For the water, turn the camera quickly, and walk and jump.
  5. Stand in a pool of water and check the in-water behavior.
HoldYou should see
Empty bucketA steel pail with a handle that sways. In water it bobs, and bubbles rise from the opening
WaterMoving blue water. The surface tilts when you turn and settles again. A splash when you jump or land
LavaOrange lava that flickers and glows, and embers. The embers stop in water
MilkWhite milk with a lighter slosh. Drinking tilts the pail and the model stays in your hand
Cod, salmon, tropical fish, pufferfishA colored fish at the surface that bobs and wags its tail, with bubbles. In water it moves faster
AxolotlThe same fish in the pink of lucy, or another color for another variant

To get an axolotl bucket of another variant, catch axolotls of different colors, or use the command on Dynamic textures. Check each color this way: a bucket that shows the lucy pink when its axolotl is another color has a map key that does not match the name the game reports for that variant. Fix the key and reload.

Video coming soon

Turn the pack on, give a bucket and hold it.

Keep working on it in Punchy! Studio

You can bring a finished pack into Studio and keep editing it there, whichever tool made it. Build from Pack reads your pack and builds a new one that Studio owns, with the model parts, clips and rules in it. The pack you start from is only read.

  1. Put Bucket pack in your resourcepacks folder. It does not need to be turned on.
  2. Press F6, pick First Person if the editor opens in Third Person, and open the Library workspace (the Library tab in the top bar, or Ctrl+O in the Animation workspace).
  3. Press Build from Pack…. The menu lists the Packs with Punchy files in your game folder, each marked Active or Not active. Pick Bucket pack.
  4. In the Build from Pack window, keep or change the New pack name and press Build.
  5. Read the status bar. It says what was built and that the new pack is being turned on.
The same steps with a different pack: pick it, keep the proposed name and press Build.

The model parts come along with their geometry, textures and clips. A shading.json does not: if your pack has one, copy it from Bucket pack into the same folder of the new pack. Open each in the Model workspace with File > Open Model Part… (Ctrl+O) and edit it. Punchy! Studio covers Build from Pack in full.

Keys this pack uses

These are the keys of the definitions above. Model part definitions has all of them. Key names in one row are aliases.

Keys of a definition
KeyTypeWhat it doesExample
itemsRequiredstring arrayThe items the definition covers. A bare id gets the minecraft namespace, and #tag covers an item tag. When items is there, item is not read, and an empty list drops the definition.["minecraft:water_bucket"]
geoRequiredresource idThe geometry file, used as written. Write the folders and the .geo.json ending. A missing file leaves the vanilla bucket in your hand.bucketpack:punchy/model_parts_items/geo/bucket.geo.json
textureRequiredresource idThe main texture. A path under punchy/model_parts_items/textures/ gets .png added when it is missing.bucketpack:punchy/model_parts_items/textures/steel
bone_texturesobject or listGives bones their own texture. The object form maps a bone name to a texture. The list form takes entries of texture and bones, and a later entry wins for a bone. A bone without an entry uses its parent's texture, then the main texture.
bone_texture_animobjectAnimates the texture of a bone, by the exact bone name. Each bone takes frames, frametime and frame_height. A bone's entry does not copy anything from the whole-model texture_anim.{ "liquid": { "frames": 4, "frametime": 10 } }
bone_emissionobjectGlow. Each bone name takes a level from 0 to 100, and blur adds a bloom layer. The names blur, clamp, strength, intensity and brightness are reserved.{ "liquid": 100, "blur": true }
animationsresource id arrayThe item clip files. Write each id in full with the .animation.json ending. Every clip is loaded, and a later file replaces a clip of the same name.["bucketpack:punchy/model_parts_items/animations/bucket.animation.json"]
modelPartsAnimationobject arrayThe entries that say which clip plays at which moment. See the next table.
bone_physicsobjectPhysics for single bones: a pendulum, creature feedback or slime squash. See the table after next.
particleslistParticle emitters. Each can be an object, a script string or a bare particle id. particle, particle_effects, particle_emission and particleEmission are read too, and the lists are joined.
dynamic_bone_texturesobject or listSwaps one bone's texture, or the whole geometry, by what the held item reports. type (default texture), bone, source (default sulfur_cube_content, or axol_variants), map and fallback.
Keys of a modelPartsAnimation entry
KeyTypeDefaultWhat it doesExample
typeRequiredstringThe moment: idle, useDrink and the others on the definitions page. Case, underscores, hyphens and spaces are ignored."idle"
animationstringThe clip to play. name and var_1 mean the same. If no clip of that name exists, the idle clip plays."bucket_idle"
in_waterbooleanThe player touching water must equal this. It is true when the player is in water, the eyes are in water or any of 27 points around the body is water. An entry that has the condition scores higher than one that has none.
disable_all_particlesbooleanfalseWhile this entry plays, no particle emitter of that hand emits.
Keys of a bone physics spec
KeyTypeDefaultWhat it doesExample
pendulum_modestring or booleannonefull swings the bone both ways. forward swings it along the view only. A spec needs a mode, enableCreaturePhysics or enableSlimePhysics, or Punchy! drops it."full"
limit_degnumber55How far the pendulum may swing, in degrees, in both directions.
camera_sensnumber0.3How strongly turning the camera moves it.
gravitynumber25The spring that pulls the pendulum back to rest. It is also part of the damping, so a lower number is softer and a higher one snaps back sooner.
motion_sensnumber0.2How strongly walking, jumping and landing move it.
forcenumber0.75Scales the push of the camera. This pack leaves it at the default.
speednumber16Part of the damping. This pack leaves it at the default.
enableCreaturePhysicsbooleanfalseCreature style feedback on this bone, like the feedback Punchy! gives a pufferfish bucket: it tilts and squashes with your movement. Also read as creature and puffer.
impactInclinationPercentnumber100Scales the creature's tilt on the side it leans while you fall or tilt the camera down, from 0 to 100. A value above 100 cannot amplify.
fallInclinationPercentnumber100Scales the creature's tilt on the other side, the punch of a landing or the camera tilted up, from 0 to 100.
Keys of a particle emitter
KeyTypeDefaultWhat it doesExample
typeparticle idminecraft:critThe particle's name. Punchy! draws its own picture for it, and the type picks the picture. A missing type uses crit; an id with no picture of its own draws the flame picture."minecraft:bubble"
bonestringnoneThe bone the particle starts at, at the bone's pivot. With no match, it starts at your hand.
offsetvector0, 0, 0Moves the start from the bone, in blocks. 16 pixels make one block.
countinteger1Particles per release, 0 to 120.
ratenumber0Releases per second for a steady emitter, 0 to 120. With no triggers and no rate, an emitter releases once per game tick.
lifenumber1.1How long a particle lives, in seconds, 0.05 to 60.
sizenumber0.028The starting half width of the particle, 0.001 to 2.
spreadvector0, 0, 0A random scatter of the start, up to this far either way on each axis.
velocityvector0, 0, 0The starting push, in blocks per tick.
gravitynumber0Changes the vertical speed by this much per second, from -2 to 2. A positive number pushes up and a negative one pulls down. Particles anchored to the item work in pixels, so it acts 16 times weaker.
triggersobjectFlags such as jump and landing. They must be written as an object. By default every trigger must be true at the same moment.
trigger_modestringallany (or or) fires when one trigger is true. Any other value means all.

Things that drop a whole file

Punchy! prints no message for any of these.

  • A definition with a value of the wrong kind. A text where a list belongs, such as "items": "minecraft:bucket", or a list where one value belongs, such as "in_water": [true], drops the whole definition, and the vanilla bucket shows. A file that is not valid JSON, a missing comma, or no items, geo or texture does the same.
  • A geometry that cannot load. A file with no minecraft:geometry list, a bone without a name, or a number list that holds text, leaves the vanilla bucket in your hand.
  • A clip that cannot be read. A key with fewer than three numbers, or a key time that is not a number, stops the file at that clip. The clips before it load, and the clips after it do not.
  • A wrong id. An id with a capital letter is not valid. A geo id that points at nothing leaves the vanilla bucket in your hand, and an animations id that points at nothing gives a bucket with no motion.

Studio’s Lint panel on the Definition tab names most of these, and the export window counts the errors.

Some smaller mistakes keep the file and fail quietly. A texture animation whose picture is not exactly frames times the frame height tall does not animate and shows the whole picture squeezed onto each face. A definition whose geo points at a missing file still covers its items, so it hides later definitions for them and draws the vanilla bucket.

Why my bucket does not look right

  • The vanilla bucket shows. Check that the pack is in Selected, that the files are under assets/bucketpack/punchy/model_parts_items/, and that the ids in the definition match the folders. Check that Resource Pack Model Parts is on in the Items & World tab of Punchy’s F8 menu, because turning it off turns the whole model parts system off after the next resource reload. In the settings file the key is disableResourcePackModelParts, which reads the other way round: true turns model parts off. Press F3+T and wait a second. Model parts draw in your own first person hands only.
  • The liquid and the fish show in the empty bucket. A bone without an entry in bone_textures takes its parent’s texture, then the main texture. liquid, surface and fish need an entry, and clear is the texture that hides them. eyes and tail follow fish.
  • The liquid is steel colored. The bone name in bone_textures has a typo, or the entry is missing for one of the two liquid bones.
  • The water does not move. water.png is not 64 pixels tall, frames is 1, or only one of liquid and surface has a bone_texture_anim entry. The animation uses the exact bone name.
  • The surface does not slosh. The spec in bone_physics has no pendulum_mode, so Punchy! dropped it, or the bone name is not surface. Turn the camera fast and raise limit_deg to see it.
  • The lava does not glow. The bone names in bone_emission must match exactly, and strength must not be 0. Check it at night.
  • No particles. Enable Particle System is off in the Effects tab of Punchy’s F8 menu. Or the entry that is playing has disable_all_particles, which the empty bucket’s dry entry and the lava’s in-water entry do on purpose.
  • A splash never fires. A jump and a landing cannot be true together. The emitter needs "trigger_mode": "any", or two separate emitters.
  • The model vanishes while I drink. The milk bucket needs its useDrink entry.
  • The clip plays the wrong way. Flip the sign of the rotation keys. In Studio the numbers you key are the numbers in the file. In Blockbench the signs of X and Y rotation and X position are flipped on export, as described in Animate the bucket.
  • A clip does not play at all. The name in the entry has a typo, so the idle clip plays instead, or the clip file did not load. See Item clips.
  • Another pack’s bucket wins. For unnamed definitions, the one whose id sorts first wins for an item. A definition with a customName that matches the held stack beats any unnamed one, whatever its position. Studio’s Export First in Order puts yours first among the definitions of its namespace. See Which definition covers an item.

Make it your own

  • Change the shapes and the colors. Replace a flat texture with a painted one and give the faces real UVs, as in Geometry and textures.
  • Add powder_snow_bucket and tadpole_bucket the same way, with a texture of your own for each.
  • Move the bucket in your hand with display, or shrink it. Model part definitions shows the numbers.
  • Keep several looks of one bucket and let players choose. Variants and presets shows how.
  • Look at how a flame and a torch do the same tricks in Recreate a 3D torch pack.

Last checked against the mod on 30 October 2026.