Making a first Luanti mod: A new block type appears!

Page created: 2025-05-26
A drawing of the Luanti logo and a rat with a heart done by Dave Gauer in Krita

Back to my Luanti pages

I pieced together enough information to make my first little Luanti mod. It creates a new "Foo" block, which can be crafted in the "Minetest Game". Now I can make a tutorial.

screenshot of foo blocks being used in a luanti minetest world

This was created with Luanti version 5.12.0, which was released May 23, 2025 (three days ago, as of this writing).

Here’s how to make a new block type appear in a Luanti game.

Find/create the "mods" directory

Start up Luanti and go the About tab in the main menu.

Select the Open User Data Directory button.

(As the tooltip when you hover over the button explains, this will open "the directory that contains user-provided worlds, games, mods, and texture packs in a file manager/explorer.")

Screenshot of the Luanti game menu and Thunar file manager as described

I’m running Linux with the XFCE desktop environment, so when I click the button, it opens the Thunar file manager with the following location:

/home/dave/.minetest/

Note: Luanti was originally called "Minetest". Confusingly, "Minetest Game" is the name of the base game I’m using for my mod. Please bear with me.

Mods go in the mods directory, which doesn’t exist until you have at least one mod installed. I didn’t have any mods installed, so I created the directory myself.

$ mkdir mods
screenshot of the mods directory icon

Note: I tend to work from the command line, but creating directories and files for Luanti mods can all be done graphically in your operating system of choice.

Make a new directory for your mod!

I’ll call my mod "Foo", so it’ll go into <luanti>/mods/foo.

$ mkdir mods/foo

Here’s a tree view in Thunar that shows what I’ve got:

screenshot of the directory tree with the foo mod dir

See if your mod is visible

Believe it or not, making the directory is already enough to make your "mod" visible in Luanti. Let’s make sure we can see it.

I am using the classic "Minetest Game" by the Luanti team, which is a lightweight base for creating my tutorial mod. If you’re following along, you’ll need to install this game to continue.

If you don’t have any games installed yet, click the "Install a game" button.

If you do have games installed, they’ll show up as a horizontal list of icons at the bottom of the menu. Click the "+" button to add another.

screenshot of an empty luanti with no games installed

You can search for it, but "Minetest Game by Luanti" is probably on the first page since it is popular.

screenshot of the game content browser in luanti

Click on Minetest Game and then click the Install button in the top right corner of the game’s description page to install it. Then click the Back button twice to return to the menu.

Now select Minetest Game from the horizontal list of installed games at the bottom of the main menu.

You’ll need to generate a new world to test with, so click the New button.

For no particular reason, I named my test world "honk".

Now for the fun part, click the Select Mods button.

screenshot of the minetest game world menu with the select mods button highlighted

And there we are! Even though it’s just an empty directory, the "foo" mod is already visible.

screenshot of the minetest game mods list with the foo mod highlighted

(Note: You can also click the little "+" button to see the Minetest Game mods. As I understand it, Luanti games are basically bundles of mods. So, knowing how to make mods is the first step in knowing how to make games.)

Create a mod.conf

A mod should have a configuration file. This is a text file called mod.conf that exists in the root of the mod’s directory.

In my case, that’ll be:

mods/foo/mod.conf

Aside: I’m a software developer on unix-like platforms, so I’ll use the Vim editor to create and edit this file, but any text editor will do. On Windows, Notepad is perfectly fine for this, but a much better choice I typically recommend is Notepad++ (notepad-plus-plus.org).

Here’s what I’ve typed in mod.conf:

name = foo
description = Adds a new Foo block.
depends = default

The name is restricted to lower-case letters, numbers, and the underscore ("_") character. It cannot have spaces. You won’t know that the name is invalid until you try to play the game.

For example, when I have an uppercase "F" in the name "Foo", I can see it in the mods list…​

screenshot of foo mod with name updated

…​but the upper-case "F" will cause an error when I try to play the game with the mod enabled:

Failed to enable mod "Foo" as it contains disallowed characters. Only
characters [a-z0-9_] are allowed.

Create an initialization script

The Lua in Luanti represents the Lua programming language (lua.org).

"Lua is a powerful, efficient, lightweight, embeddable scripting language."

In short, Lua was designed for exactly this sort of thing. It is used as a scripting language in other game engines and quite a few extensible programs. Learning a little Lua will go a long way.

As with the mod.conf file, our mod initialization script will be at the root of the mod directory and will be named init.lua. It is also a text file and should be edited with a text editor.

In classic software developer tradition, I’ll have my mod print a "Hello World!" message.

Here’s what I’ll put in my init.lua file:

core.log('"Hello World!" said Foo.')

Here’s my init.lua sitting at the root of the mod directory keeping mod.conf company:

screenshot of two file icons as described

When I re-start the game, my message prints out at the top of the screen:

screenshot of the game with the hello world message from the mod

Logging with the core.log() function makes me happy.

Now it’s time to make that Foo block.

Make a block texture

Mod textures need to go in a textures sub-directory, so I’ll create that now:

$ mkdir mods/foo/textures

Looking at the contents of the Minetest Game, I see that the basic block textures are all 16x16 pixel PNG images.

I create a new 16x16 px image in my favorite open-source drawing program, Krita:

screenshot of editing a texture in krita

I saved this texture image as: mods/foo/textures/foo.png.

screenshot of thunar showing the current directory tree with the texture png file

(Luanti can also load JPEG (.jpg) image files and sizes much larger than 16 pixels square. Do what makes sense for you.)

A new node, a new craftable

Within the Luanti engine, blocks are "nodes". To create a new block that uses my new texture, I need to "register" it with Luanti.

This will go in my init.lua file:

core.register_node("foo:foo", {
    description = "Foo Block!",
    tiles = {"foo.png"},
    groups = {cracky = 1}
})

The register_node() function takes a node name and a table of properties describing the node.

  • name: The Launti node naming convention is "<mod name>:<node name>", so the first foo in "foo:foo" is the mod. If I added a "beans" node to this mod, I could call it "foo:beans".

  • description: The node description will show up in the game (we’ll see a screenshot of that in a moment).

  • tiles: This is a list of image files. Luanti will look for these in the textures/ directory.

  • groups: Luanti lets things (nodes, items, etc.) share properties by belonging to one or more groups.

The names of some of the built-in Luanti node groups are funny: cracky, snappy, choppy, explody, and oddly_breakable_by_hand.

Okay, that makes a new block node. But how do we get the block to show up in the world?

The easiest way is probably to make it craftable so it can appear in our inventory.

I’ll make a really simple crafting recipe that creates Foo Blocks:

core.register_craft({
    type = "shapeless",
    output = "foo:foo 3",
    recipe = {"default:dirt", "default:dirt"}
})
  • type: A "shapeless" recipe can be made by putting the items in the correct order, but anywhere in the 3x3 crafting grid.

  • output: The output format is: "<thing> <quantity>", so "foo:foo 3" produces three foo:foo nodes.

  • recipe: This is a list representing the 3x3 crafting grid with the names of the input items. This one is really simple: two dirt blocks side-by-side.

Put all of this together, and the entire contents of the mod’s init.lua is now:

core.log('"Hello World!" said Foo.')

core.register_node("foo:foo", {
    description = "Foo Block!",
    tiles = {"foo.png"},
    groups = {cracky = 1}
})

core.register_craft({
    type = "shapeless",
    output = "foo:foo 3",
    recipe = {"default:dirt", "default:dirt"}
})

Does it work?

In the game, I press the i key to open the inventory/crafting menu and drag two dirt blocks into the crafting area and there’s my Foo block!

a screenshot of the new block being crafted from dirt

Note that when I hover my cursor over the block, a tooltip shows the node’s description.

a screenshot showing the tooltip

And, of course, I can start building with these blocks in the game:

screenshot of three foo blocks on the ground

This is my first Luanti tutorial; if I write additional Luanti tutorials or references, I’ll post them here.