⛏️ My First Minecraft Mod · Episode 2 of 6 · See All Episodes
🪨 Episode 2 · Custom Block · Needs Episode 1 Complete

Crystal Block!
Your First Custom Block

Add a glowing Crystal Block to Minecraft it lights up in the dark, can be mined with a pickaxe and drops your Crystal Gem when broken. Time to build with your own block!

🧑 Ages 10+ ⏱️ ~1.5 Hours ⛏️ Fabric 1.21 ✓ Free
Your Progress 0 / 10 steps
1
🧱
How Blocks Work in Fabric
Understand the difference between items and blocks before we write any code
Active
🎯
Goal for this step

Understand what extra files a block needs compared to an item, so nothing surprises you later.

📖
Blocks vs Items: In Minecraft, a Block is what sits in the world. A BlockItem is the item version you hold and place. Every block needs both registered. Blocks also need a blockstate JSON (describing which model to show) and a loot table (what drops when mined).

Files we'll create this episode

  • 1ModBlocks.java registers the Crystal Block (and its BlockItem)
  • 2models/block/crystal_block.json the 3D cube model
  • 3models/item/crystal_block.json the item version model
  • 4blockstates/crystal_block.json links state → model
  • 5textures/block/crystal_block.png the 16×16 texture
  • 6loot_table/blocks/crystal_block.json what drops when mined
  • 7recipe/crystal_block.json crafting recipe
💡
That's more files than an item! But each one is small and follows the same pattern. Once you've done it once, you can add any block in minutes.
I understand blocks need both a Block and a BlockItem registered
I know blocks need a blockstate, model, texture, and loot table
2
📝
Create ModBlocks.java
Register the Crystal Block and its BlockItem in Java
Locked
🎯
Goal for this step

Create ModBlocks.java with the Crystal Block registered as a glowing, mineable block.

  • 1Open your CrystalMod project in IntelliJ. Right-click the crystalmod package → New → Java Class. Name it ModBlocks.
  • 2Replace the file contents with:
ModBlocks.java
package com.example.crystalmod; import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.MapColor; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.item.ItemGroups; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.util.Identifier; public class ModBlocks { public static final Block CRYSTAL_BLOCK = registerBlock( "crystal_block", new Block(AbstractBlock.Settings.create() .mapColor(MapColor.CYAN) .strength(3.0f, 4.0f) // hardness, blast resistance .luminance(state -> 10) // glow level (0-15) .requiresTool() // needs pickaxe to drop .sounds(BlockSoundGroup.AMETHYST_BLOCK)) ); private static Block registerBlock(String name, Block block) { registerBlockItem(name, block); return Registry.register(Registries.BLOCK, Identifier.of(CrystalMod.MOD_ID, name), block); } private static Item registerBlockItem(String name, Block block) { return Registry.register(Registries.ITEM, Identifier.of(CrystalMod.MOD_ID, name), new BlockItem(block, new Item.Settings())); } public static void registerModBlocks() { ItemGroupEvents.modifyEntriesEvent(ItemGroups.BUILDING_BLOCKS) .register(entries -> entries.add(CRYSTAL_BLOCK)); } }
📖
luminance(state -> 10) makes the block glow with brightness 10 (like a glowstone is 15, torch is 14). requiresTool() means it only drops when mined with the correct tool (pickaxe).
ModBlocks.java created with CRYSTAL_BLOCK field
No red import errors (use Alt+Enter to fix if needed)
3
🔗
Register ModBlocks in CrystalMod.java
Call your new registerModBlocks() method so the block loads on startup
Locked
🎯
Goal for this step

Add one line to CrystalMod.java so your block gets registered when the game starts.

  • 1Open CrystalMod.java.
  • 2In the onInitialize() method, add a call to ModBlocks.registerModBlocks(); put it before the ModItems line:
CrystalMod.java onInitialize()
@Override public void onInitialize() { ModBlocks.registerModBlocks(); // ← add this line ModItems.registerModItems(); LOGGER.info("Crystal Mod loaded! 💎"); }
💡
Blocks must be registered before items because the BlockItem references the Block object. Registering blocks first avoids any ordering issues.
ModBlocks.registerModBlocks() added to onInitialize()
🎓 Teacher Note Step 3Students commonly forget that blocks need a BlockItem too — a block without a BlockItem exists in the world but can't be picked up or placed from inventory. Also watch for the registration order: blocks must be registered before items because BlockItem holds a reference to the Block object.
🚨 Stuck? Block won't register or game crashes
  • Cannot find symbol: ModBlocks check ModBlocks.java is in the com.example.crystalmod package and the package declaration at the top of the file matches.
  • Block not in creative inventory confirm registerModBlocks() adds the block via ItemGroupEvents with entries.add(CRYSTAL_BLOCK).
  • Game crashes on startup make sure ModBlocks.registerModBlocks() is called before ModItems.registerModItems() in CrystalMod.java.
  • Block is invisible when placed the blockstate or model JSON is missing or named wrong. Check Step 6.
4
🎨
Create the Block Texture
Draw a 16×16 crystal texture for your block's six faces
Locked
🎯
Goal for this step

Create a PNG texture for the Crystal Block and save it in the right folder.

  • 1In your project's resources/assets/crystalmod folder, create a new subfolder: textures/block.
  • 2Use Pixel Studio or any image editor to draw a 16×16 crystal texture. Try cyan/teal shades with lighter spots for a crystal-like appearance.
  • 3Save it as crystal_block.png in the textures/block/ folder.
🎨
Look at Minecraft's amethyst block or glass textures for inspiration simple semi-transparent looking patterns with lighter edges work really well for crystals!
crystal_block.png created at assets/crystalmod/textures/block/
5
📦
Create Block & Item Model JSON Files
Tell Minecraft which texture to use and what shape the block is
Locked
🎯
Goal for this step

Create two JSON model files one for the block in the world, one for it as a held/placed item.

Block model (the 3D cube)

  • 1In assets/crystalmod, create the folder models/block.
  • 2Create the file crystal_block.json inside it:
assets/crystalmod/models/block/crystal_block.json
{ "parent": "block/cube_all", "textures": { "all": "crystalmod:block/crystal_block" } }

Item model (what you hold)

  • 3In assets/crystalmod/models/item (which you created in Episode 1), create crystal_block.json:
assets/crystalmod/models/item/crystal_block.json
{ "parent": "crystalmod:block/crystal_block" }
📖
The item model just points to the block model — Minecraft knows how to render a block model as an item automatically. Nice and simple!
models/block/crystal_block.json created
models/item/crystal_block.json created
6
🔀
Create the Blockstate JSON
Link the block's state to its model required for every block
Locked
🎯
Goal for this step

Create the blockstates JSON this tells Minecraft which model to use for the block's default state.

  • 1In assets/crystalmod, create the folder blockstates.
  • 2Inside it create the file crystal_block.json:
assets/crystalmod/blockstates/crystal_block.json
{ "variants": { "": { "model": "crystalmod:block/crystal_block" } } }
📖
Some blocks have many variants (like stairs or slabs that can face different directions). Our Crystal Block only has one variant the empty string "" means "default state".
  • 3Add the block's name to your en_us.json language file:
    "block.crystalmod.crystal_block": "Crystal Block"
blockstates/crystal_block.json created
en_us.json updated with block name
🎓 Teacher Note Step 6A pink/magenta checkerboard block means a missing texture or wrong path. Ask students to open the Gradle run console and search for "crystalmod" any missing resource errors are listed there. Common path mistake: "textures/blocks/" (with an s) instead of the correct "textures/block/".
🚨 Stuck? Block shows as pink/black checkerboard
  • Pink checkerboard = missing texture. The PNG must be at assets/crystalmod/textures/block/crystal_block.png folder is block, not blocks.
  • Blockstate not found the JSON must be at assets/crystalmod/blockstates/crystal_block.json folder is blockstates (with an s, unlike texture).
  • JSON syntax error a missing comma or bracket breaks the whole file. Paste your JSON at jsonlint.com to check.
  • Block model not found block model goes in models/block/ and the item model goes in models/item/. Two separate files in two separate folders!
7
💰
Add a Loot Table Drop Crystal Gem When Mined
Tell Minecraft what items to drop when the Crystal Block is broken
Locked
🎯
Goal for this step

Create a loot table so that mining the Crystal Block drops 1 Crystal Gem.

  • 1In src/main/resources, navigate to the data folder. Create the path: data/crystalmod/loot_table/blocks/
  • 2Create the file crystal_block.json inside it:
data/crystalmod/loot_table/blocks/crystal_block.json
{ "type": "minecraft:block", "pools": [ { "rolls": 1, "bonus_rolls": 0, "entries": [ { "type": "minecraft:item", "name": "crystalmod:crystal_gem" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] } ] }
📖
rolls: 1 means drop 1 item. survives_explosion means creepers won't drop the gem (realistic behaviour blow up a block and you lose the loot!). Remove that condition if you want it to always drop.
loot_table/blocks/crystal_block.json created
8
🔨
Add a Crafting Recipe
Let players craft the Crystal Block using 9 Crystal Gems in a 3×3 grid
Locked
🎯
Goal for this step

Create a crafting recipe so players can turn 9 Crystal Gems into 1 Crystal Block (like iron ingots → iron block).

  • 1In data/crystalmod, create a recipe folder.
  • 2Create the file crystal_block.json inside it:
data/crystalmod/recipe/crystal_block.json
{ "type": "minecraft:crafting_shaped", "pattern": [ "GGG", "GGG", "GGG" ], "key": { "G": { "item": "crystalmod:crystal_gem" } }, "result": { "id": "crystalmod:crystal_block", "count": 1 } }
💡
Want a different recipe? Change the pattern! "G G" with spaces means the middle column is empty. You could make a 2×2 recipe using just 4 gems by using only the top-left 2×2 area of the pattern.
data/crystalmod/recipe/crystal_block.json created
9
🏃
Run Minecraft & Test Your Block!
Launch the game and place your glowing Crystal Block in the world
Locked
🎯
Goal for this step

Launch Minecraft, find your Crystal Block in creative mode, place it and see it glow!

  • 1In IntelliJ, select Minecraft Client from the run dropdown and click ▶ Play.
  • 2Create or open a creative world.
  • 3Press E → search for Crystal Block. It should appear in the Building Blocks tab.
  • 4Place it in the world. It should look like your texture and glow in the dark!
  • 5Switch to Survival mode (/gamemode survival) and try to mine it you'll need a pickaxe, and it should drop a Crystal Gem when broken.
  • 6Test the crafting recipe: open a crafting table and fill all 9 slots with Crystal Gems you should get 1 Crystal Block.
⚠️
If the block appears purple/black (missing texture) check the texture file is exactly named crystal_block.png and is in the right folder. Check the blockstates JSON matches that name too.
Crystal Block appears in creative inventory
Block glows in the dark when placed
Mining with a pickaxe drops a Crystal Gem
Crafting recipe works in a crafting table
10
🌟
Challenge: Tweak Your Block's Properties
Experiment with hardness, glow level, sounds and map colour
Locked
🎯
Goal for this step

Customise your Crystal Block's properties to make it exactly the way you want it.

🎨
Try changing these values in your block settings and see what happens:
  • 1Glow: Change luminance(state -> 10) to 15 for maximum brightness, or 4 for a subtle glow.
  • 2Hardness: Change strength(3.0f, 4.0f) to strength(50.0f, 1200.0f) to make it as hard as obsidian!
  • 3Sound: Try BlockSoundGroup.GLASS, BlockSoundGroup.METAL or BlockSoundGroup.STONE each gives a different sound when walked on and mined.
  • 4Map colour: Try MapColor.BLUE, MapColor.PURPLE or MapColor.EMERALD_GREEN this changes the colour the block shows on a map.
  • 5Reload Minecraft after each change to see it work.
I tried at least one property change and saw it work
🎉🪨💎🎊✨
You Built a Custom Block!

You now know how to add blocks, textures, blockstates, loot tables and crafting recipes to Minecraft. Episode 3 adds a magic food item with potion effects!

🍪 Episode 3: Magic Cookie → ⭐ View My Progress & Certificates

This workshop was free and took many hours to build. If it helped you learn something new, consider supporting the project.

☕ Support on Ko-fi