Skip to content

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.py and requirements.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.