The built-in extras become official mods; these are the calls the FPS
counter and keystrokes overlay need to look and behave the same:
- render.set-corner(corner, w, h, shapes): a box the game places with
its own corner stacking (under the status effects, with the overlays
and hud panels), clear-corner; text-width(text) in the HUD font
(advances for U+0000..U+024F, 6 otherwise); frame-stats(): the game's
FPS counter (fps, min, 1% low).
- input.mapping(name): a movement or click mapping's key label and
whether it is held; clicks-per-second() for attack and use.
- ui: a button widget (200 x 20, select(id, 0)) for settings pages.
- The game keeps its FPS and click counters running while a mod runs,
and refreshes the snapshot every frame for mods with a frame hook.
- The ui test guest gains /corner and /readings, with a sandbox test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 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>
Mods draw through the game's own renderer, never their own shaders:
- WIT `render`: set-hud(shapes) with fill, quad (any four corners),
sprite (the game's GUI sprites), item (scaled) and text shapes, up
to 1024, kept until replaced; gui-size(); shake(strength, seconds).
- Drawn over the HUD after the extras, under chat and screens, hidden
with F1 (game/mod_render.rs). Colours are 0xAARRGGBB.
- shake turns the view, not the player: jolts fade out squared, add up
to 1, at most 3 degrees of yaw and 2 of pitch, scaled by Distortion
Effects (screenEffectScale; 0 turns it off).
- Experimental: the manifest needs experimental = ["render"].
- No mod drawing, no cost: an empty iterator and an is_empty check.
- cargo horizon-mod check reports shakes and HUD shapes. The ui test
guest gains /render_hud, /render_clear and /render_shake, with a
sandbox test; HudBatch gets fill_quad.
- Docs: mods.md, stability.md, the changelog, the regenerated reference.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New WIT interface `ui` (text, item and list widgets; open-screen,
close-screen, set-settings) plus a `ui-events` export (select, closed,
settings-opened), in a second world `horizon-ui-mod` so mods built before
it keep loading. The game lays out and draws the widgets with its own
menus' code: a screen the mod owns (Esc/Done to leave) and a Settings
button on the mod's Options > Mods row that opens its page.
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
docs/api/mods-reference.md lists every capability, world, interface, type,
function and hook of horizon:mods, generated from
crates/horizon-mod-sdk/wit/horizon.wit and the manifest's capabilities by a
test in horizon-mods (feature pack, as CI runs it). The test fails when the
page is out of date (HORIZON_WRITE_DOCS=1 rewrites it), when a function has
no doc comment, or when a capability grants an interface the contract lacks.
The WIT's undocumented functions and fields get doc comments (no change to
the contract itself).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>