- WIT `input`: claim-items(ids) makes the use button on those items the mod's: use-start, then use-stop with the ticks held (button up, item out of the hand, or a screen opening); the game does nothing else with the click. register-key(name, label, key) for up to 16 keys (key.keyboard.r), heard as key-down / key-up while playing; the game's own mapping on the key still runs. held(), poll() (256 kept). - game/mod_input.rs: play_mouse asks mod_use first (local and remote windows), the tick ends a use whose item left the hand, the keyboard and horizon-ctl's key send the physical key to mod_key. - No claim and no key, no cost: one check each. - Experimental: the manifest needs experimental = ["input"]. - The ui test guest gains /input_claim, /input_poll and /input_held, with a sandbox test. Docs: mods.md, stability.md, the changelog, the regenerated reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
14 KiB
Mod API reference
The contract between Horizon and its mods: the WIT package horizon:mods@0.1.0, every interface, type, function and hook in it, and the capabilities a manifest may list. The guide is mods.md; stability and versions: stability.md. Manifest api lines this game serves: 0.1, 0.2.
Capabilities
In capabilities |
Grants | The player reads "May …" |
|---|---|---|
game-read |
game |
see your position, health and the time |
chat |
chat |
show you chat messages |
hud |
hud |
draw text on your screen |
storage |
storage |
save its own settings to disk |
registries |
data files (assets/, data/), no interface |
add blocks and items to your worlds |
ui |
ui |
show its own screens and a settings page |
render |
render |
draw on your screen and shake the camera |
input |
input |
take over the use button on its own items, and add keys |
World horizon-mod
- Imports (what the game offers):
log,game,chat,hud,storage - Exports (what the mod provides):
events
World horizon-ui-mod
A mod with widgets (capability ui): the SDK builds every mod against this world. Mods built for horizon-mod alone (no ui-events export) still load and simply hear nothing of their widgets.
- Imports (what the game offers):
ui,render,input,log,game,chat,hud,storage - Exports (what the mod provides):
ui-events,events
World ui-host
The game's side of horizon-ui-mod beyond horizon-mod.
- Imports (what the game offers):
ui - Exports (what the mod provides):
ui-events
World render-host
The game's side of capability render (imports only).
- Imports (what the game offers):
render,input - Exports (what the mod provides):
log
Access: always granted.
The mod's log, in the game's log under the mod's id. Always granted.
enum level
| Case | |
|---|---|
debug |
|
info |
|
warn |
|
error |
| Function | Signature | What it does |
|---|---|---|
write |
func(level: level, message: string) |
One line in the game's log as [mod <id>] message, at that level. |
game
Access: capability game-read.
Capability game-read: the local player and the world clock.
record player
| Field | Type | |
|---|---|---|
x |
f64 |
Feet position, in blocks. |
y |
f64 |
|
z |
f64 |
|
yaw |
f32 |
Degrees, as F3 shows them. |
pitch |
f32 |
Degrees: -90 looks straight up, 90 straight down. |
health |
f32 |
Hit points as vanilla counts them: 20 is full health without effects. |
food |
u32 |
0 to 20, as the hunger bar. |
dimension |
string |
minecraft:overworld, minecraft:the_nether, ... |
record clock
| Field | Type | |
|---|---|---|
game-time |
u64 |
Ticks since the world was created. |
day-time |
u64 |
24000 ticks per day; 0 is 6:00 on the first day. |
| Function | Signature | What it does |
|---|---|---|
get-player |
func() -> option<player> |
None on the title screen. |
get-clock |
func() -> option<clock> |
None on the title screen. |
chat
Access: capability chat.
Capability chat: messages only the local player sees.
| Function | Signature | What it does |
|---|---|---|
show |
func(text: string) |
Shown in chat after the mod's name, like a system message. |
hud
Access: capability hud.
Capability hud: one panel of text lines per mod, drawn by the game every frame until the mod changes or clears it (no call per frame).
enum corner
| Case | |
|---|---|
top-left |
|
top-right |
|
bottom-left |
|
bottom-right |
record line
| Field | Type | |
|---|---|---|
text |
string |
Plain text, up to 256 characters. |
color |
u32 |
0xRRGGBB. |
| Function | Signature | What it does |
|---|---|---|
set-panel |
func(corner: corner, lines: list<line>) |
Replaces the mod's panel: up to 16 lines in that corner of the screen. |
clear |
func() |
Removes the mod's panel. |
storage
Access: capability storage.
Capability storage: a per-mod folder of small key/value files, quota'd (docs/mods.md). Keys are [a-z0-9_.-]{1,64}, one path segment.
| Function | Signature | What it does |
|---|---|---|
get |
func(key: string) -> option<list<u8>> |
None if key has never been set, or the key is not well-formed. |
set |
func(key: string, value: list<u8>) -> result<_, string> |
Errs on a malformed key or over quota (bytes for the whole mod). |
delete |
func(key: string) |
No error if key was already absent. |
ui
Access: capability ui.
Capability ui: widgets the game draws with its own menus' widgets, for a screen the mod owns and a settings page in Options > Mods. Layout and drawing are the game's: a mod says what its widgets hold, never where they sit or how they look, and the game clips everything it is handed.
record text-widget
A line of text.
| Field | Type | |
|---|---|---|
id |
u32 |
The mod's own name for the widget; ui-events calls echo it. |
text |
string |
Up to 256 characters. |
color |
u32 |
0xRRGGBB; 0 is the menus' white. |
record item-widget
An item's icon and a name beside it, as recipe viewers show them.
| Field | Type | |
|---|---|---|
id |
u32 |
The mod's own name for the widget. |
item |
string |
minecraft:diamond, <mod>:<path>; an unknown id draws a "?". |
name |
string |
The name shown beside the icon (empty: the item's own). |
record list-widget
Rows the player picks one of, as an options page lists choices: a pick is ui-events::select, selected is the row to mark now.
| Field | Type | |
|---|---|---|
id |
u32 |
The mod's own name for the widget; ui-events::select echoes it. |
rows |
list<string> |
The rows' texts, at most 512, each up to 256 characters. |
selected |
option<u32> |
The row to mark as the current choice, if any. |
variant widget
A thing on a mod's screen or settings page.
| Case | Payload | |
|---|---|---|
text |
text-widget |
Text the player reads. |
item |
item-widget |
An item's icon and name. |
list |
list-widget |
Rows the player picks from. |
record screen
A screen the mod owns: a title over widgets stacked down the middle, the Done button the game adds, and Esc to leave it.
| Field | Type | |
|---|---|---|
title |
string |
Its title, up to 256 characters. |
widgets |
list<widget> |
Its widgets, in order, at most 64. |
| Function | Signature | What it does |
|---|---|---|
open-screen |
func(screen: screen) |
Show screen over the game; a second call while it is open replaces it. Only the last call of one hook counts. |
close-screen |
func() |
Close the mod's screen when it is open (the mod hears no closed for this: it was its own doing). |
set-settings |
func(widgets: list<widget>) |
The mod's page in Options > Mods, reached from a settings button on its row: the widgets it shows, an empty list for no page. The player opening the page is ui-events::settings-opened: push fresh widgets then; later calls update the page while it shows. |
ui-events
Access: exported by the mod: the game calls it.
What the game calls on a mod that shows widgets (capability ui): what the player did with them.
| Function | Signature | What it does |
|---|---|---|
select |
func(id: u32, row: u32) |
A row of one of the mod's list widgets was picked: the widget's id and the row, on the screen or the settings page that showed it. |
closed |
func() |
The player left the mod's screen (Esc or Done); not for a screen the mod closed itself or one that went away with the mod. |
settings-opened |
func() |
The player opened the mod's settings page in Options > Mods: call ui::set-settings now to fill it with fresh widgets. |
input
Access: capability input.
Capability input (experimental: the manifest needs experimental = ["input"]): the use button on items the mod claims, and the mod's own keys. Events wait for poll, at most 256.
record held-item
The main hand's stack.
| Field | Type | |
|---|---|---|
id |
string |
minecraft:spyglass, <mod>:<path>. |
count |
u32 |
|
slot |
u32 |
The hotbar slot, 0 to 8. |
record item-use
| Field | Type | |
|---|---|---|
item |
held-item |
|
ticks |
u32 |
Game ticks the button was held (0 on use-start). |
variant event
| Case | Payload | |
|---|---|---|
use-start |
item-use |
The use button went down with a claimed item in the main hand. The game does nothing else with the click: no placing, no eating, no swing. |
use-stop |
item-use |
It came up again, or the item left the hand, or a screen opened. |
key-down |
string |
A key register-key named went down or up while playing (no screen open). The game's own mapping on that key still runs. |
key-up |
string |
| Function | Signature | What it does |
|---|---|---|
claim-items |
func(ids: list<string>) |
The items whose use the mod handles instead of the game, by id (at most 64). Replaces the previous list. |
register-key |
func(name: string, label: string, key: string) -> result<_, string> |
A key of the mod's: name comes back in key-down and key-up, label says what it does, key is the key as options.txt writes it (key.keyboard.r). At most 16; an unknown key is an error. |
held |
func() -> option<held-item> |
The main hand's stack, as of this tick; none when it is empty. |
poll |
func() -> list<event> |
The events since the last call, oldest first. |
render
Access: capability render.
Capability render (experimental: the manifest needs experimental = ["render"]): shapes the game draws for the mod with its own renderer, kept until the mod replaces them (no call per frame). A mod never supplies shader code.
record rect
A rectangle in GUI pixels: the top left corner and the size.
| Field | Type | |
|---|---|---|
x |
f32 |
|
y |
f32 |
|
w |
f32 |
|
h |
f32 |
record point
A point in GUI pixels from the screen's top left.
| Field | Type | |
|---|---|---|
x |
f32 |
|
y |
f32 |
record fill-shape
| Field | Type | |
|---|---|---|
rect |
rect |
|
color |
u32 |
0xAARRGGBB. |
record quad-shape
Any four-cornered shape (a wheel's segment, an arrow): the corners in order round it.
| Field | Type | |
|---|---|---|
corners |
tuple<point, point, point, point> |
|
color |
u32 |
0xAARRGGBB. |
record sprite-shape
| Field | Type | |
|---|---|---|
sprite |
string |
One of the game's GUI sprites, as gui/sprites/ names them (hud/heart/full, widget/button), the resource packs' versions included. An unknown one draws nothing. |
rect |
rect |
|
color |
u32 |
A tint, 0xAARRGGBB: 0xFFFFFFFF draws it as it is. |
record item-shape
| Field | Type | |
|---|---|---|
item |
string |
minecraft:diamond, <mod>:<path>; an unknown one draws nothing. |
at |
point |
The icon's top left. |
scale |
f32 |
1.0 is the hotbar's 16 × 16. |
record text-shape
| Field | Type | |
|---|---|---|
text |
string |
Up to 256 characters, one line. |
at |
point |
|
color |
u32 |
0xRRGGBB, as hud's lines. |
centered |
bool |
Centred on at.x instead of starting there. |
shadow |
bool |
variant shape
| Case | Payload | |
|---|---|---|
fill |
fill-shape |
|
quad |
quad-shape |
|
sprite |
sprite-shape |
|
item |
item-shape |
|
text |
text-shape |
| Function | Signature | What it does |
|---|---|---|
set-hud |
func(shapes: list<shape>) |
Replaces the mod's HUD shapes: up to 1024, drawn every frame in order over the HUD (after the hotbar, under chat and screens), hidden with the HUD (F1). An empty list removes them. |
gui-size |
func() -> tuple<f32, f32> |
The screen's size in GUI pixels (width, height), as of this tick. |
shake |
func(strength: f32, seconds: f32) |
Shakes the camera: a jolt of strength (0 to 1, 1 the hardest) that fades out over seconds (at most 10). Jolts add up to 1. The view turns, the player doesn't, and the player's Distortion Effects option scales it (0 turns it off). |
events
Access: exported by the mod: the game calls it.
What the game calls. Only the hooks init asks for are ever called.
record registration
| Field | Type | |
|---|---|---|
commands |
list<string> |
Chat commands, without the slash. A name vanilla already uses is refused (vanilla's command runs). |
tick |
bool |
Call tick every game tick (20 per second while playing). |
frame |
bool |
Call frame every rendered frame. Budget: 0.1 ms. |
chat |
bool |
Call chat for each chat line the player receives. |
| Function | Signature | What it does |
|---|---|---|
init |
func() -> result<registration, string> |
Once, after loading. An error keeps the mod off and is shown. |
tick |
func(tick: u64) |
Each game tick while in a world, with the game's tick counter. |
frame |
func(seconds: f32) |
Each rendered frame, with the seconds since the last one. |
command |
func(name: string, args: string) -> result<option<string>, string> |
/name args: ok(some(text)) is shown as feedback, err(text) in red. |
chat |
func(text: string) |
Each chat line the player receives, as plain text. |