Your first game¶
This page takes you from an empty folder to a game that builds and runs, and then makes your first change to its Trait source. The game you start with is a board of cells, each on or off, drawn white or black. By the end, it will follow the rules of Conway's Game of Life.
What you need¶
- Git, CMake 3.28 or later, and Python 3.
- A C++ compiler: Visual Studio 2026 on Windows; GCC or Clang, with Ninja, on Linux or a Mac.
- The Vulkan SDK, 1.4.357 or later. lusine checks this when you configure and tells you if it is too old.
- A graphics card with Vulkan. On Linux without one, Mesa's lavapipe (a Vulkan device on the CPU) works, slowly: Building a game says how to install it.
You do not need to install vcpkg (the C++ package manager) or the Trait compiler yourself: the build finds or fetches both.
1. Make the game's repository¶
A game is its own Git repository, with lusine inside it as a submodule:
mkdir mygame
cd mygame
git init
git submodule add https://github.com/spooq/lusine lusine
git submodule update --init --recursive
The last command also fetches the Trait compiler, which lives inside lusine.
2. Write the starter files¶
From the game's folder, ask lusine to write a game that builds and runs:
python lusine/tools/lusine/init.py --name mygame
The name must start with a lower-case letter and use only lower-case letters, digits and underscores. lusine writes:
CMakeLists.txt: the whole build, one line that names your game and its sources;CMakePresets.json: the build configurations, taken from lusine;trait.toml: tells the compiler where lusine's library is;trait/mygame.trait: your game's Trait source;src/main.cpp: a small C++ main that opens a window and runs the game;.gitignore, and a few files lusine keeps current for you (its CI workflows,tools/gates.pyandrequirements.txt).
These starters are yours from now on: edit them freely. Running init.py again later never overwrites them.
3. Build it¶
Configure and build with the preset for your platform:
cmake --preset linux-debug # or vs2026-debug on Windows, macos-debug on a Mac
cmake --build --preset linux-debug
The first build takes a while: vcpkg builds lusine's libraries, and the Trait compiler is set up. During the build, the compiler turns trait/mygame.trait into the game's unit, and the C++ compiler builds your executable around it.
4. Run it¶
The executable is in the build folder: build-linux-debug/mygame on Linux (build-macos-debug/mygame on a Mac, build\Debug\mygame.exe with Visual Studio). Run it:
./build-linux-debug/mygame
A window opens on a board of 160 by 90 cells, about half of them on (white). The program takes a few options; --help lists them. For example:
./build-linux-debug/mygame --size 320x180 --fill mygame.board.on=0.2 --seed 7
The build also registers a test that runs 60 steps with no window. Run it with:
ctest --test-dir build-linux-debug
5. Your first change: the Game of Life¶
Open trait/mygame.trait. It declares the game's version number (lusine.version version = { { number = 1 } };: every namespace declares exactly one, and it only grows; the language means it to order a save's renames and upgrades, which lusine does not do yet, so a save a newer build changed is refused; lusine.version is its type, from lusine's library), what a cell is (on, and its colour), the board, a shade function that colours a cell, and main, which says what every step does. Right now a step only colours the cells, so the picture never changes.
Add a rule above main, and call it from main:
// The rule: a cell on stays on with two or three neighbours on; a cell off turns on with exactly three.
bool generation(bool on)
{
let n = count(previous(neighbours(8).on)) where on;
if (previous(on)) return n >= 2 && n <= 3;
return n == 3;
}
void main()
{
board.on = generation(board.on);
board.colour = shade(board.on);
}
neighbours(8) is the eight cells around a cell, previous(...) reads a value as it was when the step began, and count(...) where on counts the neighbours that are on. Build and run again: the board now lives, shifts and settles, a step at a time.
If the compiler refuses your source, it says where and why, with the file, line and column. The Trait language explains how to read a refusal and fix it.
6. In a web browser¶
The same source can run as a web page, on WebGPU. You need Node.js and uv (A web game has the details). From the game's folder:
node lusine/tools/lusine/web/pack.mjs --out web --extents 160x90 --seed mygame.board.on --pattern random:1:0.5 --single trait/mygame.trait
This writes web.html, one file that runs in a browser with WebGPU (recent Chrome, Edge, Safari or Firefox) when you open it. Without --single, it writes a folder, web/, to put on a web server. --seed and --pattern fill the board: random:1:0.5 turns each cell on with a chance of one half, from the seed 1, as the native game's --fill does.
Next¶
- A desktop game and a web game: everything each kind of game can set, from the window and its panels to the page's options.
- Building a game: the rest of what the build does, including shipping your game as a zip for Windows, Linux or macOS.
- The Trait language: what else you can declare.
- The library: the kernels your game can call, from drag and buoyancy to the sun's position.