Skip to content

Examples

The example mods that ship with the SDK under <exe>/sdk/examples/<id>/, extracted from each one's mod.toml header. Copy one into your mods directory to run it; start from the one nearest to your idea.

hello-anchor — Hello Anchor

v0.1.0 · writes no guest RAM · src: hello.c

hello-anchor: the smallest code mod. A named override that logs, calls base(), and publishes a counter to the Mods panel.

The mod reads and writes no guest RAM, so gameplay is byte-identical with it enabled. The three keys below declare that to the engine; each one changes how the engine treats the mod under savestates, runahead and memory-card tagging.

natural-gems — Natural Gems

v0.1.0 · writes guest RAM · src: natural_gems.c

natural-gems: every gem pickup counts double, written against the typed wrapper surface.

OP_OVERRIDE_IMPL_CollectItem gives the override a typed Moby* parameter, op_base_CollectItem falls through with natural arguments, and op_call_Sin makes a typed call into an unrelated game function. The mod writes g_GemTotal, so it is mutative: a memory card played with it enabled carries the modset tag.

hud-stopwatch — HUD Stopwatch

v0.1.0 · writes no guest RAM · [[binding]], [[config]] · src: stopwatch.c

hud-stopwatch: an "M:SS.hh" gameplay stopwatch drawn as HUD text.

A tick hook counts sim ticks; a present hook evaluates the time at ctx->alpha and draws it, so the hundredths advance smoothly at a high --render-fps. The engine never interpolates mod visuals; the mod owns its sub-tick curve. Time base: sim ticks / 29.913. The mod draws through draw_text only and writes no guest RAM. A [[binding]] resets the watch.

crt-beans — CRT (crt-beans)

v1.0.0 · writes no guest RAM · [[config]] · src: crt_beans.c

crt-beans: CRT display simulation. A port of Andrew Duffey's crt-beans, the "fast" three-pass variant (MIT, see LICENSE).

Electron-beam spot brightness and width vary with signal intensity, so scanlines stay correct at any output resolution. An aperture-grille phosphor mask follows. Post-process only: the passes read the composed frame and write pixels, and the mod never touches guest RAM.

The [[config]] rows below are the schema the Mods panel renders. The values live in config.toml; a committed edit reloads the mod and entry re-reads them. Each help string is what the panel shows as a tooltip.

declarative-example — Declarative Example

v0.1.0 · writes no guest RAM · [[material]]

declarative-example: every feature a mod can use with no code, in one mod. No src/, no entry point, nothing compiled on the host. The mod is this manifest, three asset files and one fragment shader.

Custom levels ([[level]]) are the one declarative feature not shown here; the Custom levels page and grim-garden cover them. [[binding]] and [[config]] rows are read by a mod's own code, so they belong to a code mod; hud-stopwatch shows both.

What each part demonstrates:

assets/textures/57c653dc7ca515a1-0x0+256x129-a2fb97e3755b706b-8bpp.png A texture replacement named by content: the upload's hash, the texel box within the upload, the palette hash and the bit depth. This one is the title-screen logo, a 256x129 box of the 512x256 title UI atlas. Run the game with OPENPETE_TEXPACK_DUMP_DIR=<dir> set and every drawn texture is written under its content name, so a replacement starts by copying a dumped file's name. The image is a 512x258 magenta and cyan checker, twice the box in each axis: the renderer samples a replacement at its own resolution, so a larger file is an HD replacement. The other name form, <name>.png, names a texture by a symbolic identity the game layer annotates, such as title_ui for the whole atlas.

assets/music/manifest.txt + assets/music/title_theme.wav A music replacement through the manifest form: each line maps a track index to a file in this directory. The shorter form is a file named track_NN.wav with no manifest. Track 20 is the title theme; the file is a 440 Hz tone, so the substitution is audible at once.

assets/sfx/gemPickup.wav A sound replacement named by role. gemPickup is the sound-table slot the game plays when Spyro collects a gem, in every level. The other forms name one recording by content hash. The file is a synthesised two-note chime. The game still decides duration, pitch, variance, volume and looping; a -flat suffix pins the file to its own rate.

[[material]] rows + shaders/tint.frag Each row registers the shader with a selector. The engine decides per draw whether the shader runs; the shader receives the colour the engine was about to write and returns the colour to write. A material inherits its draw group's blend mode and draw order and changes colour math only. The rows below use every selector key that needs no per-level id: channel, ident, tier, textured, env_anim, params, enabled. class, texture and level key on ids that differ per level.

Nothing in an asset-only mod reaches guest RAM: every substitution happens on the host, so gameplay is byte-identical with the mod enabled, and the engine derives sim_mutative = false from the absence of src/ and [[level]].

When several enabled mods ship the same file or select the same draw, the mod listed later in enabled.txt wins.

v0.1.0 · writes no guest RAM · [[config]] · src: channel_gallery.c

channel-gallery: one material selector per render channel, toggled live.

Every row registers the same highlight shader with a different selector, so ticking a row shows exactly what that selector claims. It answers "can I shade only X?" for each channel and key, and shows which draw paths are not separately addressable.

Materials are display-only: they reshade what the renderer already drew and cannot move, reorder or re-composite anything.

Rows are claims about the engine. A row that lights is selectable; a row that stays dark is not yet. A change to what is selectable updates this mod in the same change: a new channel or key gets a row, a newly reachable draw path gets its row re-verified. Rows that cannot light yet stay, labelled as known gaps.

teapot-dragons — Teapot Dragons

v0.1.0 · writes guest RAM · [[config]] · src: teapot_dragons.c

teapot-dragons: every crystallised dragon statue is a Utah teapot.

The densest single model the Spyro 1 animated-moby format admits (a 255-vertex count byte, 9-bit face indices), parked in the mod arena and installed over the level's crystal-dragon class (250, the last model of every level) from a PatchMobyModelPointers post-hook. The geometry is generated from the public-domain Newell teapot patch data by tools/gen_teapot.py into assets/teapot_s1pack.bin, so the mod ships no disc-derived bytes.