Skip to content

Adding a Custom Block

This guide shows how to create an Enchanting Plus Table block with Anvil. It's written for Anvil beginners who already understand Minecraft concepts. Each step highlights what's necessary versus optional.


Define the Block

blocks/enchanting_plus_table.py
from anvil.api.blocks.blocks import Block

# Namespace is inferred from anvilconfig; only provide the short name here.
def enchanting_plus_table():
    block = Block("enchanting_plus_table")
    return block

Warning

Declare a Block with a unique name (e.g., "enchanting_plus_table"). Namespace comes from anvilconfig.


Server Description & States

server description
from anvil.lib.enums import ItemCategory

# Show the block in the creative inventory (optional)
block.server.description.menu_category(ItemCategory.Construction)
block.server.description.add_state("is_awesome", (False, True))

Note

Server‑side states are optional. If you don't define any, the block still exports and works.


Components — Visuals & Basics

components: visuals & basics
from anvil.api.blocks.components import (
    BlockCollisionBox,
    BlockSelectionBox,
    BlockDisplayName,
    BlockMaterialInstance,
    BlockGeometry,
    BlockDestructibleByMining,
)

# Visuals (mandatory): geometry + at least one material instance
block.server.components.add(
    BlockCollisionBox((16, 12, 16), (0, 0, 0)),
    BlockSelectionBox((16, 12, 16), (0, 0, 0)),
    BlockDisplayName("Enchanting Plus Table"),
    BlockMaterialInstance().add_instance(block.name, "enchanting_plus_table"),
    BlockGeometry("enchanting_plus_table"),
    BlockDestructibleByMining(1.5),
)

Blockbench references

The identifier passed to BlockGeometry(...) must map to a Blockbench file under assets/blockbench, and its internal geometry/material names must match. Mismatches raise an export error.

Failure

Visuals are mandatory. Without a BlockGeometry and at least one material instance, the block won't export.

Enchanting Plus Table Blockbench preview


Crafting Recipe

crafting
from anvil.api.items.crafting import ShapedCraftingRecipe
from anvil.api.vanilla.items import MinecraftItemTypes
from anvil.api.vanilla.blocks import MinecraftBlockTypes

recipe = ShapedCraftingRecipe(block.name)
recipe.result(block.identifier, count=1)
recipe.ingredients([
    [MinecraftItemTypes.AmethystShard, MinecraftBlockTypes.EnchantingTable(), MinecraftItemTypes.AmethystShard],
    [MinecraftBlockTypes.GoldBlock(),    MinecraftBlockTypes.GoldBlock(),       MinecraftBlockTypes.GoldBlock()],
])
recipe.unlock_items([
    MinecraftItemTypes.AmethystShard,
    MinecraftBlockTypes.EnchantingTable(),
    MinecraftBlockTypes.GoldBlock(),
])
recipe.queue()

Note

Recipes are optional. If omitted, the block can still be obtained via creative inventory or commands.


Block Item

block item
from anvil.api.items.components import ItemBlockPlacer, ItemDisplayName, ItemIcon, ItemMaxStackSize
from anvil.lib.enums import ItemCategory

item = block.item
item.server.description.category(ItemCategory.Construction)
item.server.components.add(
    ItemMaxStackSize(64),
    ItemIcon(item.name),
    ItemBlockPlacer(block.identifier),
    ItemDisplayName("Enchanting Plus Table"),
)

Tip

The block's item is available as block.item. Accessing it auto‑creates a corresponding item.


Queue the Block

finalize
block.queue()
return block

Success

Queuing is mandatory. If you don't call block.queue(), the framework will not export the block.

Queuing the block will also queue any associated item.

Queue groups

You can also group exports by calling block.queue("group") if you prefer a structured output directory.


Full Example — Enchanting Plus Table

blocks/enchanting_plus_table.py
from anvil.api.blocks.blocks import Block
from anvil.api.blocks.components import (
    BlockCollisionBox,
    BlockSelectionBox,
    BlockDisplayName,
    BlockMaterialInstance,
    BlockGeometry,
    BlockDestructibleByMining,
)
from anvil.api.items.components import ItemBlockPlacer, ItemDisplayName, ItemIcon, ItemMaxStackSize
from anvil.api.items.crafting import ShapedCraftingRecipe
from anvil.api.vanilla.items import MinecraftItemTypes
from anvil.api.vanilla.blocks import MinecraftBlockTypes
from anvil.lib.enums import ItemCategory


def enchanting_plus_table():
    block = Block("enchanting_plus_table")

    block.server.description.menu_category(ItemCategory.Construction)
    block.server.description.add_state("is_awesome", (False, True))

    # Visuals (mandatory)
    block.server.components.add(
        BlockCollisionBox((16, 12, 16), (0, 0, 0)),
        BlockSelectionBox((16, 12, 16), (0, 0, 0)),
        BlockDisplayName("Enchanting Plus Table"),
        BlockMaterialInstance().add_instance(block.name, "enchanting_plus_table"),
        BlockGeometry("enchanting_plus_table"),
        BlockDestructibleByMining(1.5),
    )

    # Crafting recipe (optional)
    recipe = ShapedCraftingRecipe(block.name)
    recipe.result(block.identifier, count=1)
    recipe.ingredients([
        [MinecraftItemTypes.AmethystShard, MinecraftBlockTypes.EnchantingTable(), MinecraftItemTypes.AmethystShard],
        [MinecraftBlockTypes.GoldBlock(),    MinecraftBlockTypes.GoldBlock(),       MinecraftBlockTypes.GoldBlock()],
    ])
    recipe.unlock_items([
        MinecraftItemTypes.AmethystShard,
        MinecraftBlockTypes.EnchantingTable(),
        MinecraftBlockTypes.GoldBlock(),
    ])
    recipe.queue()

    # Block item (optional)
    item = block.item
    item.server.description.category(ItemCategory.Construction)
    item.server.components.add(
        ItemMaxStackSize(64),
        ItemIcon(item.name),
        ItemBlockPlacer(block.identifier),
        ItemDisplayName("Enchanting Plus Table"),
    )

    # Finalize (mandatory)
    block.queue()
    return block


EnchantingPlusTable = enchanting_plus_table()