Axiom/Docs
Get started / Your first mod

Your first mod

A HUD panel that counts live entities and redraws every frame. Three commands to scaffold it, about forty lines to make it do something, and a hot reload loop under a second.

Scaffold it

The template picks your tier and language and generates the bindings from the surface definition. Nothing is downloaded that is not pinned.

$ axiom new myhud --tier wasm --lang cpp
generated include/axiom/surface.hpp, 42 calls, 9 bulk forms

Tier W is the default for a reason. A WASM mod survives a game update, runs on every backend, hot-reloads, and cannot take the game down with it. Reach for native only when the frame budget demands it.

Declare what you need

Capabilities are resolved before any mod code runs. Asking for one you do not use is noise on the install prompt; using one you did not ask for is a Denied at the call site.

MANIFESTaxiom.toml
[capabilities]
require = ["entities", "overlay"]

Write it

Read the world in on_frame, submit a widget tree in on_draw. Keeping them apart lets the host skip drawing entirely while the overlay is closed.

src/main.cpp
#include <axiom/surface.hpp>

struct MyHud final : axiom::Mod {
  void on_frame(axiom::Frame& f) override {
    count_ = f.entities().alive().size();
  }

  void on_draw(axiom::ui::Surface& ui) override {
    auto p = ui.panel("My HUD", axiom::ui::Anchor::TopRight);
    p.text("{} entities", count_);
    ui.submit(std::move(p));
  }

  std::size_t count_ = 0;
};

AXIOM_MOD(MyHud);
Watch the boundary

Calling position() once per entity inside on_frame is one crossing per entity. Use positions(), the bulk form, and cross once. The linter warns about this at build.

Run it

Attach to a running game, or launch one through Axiom. Either way the watcher rebuilds and reloads on save, keeping the mod's state.

$ axiom watch --game treyarch.bo2
attached to t6mp.exe pid 18244, pack build 1.0.0.3
[ OK ] hot reload armed, watching src/ and assets/
reloaded myhud in 38 ms, state preserved