You know that feeling when you open a new programming language and for the first 20 minutes you think, "Well, that's easy"? And then it starts. The brackets are wrong, you forgot the semicolons, the compiler is yelling at you like a neighbor from upstairs at 3 in the morning.
Lua is different. Seriously. This language is so concise that you can learn its basics over a cup of coffee. And in the evening, you can assemble a fully working mini-project. Don't you believe me? Well, let's check it out.

What is Lua and why do I need it?
Lua (pronounced "Lou-a", not "Loua" - but, honestly, everyone says it however they like) is a lightweight scripting language that was born in Brazil in 1993. Yes, it is older than most JavaScript frameworks. And, unlike them, it is still not deprecated.
Where Lua is used:
Games - Roblox, World of Warcraft, Garry's Mod, Love2D. If you have ever written an add-on for WoW, then you are already a Lua developer, congratulations.
Nginx and OpenResty — high-load web servers run Lua scripts to process requests.
Neovim — if you're one of those people who spends more time setting up their editor than writing code, Lua is your new best friend.
Embedded systems and IoT — Lua is so lightweight that it works even where Python is suffocating.
In short, Lua is like a Swiss knife, only without a corkscrew. Compact, useful and surprisingly powerful.
Step 0: Installation (faster than npm install)
Linux/macOS:
# Ubuntu / Debian
sudo apt install lua5.4
# macOS
brew install luaWindows:
Download LuaBinaries from official website or put through scoop:
scoop install luaWe check:
lua -v
# Lua 5.4.x Copyright (C) ...Done. No Docker, no virtual environment, no package.json on 300 lines. It just works.
Step 1: Hello World and the first basics
Create the hello.lua file:
print("Hello, World!")
print("Lua is easier than you thought")Launch:
lua hello.luaThat's it. Without public static void main, without import sys, without use strict. You just write and run.
Variables — no types, no problems
local name = "Alexey"
local age = 25
local is_developer = true
print(name .. " — developer: " .. tostring(is_developer))Note: .. is a concatenation of strings. Not +, not template strings. Two modest points. Lua is a minimalist.
Conditions - good old classic
local level = 42
if level >= 100 then
print("You're a legend!")
elseif level >= 50 then
print("Almost there!")
else
print("Keep swinging")
endNote: then and end instead of curly braces. It's unusual at first, but after an hour you don't notice it anymore.
Cycles — three types for all occasions
-- Цикл for (классический)
for i = 1, 5 do
print("Iteration: " .. i)
end
-- Цикл while
local count = 0
while count < 3 do
count = count + 1
print("Counter: " .. count)
end
-- Перебор таблицы (о таблицах — ниже)
local fruits = {"apple", "banana", "mango"}
for index, fruit in ipairs(fruits) do
print(index .. ". " .. fruit)
endStep 2: Tables are the only data structure (and that's enough)
Lua has no arrays, dictionaries, objects, sets, tuples, decks... There are tables. And they replace everything. It's as if a JavaScript object and an array merged into one entity:
-- Как массив
local colors = {"Red", "Green", "Blue"}
print(colors[1]) -- "Red" (индексация с 1, да-да)
-- Как словарь
local player = {
name = "Hero",
hp = 100,
level = 1
}
print(player.name) -- "Hero"
print(player["hp"]) -- 100 (тоже работает)
-- Комбинированный вариант
local config = {
title = "My Game",
resolution = {1920, 1080},
fullscreen = true
}Indexing from 1 — yes, it's a shock after all the languages with zero indexation. But you'll get used to it. Probably. Someday.
Step 3: Functions — First-Class Citizens
-- Обычная функция
local function greet(name)
return "Hi, " .. name .. "!"
end
print(greet("world"))
-- Функция как переменная (анонимная)
local square = function(x)
return x * x
end
print(square(7)) -- 49
-- Множественный возврат (это Lua-суперсила!)
local function get_player_stats()
return "Hero", 100, 15
end
local name, hp, attack = get_player_stats()
print(name .. " | HP: " .. hp .. " | ATK: " .. attack)Multiple return values are one of those things in Lua that makes you sigh: "Why isn't it like that everywhere?"
Step 4: Assemble a mini-project — a text quest!
Theory is good, but we're not giving a lecture here. Let's write a real mini-project — a text RPG quest. You have to explore the dungeon, fight monsters and (possibly) survive.
Create the dungeon.lua file:
-- === ТЕКСТОВЫЙ КВЕСТ: ПОДЗЕМЕЛЬЕ ===
math.randomseed(os.time())
-- Состояние игрока
local player = {
name = "",
hp = 100,
attack = 15,
potions = 3
}
-- Список монстров
local monsters = {
{name = "Goblin", hp = 30, attack = 8, xp = 10},
{name = "Skeleton", hp = 50, attack = 12, xp = 20},
{name = "Dark Mage", hp = 40, attack = 18, xp = 25},
{name = "Ogr", hp = 80, attack = 10, xp = 30},
}
-- Вспомогательные функции
local function separator()
print(string.rep("-", 40))
end
local function show_status()
separator()
print("HP: " .. player.hp .. " | Potions: " .. player.potions)
separator()
end
local function ask(question, options)
print("\n" .. question)
for i, opt in ipairs(options) do
print(" " .. i .. ") " .. opt)
end
io.write("Your choice: ")
local choice = tonumber(io.read())
if not choice or choice < 1 or choice > #options then
print("Incomprehensible choice, try again.")
return ask(question, options)
end
return choice
end
-- Система боя
local function battle(monster)
print("\n⚔️ Appears in front of you " .. monster.name .. "! (HP: " .. monster.hp .. ")")
local enemy_hp = monster.hp
while enemy_hp > 0 and player.hp > 0 do
show_status()
local action = ask("What are you doing?", {"Attack", "Drink the potion", "Try to escape"})
if action == 1 then
local damage = math.random(player.attack - 5, player.attack + 5)
enemy_hp = enemy_hp - damage
print("You inflict " .. damage .. " damage!")
if enemy_hp > 0 then
local enemy_damage = math.random(monster.attack - 3, monster.attack + 3)
player.hp = player.hp - enemy_damage
print(monster.name .. " beats you on " .. enemy_damage .. " damage!")
end
elseif action == 2 then
if player.potions > 0 then
local heal = math.random(20, 35)
player.hp = player.hp + heal
player.potions = player.potions - 1
print("You are restoring " .. heal .. " HP!")
else
print("You don't have any potions! You lose a turn...")
end
local enemy_damage = math.random(monster.attack - 3, monster.attack + 3)
player.hp = player.hp - enemy_damage
print(monster.name .. " beats you on " .. enemy_damage .. " damage!")
elseif action == 3 then
if math.random(1, 100) <= 40 then
print("You managed to escape!")
return false
else
print("Couldn't escape!")
local enemy_damage = math.random(monster.attack - 3, monster.attack + 5)
player.hp = player.hp - enemy_damage
print(monster.name .. " beats you on " .. enemy_damage .. " damage!")
end
end
end
if enemy_hp <= 0 then
print("\n🎉 " .. monster.name .. " defeated!")
if math.random(1, 100) <= 30 then
player.potions = player.potions + 1
print("You find a potion!")
end
return true
end
return false
end
-- Комнаты подземелья
local function explore_room(room_number)
separator()
print("\n🚪 Room " .. room_number)
local events = {"monster", "monster", "treasure", "trap", "empty"}
local event = events[math.random(1, #events)]
if event == "monster" then
local monster = monsters[math.random(1, #monsters)]
return battle(monster)
elseif event == "treasure" then
print("You find a treasure chest!")
local bonus = ask("What are you taking?", {"Health Potion (+1)", "Grinding stone (+3 to attack)"})
if bonus == 1 then
player.potions = player.potions + 1
print("Potions: " .. player.potions)
else
player.attack = player.attack + 3
print("Attack now: " .. player.attack)
end
return true
elseif event == "trap" then
print("Trap! Thorns shoot out of the wall!")
local trap_damage = math.random(5, 15)
player.hp = player.hp - trap_damage
print("You get " .. trap_damage .. " damage.")
return true
else
print("An empty room. Silence and dust.")
if math.random(1, 100) <= 20 then
print("You find a potion in the corner!")
player.potions = player.potions + 1
end
return true
end
end
-- === НАЧАЛО ИГРЫ ===
print("╔══════════════════════════════════════╗")
print("║ DUNGEON: TEXT QUEST ║")
print("║ Written in Lua ║")
print("╚══════════════════════════════════════╝")
io.write("What's your name, adventurer? ")
player.name = io.read()
print("\nWelcome, " .. player.name .. "!")
print("You are facing the entrance to a dungeon with 5 rooms.")
print("Go through them all and become a legend.\n")
local rooms_cleared = 0
for room = 1, 5 do
if player.hp <= 0 then
break
end
explore_room(room)
if player.hp <= 0 then
break
end
rooms_cleared = rooms_cleared + 1
if room < 5 then
show_status()
local choice = ask("Going further?", {"Go ahead!", "Enough for today"})
if choice == 2 then
print("\nYou decide to return. Sometimes retreating is also wise.")
break
end
end
end
separator()
separator()
if player.hp <= 0 then
print("\n💀 " .. player.name .. " fell into the dungeon...")
print("Rooms passed: " .. rooms_cleared .. " of 5")
print("Try again — the dungeon is waiting!")
else
if rooms_cleared == 5 then
print("\n🏆 " .. player.name .. " completed the entire dungeon!")
print("HP: " .. player.hp .. " | Remaining potions: " .. player.potions)
print("You are a true legend!")
else
print("\n🏠 " .. player.name .. " returned from the dungeon.")
print("Rooms passed: " .. rooms_cleared .. " of 5")
end
end
print("\nThank you for playing! 🎮")Launch:
lua dungeon.luaAnd now you have already written a full-fledged project on Lua. With a combat system, random, inventory and plot branching. Not some calculator, but a real game.
What's next? Where to grow
Lua is a great entry point, and here's where you can move:
Love2D — framework for 2D games on Lua. If you like the text quest, imagine what will happen with the graphics.
Neovim plugins — your own plugin for the editor, written in Lua, is a separate kind of pleasure.
OpenResty — embed Lua scripts directly into nginx and process millions of requests.
Roblox — seriously, Roblox earns real money, and all the logic is written in Lua.
Do you want to continue your studies?
Come to Kodik!
If you like this format — from theory to practice in one sitting — you will definitely like it Code. This is an application for learning programming, where each lesson is not just a wall of text, but tasks that you solve with your hands. Python, JavaScript, HTML, CSS and other technologies - all with real practice, without water and boredom.
And we also have Telegram channel, where useful posts are regularly published: concept reviews, cheat sheets, mini-tasks and memes for developers. This is a great way to repeat programming in a convenient format — on the way to work, during a lunch break, or when you have “five more minutes” before bed. Subscribe and let programming be a part of every day.
Lua is a language that proves that you don't have to be complex to be powerful. In one evening, you went from print("Hello") to a text RPG quest with a combat system. And at the same time, you didn't install a single dependency, didn't write a single config, and didn't break a single package-lock.json.
Now you have a working project, an understanding of the basics and a direction for growth. And this is already more than 90% of people who "were going to start learning programming next week."
Go for it. 🚀
