Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

A bundle

The project and its .hmod have the same flat layout, with no mod-id directory level inside the archive:

my_mod/
  horizon-mod.toml        # the only manifest; mod identity and build pins
  icon.png               # optional launcher icon
  assets/my_mod/
  data/my_mod/
  Cargo.toml             # one crate; Cargo metadata is not mod identity
  src/lib.rs             # impl Hooks
  src/frame.rs           # optional injection callback module

Without Cargo.toml, it is a content mod. Code requires both Cargo.toml and [native]; inconsistent declarations are refused. The mod's id and version come only from horizon-mod.toml, not Cargo's package name or version. An id is a plain [a-z0-9_]{1,64} name, also used as its resource namespace. A code mod has no rust-toolchain.toml: the pinned Horizon commit decides the toolchain that builds it. There is no input native/ or rust/ directory, horizon-native.json or hand-written horizon-mixin.toml. The launcher writes the tool's manifest and stages the crate itself; those internal paths are not package layouts.

The manifest keeps the content fields, including the exact api = "0.2" contract and capabilities = ["registries"]. A code mod adds:

[native]
game = "26.3"
horizon = "<exact 40-character lowercase Horizon commit>"
mixins = "<exact 40-character lowercase horizon-mixins commit>"

The placeholders above must be replaced by exact commits; the native template fills them in. Unknown fields are refused. icon.png has no manifest key: when present it must be a valid, nonzero square PNG, at most 512 × 512 pixels and 256 KiB encoded. It is optional for both content and code mods; the scaffold does not create one.

Injections belong in the same manifest as top-level [[inject]] tables, with access = "api" or "internals". The decision ladder, the fields and the forms are in the modding book: Injections.