Wiki 9Minecraft Wiki 9Minecraft

Bedrock Geometry and Modeling Format

How to structure custom 3D models for entities, blocks, and attachables in resource packs.

5Sections
2Code examples
4Known errors

Bedrock geometry files define the 3D meshes used by custom entities, blocks, and items. They are stored as JSON in the resource pack and organize flat cuboids into a hierarchy of named bones. You work with this format whenever you export a model from a 3D editor like Blockbench or need to manually adjust pivots, UV mappings, and attachable locator points.

File Location and Format Structure

All custom geometry lives in the resource pack under the RP/models/ directory. By convention, entity models go into RP/models/entity/ and custom block models go into RP/models/blocks/, though the game actually discovers models by their identifier rather than their folder path. A single .geo.json file can hold one model or an array of several related models.

Modern add-ons should use format_version 1.12.0 or 1.16.0. Version 1.12.0 moved the model identifier and texture bounds into a dedicated description object, replacing the older 1.8.0 format where the identifier was used as a dynamic JSON key. Every model identifier must start with the geometry. prefix, followed by a namespace or project name and the model name.

RP/models/entity/beetle.geo.json
{
  "format_version": "1.12.0",
  "minecraft:geometry": [
    {
      "description": {
        "identifier": "geometry.wiki.beetle",
        "texture_width": 32,
        "texture_height": 32,
        "visible_bounds_width": 1.5,
        "visible_bounds_height": 1.0,
        "visible_bounds_offset": [0.0, 0.5, 0.0]
      },
      "bones": [
        {
          "name": "root",
          "pivot": [0, 0, 0]
        },
        {
          "name": "body",
          "parent": "root",
          "pivot": [0, 3, 0],
          "cubes": [
            {
              "origin": [-4, 1, -5],
              "size": [8, 5, 10],
              "uv": [0, 0]
            }
          ]
        },
        {
          "name": "head",
          "parent": "body",
          "pivot": [0, 3, -5],
          "rotation": [10, 0, 0],
          "cubes": [
            {
              "origin": [-2.5, 1.5, -8],
              "size": [5, 3, 3],
              "uv": [0, 15],
              "inflate": 0.1
            }
          ],
          "locators": {
            "mouth_particles": [0, 2, -8]
          }
        }
      ]
    }
  ]
}

Coordinate System and Units

Bedrock geometry uses pixel units, where 16 units equal 1 full block in the world. The origin [0, 0, 0] is typically placed at the bottom-center of the entity, directly between its feet on the ground plane. When you define a cube, its origin property specifies the bottom-front-right corner (the minimum X, Y, and Z values) before any rotation is applied, and the size array extends the cube in the positive X, Y, and Z directions from that point.

Wait—axes orientation in Bedrock can be confusing when writing JSON by hand. Positive Y is always up. In the model space, negative Z faces North (the forward direction of the entity), and positive Z faces South (backward). Positive X points to the entity's left (West), and negative X points to the entity's right (East). Because of this, a cube centered horizontally with a width of 8 will have an X origin of -4.

PropertyWhat it doesNotes
originBottom-lowest corner of a cube [X, Y, Z]Measured in 1/16th block units from [0, 0, 0]
sizeDimensions of the cube [width, height, depth]Extends positively from the origin
pivotCenter of rotation for a bone or individual cubeAnimations rotate the bone around this exact point
inflateExpands all six faces outward by the given unit amountDoes not change UV mapping; useful for armor layers
mirrorFlips the texture UV mapping horizontally across the X axisCommonly used on paired limbs sharing one texture space

Bones, Parenting, and Pivots

Models are built from an array of bones. A bone is an invisible group that holds cubes, locators, and a pivot point. Bones do not have to contain cubes; empty bones are frequently used as organizational folders or intermediate animation joints. By setting the parent string on a bone to the name of another bone, you create a hierarchy: whenever the parent bone moves, rotates, or scales in an animation, all of its child bones move with it.

Every bone requires a pivot point. If you rotate a leg bone during a walk cycle, it hinges around its pivot, so a leg's pivot should be placed at the hip joint rather than the center of the leg or [0, 0, 0]. Starting in format_version 1.12.0, individual cubes inside a bone can also have their own pivot and rotation properties, allowing you to angle decorative elements without creating a brand new bone for every tilted cube.

Box UV versus Per-Face UV

Textures are mapped onto cubes using either Box UV or Per-Face UV. Box UV is the classic format where you provide a single [u, v] coordinate array on the cube. The game automatically unwraps all six faces in a fixed T-shaped pattern based on the cube's integer size. Box UV is compact, fast to set up for simple mobs, and required if you are modifyingcertain legacy vanilla models, but it wastes texture space and forces cube dimensions to behave like whole numbers on the texture sheet.

Per-Face UV replaces the array with an object containing keys for north, south, east, west, up, and down. Each face defines its own uv origin and uv_size. This lets you map different faces to completely separate areas of the texture, stretch a tiny texture region across a large face, or omit a face entirely to delete unseen internal polygons and improve rendering performance.

RP/models/blocks/crate.geo.json
{
  "format_version": "1.16.0",
  "minecraft:geometry": [
    {
      "description": {
        "identifier": "geometry.wiki.crate",
        "texture_width": 16,
        "texture_height": 16,
        "visible_bounds_width": 2.0,
        "visible_bounds_height": 2.0,
        "visible_bounds_offset": [0.0, 0.5, 0.0]
      },
      "bones": [
        {
          "name": "block",
          "pivot": [0, 8, 0],
          "cubes": [
            {
              "origin": [-7, 0, -7],
              "size": [14, 16, 14],
              "uv": {
                "north": { "uv": [1, 0], "uv_size": [14, 16] },
                "south": { "uv": [1, 0], "uv_size": [14, 16] },
                "east": { "uv": [1, 0], "uv_size": [14, 16] },
                "west": { "uv": [1, 0], "uv_size": [14, 16] },
                "up": { "uv": [1, 1], "uv_size": [14, 14] }
              }
            }
          ]
        }
      ]
    }
  ]
}

Visible Bounds and Block Geometry Limits

Inside the description block, visible_bounds_width, visible_bounds_height, and visible_bounds_offset define a frustum culling box measured in full blocks (not pixels). Minecraft checks if this invisible box is on the player's screen to decide whether to render the model. If your model is tall or animates far away from its origin, and you leave the visible bounds too small, the entity or block will abruptly vanish when the player looks slightly away from its feet.

When using a geometry file for a custom block via the minecraft:geometry component in a behavior pack, stricter spatial rules apply than for entities. Custom block models are centered at [0, 0, 0] horizontally and rest on Y=0, meaning a standard 16x16x16 block spans from [-8, 0, -8] to [8, 16, 8]. Furthermore, block geometry is subject to a strict size limit—generally 30x30x30 pixels centered on the block, provided at least some part of the model remains within the base 16x16x16 boundary.

Which versions this applies to

Format versions 1.12.0 and 1.16.0 are stable and supported in all modern Bedrock releases (1.16.0 through 1.21+) for both entities and custom blocks. No experimental toggles are required to use custom geometry.

When it does not work

What you seeWhyThe fix
Entity is completely invisible or renders as a floating shadow, and the Content Log reports: [Geometry][error]-Failed to find geometry 'geometry.wiki.beetle'.Either the identifier in the client entity file does not exactly match the description.identifier in the .geo.json file, the model lacks the mandatory 'geometry.' prefix, or there is a JSON syntax error preventing the file from parsing.Ensure the identifier begins with 'geometry.' in both the model file and the client entity or block definition, and validate your JSON for trailing commas.
Custom block fails to load or appears as an 'Update!' dirt block, with a Content Log error stating the block geometry exceeds allowed bounds.A cube in your custom block model extends past the maximum allowed block geometry boundary, or the model is shifted because it was built in an entity workspace rather than a block workspace.Keep all block cubes within [-15, -7, -15] to [15, 23, 15] (a 30x30x30 pixel area centered on the block) and make sure at least one element overlaps the core [-8, 0, -8] to [8, 16, 8] space.
Model disappears at the edge of the screen while part of it should still be visible, especially during large animations or on tall custom blocks.visible_bounds_width and visible_bounds_height are set too small, or visible_bounds_offset is sitting at [0, 0, 0] beneath the ground.Increase visible_bounds_width and visible_bounds_height in the description object, and raise the Y value of visible_bounds_offset so the culling box encloses the entire model.
Textures appear stretched, scrambled, or completely transparent on specific cubes.The texture_width and texture_height in the geometry description do not match the aspect ratio of the PNG file, or you are using Box UV on cubes with fractional (decimal) sizes.Match texture_width and texture_height to your image dimensions, and switch from Box UV to Per-Face UV if your cubes use decimal sizes like 1.5 or 0.25.

Reference, straight from the game files

Read out of the game itself, so the ids match the version you are building for.