Wiki 9Minecraft Wiki 9Minecraft

Custom Block Models and Geometry

How to replace the default cube with custom Bedrock geometry, textures, and bone visibility.

5Sections
3Code examples
4Known errors

By default, every custom block in Minecraft Bedrock renders as a standard 16x16x16 unit cube. When you want to build furniture, pillars, ores with protruding crystals, or machinery, you must pair a geometry file in your Resource Pack with the geometry and material instances components in your Behavior Pack. This page covers how block models are structured, linked, and constrained by the engine.

The Resource Pack Geometry File

Custom block models use the standard Bedrock geometry format (format version 1.12.0 or newer) and live inside the RP/models/blocks/ or RP/models/entity/ folder. Even though blocks are static, the game reads their meshes using the same parser as entities. You will typically create these models in Blockbench using the Bedrock Block or Bedrock Entity project type.

The coordinate space is measured in pixels, where 16 units equal one full block. Crucially, the origin (0, 0, 0) of a block geometry is at the bottom-center of the block space, not the bottom-north-west corner. This means a standard full cube spans from -8 to +8 on the X and Z axes, and from 0 to 16 on the Y axis.

Every geometry file requires a unique identifier starting with geometry. followed by your pack's namespace or custom name. You will reference this exact string inside your Behavior Pack block definition.

RP/models/blocks/pedestal.geo.json
{
  "format_version": "1.12.0",
  "minecraft:geometry": [
    {
      "description": {
        "identifier": "geometry.wiki.pedestal",
        "texture_width": 64,
        "texture_height": 64,
        "visible_bounds_width": 2,
        "visible_bounds_height": 2,
        "visible_bounds_offset": [0, 0.5, 0]
      },
      "bones": [
        {
          "name": "base",
          "pivot": [0, 0, 0],
          "cubes": [
            {"origin": [-6, 0, -6], "size": [12, 2, 12], "uv": [0, 0]},
            {"origin": [-4, 2, -4], "size": [8, 12, 8], "uv": [0, 14]}
          ]
        },
        {
          "name": "top_plate",
          "pivot": [0, 14, 0],
          "cubes": [
            {"origin": [-7, 14, -7], "size": [14, 2, 14], "uv": [0, 34]}
          ]
        }
      ]
    }
  ]
}

Applying the Model in the Behavior Pack

Unlike entity models, which are wired up entirely inside the Resource Pack, custom block models are assigned inside the Behavior Pack block JSON using the minecraft:geometry component. Whenever you use custom geometry, you must also include the minecraft:material_instances component in the same file, or the game will not know which texture or render method to apply to your mesh.

If you simply want a standard full block without making a custom model file, you can use the built-in identifier minecraft:geometry.full_block. This is especially useful when you want the advanced shading or texture control of material_instances without needing an external .geo.json file.

Remember that blocks.json in the Resource Pack should generally be omitted for modern custom blocks that use these components, as defining an entry in blocks.json can override or conflict with the Behavior Pack's geometry component.

BP/blocks/pedestal.json
{
  "format_version": "1.20.80",
  "minecraft:block": {
    "description": {
      "identifier": "wiki:pedestal"
    },
    "components": {
      "minecraft:geometry": {
        "identifier": "geometry.wiki.pedestal"
      },
      "minecraft:material_instances": {
        "*": {
          "texture": "wiki_pedestal",
          "render_method": "alpha_test"
        }
      },
      "minecraft:collision_box": {
        "origin": [-7, 0, -7],
        "size": [14, 16, 14]
      },
      "minecraft:selection_box": {
        "origin": [-7, 0, -7],
        "size": [14, 16, 14]
      }
    }
  }
}

Dynamic Models with Bone Visibility

Creating a separate geometry file for every possible state of a complex block (like pipes, fences, or multi-stage crops) quickly bloats your Resource Pack. Instead, you can build one model containing all possible parts separated into named bones, and toggle them on or off inside the minecraft:geometry component using the bone_visibility object.

Each key inside bone_visibility must match a bone name in your .geo.json file. The value can be a simple boolean (true or false) or a Molang expression string that evaluates block states using the q.block_state() query. This allows a single geometry file to adapt dynamically when permutations update.

FieldWhat it doesNotes
identifierPoints to the geometry definition in the RP.Must start with geometry. or be minecraft:geometry.full_block.
bone_visibilityHides or shows specific bones from the geometry.Accepts booleans or Molang strings querying block states.
BP/blocks/dynamic_pedestal.json
{
  "format_version": "1.20.80",
  "minecraft:block": {
    "description": {
      "identifier": "wiki:dynamic_pedestal",
      "states": {
        "wiki:has_plate": [true, false]
      }
    },
    "components": {
      "minecraft:geometry": {
        "identifier": "geometry.wiki.pedestal",
        "bone_visibility": {
          "base": true,
          "top_plate": "q.block_state('wiki:has_plate')"
        }
      },
      "minecraft:material_instances": {
        "*": {
          "texture": "wiki_pedestal",
          "render_method": "alpha_test"
        }
      }
    }
  }
}

Size Limits, Lighting, and Culling

The Bedrock rendering engine enforces strict rules on block geometry to keep chunk meshing fast. Visually, a block model is restricted to a 30x30x30 pixel area centered on the block, and at least one pixel of your geometry must overlap the base 16x16x16 block boundary. Meanwhile, your collision_box and selection_box components cannot exceed the standard 16x16x16 space (from -8 to 8 on X/Z, and 0 to 16 on Y).

When you apply a custom model, Minecraft assumes the block is no longer a solid cube and stops culling the faces of adjacent blocks (so you do not get X-ray holes into the ground beneath a custom chair). However, if part of your model sits flush against the edge of the 16x16x16 boundary, or if it extends outside the 16x16x16 space, you may see dark shadows on those faces. In your material_instances, setting ambient_occlusion to false and face_dimming to false often clears up dark shading artifacts on complex or oversized meshes.

Transparency is controlled entirely by the render_method inside minecraft:material_instances, not by the model itself. Even if your geometry is smaller than a full block, leaving render_method on opaque will render unused UV space as solid black or white; switch to alpha_test for cutout textures or blend for stained-glass style translucency.

Rotating Models with the Transformation Component

Rather than exporting four rotated copies of a model for North, South, East, and West orientations, you should combine a single model with the minecraft:transformation component inside your block permutations. The transformation component lets you rotate the entire model in 90-degree increments around the block's center, as well as translate (shift) or scale the mesh.

When you apply a rotation via minecraft:transformation, the game automatically rotates your collision_box and selection_box to match, saving you from recalculating hitbox coordinates for every direction.

Which versions this applies to

Stable in format_version 1.19.40 and above. Thebone_visibility object with Molang support requires format_version 1.19.80 or newer. No experimental toggles are required.

When it does not work

What you seeWhyThe fix
The block places in the world as an invisible barrier or a full dirt block with an 'Update!' texture, and Content Log reports: [Blocks][error]-block_name | minecraft:geometry | geometry identifier 'geometry.example' not found.Either the identifier in your BP does not exactly match the description.identifier inside the .geo.json file, the Resource Pack is not applied to the world, or the .geo.json file has a syntax error.Check that both strings match character-for-character (including the geometry. prefix) and validate your Resource Pack model JSON.
The block renders with a purple-and-black checkerboard texture across the entire custom mesh.You added minecraft:geometry to the Behavior Pack without adding minecraft:material_instances, or the texture shortname inside material_instances is missing from RP/textures/terrain_texture.json.Add a minecraft:material_instances component with a wildcard '*' instance, and verify the texture shortname is registered in terrain_texture.json.
Parts of the model turn pitch black when placed next to solid blocks, or when the model is larger than 16x16x16.Bedrock's vertex lighting calculates light levels based on the block's own coordinate space; vertices that touch or cross into an adjacent solid block's space inherit a light level of zero.Pull the model faces 0.05 pixels inward from the block boundary, or disable ambient_occlusion in the block's material_instances component.
Content Log shows an error stating the block geometry exceeds size restrictions, and the model refuses to render.One or more cubes in your geometry extend past the maximum allowed visual boundary (roughly 30x30x30 pixels centered on the block), or no part of the model overlaps the base 16x16x16 unit cube.Open the model in Blockbench, shrink or move the out-of-bounds cubes back within the 30x30x30 limit, and ensure at least one cube intersects the center 16x16x16 box.

Reference, straight from the game files

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