game
| Kind | kit |
|---|---|
| Capabilities | ffi file |
| Categories | graphics gamedev |
| Keywords | game gamedev graphics 2d raylib |
A LÖVE-inspired game development framework for Kit
Disclaimer
This project is still a work-in-progress and may not work correctly.
Files
| File | Description |
|---|---|
.editorconfig | Editor formatting configuration |
.gitignore | Git ignore rules for build artifacts and dependencies |
.tool-versions | asdf tool versions (Zig, Kit) |
LICENSE | MIT license file |
README.md | This file |
examples/breakout.kit | Breakout example with ball physics, bricks, and scoring |
examples/cache-reload-polling.kit | Context service cache/reload/debug render example |
examples/camera.kit | Camera example |
examples/collision.kit | Collision example |
examples/context-debug.kit | Context-owned debug overlay and watch example |
examples/context-replay-session.kit | Context-owned replay session service example |
examples/dev-runner-plan.kit | External dev runner script plan example |
examples/dev-session-watch.kit | Source/asset dev session watch example |
examples/fixed-render-viewport.kit | Fixed-step render queue example with action maps, camera, and a logical viewport |
examples/immediate-render-mix.kit | Mixed immediate-mode and render-command viewport example |
examples/hybrid-test.kit | Hybrid package/import smoke example |
examples/input-rebinding.kit | Local-player keyboard/controller profile switching and action rebinding example |
examples/logical-render-viewport.kit | Automatic logical render target viewport example |
examples/minimal-test.kit | Minimal import smoke example |
examples/particles.kit | Particle system example |
examples/platformer.kit | Platformer with tilemap collision, physics, camera, and debug overlay |
examples/pong.kit | Pong example |
examples/replay-export-plan.kit | Replay browser/report/manifest export plan example |
examples/replay-file-debug.kit | Replay file persistence, deterministic verification, browser panel, and render/debug diagnostics |
examples/replay-live.kit | Live input recording and playback example using fixed ticks and render commands |
examples/render-sprite-cache.kit | Render command queue example with explicit sprite-path cache ownership |
examples/render-target-screenshot.kit | Render target and screenshot example |
examples/scaffold-plan.kit | Starter project scaffold plan and safe script artifact example |
examples/shooter.kit | Shooter example |
examples/simple.kit | Simple moving-circle example |
examples/tilemap.kit | Procedural tilemap example |
examples/topdown.kit | Top-down collector with camera and high-score persistence |
examples/touch-viewport.kit | Touch and mouse input through a logical viewport |
examples/viewport-scissor.kit | Logical viewport example with backend scissor clipping |
examples/support/basic-game.kit | Support facade for basic examples |
examples/support/breakout-game.kit | Support facade for Breakout |
examples/support/collision-game.kit | Support facade for collision examples |
examples/support/particles-game.kit | Support facade for particle examples |
examples/support/platformer-game.kit | Support facade for the platformer example |
examples/support/shooter-game.kit | Support facade for the shooter example |
examples/support/tilemap-game.kit | Support facade for tilemap examples |
examples/support/topdown-game.kit | Support facade for the top-down example |
kit.toml | Package manifest with metadata, dependencies, and tasks |
src/assets.kit | Texture, sound, and font loading helpers |
src/audio.kit | Sound effect and music helpers |
src/auto-save.kit | Auto-save timer utilities |
src/backend/interface.kit | Backend-facing texture handle interface |
src/backend/raylib-slim.kit | Slim raylib FFI facade used by the framework |
src/backend/raylib.kit | Raylib backend adapter |
src/backend/select.kit | Backend selection module |
src/cache.kit | Asset cache for textures, sounds, and fonts |
src/camera.kit | 2D camera with follow, shake, and transforms |
src/collision.kit | Collision detection helpers |
src/colors.kit | Packed color constants and utilities |
src/context.kit | Runtime context helpers for opt-in context-aware loops |
src/debug.kit | Debug overlay and development tools |
src/ecs.kit | Entity Component System helpers |
src/fixed-tick.kit | Deterministic fixed-step simulation helpers |
src/game.kit | Core game loop implementation |
src/graphics.kit | Drawing primitives and text rendering |
src/input.kit | Keyboard, mouse, and gamepad input |
src/math.kit | Vector, interpolation, angle, and easing helpers |
src/package.kit | Public package entry point |
src/particles.kit | Particle emitters and effects |
src/physics.kit | Basic rigid body physics helpers |
src/pool.kit | Object pool utilities |
src/quadtree.kit | Spatial partitioning quadtree |
src/render.kit | Optional inspectable render command queue |
src/replay.kit | Input snapshot recording, JSON replay files, and deterministic playback |
src/save.kit | JSON-based save/load game state |
src/scene.kit | Scene stack and transition helpers |
src/sprite.kit | Static and animated sprite helpers |
src/template.kit | Project template generator |
src/tilemap-procedural.kit | Procedural tilemap helper surface for examples |
src/tilemap.kit | Tilemap rendering, collision, JSON loading, and TMX loading |
src/topdown-save.kit | Small high-score save helper for the top-down example |
src/viewport.kit | Logical canvas scaling and coordinate conversion helpers |
tests/auto-save.test.kit | Tests for auto-save helpers |
tests/cache.test.kit | Tests for the asset cache |
tests/collision.test.kit | Tests for collision helpers |
tests/compress.test.kit | Tests for compressed tile data helpers |
tests/context.test.kit | Tests for runtime context helpers |
tests/debug-console.test.kit | Tests for debug console helpers |
tests/debug.test.kit | Tests for debug overlay helpers |
tests/ecs.test.kit | Tests for ECS helpers |
tests/fixed-tick.test.kit | Tests for fixed-step simulation helpers |
tests/game.test.kit | Tests for core game helpers |
tests/input.test.kit | Tests for input snapshots and action maps |
tests/minimal-import.test.kit | Minimal import smoke test |
tests/module-structure.test.kit | Tests for public module structure |
tests/physics.test.kit | Tests for physics helpers |
tests/pool.test.kit | Tests for object pools |
tests/render.test.kit | Tests for render command data and queue helpers |
tests/replay.test.kit | Tests for replay recording and playback helpers |
tests/save-versioned.test.kit | Tests for versioned saves |
tests/save.test.kit | Tests for saves |
tests/template.test.kit | Tests for template generation |
tests/tmx.test.kit | Tests for TMX helpers |
tests/viewport.test.kit | Tests for viewport scaling and coordinate conversion |
Dependencies
Installation
kit add gitlab.com/kit-lang/packages/kit-game.gitUsage
import Kit.Game as Game
type State = {x: Float, y: Float, speed: Float}
init = fn => {x: 400.0, y: 300.0, speed: 200.0}
update = fn(state, dt) =>
dx = if Game.Input.key-down? "d" then
state.speed * dt
else if Game.Input.key-down? "a" then
0.0 - state.speed * dt
else
0.0
dy = if Game.Input.key-down? "s" then
state.speed * dt
else if Game.Input.key-down? "w" then
0.0 - state.speed * dt
else
0.0
{x: state.x + dx, y: state.y + dy, speed: state.speed}
draw = fn(state) =>
Game.Graphics.clear Game.Colors.dark-gray
Game.Graphics.circle state.x state.y 25.0 Game.Colors.cyan
Game.Graphics.text "WASD to move" 10.0 10.0 Game.Colors.white
main = fn =>
Game.run {
title: "My Game",
width: 800,
height: 600,
fps: 60,
init: init,
update: update,
draw: draw
}
mainGame.run Configuration
| Field | Type | Default | Description |
|---|---|---|---|
title | String | "Kit Game" | Window title |
width | Int | 800 | Window width |
height | Int | 600 | Window height |
fps | Int | 60 | Target frames per second |
init | State | required | Initial game state value |
update | fn(State, Float) => State | required | Update state with delta time |
draw | fn(State) => () | required | Render the game |
resizable | Bool | false | Allow window resizing |
vsync | Bool | true | Enable vertical sync |
fullscreen | Bool | false | Start in fullscreen |
Available Modules
Game.Graphics- Shape drawing and text renderingGame.Input- Keyboard, mouse, and gamepad inputGame.Audio- Sound effects and musicGame.Assets- Texture, sound, and font loadingGame.Sprite- Static and animated spritesGame.Tilemap- Tile-based maps, Tiled JSON, and Tiled TMX XMLGame.Camera- 2D camera with follow and shakeGame.Collision- AABB, circle, line, and swept AABB collision helpersGame.Particles- Particle emitters and effectsGame.ECS- Lightweight Entity Component SystemGame.Scene- Scene stack managementGame.Save- JSON-based save/load game stateGame.Debug- Debug overlay, FPS counter, watches, pause/step, and profilingGame.Dev- Development-time asset reload helpersGame.Math- Vectors, interpolation, angles, and easingGame.Menu- Data-first menu and pause-screen helpersGame.Colors- Packed color constants and utilitiesGame.Context- Runtime context helpers for opt-in context-aware loopsGame.FixedTick- Deterministic fixed-step simulation helpersGame.Replay- Input snapshot recording, JSON replay files, and deterministic playbackGame.Render- Optional inspectable render command queueGame.Viewport- Logical canvas scaling and coordinate conversion helpersGame.Cache- Asset cache and preload helpersGame.Release- Release packaging plan helpersGame.Template- Project template generatorGame.Pool- Object pools for reusable entitiesGame.Physics- Basic rigid body physics helpersGame.AutoSave- Periodic auto-save state helpers
Architecture
Game Loop
Module Structure
Debug Tools
The Game.Debug module provides development aids:
init = fn => {
player: {x: 100.0, y: 100.0},
debug: Game.Debug.create {enabled: false}
}
update = fn(state, dt) =>
debug = if Game.Input.key-pressed? "p" then
Game.Debug.toggle-pause state.debug
else
state.debug
debug2 = if Game.Input.key-pressed? "n" and Game.Debug.is-paused? debug then
Game.Debug.step debug
else
debug
new-player = if Game.Debug.should-advance? debug2 then
update-player state.player dt
else
state.player
debug3 = Game.Debug.consume-step debug2
debug4 = Game.Debug.update debug3 dt
{...state, player: new-player, debug: debug4}
draw = fn(state) =>
debug = Game.Debug.profile-start state.debug "draw-world"
draw-world state
debug2 = Game.Debug.profile-end debug "draw-world"
debug3 = Game.Debug.watch debug2 "Player X" (Float.to-string state.player.x)
Game.Debug.draw debug3Context-Aware Loop
Use Game.run-with-context when you want update and draw callbacks to receive
timing, window state, an input snapshot, optional viewport state, and explicit
runtime services in one record:
init = fn => {
actions: Game.Input.create-actions [
Game.Input.key-binding "jump" "space"
],
jumping: false
}
update = fn(state, ctx) =>
if Game.Input.action-down? state.actions ctx.input "jump" then
{...state, jumping: true}
else
state
draw = fn(state, ctx) =>
Game.Graphics.clear Game.Colors.black
Game.Graphics.text "Frame ${ctx.frame}" 10.0 10.0 Game.Colors.white
main = fn =>
Game.run-with-context {
title: "Context Game",
width: 800,
height: 600,
fps: 60,
init: init,
viewport: Game.Viewport.create-with-mode 320 180 "fit",
update: update,
draw: draw
}Contexts include ctx.services with explicit cache, debug, dev, and
replay slots, plus context-owned debug helpers. Pass a services: record in
the run config when callbacks should receive a specific bundle, or use the pure
helpers for synthetic contexts in tests:
services = Game.Context.services Game.Cache.create {...Game.Debug.empty, enabled: true}{}
ctx = Game.Context.with-services Game.Context.empty services
ctx2 = Game.Context.update-debug ctx
ctx3 = Game.Context.watch-debug ctx2 "Mode" "test"
debug = Game.Context.debug ctx3
service-lines = Game.Context.service-lines ctx3See examples/context-debug.kit for a loop that persists context-owned debug
state, watches, scene/entity metadata, and profile markers into game state.
Context helpers can also own development asset reload state while keeping the
cache explicit and synchronized:
reloader = Game.Dev.create-asset-reloader ctx.services.cache [
"sprites/player.png",
"audio/jump.wav"
]
ctx2 = Game.Context.with-asset-reloader ctx reloader
ctx3 = Game.Context.poll-asset-reloader ctx2
cache = ctx3.services.cache
reload-lines = Game.Context.asset-reloader-lines ctx3The same ctx.services.dev slot can hold a source-aware dev runner. Polling the
runner updates the latest command record and keeps the context cache synchronized
with the runner session:
runner = Game.Dev.create-runner ctx.services.cache ["sprites/player.png"] ["src/main.kit"]
ctx2 = Game.Context.with-runner ctx runner
ctx3 = Game.Context.poll-runner ctx2
command = Game.Context.runner-command ctx3
runner-lines = Game.Context.runner-lines ctx3
service-view = Game.Context.service-view ctx3See examples/cache-reload-polling.kit for a render-command loop that keeps
cache, asset reload state, replay state, service summaries, and debug watches
together in one context service record.
Replay sessions can live in ctx.services.replay through Game.Replay context
helpers:
ctx2 = Game.Replay.with-context-session ctx (Game.Replay.create-session replay)
ctx3 = Game.Replay.toggle-context-playback ctx2
sim-ctx = Game.Replay.step-context-session ctx3
session = Game.Replay.context-session sim-ctxSee examples/context-replay-session.kit for a synthetic context example that
steps playback input and records live input through the context service slot.
Input Action Maps
Game.Input action maps are plain records over input snapshots, so games,
tests, and replay tools can share the same input queries:
actions = Game.Input.create-actions [
Game.Input.key-binding "jump" "space",
Game.Input.key-axis-binding "move-x" "a" (0.0 - 1.0),
Game.Input.key-axis-binding "move-x" "d" 1.0,
Game.Input.gamepad-axis-binding "move-x" "left-x" 0 0.25 1.0
]
if Game.Input.action-pressed? actions ctx.input "jump" then
print "jump"
else
print "grounded"
dx = Game.Input.axis actions ctx.input "move-x"
move = Game.Input.vector actions ctx.input "move"Snapshots also carry a last-device field. Game.Input.infer-last-device
can derive it from synthetic snapshots, including mouse motion, wheel input,
touch points, gamepad axes, and held input fallback. Touch snapshots store
active points as {index, id, x, y} records:
match Game.Input.snapshot-touch-at ctx.input 0
| None -> print "no touch"
| Some touch -> print "touch ${show touch.id} at ${show touch.x}, ${show touch.y}"Use touch regions for virtual buttons in the same coordinate space as the
snapshot. With ctx.viewport, convert input to logical coordinates first:
actions = Game.Input.create-actions [
Game.Input.touch-region-binding "jump" 248.0 112.0 56.0 56.0
]
logical-input = Game.Viewport.input-to-logical ctx.viewport ctx.input
jump-held? = Game.Input.action-down? actions logical-input "jump"
jump-started? = Game.Input.action-started? actions state.previous-input logical-input "jump"
jump-ended? = Game.Input.action-ended? actions state.previous-input logical-input "jump"Touch gesture helpers compare previous/current snapshots, so they work with
live input, replay data, and viewport-converted logical input:
match Game.Input.first-touch-swipe state.previous-input logical-input 32.0
| None -> no-op
| Some swipe -> print "swipe ${swipe.direction}"
match Game.Input.touch-pinch state.previous-input logical-input
| None -> no-op
| Some pinch -> print "pinch scale ${show pinch.scale}"Gesture bindings can participate in action maps through action-started?:
actions = Game.Input.create-actions [
Game.Input.touch-swipe-binding "dash" "right" 32.0,
Game.Input.touch-pinch-binding "zoom-out" "out" 8.0
]
dash? = Game.Input.action-started? actions state.previous-input logical-input "dash"
zoom? = Game.Input.action-started? actions state.previous-input logical-input "zoom-out"Action maps can be updated immutably for rebinding workflows, round-tripped as
JSON text, or saved to explicit settings files with file capabilities:
rebound = Game.Input.rebind-key actions "jump" "enter"
with-alt = Game.Input.add-binding rebound (Game.Input.mouse-binding "jump" "left")
text = Game.Input.stringify-actions with-alt
match Game.Input.parse-actions text
| Err e -> print "Input settings error: ${e}"
| Ok loaded -> print "Bindings: ${show (List.length loaded.bindings)}"
path = Game.Input.actions-path "player1"
Game.Input.save-actions-file write-auth path with-alt
loaded-result = Game.Input.load-actions-file read-auth pathFor rebinding screens, build a preview first so the UI can show conflicts
before applying the change:
change = Game.Input.binding-change actions "jump" (Game.Input.key-binding "jump" "space")
if change.has-conflicts then
print "Conflict with ${show (List.length change.conflicts)} binding(s)"
else
print "No conflict"
updated = Game.Input.apply-binding-change-clearing-conflicts actions changeView helpers expose labels, stable source keys, conflict rows, and action
summaries for rebinding screens without changing the saved action-map data:
binding-views = Game.Input.action-binding-views actions "jump"
change-view = Game.Input.binding-change-view change
profile-summary = Game.Input.profile-view (Game.Input.create-profile "keyboard" actions)For multiple layouts, store named profiles with an active/default convention:
profiles = Game.Input.create-profiles "keyboard" [
Game.Input.create-profile "keyboard" actions,
Game.Input.create-profile "controller" controller-actions
]
profiles2 = Game.Input.set-active-profile profiles "controller"
current-actions = Game.Input.active-actions profiles2
profiles3 = Game.Input.rebind-active-key profiles2 "jump" "enter"
text = Game.Input.stringify-profiles profiles3
profiles-view = Game.Input.profiles-view profiles3Active-profile helpers also support mouse/gamepad rebinding and conflict-aware
preview/application without manually unpacking profile action maps:
change = Game.Input.active-binding-change profiles2 "jump" (Game.Input.gamepad-button-binding "jump" "a" 0)
if change.has-conflicts then
print "Active profile conflict"
else
print "Ready"
profiles4 = Game.Input.apply-active-binding-change profiles2 change
profiles5 = Game.Input.apply-active-binding-change-clearing-conflicts profiles2 changeFor local multiplayer, wrap each player's profile set in a player profile set.
This gives menus one active player, per-player active profiles, view data, and a
single JSON/file persistence surface:
players = Game.Input.create-player-profile-set "p1" [
Game.Input.create-player-profiles "p1" profiles,
Game.Input.create-player-profiles "p2" profiles2
]
players2 = Game.Input.set-active-player players "p2"
players3 = Game.Input.set-player-active-profile players2 "p2" "controller"
actions = Game.Input.active-player-actions players3
view = Game.Input.player-profile-set-view players3
path = Game.Input.player-profile-set-path "local"
Game.Input.save-player-profile-set-file write-auth path players3
loaded-players = Game.Input.load-player-profile-set-file read-auth pathLogical Viewports
Game.Viewport maps a logical canvas to a physical window. It supports
"fit", "fill", "stretch", and "integer-fit" scaling modes and composes
with Game.Camera for world coordinate conversion:
viewport = Game.Viewport.from-window 320 180{
width: 800,
height: 600,
focused: true,
fullscreen: false,
minimized: false
} "fit"
logical = Game.Viewport.screen-to-logical viewport 400.0 300.0
screen = Game.Viewport.logical-to-screen viewport logical.x logical.yContext-aware loops resize config.viewport to the live window each frame and
attach it to ctx.viewport. Mouse and touch snapshots can be converted into
logical canvas coordinates:
update = fn(state, ctx) =>
logical-input = Game.Viewport.input-to-logical ctx.viewport ctx.input
mouse = logical-input.mouse
{...state, cursor: {x: mouse.x, y: mouse.y}}Safe-area helpers accept physical screen insets and return both physical and
logical rectangles after intersecting those insets with the viewport:
insets = Game.Viewport.safe-insets 24.0 48.0 24.0 0.0
safe = Game.Viewport.safe-area ctx.viewport insets
menu-pos = Game.Viewport.clamp-safe-logical ctx.viewport insets state.menu.x state.menu.yMenus And Pause Screens
Game.Menu provides pure menu state helpers that work with input action maps,
snapshots, render queues, and replay data:
menu = Game.Menu.create [
Game.Menu.item "resume" "Resume",
Game.Menu.item "restart" "Restart",
Game.Menu.disabled-item "save" "Save"
]
result = Game.Menu.update-with-actions menu Game.Menu.default-actions ctx.input
menu2 = result.menu
match result.action.kind
| "confirm" ->
match result.action.item
| Some item -> print "Selected ${item.id}"
| None -> no-op
| "back" -> print "Closed menu"
| _ -> no-opGame.Menu.lines returns render-friendly line records with selected and
enabled flags, so games can draw menus with immediate-mode APIs or
Game.Render commands. See examples/menu-pause-screen.kit for a pause
overlay built with Game.run-render-with-context.
Render Command Queue
Game.Render provides an optional data-first drawing path. Render callbacks
return commands, and the render loop executes them through the existing drawing
modules:
render = fn(state, ctx) => [
Game.Render.clear Game.Colors.black,
Game.Render.circle state.x 90.0 16.0 Game.Colors.cyan,
Game.Render.text "Frame ${show ctx.frame}" 10.0 10.0 Game.Colors.white
]
main = fn =>
Game.run-render-with-context {
title: "Render Queue",
width: 800,
height: 600,
fps: 60,
init: {x: 160.0},
viewport: Game.Viewport.create-with-mode 320 180 "fit",
update: fn(state, -ctx) => state,
render: render
}The command surface covers primitive graphics plus sprites, animated sprites,
tilemaps, particles, debug overlays, and camera boundaries. Queues are plain
lists, so tests and debug overlays can inspect them without opening a window:
commands = [
Game.Render.clear Game.Colors.black,
Game.Render.circle 10.0 20.0 5.0 Game.Colors.cyan,
Game.Render.sprite player-sprite 32.0 48.0
]
info = Game.Render.inspect commands
debug = Game.Render.watch-debug Game.Debug.empty commands
assert-eq! info.kinds ["clear", "circle", "sprite"]Render queues can also be executed from an immediate-mode draw callback when
only part of a screen benefits from data-first commands. ctx.viewport keeps
both paths aligned:
draw = fn(state, ctx) =>
Game.Render.execute (Game.Render.letterbox-bars ctx.viewport Game.Colors.black)
p = Game.Viewport.logical-to-screen ctx.viewport state.x 90.0
scale = Float.min ctx.viewport.scale-x ctx.viewport.scale-y
Game.Graphics.circle p.x p.y (16.0 * scale) Game.Colors.cyan
Game.Render.execute (Game.Render.with-viewport ctx.viewport [
Game.Render.text-size "Command HUD" 10.0 10.0 12 Game.Colors.white
])Sprite paths can be resolved through an explicit cache owner while building a
command queue:
queued = Game.Render.sprite-path-queue state.cache [
Game.Render.sprite-ref "assets/player.png" 80.0 90.0,
Game.Render.sprite-ref-tinted "assets/enemy.png" 150.0 90.0 Game.Colors.red
]
state2 = {...state, cache: queued.cache}
commands = queued.commandsWrap world-space commands with a camera using Game.Render.with-camera:
world-commands = Game.Render.with-camera state.camera [
Game.Render.circle state.player.x state.player.y 12.0 Game.Colors.yellow,
Game.Render.tilemap state.map Game.Colors.white
]For path-based sprite commands, keep cache ownership explicit. sprite-path
and sprite-path-tinted return {cache, command} so state can store the
updated cache while rendering stays command-based:
result = Game.Render.sprite-path state.cache "sprites/player.png" state.x state.y
state2 = {...state, cache: result.cache}
commands = [result.command]If the loaded texture is invalid, the command is a missing-asset fallback that
draws an outlined box with a diagonal cross.
Convert logical-canvas commands to physical screen coordinates through a
viewport with Game.Render.with-viewport. Game.Render.with-letterbox also
prepends bar commands for the space outside the viewport. Commands inside a
Game.Render.with-camera block remain in world coordinates while the camera
offset and zoom are scaled to the viewport:
render = fn(state, ctx) =>
Game.Render.with-letterbox ctx.viewport Game.Colors.black [
Game.Render.clear Game.Colors.dark-gray,
Game.Render.circle 160.0 90.0 12.0 Game.Colors.cyan
]Use Game.Render.with-clipped-viewport or
Game.Render.with-clipped-letterbox when the logical scene should be clipped
to the viewport rectangle through the backend scissor mode:
render = fn(state, ctx) =>
Game.Render.with-clipped-letterbox ctx.viewport Game.Colors.black [
Game.Render.clear Game.Colors.dark-gray,
Game.Render.circle state.x state.y 16.0 Game.Colors.cyan
]Use Game.run-logical-render-with-context when the whole render callback should
draw in logical viewport coordinates through a loop-owned render target. This
keeps resize/letterbox presentation out of the render callback while preserving
explicit ctx.viewport access for input and layout. Optional present
callbacks run after the target is drawn to the window, so use them for
screen-space overlays and framebuffer screenshots:
render = fn(state, ctx) => [
Game.Render.clear Game.Colors.black,
Game.Render.circle state.x 90.0 16.0 Game.Colors.cyan,
Game.Render.text-size (String.concat "Frame " (show ctx.frame)) 8.0 8.0 10 Game.Colors.white
]
present = fn(state, ctx) =>
overlay = Game.Render.with-viewport ctx.viewport [
Game.Render.text-size "Press S to capture" 8.0 156.0 10 Game.Colors.white
]
if state.screenshot? then
List.append overlay [Game.Render.screenshot "frame.png"]
else
overlay
main = fn =>
Game.run-logical-render-with-context {
title: "Logical Render",
width: 960,
height: 540,
fps: 60,
init: {x: 160.0, screenshot?: false},
viewport: Game.Viewport.create-with-mode 320 180 "fit",
update: fn(state, ctx) =>
{...state, screenshot?: Game.Input.snapshot-key-pressed? ctx.input "s"},
render: render,
present: present
}Render targets are explicit Game.Graphics resources. Lifecycle helpers keep
target ownership in game state while creating or replacing targets after the
window has opened. Draw into targets with begin-render-target /
end-render-target, then draw them back with immediate helpers or render
commands. Viewport helpers provide the source and destination rectangles for
logical-canvas render targets:
state2 = {
...state,
target-state: Game.Graphics.ensure-viewport-target state.target-state ctx.viewport
}
target = Game.Graphics.render-target-state-target state2.target-state
Game.Graphics.begin-render-target target
Game.Graphics.clear Game.Colors.black
Game.Graphics.circle 160.0 90.0 24.0 Game.Colors.cyan
Game.Graphics.end-render-target
commands = Game.Render.render-target-presentation target ctx.viewport Game.Colors.white Game.Colors.black [
Game.Render.text-size "Captured after presentation" 24.0 20.0 12 Game.Colors.white,
Game.Render.screenshot "frame.png"
]Fixed-Tick Simulation
Use Game.run-fixed when simulation should advance at a deterministic rate
while rendering still happens once per frame:
fixed-update = fn(state, ctx) =>
speed = 120.0 * ctx.dt
dx = Game.Input.axis state.actions ctx.input "move-x" * speed
{...state, x: state.x + dx}
draw = fn(state, ctx) =>
Game.Graphics.clear Game.Colors.black
Game.Graphics.circle state.x 300.0 16.0 Game.Colors.cyan
main = fn =>
Game.run-fixed {
title: "Fixed Tick Game",
width: 800,
height: 600,
fps: 60,
fixed-fps: 60,
init: {
x: 400.0,
actions: Game.Input.create-actions [
Game.Input.key-axis-binding "move-x" "a" (0.0 - 1.0),
Game.Input.key-axis-binding "move-x" "d" 1.0
]
},
fixed-update: fixed-update,
draw: draw
}For tests and replay-style workflows, Game.FixedTick.run-snapshots and
Game.Replay.run run one fixed update per input snapshot without opening a
window.
Fixed render callbacks receive ctx.alpha, the normalized interpolation factor
for the current accumulated partial tick. Keep previous and current simulation
values in state, then opt into interpolation during rendering:
fixed-update = fn(state, ctx) =>
next-x = state.x + 120.0 * ctx.dt
{...state, previous-x: state.x, x: next-x}
draw = fn(state, ctx) =>
x = Game.FixedTick.interpolate-float state.previous-x state.x ctx.alpha
Game.Graphics.circle x 300.0 16.0 Game.Colors.cyanReplay Recording And Playback
Game.Replay stores input snapshots as JSON-compatible data and can play them
back through Game.FixedTick. Replays can also be saved to explicit file paths
with FileWriteAuth and loaded with FileReadAuth:
replay0 = Game.Replay.create "move-right" 60
replay1 = Game.Replay.record replay0 {
...Game.Input.empty-snapshot,
keys-down: ["right"]
}
replay2 = Game.Replay.record replay1 Game.Input.empty-snapshot
text = Game.Replay.stringify replay2
fixed-update = fn(state, ctx) =>
dx = if Game.Input.snapshot-key-down? ctx.input "right" then 1 else 0
{x: state.x + dx}
match Game.Replay.parse text
| Err e -> print "Replay error: ${e}"
| Ok replay ->
window = Game.Context.window-state 800 600 true false false
clock = Game.FixedTick.create replay.fps window
result = Game.Replay.run replay {x: 0} clock fixed-update
print "Frame ${show result.clock.frame}"For tests, Game.Replay.run-frames and Game.Replay.state-after make
intermediate assertions straightforward. For live tooling, Game.Replay
provides lower-level recorder/player helpers plus a session helper that bundles
recording, playback toggles, playback input, and frame advancement. Use
Game.Replay.path, default-path, save-file, and load-file for
file-backed recordings.
session0 = Game.Replay.create-session (Game.Replay.create "session" 60)
session1 = Game.Replay.toggle-session-recording session0 (Game.Replay.create "session" 60)
stepped = Game.Replay.step-session session1 ctx
session2 = Game.Replay.toggle-session-recording stepped.session (Game.Replay.create "session" 60)
session3 = Game.Replay.toggle-session-playback session2
playback-step = Game.Replay.step-session session3 ctx
replay-ctx = playback-step.ctx
state-at-10 = Game.Replay.state-after (Game.Replay.session-replay session2) init-state clock fixed-update 10Context-service helpers store the same session shape in ctx.services.replay,
which lets a context-aware loop pass the updated session alongside playback input:
ctx2 = Game.Replay.with-context-session ctx session0
ctx3 = Game.Replay.toggle-context-recording ctx2 (Game.Replay.create "capture" 60)
sim-ctx = Game.Replay.step-context-session ctx3
session = Game.Replay.context-session sim-ctxSee examples/context-replay-session.kit for the pure helper flow.
Replay comparison helpers support regression browsing and smaller failure
reproductions:
summary = Game.Replay.compare expected-replay actual-replay
match summary.first
| None -> print "Replay matched"
| Some diff ->
repro = Game.Replay.prefix-through-first-difference actual-replay expected-replay
print "First replay difference at frame ${show diff.frame}: ${diff.reason}"
report = Game.Replay.comparison-report expected-replay actual-replay
lines = Game.Replay.comparison-lines expected-replay actual-replay
path = Game.Replay.default-path actual-replay.name
entry = Game.Replay.default-entry actual-replay
browser = Game.Replay.create-browser [
Game.Replay.loaded-entry path actual-replay
]
panel-lines = Game.Replay.browser-lines browser
selected-report = Game.Replay.browser-selected-report-lines browser expected-replay
browser-view = Game.Replay.replay-browser-view browser
report-view = Game.Replay.replay-browser-selected-report-view browser expected-replay
debug = Game.Replay.register-browser-commands Game.Debug.empty browser expected-replay
report-path = Game.Replay.report-path actual-replay.name
Game.Replay.save-comparison-report-file write-auth report-path expected-replay actual-replay
Game.Replay.save-browser-list-file write-auth (Game.Replay.report-path "browser") browser
manifest = Game.Replay.manifest-from-browser "index" browser
manifest-path = Game.Replay.replay-manifest-path "index"
Game.Replay.save-manifest-file write-auth manifest-path manifest
loaded-browser = Game.Replay.load-browser-from-manifest-file read-auth manifest-path
export-plan = Game.Replay.export-plan-in "reports" "nightly" browser expected-replay
export-lines = Game.Replay.export-plan-lines export-plan
export-conflicts = Game.Replay.export-plan-conflicts-file read-auth export-plan
if Game.Replay.export-plan-has-conflicts? export-conflicts then
print (String.join "\n" (Game.Replay.export-plan-conflict-lines export-conflicts))
# export-plan.steps contains browser-list, selected-report, and manifest write steps
write-summary = Game.Replay.save-export-plan-files write-auth export-plan
safe-write-summary = Game.Replay.save-export-plan-files-safe read-auth write-auth export-planSee examples/replay-live.kit for live recording/playback and
examples/replay-file-debug.kit for file-backed replay diagnostics and a
small replay browser panel. Browser command helpers register replay-list and
replay-report console commands on a Game.Debug state. Report file helpers
write the same browser/comparison text to explicit paths for editor or CI
artifacts. Manifest helpers write named replay indexes so external tools can
discover replay/report paths and hydrate browser entries without relying on
directory scanning. Browser view helpers expose selected, loaded, path, report,
and comparison status fields for editor panels without coupling the replay API
to a specific UI toolkit. Export plan helpers bundle the browser listing,
selected comparison report, and manifest into write-step records for editor or
CI artifacts. export-plan-conflicts-file and export-plan-conflict-lines
let tools preview overwrite conflicts before calling
save-export-plan-files-safe; see examples/replay-export-plan.kit.
Asset Cache
The Game.Cache module prevents repeated disk loads:
init = fn => {
cache: Game.Cache.create,
player: {x: 100.0, y: 100.0}
}
result = Game.Cache.get-texture state.cache "sprites/player.png"
texture = result.asset
cache2 = result.cache
cache3 = Game.Cache.preload-textures cache2 ["bg.png", "enemy.png"]Render command helpers can use the same explicit cache state for path-based
sprites:
sprite-result = Game.Render.sprite-path state.cache "sprites/player.png" state.x state.y
cache2 = sprite-result.cache
command = sprite-result.commandFor development reload workflows, invalidate cache entries without invoking
backend unload calls. The next get-* or render path helper call will load the
asset again. File watchers can use invalidate-path / invalidate-paths when
they only know which paths changed. watch-paths and poll-reload provide a
small polling loop for modification-time based reloads without hidden global
cache state:
cache2 = Game.Cache.invalidate-texture state.cache "sprites/player.png"
cache3 = Game.Cache.invalidate-path cache2 "audio/jump.wav"
cache4 = Game.Cache.invalidate-paths cache3 changed-paths
cache5 = Game.Cache.invalidate-all cache4
watch = Game.Cache.watch-paths ["sprites/player.png", "audio/jump.wav"]
polled = Game.Cache.poll-reload state.cache watch
state2 = {...state, cache: polled.cache, watch: polled.watch}Game.Dev wraps those cache primitives into an explicit asset reloader state
for development builds. Game.Context can carry the same reloader in
ctx.services.dev and synchronize the reloader cache with ctx.services.cache:
reloader = Game.Dev.create-asset-reloader Game.Cache.create [
"sprites/player.png",
"audio/jump.wav"
]
polled = Game.Dev.poll-asset-reloader state.reloader
lines = Game.Dev.asset-reloader-lines polled
state2 = {...state, reloader: polled}
ctx2 = Game.Context.with-asset-reloader ctx state.reloader
ctx3 = Game.Context.poll-asset-reloader ctx2
state3 = {...state, reloader: Game.Context.asset-reloader ctx3}State handoff helpers wrap JSON-compatible state in a versioned envelope that
a future dev runner or project script can persist before restart and reload
after launch:
handoff = Game.Dev.create-state-handoff "session" state-json
path = Game.Dev.default-state-handoff-path "session"
Game.Dev.save-state-handoff-file write-auth path handoff
loaded = Game.Dev.load-state-handoff-file read-auth pathFor source-aware dev tooling, compose asset reload watches with source watches.
Asset changes invalidate cache entries; source changes request a restart and
point at the state handoff path a runner can write before relaunching:
session = Game.Dev.create-session-with
mod-time
Game.Cache.create
["assets/player.png"]
["main.kit", "src/game.kit"]
polled = Game.Dev.poll-session-with mod-time session
command = Game.Dev.session-command polled
lines = Game.Dev.runner-command-lines command
# command.action is "reload-assets", "restart", or "none"Runner helpers keep the same decisions in explicit state for external tooling:
runner = Game.Dev.create-runner-with mod-time Game.Cache.create ["assets/player.png"] ["main.kit"]
runner2 = Game.Dev.poll-runner-with mod-time runner
command = Game.Dev.runner-command runner2
summary = Game.Dev.runner-lines runner2For project scripts or future CLI integration, generate an external dev-runner
script plan. The generated shell script polls asset and source modification
times, prints asset-only changes, and restarts the configured command when
source files change:
plan = Game.Dev.create-dev-runner-plan {
main: "src/main.kit",
asset-paths: ["assets/player.png"],
source-paths: ["src/main.kit"]
}
packaged = Game.Dev.with-dev-runner-script plan
script-step = Game.Dev.dev-runner-script-step plan
launch = Game.Dev.dev-runner-launch-action packaged
print launch.command
# '.kit-game/dev-runner.sh'
script-text = script-step.content
artifact-script = Game.Dev.dev-runner-artifact-script packaged
conflicts = Game.Dev.dev-runner-plan-conflicts-file read-auth packaged
if Game.Dev.dev-runner-plan-has-conflicts? conflicts then
print (String.join "\n" (Game.Dev.dev-runner-plan-conflict-lines conflicts))
write-result = Game.Dev.save-dev-runner-script-file write-auth plan
safe-write-result = Game.Dev.save-dev-runner-plan-files-safe read-auth write-auth packaged
plan-lines = Game.Dev.dev-runner-plan-lines planUse create-asset-reloader-with and poll-asset-reloader-with in tests or
tools that provide their own modification-time probe. See
examples/cache-reload-polling.kit for render-command usage that composes
context-owned cache, asset reload state, and debug watches without hidden
globals. See examples/dev-session-watch.kit for a pure source/asset session
watch recipe, and examples/dev-runner-plan.kit for the external runner script
plan. save-dev-runner-script-file, save-dev-runner-plan-files, and
save-dev-runner-plan-files-safe write the generated script artifact for
project-level tooling. dev-runner-plan-conflicts-file and
dev-runner-plan-conflict-lines let tools preview overwrite conflicts before
safe writes. dev-runner-launch-command and
dev-runner-launch-action expose the generated script command without spawning
a process. dev-runner-artifact-script generates a shell installer for the
plan artifacts, including parent directory creation and executable mode commands
where supported by the shell.
Project Templates
Generate starter project files with Game.Template:
print (Game.Template.main-file "My Game")
print (Game.Template.kit-toml "my-game" "0.1.0")
scaffold = Game.Template.scaffold "my-game" "My Game"
# scaffold.main, scaffold.kit-toml, scaffold.readme, scaffold.gitignore
plan = Game.Template.scaffold-plan "my-game" "My Game"
script = Game.Template.scaffold-script plan
# plan.files contains main.kit, kit.toml, README.md, .gitignore
project-plan = Game.Template.scaffold-plan-in "games/my-game" "my-game" "My Game"
conflicts = Game.Template.scaffold-conflicts-file read-auth project-plan
safe-script = Game.Template.scaffold-safe-script project-plan
packaged = Game.Template.with-safe-scaffold-script project-plan
launch = Game.Template.scaffold-launch-action packaged
print launch.command
# 'games/my-game/scaffold-project.sh'
write-result = Game.Template.save-scaffold-plan-files-safe read-auth write-auth packaged
lines = Game.Template.scaffold-plan-lines packagedScaffold plan/script helpers return file entries and shell script text for
project scripts or a future kit game new command. Use scaffold-plan-in to
target a project directory, scaffold-conflicts-with or
scaffold-conflicts-file to inspect existing targets, and
scaffold-safe-script to generate a script that checks every target before
writing. with-safe-scaffold-script appends a runnable script artifact step,
save-scaffold-plan-files-safe writes the plan only when no target path exists,
scaffold-launch-command and scaffold-launch-action expose the generated
script command without spawning a process, and scaffold-plan-lines exposes a
compact summary for tools. See
examples/scaffold-plan.kit.
Release Packaging Plans
Game.Release creates pure packaging plans for build commands, asset copy
steps, release metadata, and executable shell script text. The helpers do not
run shell commands; they return records and strings that a project script or
future CLI can execute:
meta = Game.Release.metadata {
title: "Star Courier",
version: "1.0.0",
author: "Example Studio",
executable: "star-courier",
icon: Some "assets/icon.png",
save-dir: "star-courier-saves",
width: 960,
height: 540,
fps: 60,
resizable: true
}
assets = [
Game.Release.asset-from-root meta.asset-root "sprites/player.png",
Game.Release.asset-to "LICENSE" "LICENSE"
]
plan = Game.Release.plan meta Game.Release.release-profile assets
print plan.build.command
# kit build main.kit -o dist/release/star-courier --release
script = Game.Release.script plan
# #!/usr/bin/env sh
# set -eu
# mkdir -p 'dist/release'
# kit build main.kit -o dist/release/star-courier --release
packaged = Game.Release.with-release-package-script plan
safe-packaged = Game.Release.with-safe-release-package-script plan
print packaged.package-script.path
# dist/release/release-package.sh
distribution = Game.Release.plan meta Game.Release.distribution-profile assets
print distribution.bundle.root
# dist/distribution/bundle
package-plan = Game.Release.package-plan packaged
action-lines = Game.Release.package-plan-lines package-plan
launch = Game.Release.launch-action packaged
print launch.command
# 'dist/release/star-courier'
preflight-issues = Game.Release.package-preflight-with source-exists? target-exists? package-plan
preflight-lines = Game.Release.package-preflight-lines preflight-issues
preflight-guards = Game.Release.package-preflight-guard-lines package-plan
safe-package-script = Game.Release.package-safe-script package-plan
file-artifacts = Game.Release.plan-file-steps packaged
file-conflicts = Game.Release.plan-file-conflicts-file read-auth packaged
if Game.Release.package-preflight-has-issues? file-conflicts then
print (String.join "\n" (Game.Release.package-preflight-lines file-conflicts))
write-result = Game.Release.save-plan-files write-auth packaged
safe-write-result = Game.Release.save-plan-files-safe read-auth write-auth safe-packaged
summary = Game.Release.plan-view packaged
lines = Game.Release.plan-lines packagedUse Game.Release.debug-profile, release-profile, or
distribution-profile for common output layouts, or create a custom profile
with Game.Release.profile / profile-with. See
examples/release-plan.kit for a compact packaging recipe. Package-script
helpers add a runnable script artifact step to a plan without executing shell
commands. Plan view helpers expose labels, counts, paths, and display lines for
future CLIs or release screens. plan-file-steps, save-step-file, and
save-plan-files let project tooling write release text artifacts such as the
manifest and generated package script while leaving build/copy process execution
to script output or a future CLI. plan-file-conflicts-file previews
overwrite conflicts for those text artifacts, and save-plan-files-safe
refuses to overwrite existing artifact targets. When metadata includes
icon: Some path, release
plans copy that icon into the profile output root and include the icon source in
the manifest. Release metadata also carries asset-root plus window defaults
(width, height, fps, and resizable) into manifest text and plan summary
lines so packaging tools can inspect the intended launch configuration.
Bundled profiles, including distribution-profile, use a generic layout under
<output-dir>/<bundle-dir>/ with bin, assets, and metadata directories;
bundle-layout, bundle-root-path, bundle-bin-dir, bundle-assets-dir, and
bundle-metadata-dir expose those paths as pure data for a future packaging
command. Package action helpers expand release steps into structured
ensure-dir, run-command, copy-file, write-file, and chmod records, so
future tooling can execute packaging work without parsing generated shell text.
launch-command and launch-action expose the built executable command and
bundle metadata for project scripts or a future kit game package/run command.
package-script-lines and package-script rebuild shell scripts from those
structured actions, while package-preflight-guard-lines,
package-safe-script-lines, and package-safe-script add shell guards that
fail before missing build/copy sources or overwrite-risk targets.
release-safe-package-script-step and with-safe-release-package-script package
that guarded script as a writable executable artifact. Preflight helpers report
the same source/target issues from action records with either caller-provided
predicates or package-preflight-file.
Tilemap Loading
The Game.Tilemap module supports both Tiled JSON (.tmj) and Tiled TMX XML (.tmx) formats.
See Game.Tilemap docs.
Tiled JSON (.tmj / .json)
import Auth.File.{FileAuth}
tileset = Game.Assets.load-texture "tiles.png"
match Game.Tilemap.load FileAuth "level1.tmj" tileset
| Ok map ->
# Use map.tile-width, map.tile-height, map.layers, etc.
no-op
| Err e -> print "Failed: ${show e}"Tiled TMX XML (.tmx)
Requires the kit-xml package.
See kit-xml docs.
import Auth.File.{FileAuth}
tileset = Game.Assets.load-texture "tiles.png"
match Game.Tilemap.load-tmx FileAuth "level1.tmx" tileset
| Ok map ->
no-op
| Err e -> print "Failed: ${show e}"TMX notes:
- CSV, uncompressed Base64, zlib-compressed Base64, and gzip-compressed Base64 tile data are supported.
- External tilesets (
.tsxfiles referenced viasource="tileset.tsx") are loaded automatically. - Layer
visibleandsolidcustom properties are supported. - Object layers are parsed via
Game.Tilemap.parse-tmx-objectgroups xml-str. - TMX parsing uses libxml2 FFI and only works in compiled builds. The
kitinterpreter has a runtime conflict between the Raylib and libxml2 FFI modules, soload-tmx/from-tmx-xmlwill panic in interpreted tests. Usekit checkand compiled examples to verify TMX functionality. - In Tiled, go to
File -> Export As... -> Tiled Map Files (*.tmx)to save as TMX.
Development
Running Examples
Run examples with the interpreter:
kit run examples/simple.kit
kit run examples/cache-reload-polling.kit
kit run examples/context-debug.kit
kit run examples/context-replay-session.kit
kit run examples/fixed-render-viewport.kit
kit run examples/immediate-render-mix.kit
kit run examples/input-rebinding.kit
kit run examples/logical-render-viewport.kit
kit run examples/replay-file-debug.kit
kit run examples/replay-live.kit
kit run examples/render-sprite-cache.kit
kit run examples/render-target-screenshot.kit
kit run examples/touch-viewport.kit
kit run examples/viewport-scissor.kitCompile examples to a native binary:
kit build examples/simple.kit && ./simple
kit build examples/cache-reload-polling.kit && ./cache-reload-polling
kit build examples/context-debug.kit && ./context-debug
kit build examples/context-replay-session.kit && ./context-replay-session
kit build examples/fixed-render-viewport.kit && ./fixed-render-viewport
kit build examples/immediate-render-mix.kit && ./immediate-render-mix
kit build examples/input-rebinding.kit && ./input-rebinding
kit build examples/logical-render-viewport.kit && ./logical-render-viewport
kit build examples/replay-file-debug.kit && ./replay-file-debug
kit build examples/replay-live.kit && ./replay-live
kit build examples/render-sprite-cache.kit && ./render-sprite-cache
kit build examples/render-target-screenshot.kit && ./render-target-screenshot
kit build examples/touch-viewport.kit && ./touch-viewport
kit build examples/viewport-scissor.kit && ./viewport-scissorRunning Tests
Run the test suite:
kit testRun the test suite with coverage:
kit test --coverageRunning Parity Checks
Check interpreter/build parity for the examples:
kit parity --failures-onlyRunning kit dev
Run the standard development workflow (format, check, test):
kit devThis will:
- Format and check source files in
src/ - Run tests in
tests/with coverage
Generating Documentation
Generate API documentation from doc comments:
kit docNote: Kit sources with doc comments (##) will generate HTML documents in docs/*.html
Building Releases
Build a native binary for distribution:
kit build main.kit -o my-game
kit build main.kit -o my-game --releaseCleaning Build Artifacts
Remove generated files, caches, and build artifacts:
kit task cleanNote: Defined in kit.toml.
Local Installation
To install this package locally for development:
kit installThis installs the package to ~/.kit/packages/@kit/game/, making it available for import as Kit.Game in other projects.
License
This package is released under the MIT License - see LICENSE for details.
Exported Functions & Types
rgb
Create a color from RGB values (0-255)
rgba
Create a color from RGBA values (0-255)
hex
Create a color from a hex value (e.g., 0xFF0000 for red)
white
Pure white (255, 255, 255)
black
Pure black (0, 0, 0)
blank
Fully transparent (alpha = 0)
light-gray
Light gray (200, 200, 200)
gray
Medium gray (130, 130, 130)
dark-gray
Dark gray (80, 80, 80)
red
Pure red (230, 41, 55)
green
Pure green (0, 228, 48)
blue
Pure blue (0, 121, 241)
yellow
Bright yellow (253, 249, 0)
orange
Orange (255, 161, 0)
pink
Pink (255, 109, 194)
purple
Purple (200, 122, 255)
violet
Violet (135, 60, 190)
magenta
Magenta (255, 0, 255)
gold
Gold (255, 203, 0)
maroon
Maroon (190, 33, 55)
lime
Lime green (0, 158, 47)
dark-green
Dark green (0, 117, 44)
sky-blue
Sky blue (102, 191, 255)
dark-blue
Dark blue (0, 82, 172)
beige
Beige (211, 176, 131)
brown
Brown (127, 106, 79)
dark-brown
Dark brown (76, 63, 47)
cyan
Cyan (0, 255, 255)
teal
Teal (0, 128, 128)
coral
Coral (255, 127, 80)
salmon
Salmon (250, 128, 114)
navy
Navy blue (0, 0, 128)
olive
Olive (128, 128, 0)
indigo
Indigo (75, 0, 130)
with-alpha
Make a color transparent (alpha = 0-255)
fade
Fade a color (factor 0.0-1.0)
create
Create a new quadtree
Config fields (all required — records have no optional fields): bounds: {x, y, width, height} - The region to cover. Objects outside this region are stored at the root but only returned by queries that intersect it, so size bounds to cover the whole world. max-objects: Int - Objects per node before split (10 is typical) max-depth: Int - Maximum tree depth (5 is typical)
Quadtree.create {
bounds: {x: 0.0, y: 0.0, width: 800.0, height: 600.0},
max-objects: 10,
max-depth: 5
}insert
Insert an object into the quadtree Object must have: x, y, width, height fields (or provide bounds)
insert-all
Insert multiple objects
query
Query for all objects that could collide with a given bounds
query-point
Query for objects at a specific point
query-radius
Query for objects within a radius of a point
clear
Clear all objects from the tree
rebuild
Rebuild the tree with new objects (useful after many removals)
Quadtree -> List -> Quadtree
get-all
Get all objects in the tree
count
Count all objects in the tree
find-collision-pairs
Find all pairs of potentially colliding objects. Objects must carry a unique, comparable id field (in addition to x/y/width/height); each pair is reported exactly once, ordered so that a.id < b.id.
get-all-bounds
Get all node bounds for debug drawing
stats
Get tree statistics
default-emitter-config
Default emitter configuration; spread it to build a custom config.
create-emitter
Create a particle emitter from a complete config record. Records have no optional fields — build the config by spreading Particles.default-emitter-config and overriding what you need.
Config fields: max-particles: Int - Maximum particles emission-rate: Float - Particles per second lifetime: {min: Float, max: Float} - Particle lifetime range speed: {min: Float, max: Float} - Initial speed range angle: {min: Float, max: Float} - Emission angle range in degrees (0 = right) size: {start: Float, end: Float} - Size over lifetime colors: List Int - Colors to cycle through gravity: {x: Float, y: Float} - Gravity force rotation-speed: {min: Float, max: Float} - Rotation speed range
Particles.create-emitter {
...Particles.default-emitter-config,
max-particles: 200,
emission-rate: 50.0,
size: {start: 8.0, end: 2.0},
colors: [Colors.yellow, Colors.orange, Colors.red]
}create-emitter-at
Create emitter at a specific position (takes a complete config; see create-emitter)
set-position
Set emitter position
move
Move emitter by delta
start
Start emitting
stop
Stop emitting (existing particles continue)
clear
Clear all particles
has-particles?
Check if emitter has active particles
particle-count
Get particle count
burst
Emit multiple particles at once
update
Update emitter and all particles
draw
Draw all particles as circles
draw-rects
Draw particles as rectangles
draw-faded
Draw particles with fade based on lifetime
draw-textured
Draw particles with texture
preset-fire
Create a fire effect emitter
preset-smoke
Create a smoke effect emitter
preset-sparks
Create a spark/explosion burst emitter
preset-rain
Create a rain effect emitter
preset-snow
Create a snow effect emitter
create
Create an empty tilemap
Config fields: tile-width: Int - Width of each tile in pixels tile-height: Int - Height of each tile in pixels width: Int - Map width in tiles height: Int - Map height in tiles tileset: Texture - The tileset texture
Tilemap.create {
tile-width: 16,
tile-height: 16,
width: 50,
height: 30,
tileset: tileset-texture
}add-layer
Add a layer to the tilemap
create-layer
Create a layer with empty data
create-layer-with-data
Create a layer with initial data
get-tile
Get tile index at position (in tile coordinates)
set-tile
Set tile at position (returns new tilemap)
get-tile-at
Get tile at world position (in pixels)
world-to-tile
Convert world position to tile position
tile-to-world
Convert tile position to world position (top-left corner)
get-layer
Get layer by name
set-layer-visible
Set layer visibility
toggle-layer
Toggle layer visibility
draw
Draw all visible layers
draw-layer
Draw a specific layer
draw-in-bounds
Draw tilemap within camera bounds (optimized)
is-solid?
Check if a tile position is solid
is-solid-at?
Check if a world position is solid
rect-collides?
Check if a rectangle collides with any solid tiles Tests every tile the rectangle overlaps, so entities larger than one tile cannot straddle a solid tile undetected
get-colliding-tiles
Get all solid tiles that a rectangle overlaps with
resolve-collision
Resolve collision by pushing entity out of solid tiles Returns adjusted position {x, y}
pixel-width
Get tilemap dimensions in pixels
pixel-height
fill-rect
Fill a rectangular region with a tile
clear-layer
Clear all tiles in a layer
TilemapError
Error type for tilemap loading
Type
Variants
TilemapParseError {_0}TilemapMissingField {_0}TilemapInvalidFormat {_0}load
Load a tilemap from a Tiled JSON file (.tmj or .json)
Parameters:
path- String - Path to the JSON filetileset- Texture - The tileset texture to use (loaded separately)
Returns: Result Tilemap TilemapError
Parameters:
tileset = Assets.load-texture "tiles.png"
match Tilemap.load fa "level1.tmj" tileset
| Ok map -> use map
| Err e -> print "Failed to load: ${show e}"
Load a Tiled JSON map from a file.
fa: FileReadAuth supplied by the consuming app
path: String - Path to the .tmj file
tileset: Texture - The loaded tileset texture
Note: The tileset texture must be loaded separately using Assets.load-texture.from-tiled-json
Parse a Tiled JSON string into a tilemap
Parameters:
json-str- String - JSON content from a Tiled map filetileset- Texture - The tileset texture
Returns: Result Tilemap TilemapError
get-tileset-info
Get tileset info from Tiled JSON (helper for loading tileset)
Parameters:
fa- FileReadAuth supplied by the consuming apppath- String - Path to the Tiled JSON file
Returns: Result {image: String, tile-width: Int, tile-height: Int} TilemapError
match Tilemap.get-tileset-info fa "level1.tmj"
| Ok info ->
tileset = Assets.load-texture info.image
Tilemap.load fa "level1.tmj" tileset
| Err e -> print "Error: ${show e}"load-tmx
Load a tilemap from a Tiled TMX XML file (.tmx)
Parameters:
path- String - Path to the TMX filetileset- Texture - The tileset texture to use (loaded separately)
Returns: Result Tilemap TilemapError
Note: Only CSV-encoded tile data is currently supported. Base64, zlib, gzip, and other encodings are not yet supported.
tileset = Assets.load-texture "tiles.png"
match Tilemap.load-tmx fa "level1.tmx" tileset
| Ok map -> use map
| Err e -> print "Failed to load: ${show e}"from-tmx-xml
Parse a Tiled TMX XML string into a tilemap
Parameters:
xml-str- String - XML content from a Tiled TMX filetileset- Texture - The tileset texture
Returns: Result Tilemap TilemapError
Note: Only CSV-encoded tile data is currently supported.
parse-tmx-objectgroups
Parse object group layers from a TMX XML document string.
Returns a list of {name: String, visible: Bool, objects: List} records. Each object has: id, x, y, width, height, kind, name.
Note: This is a separate utility function. Object groups are not yet integrated into the main tilemap structure.
get-tileset-info-tmx
Get tileset info from a Tiled TMX file.
Parameters:
path- String - Path to the TMX file
Returns: Result {image: String, tile-width: Int, tile-height: Int, tile-count: Int} TilemapError
Note: For external tilesets, the .tsx file is loaded and parsed automatically.
match Tilemap.get-tileset-info-tmx fa "level1.tmx"
| Ok info ->
tileset = Assets.load-texture info.image
Tilemap.load-tmx fa "level1.tmx" tileset
| Err e -> print "Error: ${show e}"snapshot-to-json
Convert an input snapshot record to a JSON value.
snapshot-from-json
Convert a JSON value to an input snapshot record. Missing fields default to Input.empty-snapshot.
create
Create an empty replay.
record
Append an input snapshot to a replay.
record-context
Append the input snapshot from a runtime context.
count
Count snapshots in a replay.
snapshot-at
Get a replay snapshot by index.
playback-snapshot
Get a replay snapshot by frame number, defaulting to empty input when the frame is outside the recording.
playback-context
Replace a context's input with the replay snapshot for ctx.frame.
run
Run one fixed update for each recorded snapshot. update receives (state, ctx) and returns the next state.
run-frames
Run up to frames fixed updates from the replay. Useful for test assertions against intermediate replay states.
state-after
Return only the state after frames replay updates.
with-snapshots
Replace the snapshots in a replay while preserving metadata.
take-frames
Keep the first frames snapshots.
slice-frames
Keep a range of snapshots starting at start with length frames.
prefix-through-frame
Keep frames from the start of the replay through frame, inclusive.
snapshot-signature
Deterministic JSON signature for an input snapshot.
snapshot-equal?
Compare two snapshots by their replay JSON representation.
difference-at
Return the difference at a frame, or None when both replays match there. Reasons are left-missing, right-missing, or snapshot-mismatch.
first-difference
Return the first differing frame between two replays.
equal?
Check whether two replays have equal snapshots and equal lengths.
difference-frames
Return every frame index that differs between two replays.
difference-detail-at
Return a richer difference row for replay browsers and debug reports.
difference-details
Return richer difference rows for every differing frame.
compare
Build a comparison summary for browsing or debug overlays.
describe-difference
Format one difference row for debug overlays or console reports.
comparison-lines
Return text lines summarizing a replay comparison.
format-comparison
Format a replay comparison as a newline-delimited report.
comparison-report
Build a structured report with summary counts, detail rows, and text lines.
prefix-through-first-difference
Keep the left replay prefix through its first difference from right. Equal replays are returned unchanged.
create-recorder
Create a paused recorder around a replay record.
start-recording
Start recording frames.
stop-recording
Stop recording frames.
toggle-recording
Toggle recording state.
recording?
Check whether a recorder is active.
record-frame
Append ctx.input when the recorder is active.
create-player
Create a paused playback cursor around a replay record.
create-looping-player
Create a paused playback cursor that loops when it reaches the end.
with-player-loop
Set whether the playback cursor loops.
start-playback
Start playback from the first recorded frame.
stop-playback
Stop playback without changing the current frame.
toggle-playback
Toggle playback. Starting playback always starts from the first frame.
reset-playback
Reset playback to the first frame.
playing?
Check whether a player is active.
playback-done?
Check whether the playback cursor is at or beyond the replay length.
player-snapshot
Get the player's current input snapshot. Paused players produce empty input.
player-context
Replace a context's input with the player's current input snapshot.
advance-player
Advance a playback cursor by one frame.
step-player
Apply the current playback input to a context and advance the cursor.
create-session
Create a paused replay session with a recorder and playback cursor.
create-looping-session
Create a paused replay session whose playback cursor loops at the end.
session-replay
Return the replay currently owned by a session recorder.
session-count
Return the number of recorded session frames.
session-recording?
Check whether the session recorder is active.
session-playing?
Check whether the session player is active.
session-can-play?
Check whether a session has a replay that can be played now.
toggle-session-recording
Toggle session recording. Starting recording uses fresh-replay and stops any active playback; stopping recording preserves captured frames.
toggle-session-playback
Toggle session playback from the recorder's current replay. Empty or actively recording sessions are left unchanged.
session-context
Return a context using the current playback input when the session is playing.
record-session-frame
Record a frame through the session recorder.
advance-session-player
Advance the session playback cursor.
step-session
Build the playback-aware context, record the live frame, and advance playback. Returns {session, ctx} where ctx is the input source for simulation.
context-replay-services
Return the replay service state stored in ctx.services.replay.
with-context-replay-services
Replace the replay service state stored in ctx.services.replay.
context-session
Return the replay session stored in ctx.services.replay. Missing replay service state defaults to an empty paused session.
with-context-session
Replace the replay session stored in ctx.services.replay.
context-recording?
Check whether the context-owned replay session is recording.
context-playing?
Check whether the context-owned replay session is playing.
toggle-context-recording
Toggle the context-owned replay recording state. Starting recording uses fresh-replay; stopping recording preserves frames.
toggle-context-playback
Toggle playback on the context-owned replay session.
step-context-session
Step the context-owned replay session. Returns a context whose input is playback input when playback is active, and whose services contain the updated replay session.
to-json
Convert a replay record to a JSON value.
from-json
Convert replay JSON to a replay record.
stringify
Convert a replay record to JSON text.
parse
Parse replay JSON text.
default-directory
Conventional directory for replay files.
String
filename
Default replay file name for a replay name.
String -> String
path
Default replay file path for a name.
String -> String
path-in
Default replay file path inside a directory.
String -> String -> String
default-path
Default replay file path inside Game.Replay.default-directory.
String -> String
report-filename
Default replay comparison report file name for a replay name.
String -> String
report-path
Default replay comparison report file path for a replay name.
String -> String
report-path-in
Default replay comparison report file path inside a directory.
String -> String -> String
default-report-path
Default replay comparison report path inside Game.Replay.default-directory.
String -> String
replay-manifest-filename
Default replay manifest file name for a manifest name.
String -> String
replay-manifest-path
Default replay manifest file path for a manifest name.
String -> String
replay-manifest-path-in
Default replay manifest file path inside a directory.
String -> String -> String
default-replay-manifest-path
Default replay manifest path inside Game.Replay.default-directory.
String -> String
file-entry
Build a browser/index entry for a loaded replay file.
default-entry
Build a browser/index entry using the default replay directory.
loaded-entry
Build a browser/index entry that also carries the loaded replay.
default-loaded-entry
Build a loaded browser/index entry using the default replay directory.
manifest-entry
Build a replay manifest entry for editor or external tooling discovery.
default-manifest-entry
Build a manifest entry using default replay and report paths.
manifest-entry-from-browser-entry
Build a manifest entry from an existing replay browser entry.
create-manifest
Create a named replay manifest.
manifest-from-browser
Create a manifest from replay browser entries.
manifest-from-replays
Create a manifest from replays using default replay/report paths.
manifest-to-json
Convert a replay manifest to a JSON value.
manifest-from-json
Convert replay manifest JSON to a manifest record.
stringify-manifest
Convert a replay manifest to JSON text.
parse-manifest
Parse replay manifest JSON text.
create-browser
Create a replay browser state from loaded or file-only entries.
browser-from-manifest
Create a file-only replay browser from a manifest. Use load-browser-from-manifest when selected reports need loaded replay data.
browser-count
Count entries in a replay browser.
browser-empty?
Check whether a replay browser has no entries.
browser-with-entries
Replace browser entries while keeping the selection in range.
browser-select
Select a browser entry by index, clamped to the valid range.
browser-next
Select the next browser entry, wrapping at the end.
browser-prev
Select the previous browser entry, wrapping at the start.
browser-selected-entry
Return the selected browser entry.
replay-browser-entry-view
Build a UI-friendly replay browser row record.
replay-browser-entry-views
Return UI-friendly replay browser rows.
replay-browser-selected-view
Return the selected replay browser row, if any.
replay-browser-view
Return a UI-friendly replay browser panel model.
browser-lines
Return text lines for a replay browser panel.
browser-selected-report
Compare reference with the selected loaded replay entry. Entries should be built with loaded-entry or default-loaded-entry.
browser-selected-report-lines
Return comparison text lines for the selected loaded replay entry.
replay-browser-selected-report-view
Return a UI-friendly selected replay report model. Status is empty, unloaded, match, or different.
browser-list-output
Return a newline-delimited replay browser listing for console tools.
browser-report-output
Return a newline-delimited selected replay report for console tools.
replay-export-list-filename
Default replay browser listing artifact file name.
String -> String
replay-export-list-path
Default replay browser listing artifact path.
String -> String
replay-export-list-path-in
Default replay browser listing artifact path inside a directory.
String -> String -> String
default-replay-export-list-path
Default replay browser listing artifact path inside the replay directory.
String -> String
replay-export-selected-report-filename
Default selected replay comparison artifact file name.
String -> String
replay-export-selected-report-path
Default selected replay comparison artifact path.
String -> String
replay-export-selected-report-path-in
Default selected replay comparison artifact path inside a directory.
String -> String -> String
default-replay-export-selected-report-path
Default selected replay comparison artifact path inside the replay directory.
String -> String
replay-export-step
Create one replay export artifact step.
replay-export-conflict
Create one replay export conflict entry.
export-plan-in
Create an inspectable replay export plan inside an explicit directory. The plan writes a browser listing, selected comparison report, and manifest.
export-plan
Create an inspectable replay export plan in the default replay directory.
export-plan-view
Return a UI/tooling-oriented summary for a replay export plan.
export-plan-lines
Return display lines for a replay export plan summary.
save-export-step-file
Save one replay export plan step to its path.
save-export-plan-files
Save every replay export plan step to disk. Returns a summary with written steps, paths, and count.
export-plan-conflicts-with
Detect replay export conflicts using a caller-provided path-exists predicate.
export-plan-conflicts-file
Detect replay export conflicts on disk using file read auth.
export-plan-has-conflicts?
Return true when a replay export conflict list is non-empty.
List -> Bool
export-plan-conflict-lines
Return display lines for replay export conflicts.
List -> List
save-export-plan-files-safe
Save every replay export plan step only when none of the target paths exists.
save-comparison-report-file
Save comparison report text to an explicit file path.
save-browser-list-file
Save replay browser listing text to an explicit file path.
save-browser-report-file
Save selected replay browser comparison report text to an explicit file path.
register-browser-commands
Register replay browser console commands on a Game.Debug state. Adds or replaces: - replay-list - replay-report
save-file
Save a replay to an explicit file path.
load-file
Load a replay from an explicit file path.
save-manifest-file
Save a replay manifest to an explicit file path.
load-manifest-file
Load a replay manifest from an explicit file path.
load-browser-from-manifest
Load replay files referenced by a manifest into a replay browser.
load-browser-from-manifest-file
Load a manifest file and hydrate its replay browser entries.
exists-file?
Check if a replay file exists.
FileReadAuth -> String -> Bool
delete-file
Delete a replay file.
FileAuth -> String -> Result Bool String
empty
Empty viewport for default contexts and tests.
create
Create a viewport using aspect-fit scaling.
create-with-mode
Create a viewport with an explicit scaling mode. Modes: "fit", "fill", "stretch", "integer-fit". Aliases: "aspect-fit", "aspect-fill", "letterbox", "integer".
resize
Resize an existing viewport for a physical window size.
from-window
Build a viewport for a window record with width and height fields.
with-mode
Change the scaling mode while preserving logical and physical sizes.
logical-rect
Get the logical canvas rectangle.
physical-rect
Get the physical render rectangle inside the window.
letterboxed?
True when the viewport leaves visible bars inside the physical window.
contains-screen?
True when a physical screen point is inside the viewport render rectangle.
contains-logical?
True when a logical point is inside the logical canvas.
safe-insets
Create physical screen insets for safe-area calculations. Values are measured in physical screen pixels.
no-safe-insets
Empty physical screen insets.
physical-clip-rect
Get the physical viewport rectangle clipped to the window bounds.
scissor-rect
Get the physical rectangle suitable for backend scissor/clipping.
screen-safe-rect
Get the physical screen rectangle after applying safe-area insets.
physical-safe-rect
Get the physical drawable rectangle inside both the viewport and safe area.
logical-safe-rect
Get the logical canvas rectangle inside the safe area.
safe-area
Get screen, physical viewport, and logical safe-area rectangles together.
contains-safe-logical?
True when a logical point is inside the logical safe area.
clamp-safe-logical
Clamp a logical point to the logical safe area.
screen-to-logical
Convert physical screen coordinates to logical canvas coordinates.
logical-to-screen
Convert logical canvas coordinates to physical screen coordinates.
clamp-logical
Clamp a logical point to the logical canvas bounds.
render-target-size
Get the recommended render target size for this logical viewport.
render-target-source
Get the source rectangle for drawing a viewport-sized render target right-side-up. The height is negative because render targets use the backend texture coordinate origin.
render-target-destination
Get the destination rectangle for drawing a render target through this viewport.
render-target-layout
Get the size, source, destination, and clip rectangles used by viewport render-target helpers.
screen-to-world
Convert a physical screen point through the viewport and then through a camera.
world-to-screen
Convert a world point through a camera and then through the viewport.
input-to-logical
Convert a snapshot's mouse coordinates from physical screen space to logical canvas space. Touch points are converted to logical canvas coordinates. Button/key/gamepad state is preserved.
rect
A rectangle for collision detection Fields: x, y, width, height (all Float)
Create a rectangle
rect-from
Create a rectangle from position and size records
rect-centered
Create a rectangle centered at a point
point-in-rect?
Check if a point is inside a rectangle
point-in-circle?
Check if a point is inside a circle
Float -> Float -> Float -> Float -> PositiveFloat -> Bool
rects-overlap?
Check if two rectangles overlap (AABB collision)
rect-overlap
Get the overlap between two rectangles (returns None if no overlap)
check-rects
Get collision info between two rectangles Returns Option with {overlap: {x, y}, normal: {x, y}, penetration: Float} The normal points away from rect2, toward rect1 — the direction rect1 must move (by penetration) to separate.
rect-intersection
Get the intersection rectangle of two overlapping rectangles
circles-overlap?
Check if two circles overlap
Float -> Float -> Float -> Float -> Float -> Float -> Bool
check-circles
Get collision info between two circles Returns Option with {normal: {x, y}, penetration: Float} The normal points away from circle 2, toward circle 1 — the direction circle 1 must move to separate (same convention as check-rects and check-circle-rect).
Float -> Float -> Float -> Float -> Float -> Float -> Option
circle-rect-overlap?
Check if a circle and rectangle overlap
check-circle-rect
Get collision info between circle and rectangle Returns Option with {closest: {x, y}, normal: {x, y}, penetration: Float} The normal points away from the rectangle, toward the circle — the direction the circle must move to separate.
lines-intersect?
Check if two line segments intersect
Float -> Float -> Float -> Float -> Float -> Float -> Float -> Float -> Bool
line-intersection
Get intersection point of two line segments
Float -> Float -> Float -> Float -> Float -> Float -> Float -> Float -> Option
line-rect-intersect?
Check if a line segment intersects a rectangle
expand-rect
Expand a rectangle by a margin
shrink-rect
Shrink a rectangle by a margin
rect-center
Get the center point of a rectangle
distance
Get the distance between two points
Float -> Float -> Float -> Float -> Float
distance-squared
Get the squared distance between two points (faster than distance)
Float -> Float -> Float -> Float -> Float
rect-contains-rect?
Check if a rectangle contains another rectangle
rect-contains-circle?
Check if a rectangle contains a circle
layer-default
Collision layers use bitmasks for efficient filtering Each layer is a power of 2: 1, 2, 4, 8, 16, 32, etc.
Default collision layer (1)
Int
layer-player
Player collision layer (2)
Int
layer-enemy
Enemy collision layer (4)
Int
layer-bullet
Bullet/projectile collision layer (8)
Int
layer-wall
Wall/obstacle collision layer (16)
Int
layer-pickup
Pickup/collectible collision layer (32)
Int
layer-trigger
Trigger zone collision layer (64)
Int
combine-layers
Combine multiple layers into a mask
List -> Int
layers-collide?
Check if two layer masks can collide Returns true if they share any bits
Int -> Int -> Bool
create-filter
Create a collision filter entity-layer: the layer this entity belongs to collides-with: mask of layers this entity collides with
filters-collide?
Check if two filters allow collision
filter-player
Player collision filter - collides with enemies, walls, pickups, triggers
filter-enemy
Enemy collision filter - collides with player, bullets, walls
filter-bullet
Bullet collision filter - collides with enemies, walls
filter-wall
Wall collision filter - collides with player, enemies, bullets
filter-pickup
Pickup collision filter - collides with player only
filter-trigger
Trigger collision filter - collides with player only
separate-circles
Separate two overlapping circles Returns new positions for both circles
push-out-of-rect
Push an entity out of a static rectangle Returns the adjusted position
reflect-velocity
Reflect a velocity vector off a surface normal: {x, y} - the surface normal (should be normalized) vx, vy: velocity components Returns new velocity
reflect-velocity-damped
Reflect with dampening (for bouncing) bounce: 0.0 = no bounce, 1.0 = perfect bounce
sweep-rect
Swept AABB collision - find when a moving rectangle hits a static rectangle. Prevents tunneling where fast objects pass through thin walls between frames.
moving: {x, y, width, height} - rectangle at current position static-rect: {x, y, width, height} - static rectangle vx, vy: Float - velocity of moving rectangle for this frame
Returns Option with {time: Float (0-1), normal: {x, y}, contact: {x, y}}
sweep-move
Move a rectangle with swept collision against a static rectangle. Returns the new position, collision time, hit flag, and normal.
sweep-move-many
Move a rectangle with swept collision against multiple static rectangles. Tests all obstacles and returns the result of the nearest collision.
moving: {x, y, width, height} - rectangle at current position obstacles: List of {x, y, width, height} - static rectangles vx, vy: Float - velocity of moving rectangle for this frame
Returns {x, y, time, hit, normal}
Input
Input handling module - keyboard, mouse, gamepad
Module
Graphics
Graphics primitives module - drawing shapes, text
Module
Colors
Color constants and utilities module
Module
Context
Runtime context module for opt-in context-aware game loops
Module
FixedTick
Fixed-step simulation helpers
Module
Replay
Input recording and deterministic playback helpers
Module
Render
Optional render command queue module
Module
Viewport
Logical canvas viewport and coordinate conversion helpers
Module
Audio
Audio module - sound effects and music
Module
Math
Math utilities module - vectors, angles, interpolation
Module
Menu
Menu and pause-screen state helpers
Module
Dev
Development-time helpers for explicit runtime tooling state
Module
Release
Release packaging plan helpers
Module
Sprite
Sprite and animation module
Module
Camera
2D camera module with smooth follow and effects
Module
Collision
Collision detection module - AABB, circles, lines
Module
Assets
Asset loading module - textures, sounds, fonts
Module
Scene
Scene management module
Module
Tilemap
Tilemap rendering module
Module
Particles
Particle effects module
Module
Quadtree
Spatial partitioning quadtree module
Module
Cache
Asset cache module - preload and reuse textures, sounds, fonts
Module
ECS
Entity Component System module
Module
Save
Save/load game state module
Module
Debug
Debug overlay and development tools module
Module
Template
Project template generator module
Module
Pool
Object pool module for recycling short-lived entities
Module
Physics
Basic rigid body physics module with gravity, forces, and collision resolution
Module
AutoSave
Auto-save timer module for periodic game state saves
Module
run
Run the game with a configuration record
Record -> ()
run-with-options
Run the game with explicit window options (vsync, resizable, fullscreen, msaa)
Record -> Record -> ()
run-render
Run a game whose render callback returns Game.Render commands
Record -> ()
run-render-with-options
Run a render-command game with explicit window options
Record -> Record -> ()
run-with-context
Run a context-aware game with update/draw callbacks receiving (state, ctx)
Record -> ()
run-with-context-options
Run a context-aware game with explicit window options
Record -> Record -> ()
run-render-with-context
Run a context-aware render-command game
Record -> ()
run-render-with-context-options
Run a context-aware render-command game with explicit window options
Record -> Record -> ()
run-logical-render-with-context
Run a context-aware logical render-command game
Record -> ()
run-logical-render-with-context-options
Run a context-aware logical render-command game with explicit window options
Record -> Record -> ()
run-fixed
Run a fixed-step game with fixed-update callbacks receiving (state, ctx)
Record -> ()
run-fixed-with-options
Run a fixed-step game with explicit window options
Record -> Record -> ()
run-fixed-render
Run a fixed-step render-command game
Record -> ()
run-fixed-render-with-options
Run a fixed-step render-command game with explicit window options
Record -> Record -> ()
run-fixed-logical-render
Run a fixed-step logical render-command game
Record -> ()
run-fixed-logical-render-with-options
Run a fixed-step logical render-command game with explicit window options
Record -> Record -> ()
default-options
Default window options for run-with-options; override with spread
Record
delta-time
Get the current frame time (delta time)
() -> Float
fps
Get the current frames per second
() -> Int
time
Get the time since the game started
() -> Float
should-close?
Check if the window should close
() -> Bool
set-title
Set the window title
String -> ()
toggle-fullscreen
Toggle fullscreen mode
() -> ()
is-fullscreen?
Check if the window is fullscreen
() -> Bool
is-focused?
Check if the window is focused
() -> Bool
is-minimized?
Check if the window is minimized
() -> Bool
minimize
Minimize the window
() -> ()
maximize
Maximize the window
() -> ()
restore
Restore the window from minimized/maximized state
() -> ()
default-options
Default window options for run-with-options. Override fields with record spread: {...Game.default-options, fullscreen: true}
run
Run a game until the window should close, with default window options.
run-render
Run a game whose render callback returns Game.Render commands. Config fields mirror run, but use render(state) => List.
run-with-context
Run a context-aware game until the window should close, with default window options. Config fields mirror run, but update/draw receive (state, ctx). Optional field: input-config - capture config for Game.Input.snapshot-with viewport - Game.Viewport record to resize and attach to ctx
run-render-with-context
Run a context-aware game whose render callback returns Game.Render commands. Config fields mirror run-with-context, but use render(state, ctx) => List.
run-logical-render-with-context
Run a context-aware logical render-command game until the window should close, with default window options. The render callback returns commands in logical viewport coordinates; the loop owns and presents a render target. Optional present(state, ctx) commands run after presentation.
run-fixed
Run a fixed-step game until the window should close, with default window options. Config fields mirror run, but use fixed-fps, fixed-update(state, ctx), and draw(state, ctx). Optional fields: input-config - capture config for Game.Input.snapshot-with viewport - Game.Viewport record to resize and attach to ctx max-fixed-steps - maximum catch-up updates per rendered frame
run-fixed-render
Run a fixed-step game whose render callback returns Game.Render commands. Config fields mirror run-fixed, but use render(state, ctx) => List.
run-fixed-logical-render
Run a fixed-step logical render-command game until the window should close, with default window options. The render callback returns commands in logical viewport coordinates; the loop owns and presents a render target. Optional present(state, ctx) commands run after presentation.
run-with-options
Run a game with explicit window options. options fields (all Bool, all required — spread Game.default-options): resizable - Allow window resizing vsync - Enable vertical sync fullscreen - Start in fullscreen msaa - Enable 4x anti-aliasing
Game.run-with-options config {...Game.default-options, fullscreen: true}run-render-with-options
Run a render-command game with explicit window options.
run-with-context-options
Run a context-aware game with explicit window options.
run-render-with-context-options
Run a context-aware render-command game with explicit window options.
run-logical-render-with-context-options
Run a context-aware logical render-command game with explicit window options.
run-fixed-with-options
Run a fixed-step game with explicit window options.
run-fixed-render-with-options
Run a fixed-step render-command game with explicit window options.
run-fixed-logical-render-with-options
Run a fixed-step logical render-command game with explicit window options.
delta-time
Get the current frame time (delta time)
() -> Float
fps
Get the current FPS
() -> Int
time
Get the time since the game started
() -> Float
should-close?
Check if the window should close (user pressed close button or escape)
() -> Bool
set-title
Set the window title
NonEmptyString -> ()
toggle-fullscreen
Toggle fullscreen mode
() -> ()
is-fullscreen?
Check if the window is fullscreen
() -> Bool
is-focused?
Check if the window is focused
() -> Bool
is-minimized?
Check if the window is minimized
() -> Bool
minimize
Minimize the window
() -> ()
maximize
Maximize the window
() -> ()
restore
Restore the window from minimized/maximized state
() -> ()
clear
Clear the screen with a color
Int -> ()
width
Get the screen width
() -> Int
height
Get the screen height
() -> Int
take-screenshot
Save the current framebuffer to an image file.
String -> ()
circle
Draw a filled circle
Float -> Float -> PositiveFloat -> Int -> ()
circle-outline
Draw a circle outline
Float -> Float -> PositiveFloat -> Int -> ()
rect
Draw a filled rectangle
Float -> Float -> Float -> Float -> Int -> ()
rect-outline
Draw a rectangle outline
Float -> Float -> Float -> Float -> Int -> ()
rect-rounded
Draw a rounded rectangle
Float -> Float -> Float -> Float -> Float -> Int -> ()
line
Draw a line
Float -> Float -> Float -> Float -> Int -> ()
line-thick
Draw a line with thickness
Float -> Float -> Float -> Float -> Float -> Int -> ()
point
Draw a point (1x1 pixel)
Float -> Float -> Int -> ()
triangle
Draw a triangle
Float -> Float -> Float -> Float -> Float -> Float -> Int -> ()
polygon
Draw a polygon
Float -> Float -> Int -> PositiveFloat -> Float -> Int -> ()
ellipse
Draw an ellipse
Float -> Float -> Float -> Float -> Int -> ()
ellipse-outline
Draw an ellipse outline
Float -> Float -> Float -> Float -> Int -> ()
text
Draw text at a position
String -> Float -> Float -> Int -> ()
text-size
Draw text with a specific font size
String -> Float -> Float -> Int -> Int -> ()
measure-text
Measure text width for default font
String -> Int -> Int
rect-rotated
Draw a rectangle with rotation and origin
Float -> Float -> Float -> Float -> Float -> Float -> Float -> Int -> ()
ring
Draw a ring (donut shape)
Float -> Float -> Float -> Float -> Float -> Float -> Int -> ()
sector
Draw a pie/sector of a circle
Float -> Float -> PositiveFloat -> Float -> Float -> Int -> ()
load-render-target
Create a render target for off-screen drawing. Create render targets after the window has opened.
load-viewport-target
Create a render target sized for a logical viewport. Create render targets after the window has opened.
unload-render-target
Release a render target.
render-target-valid?
Check whether a render target was created successfully.
empty-render-target-state
Empty render target lifecycle state. Store this in game state, then call ensure-render-target or ensure-viewport-target after the window opens.
render-target-state
Create lifecycle state from an existing render target.
render-target-state-ready?
Return whether lifecycle state contains a valid target.
render-target-state-matches?
Return whether lifecycle state contains a valid target of the requested size.
render-target-state-target
Return the target from lifecycle state or a zero-size placeholder.
ensure-render-target-with
Ensure lifecycle state owns a valid render target of the requested size using injected loader/unloader functions. The injected variant is deterministic in tests and lets tools own backend details. Returns state with changed: true when a target was loaded or replaced this call.
ensure-render-target
Ensure lifecycle state owns a valid render target of the requested size. Create render targets after the window has opened.
ensure-viewport-target-with
Ensure lifecycle state owns a target sized for a logical viewport.
ensure-viewport-target
Ensure lifecycle state owns a target sized for a logical viewport. Create render targets after the window has opened.
unload-render-target-state-with
Release lifecycle state through an injected unloader and return empty state.
unload-render-target-state
Release lifecycle state and return empty state.
begin-render-target
Begin drawing to a render target.
end-render-target
End render target drawing.
() -> ()
render-target-width
Get a render target's current texture width.
render-target-height
Get a render target's current texture height.
draw-render-target
Draw a render target at its native size.
draw-render-target-to-viewport
Draw a render target through a viewport's physical destination rectangle.
draw-render-target-pro
Draw a render target with an explicit source and destination rectangle. Use a negative source height when drawing a target right-side-up.
create
Create a test config record with defaults.
create
Create a new empty ECS world
create-with-capacity
Create a world with initial capacity hint (for documentation only, functional lists don't pre-allocate)
add
Add an entity to the world. The entity should not have an id field; one will be assigned automatically. Returns {world: Record, id: Int}
add-simple
Add an entity to the world (convenience, returns just world)
add-many
Add multiple entities to the world Returns the new world and a list of assigned IDs
remove
Remove an entity by ID
remove-where
Remove all entities matching a predicate
get
Get an entity by ID (returns Option)
has?
Check if an entity with the given ID exists
query
Find all entities matching a predicate
query-first
Find first entity matching a predicate (returns Option)
update
Update a single entity by ID Returns unchanged world if entity not found
update-where
Update all entities matching a predicate
map-entities
Map a function over all entities
count
Count all entities
count-where
Count entities matching a predicate
sort-by
Sort entities by a key function (lowest first)
create
Create an empty asset cache.
get-texture
Get a texture from the cache, loading it if not present. Returns {asset: Texture, cache: Record}
preload-textures
Preload multiple textures into the cache.
has-texture?
Check if a texture is already cached.
unload-texture
Remove a texture from the cache and unload it.
invalidate-texture
Remove a texture from the cache without unloading it. Useful for development reload workflows where ownership of the previous backend handle is managed elsewhere.
get-sound
Get a sound from the cache, loading it if not present. Returns {asset: Ptr, cache: Record}
preload-sounds
Preload multiple sounds into the cache.
has-sound?
Check if a sound is already cached.
unload-sound
Remove a sound from the cache and unload it.
invalidate-sound
Remove a sound from the cache without unloading it.
get-font
Get a font from the cache, loading it if not present. Returns {asset: Ptr, cache: Record}
has-font?
Check if a font is already cached.
invalidate-font
Remove a font from the cache without unloading it.
get-music
Get music from the cache, loading it if not present. Returns {asset: Ptr, cache: Record}
has-music?
Check if music is already cached.
invalidate-music
Remove music from the cache without unloading it.
has-path?
Check whether any cached asset bucket contains a path. Useful for file watchers that receive changed paths without asset-kind metadata.
invalidate-path
Remove a path from every cached asset bucket without unloading handles. This preserves explicit cache ownership while giving development watchers a single invalidation hook for changed files.
invalidate-paths
Remove multiple paths from every cached asset bucket.
watch-entry
Create a watched path entry.
watch-paths-with
Snapshot file modification times for paths using an injected probe. The injected variant keeps tests deterministic and lets tools provide their own filesystem watcher data without hidden global cache state.
Function -> List -> List
watch-paths
Snapshot file modification times for paths using the active backend.
List -> List
watch-all-with
Snapshot all paths from a preload-style asset list record. asset-lists fields: textures, sounds, fonts, music.
watch-all
Snapshot all paths from a preload-style asset list record using the backend.
changed-paths
Return paths whose watched modification times are new or changed.
List -> List -> List
poll-watch-with
Refresh a watch list with an injected modification-time probe. Returns {watch, changed}.
poll-watch
Refresh a watch list with the active backend. Returns {watch, changed}.
poll-reload-with
Refresh a watch list and invalidate changed cached paths. Returns {cache, watch, changed}.
poll-reload
Refresh a watch list using the backend and invalidate changed cached paths. Returns {cache, watch, changed}.
preload-fonts
Preload a list of fonts into the cache.
preload-music
Preload a list of music streams into the cache.
preload-all
Preload textures, sounds, fonts, and music from asset lists. asset-lists fields: textures, sounds, fonts, music — each a List of paths. Pass [] for kinds you don't need.
unload-all
Unload all cached assets and return an empty cache.
invalidate-all
Remove all cached asset entries without unloading them. This is useful for tests and development reload flows that want the next access to load fresh assets without invoking backend unload calls.
size
Get the total number of cached assets.
save
Save the top-down example high score to a slot.
load
Load the top-down example high score from a slot.
slot-path
Get the file path for a top-down save slot. Distinct from Game.Save's "save-${slot}.json" scheme so the two modules can share a slot name without clobbering each other, and a .txt extension because the content is a bare integer, not JSON.
create
Create debug state from a complete configuration record. All config fields are required (records have no optional fields): enabled: Bool show-fps: Bool show-frame-time: Bool max-frame-history: Int For partial overrides, spread over the default state instead: dbg = {...Game.Debug.empty, enabled: true}
empty
Default debug state. Use as Game.Debug.empty.
toggle
Toggle overlay visibility
enable
Enable the overlay
disable
Disable the overlay
watch
Add a watch variable to display on the overlay. The value should be a string; use interpolation for non-string values.
update
Update debug state each frame. Records frame time and clears watches and profile markers for the next frame (read profiles with profile-get before the next update). Call this in your update function.
set-entity-count
Set entity count to display on overlay (0 to hide)
set-scene-name
Set current scene name to display on overlay ("" to hide)
pause
Pause the game. When paused, is-paused? returns true and should-advance? returns false until step or unpause is called.
unpause
Unpause the game.
toggle-pause
Toggle pause state.
step
Request a single frame advance while paused. Call this when the step key is pressed.
is-paused?
Check if the game is currently paused.
should-advance?
Check if the game should advance this frame. Returns true if not paused, or if a step was requested. Call this in your update function to decide whether to process game logic.
consume-step
Consume a step request. Call after advancing one paused frame.
profile-start
Start timing a named profile marker. Note: the clock has millisecond resolution; sections faster than 1ms report 0.0.
profile-end
End timing a named profile marker. Finds the most recent un-ended marker with this name and records elapsed time.
profile-get
Get the elapsed time of the most recent completed profile marker. Returns 0.0 if no matching completed marker exists.
clear-profiles
Clear all profile markers.
toggle-console
Toggle the debug console open/closed.
console-open?
Check if the debug console is open.
register-command
Register a console command. name: command name (first word typed) handler: fn(String) -> String - receives args string, returns output
console-input-char
Append a character to the console input. Only works when console is open.
console-backspace
Remove the last character from console input. Only works when console is open.
console-submit
Submit the current console input, execute the command, and add to history. Returns updated state with cleared input.
console-clear
Clear the console input and history.
get-history
Get the console history as a list of {input, output} records.
get-console-input
Get the current console input string.
draw-console
Draw the debug console if open. Call this in your draw function after drawing the game.
draw
Draw the debug overlay if enabled. Call this at the end of your draw function.
draw-bounds
Draw a rectangle outline for visual debugging (e.g. collision bounds). Only draws if debug state is enabled.
draw-vector
Draw a line representing a vector from a point. Only draws if debug state is enabled.
draw-circle
Draw a circle for visual debugging. Only draws if debug state is enabled.
draw-point
Draw a point/crosshair for visual debugging.
default-body
Default dynamic body. Override fields with record spread.
default-world
Default physics world with gravity (0, 300).
static-body
Create a static body (obstacle/wall).
create-world
Create a world with custom gravity.
add-body
Add a body to the world. Returns the updated world and the assigned id. Ids are monotonic and never reused, even after remove-body.
get-body
Get a body by id (returns Option).
set-body
Update a body by id.
remove-body
Remove a body by id.
body-count
Count bodies in the world.
step
Step the physics simulation forward by dt seconds. Applies gravity, integrates velocity, applies friction. Only dynamic bodies are updated.
step-with-collisions
Step with collision resolution between all bodies. Resolves overlaps and applies bounce (restitution).
apply-force
Apply a force to a body (affects acceleration). Force is cleared after each step.
apply-impulse
Apply an instantaneous impulse to a body (affects velocity directly).
set-velocity
Set the body's velocity directly.
set-position
Set the body's position directly.
set-size
Set the body's size.
stop
Zero out the velocity.
scale-velocity
Scale the velocity (for time dilation / slow motion).
get-position
Get the position as a {x, y} record.
get-velocity
Get the velocity as a {x, y} record.
get-bounds
Get the body's AABB bounds.
point-in-body?
Check if a point is inside a body's bounds.
on-ground?
Check if a body is on the ground (has downward collision). Tests a small ray below the body against static bodies.
move-and-slide
Move a body and resolve collisions with static bodies in the world. Returns the updated world with the moved body.
resolve-all-collisions
Resolve all body-vs-body collisions in the world. Static-static pairs are skipped. Dynamic-dynamic pairs get mutual separation.
empty-asset-reloader
Empty asset reloader state.
create-asset-reloader-with
Create an asset reloader from paths using an injected modification-time probe. The injected variant keeps tests deterministic and lets tools provide filesystem watcher data without hidden global state.
create-asset-reloader
Create an asset reloader from paths using the active backend.
create-asset-reloader-for-assets-with
Create an asset reloader from preload-style asset lists using an injected modification-time probe. asset-lists fields: textures, sounds, fonts, music.
create-asset-reloader-for-assets
Create an asset reloader from preload-style asset lists using the backend.
replace-asset-reloader-paths-with
Replace the watched paths and refresh modification-time snapshots using an injected probe.
replace-asset-reloader-paths
Replace the watched paths and refresh modification-time snapshots.
set-asset-reloader-active
Enable or disable polling. Disabled reloaders keep cache/watch state stable and report no changed paths.
poll-asset-reloader-with
Poll watched paths with an injected modification-time probe and invalidate changed cache entries. reload-count increments once per poll that reports one or more changed paths.
poll-asset-reloader
Poll watched paths using the active backend and invalidate changed cache entries.
asset-reloader-changed?
Return whether the most recent poll found changed paths.
asset-reloader-lines
Return compact status lines for debug overlays or render-command panels.
default-state-handoff-directory
Conventional directory for development state handoff files.
String
state-handoff-filename
Default development state handoff file name for a state name.
String -> String
state-handoff-path
Default development state handoff file path for a state name.
String -> String
state-handoff-path-in
Default development state handoff file path inside a directory.
String -> String -> String
default-state-handoff-path
Default development state handoff path inside .kit-game.
String -> String
create-state-handoff
Create a development state handoff envelope from a JSON-compatible state. The state field is an Encoding.JSON value.
state-handoff-to-json
Convert a state handoff envelope to a JSON value.
state-handoff-from-json
Convert state handoff JSON to a handoff envelope.
stringify-state-handoff
Convert a state handoff envelope to JSON text.
parse-state-handoff
Parse state handoff JSON text.
state-handoff-lines
Return compact status lines for debug overlays or external tooling.
save-state-handoff-file
Save a state handoff envelope to an explicit file path.
load-state-handoff-file
Load a state handoff envelope from an explicit file path.
exists-state-handoff-file?
Check if a state handoff file exists.
FileReadAuth -> String -> Bool
delete-state-handoff-file
Delete a state handoff file.
FileAuth -> String -> Result Bool String
empty-dev-session
Empty development session state. A dev session composes the asset reloader with source-file watch state and records whether the most recent poll should restart the running app after writing a state handoff.
create-named-dev-session-with
Create a named development session using an injected modification-time probe. Asset paths are invalidated through the asset reloader; source paths request a restart when their modification times change.
create-dev-session-with
Create a default-named development session using an injected modification-time probe.
create-named-dev-session
Create a named development session using the active backend.
create-dev-session
Create a default-named development session using the active backend.
create-dev-session-for-assets-with
Create a development session from preload-style asset lists using an injected modification-time probe.
create-dev-session-for-assets
Create a development session from preload-style asset lists using the active backend.
replace-dev-session-paths-with
Replace the watched asset/source paths using an injected modification-time probe.
replace-dev-session-paths
Replace the watched asset/source paths using the active backend.
set-dev-session-handoff-path
Override the state handoff path associated with a dev session.
set-dev-session-active
Enable or disable session polling. Disabling clears transient change and restart flags while preserving watch snapshots and counters.
poll-dev-session-with
Poll a development session with an injected modification-time probe. Asset changes invalidate cache entries through the asset reloader; source changes request a restart but leave process execution to a caller-owned runner.
poll-dev-session
Poll a development session using the active backend.
dev-session-cache
Return the cache owned by the session asset reloader.
dev-session-changed?
Return whether the session saw asset or source changes on the last poll.
dev-session-restart-requested?
Return whether the last poll requested a process restart.
dev-session-action
Return the most important action implied by the latest poll.
dev-session-view
Return UI/tooling-oriented session state.
dev-session-lines
Return compact status lines for debug overlays or external dev tools.
empty-session
Empty development session using the canonical shorter session naming.
create-named-session-with
Create a named development session using an injected modification-time probe.
create-session-with
Create a development session using an injected modification-time probe.
create-named-session
Create a named development session using the active backend.
create-session
Create a development session using the active backend.
create-session-for-assets-with
Create a development session from asset lists using an injected probe.
create-session-for-assets
Create a development session from asset lists using the active backend.
replace-session-paths-with
Replace session asset/source watch paths using an injected probe.
replace-session-paths
Replace session asset/source watch paths using the active backend.
set-session-handoff-path
Set the state handoff path associated with a session.
set-session-active
Enable or disable session polling.
poll-session-with
Poll session asset/source watches using an injected probe.
poll-session
Poll session asset/source watches using the active backend.
session-cache
Return the cache owned by the session asset reloader.
session-action
Return the action implied by the last session poll.
session-view
Return UI/tooling-oriented session state.
session-lines
Return compact status lines for debug overlays or external dev tools.
session-changed?
Return whether the session saw asset or source changes on the last poll.
session-restart-requested?
Return whether the last poll requested a process restart.
empty-runner-command
Empty development runner command. Runner commands are data records that describe what an external dev loop should do next; this module does not own process spawning.
create-session-handoff
Create the state handoff envelope associated with a development session.
save-session-handoff-file
Save a state handoff envelope to the session's configured handoff path.
save-session-restart-handoff-file
Save a session handoff only when the session currently requests restart. Returns Ok false when no restart is pending.
session-command
Convert a polled development session into the command an external dev runner should execute next.
runner-command-lines
Return compact status lines for a development runner command.
empty-runner
Empty development runner state. A runner stores the current session, latest command, and non-idle command history; it still leaves process execution to caller-owned tooling.
create-named-runner-with
Create a named development runner using an injected modification-time probe.
create-runner-with
Create a default-named development runner using an injected modification-time probe.
create-named-runner
Create a named development runner using the active backend.
create-runner
Create a default-named development runner using the active backend.
runner-session
Return the session owned by a runner.
runner-command
Return the latest command produced by a runner.
poll-runner-with
Poll a runner using an injected modification-time probe.
poll-runner
Poll a runner using the active backend.
runner-lines
Return compact runner status lines.
dev-runner-script-filename
Default generated dev runner script file name.
String
default-dev-runner-script-path
Default generated dev runner script path inside .kit-game.
String
dev-runner-command
Return the default kit run command for a main file.
String -> String
dev-runner-plan
Create an inspectable external dev runner script plan from explicit fields. Asset paths are watched for reload notices; source paths trigger process restarts in the generated shell script.
create-dev-runner-plan
Create an external dev runner script plan from a partial config record. Optional fields: name, main, command, asset-paths, source-paths, poll-interval, handoff-path, script-path.
dev-runner-script-lines
Return shell script lines for an external dev runner plan. These are pure strings for a project script or future CLI to execute.
dev-runner-script
Return a shell script for an external dev runner plan.
dev-runner-launch-command
Return the shell command that runs a generated external dev runner script.
dev-runner-launch-action
Return structured launch data for project scripts or a future CLI.
dev-runner-script-step
Create a write step for a runnable external dev runner script artifact.
with-dev-runner-script
Return a dev runner plan with a script artifact step attached.
dev-runner-step-label
Return a human-readable label for a dev runner artifact step.
dev-runner-step-view
Return a UI/tooling-oriented view record for one dev runner artifact step.
save-dev-runner-script-file
Save a generated external dev runner script to its configured path. The returned step keeps mode metadata for a caller or CLI to apply.
dev-runner-plan-step-views
Return view records for all dev runner artifact steps.
dev-runner-step-script-lines
Return shell command lines for materializing one dev runner artifact step. These commands are intended for project scripts or a future CLI.
dev-runner-artifact-script-lines
Return shell command lines for materializing all dev runner artifacts. Plans without an attached steps list default to the generated runner script.
dev-runner-artifact-script
Return a shell script for materializing all dev runner artifacts.
save-dev-runner-plan-files
Save every file artifact in an external dev runner plan. Plans without an attached steps list default to the generated runner script.
dev-runner-conflict
Create one dev runner artifact conflict entry.
dev-runner-plan-conflicts-with
Detect dev runner artifact conflicts using a caller-provided predicate.
dev-runner-plan-conflicts-file
Detect dev runner artifact conflicts on disk using file read auth.
dev-runner-plan-has-conflicts?
Return true when a dev runner conflict list is non-empty.
List -> Bool
dev-runner-plan-conflict-lines
Return display lines for dev runner artifact conflicts.
List -> List
save-dev-runner-plan-files-safe
Save every external dev runner file artifact only when none of the target paths exists.
dev-runner-plan-view
Return a UI/tooling-oriented summary for a dev runner plan.
dev-runner-plan-lines
Return display lines for a dev runner plan summary.
create
Create a pool from a list of pre-allocated objects. Each object is wrapped with an id and active flag.
create-with-factory
Create a pool with a factory function called N times.
acquire
Acquire an available object from the pool. Returns {pool: Record, data: Option, id: Int}. id is -1 if no object is available.
release
Release an object back to the pool by id.
release-all
Release all active objects back to the pool.
is-active?
Check if an entry is active.
get
Get an active entry's data by id (returns None if inactive or missing).
active-list
Get all active entries as a list of {id, data} records.
active-data
Get only the data of all active objects.
active-count
Count active objects.
available-count
Count available (inactive) objects.
capacity
Total pool capacity.
has-available?
Check if pool has any available objects.
is-empty?
Check if pool is completely inactive.
update
Update an active object's data by id. Only updates if the entry is active.
map-active
Map a function over all active objects' data. Inactive objects are left unchanged.
filter-active
Filter active objects by predicate, releasing those that don't match.
grow
Resize the pool by adding new inactive objects. Preserves existing active entries.
up-action
Conventional action names used by default-actions and update-with-actions.
String
down-action
Down navigation action name used by default-actions and update-with-actions.
String
confirm-action
Confirm action name used by default-actions and update-with-actions.
String
back-action
Back/cancel action name used by default-actions and update-with-actions.
String
default-actions
Default keyboard menu bindings.
item
Create an enabled menu item.
disabled-item
Create a disabled menu item.
empty
Empty menu state.
create
Create a menu from item records.
create-with
Create a menu from a config record. Required field: items. Optional fields: selected, wrap, active.
count
Count menu items.
selected-item
Return the selected item if it exists and is enabled.
selected-id
Return the selected item id if available.
lines
Return render-friendly line records for all menu items.
select
Select a specific item index, clamped to the menu bounds. Disabled indices select the first enabled item instead.
select-next
Move to the next enabled item.
select-prev
Move to the previous enabled item.
set-active
Enable or disable menu input handling.
no-action
No menu action.
confirm
Build a confirm action from the current selected item.
back
Build a back/cancel action.
update-with-actions
Update selection from action-map input and return {menu, action}. Navigation consumes one edge per call. Confirm and back return action records for the caller to interpret.
pi
Pi (3.14159...)
Float
tau
Tau (2 * Pi, full circle in radians)
Float
clamp
Clamp a value between min and max
Float -> Float -> Float -> Float
lerp
Linear interpolation between two values
Float -> Float -> Float -> Float
inverse-lerp
Inverse lerp: get t from a value between a and b
Float -> Float -> Float -> Float
remap
Remap a value from one range to another
Float -> Float -> Float -> Float -> Float -> Float
sign
Get the sign of a number (-1, 0, or 1)
Float -> Float
move-toward
Move a value toward a target by a maximum delta
Float -> Float -> Float -> Float
deg-to-rad
Convert degrees to radians
Float -> Float
rad-to-deg
Convert radians to degrees
Float -> Float
vec2
Create a 2D vector
vec2-zero
Zero vector (0, 0)
vec2-up
Unit vector pointing up (0, -1)
vec2-down
Unit vector pointing down (0, 1)
vec2-left
Unit vector pointing left (-1, 0)
vec2-right
Unit vector pointing right (1, 0)
vec2-add
Add two vectors
vec2-sub
Subtract two vectors
vec2-scale
Multiply a vector by a scalar
vec2-div
Divide a vector by a scalar
vec2-negate
Negate a vector
vec2-length
Get the length of a vector
vec2-length-squared
Get the squared length of a vector (faster than length)
vec2-normalize
Normalize a vector to unit length
vec2-dot
Dot product of two vectors
vec2-cross
Cross product (returns scalar z-component)
vec2-distance
Distance between two points
vec2-distance-squared
Squared distance between two points
vec2-lerp
Linear interpolation between two vectors
vec2-rotate
Rotate a vector by an angle (in radians)
vec2-angle
Get the angle of a vector (from positive x-axis)
vec2-perpendicular
Get a perpendicular vector (90 degrees counter-clockwise)
vec2-reflect
Reflect a vector off a surface with the given normal
vec2-clamp-length
Clamp a vector to a maximum length
vec2-from-angle
Create a unit vector from an angle (in radians)
vec3
Create a 3D vector.
vec3-zero
Zero vector (0, 0, 0).
vec3-div
Divide a 3D vector by a scalar.
vec3-length
Get the length of a 3D vector.
vec3-normalize
Normalize a 3D vector to unit length.
Vec3
Namespaced 3D vector helpers.
mat4-mul
Multiply two 4x4 matrices.
[Float] -> [Float] -> [Float]
mat4-perspective
Build a perspective projection matrix.
Float -> Float -> Float -> Float -> [Float]
mat4-rotate-x
Build a rotation matrix around the X axis.
Float -> [Float]
mat4-rotate-y
Build a rotation matrix around the Y axis.
Float -> [Float]
mat4-translate
Build a translation matrix from x/y/z fields.
Mat4
Namespaced 4x4 matrix helpers.
ease-linear
Linear easing (no easing)
Float -> Float
ease-in-quad
Quadratic ease in
Float -> Float
ease-out-quad
Quadratic ease out
Float -> Float
ease-in-cubic
Cubic ease in
Float -> Float
ease-out-cubic
Cubic ease out
Float -> Float
empty-dev-services
Empty runtime services for tests and synthetic runtime sources.
empty-replay-services
Empty replay services for tests and synthetic runtime sources.
empty-services
Empty runtime services for tests and synthetic runtime sources.
services
Create an explicit runtime services record.
empty
Empty context for tests and synthetic runtime sources.
window-state
Create a window state record.
create
Create a context from a complete config record. Required fields: dt, time, fps, frame, window, input, platform. Optional field: viewport.
create-with-viewport
Create a context with an explicit viewport.
next-frame
Advance an existing context with new frame data. Required frame-data fields: dt, time, fps, window, input. Optional field: viewport.
with-services
Replace all runtime service state on a context.
with-cache
Replace the context-owned asset cache.
with-debug
Replace the context-owned debug state.
debug
Return the context-owned debug state.
toggle-debug
Toggle the context-owned debug overlay.
enable-debug
Enable the context-owned debug overlay.
disable-debug
Disable the context-owned debug overlay.
watch-debug
Add a watch to the context-owned debug overlay.
update-debug
Update the context-owned debug overlay using ctx.dt.
set-debug-entity-count
Set the context-owned debug entity count.
set-debug-scene-name
Set the context-owned debug scene name.
debug-profile-start
Start a context-owned debug profile marker.
debug-profile-end
End a context-owned debug profile marker.
with-dev
Replace the context-owned development tooling state.
replay-services
Return the context-owned replay service state.
with-replay-services
Replace the context-owned replay service state.
asset-reloader
Return the context-owned asset reloader, defaulting to the current cache.
with-asset-reloader
Replace the context-owned asset reloader and synchronize ctx.services.cache.
poll-asset-reloader-with
Poll the context-owned asset reloader with an injected modification-time probe.
poll-asset-reloader
Poll the context-owned asset reloader using the active backend.
asset-reloader-changed?
Return whether the context-owned asset reloader found changes last poll.
asset-reloader-lines
Return compact status lines for the context-owned asset reloader.
runner
Return the context-owned development runner, defaulting to the current cache.
with-runner
Replace the context-owned development runner and synchronize ctx.services.cache with the runner session cache.
poll-runner-with
Poll the context-owned development runner with an injected modification-time probe.
poll-runner
Poll the context-owned development runner using the active backend.
runner-session
Return the context-owned runner session.
runner-command
Return the latest context-owned runner command.
runner-command-lines
Return compact status lines for the latest context-owned runner command.
runner-lines
Return compact status lines for the context-owned runner.
service-view
Return a compact summary of context-owned runtime services.
service-lines
Return compact display lines for context-owned runtime services.
live-window
Read current window state from the backend.
live
Create a context from live backend timing/window state and an input snapshot.
live-with-services
Create a live context with explicit runtime services.
live-with-viewport
Create a live context with an explicit viewport.
live-with-viewport-and-services
Create a live context with an explicit viewport and runtime services.
create
Create an empty tilemap.
add-layer
Add a layer to the tilemap.
create-layer-with-data
Create a layer with initial data.
get-tile
Get tile index at position (in tile coordinates).
toggle-layer
Toggle layer visibility.
world-to-tile
Convert world position to tile position.
is-solid?
Check if a tile position is solid.
is-solid-at?
Check if a world position is solid.
rect-collides?
Check if a rectangle collides with any solid tiles. Tests every tile the rectangle overlaps, so entities larger than one tile cannot straddle a solid tile undetected.
resolve-collision
Resolve collision by pushing entity out of solid tiles.
draw
Draw all visible layers.
create
Create a static sprite from a texture
Texture -> Sprite
create-centered
Create a static sprite with centered origin
Texture -> Sprite
draw
Draw a static sprite
Sprite -> Float -> Float -> ()
draw-tinted
Draw a static sprite with tint
Sprite -> Float -> Float -> Int -> ()
draw-ex
Draw a static sprite with rotation and scale. Rotates around the sprite origin (like draw-pro), so centered sprites spin around their center.
Sprite -> Float -> Float -> Float -> Float -> Int -> ()
draw-pro
Draw a static sprite with full control
Sprite -> Float -> Float -> Float -> Float -> Float -> Int -> ()
animated
Create an animated sprite from a sprite sheet
Config fields: texture: Ptr - The sprite sheet texture frame-width: Int - Width of each frame in pixels frame-height: Int - Height of each frame in pixels animations: Map - Map of animation name to {frames: [Int], fps: Float} default-animation: String - Name of the animation to start with (optional)
{texture: Texture, frame-width: Int, frame-height: Int, animations: Map, default-animation: String} -> AnimatedSprite
animated-centered
Create an animated sprite with centered origin
{texture: Texture, frame-width: Int, frame-height: Int, animations: Map, default-animation: String} -> AnimatedSprite
set-animation
Set the current animation
AnimatedSprite -> NonEmptyString -> AnimatedSprite
update
Update an animated sprite Advances the current animation based on its fps and frames list.
AnimatedSprite -> Float -> AnimatedSprite
update-with
Update with explicit animation data
AnimatedSprite -> Float -> List -> Float -> AnimatedSprite
play
Play the animation
AnimatedSprite -> AnimatedSprite
pause
Pause the animation
AnimatedSprite -> AnimatedSprite
reset
Reset the animation
AnimatedSprite -> AnimatedSprite
set-flip-x
Set horizontal flip
AnimatedSprite -> Bool -> AnimatedSprite
set-flip-y
Set vertical flip
AnimatedSprite -> Bool -> AnimatedSprite
draw-animated
Draw an animated sprite
AnimatedSprite -> Float -> Float -> Int -> Int -> ()
draw-current
Draw current frame Looks up the current animation's frame list to resolve the sprite sheet index.
AnimatedSprite -> Float -> Float -> Int -> ()
draw-animated-ex
Draw with rotation and scale
AnimatedSprite -> Float -> Float -> Int -> Float -> Float -> Int -> ()
frame-count
Calculate the total number of frames in a sprite sheet
Texture -> Int -> Int -> Int
frame-position
Calculate the position of a frame in a sprite sheet
Texture -> Int -> Int -> Int -> {x: Int, y: Int}
row-frames
Get frame indices for a row
Texture -> Int -> Int -> Int -> List
col-frames
Get frame indices for a column
Texture -> Int -> Int -> Int -> Int -> List
set-origin
Set the origin of a sprite
Sprite -> Float -> Float -> Sprite
center-origin
Center the origin of a sprite
Sprite -> Sprite
bottom-center-origin
Set the origin to bottom-center
Sprite -> Sprite
init
Initialize the audio device. Call this before loading or playing audio.
() -> ()
close
Close the audio device
() -> ()
ready?
Check if the audio device is ready
() -> Bool
set-master-volume
Set the master volume (0.0 to 1.0)
Float -> ()
get-master-volume
Get the master volume
() -> Float
load-sound
Load a sound from a file
NonEmptyString -> Ptr
unload-sound
Unload a sound from memory
Ptr -> ()
play
Play a sound
Ptr -> ()
stop-sound
Stop a sound
Ptr -> ()
pause-sound
Pause a sound
Ptr -> ()
resume-sound
Resume a paused sound
Ptr -> ()
sound-playing?
Check if a sound is playing
Ptr -> Bool
set-sound-volume
Set the volume for a sound (0.0 to 1.0)
Ptr -> Float -> ()
set-sound-pitch
Set the pitch for a sound (1.0 is normal)
Ptr -> Float -> ()
set-sound-pan
Set the pan for a sound (0.0 left, 0.5 center, 1.0 right)
Ptr -> Float -> ()
play-at-volume
Play a sound at a specific volume
Ptr -> Float -> ()
load-music
Load music from a file (streaming)
NonEmptyString -> Ptr
unload-music
Unload music from memory
Ptr -> ()
play-music
Play music (must call update-music each frame)
Ptr -> ()
stop-music
Stop music
Ptr -> ()
pause-music
Pause music
Ptr -> ()
resume-music
Resume paused music
Ptr -> ()
update-music
Update music stream buffer (call each frame)
Ptr -> ()
music-playing?
Check if music is playing
Ptr -> Bool
set-music-volume
Set music volume (0.0 to 1.0)
Ptr -> Float -> ()
set-music-pitch
Set music pitch (1.0 is normal)
Ptr -> Float -> ()
set-music-pan
Set music pan (0.0 left, 0.5 center, 1.0 right)
Ptr -> Float -> ()
music-length
Get the total length of music in seconds
Ptr -> Float
music-position
Get the current playback position in seconds
Ptr -> Float
seek-music
Seek to a specific position in music (in seconds)
Ptr -> Float -> ()
set-music-looping
Set whether music should loop. UNIMPLEMENTED: currently a no-op — raylib music loops by default and the backend does not yet support disabling it (kit-game issue #20).
Ptr -> Bool -> ()
make
Create a test record containing hyphenated fields.
main-file
Generate a starter main.kit file content. title: the game window title
String -> String
kit-toml
Generate a starter kit.toml file content. name: package name version: e.g. "0.1.0"
String -> String -> String
readme
Generate a starter README.md file content. title: project title
String -> String
gitignore
Generate a starter .gitignore file content.
() -> String
scaffold
Generate all starter file contents as a record. Fields: main, kit-toml, readme, gitignore
scaffold-file
Create one scaffold file entry.
scaffold-files
Generate starter project file entries.
String -> String -> List
scaffold-files-in
Generate starter project file entries under a target root directory.
String -> String -> String -> List
scaffold-plan
Generate an inspectable starter project scaffold plan.
scaffold-plan-in
Generate an inspectable starter project scaffold plan under a root directory.
scaffold-conflict
Create one scaffold conflict entry.
scaffold-conflicts-with
Detect scaffold conflicts using a caller-provided path-exists predicate.
scaffold-conflicts-file
Detect scaffold conflicts on disk using file read auth.
scaffold-has-conflicts?
Return true when a conflict list is non-empty.
List -> Bool
scaffold-script-lines
Return shell command lines for writing a scaffold plan. These are pure strings for a project script or future CLI to execute.
scaffold-script
Return a shell script for writing a scaffold plan.
scaffold-safe-script-lines
Return shell command lines that refuse to overwrite existing scaffold files. The generated script checks every target path before writing any file.
scaffold-safe-script
Return a shell script that refuses to overwrite existing scaffold files.
scaffold-script-filename
Default generated scaffold script file name.
String
scaffold-script-path
Return the generated scaffold script path for a scaffold plan.
scaffold-launch-command
Return the shell command that runs a generated safe scaffold script.
scaffold-launch-action
Return structured launch data for project scripts or a future CLI.
scaffold-file-view
Return a UI/tooling-oriented view for one scaffold file.
scaffold-file-views
Return view records for all scaffold files.
scaffold-plan-view
Return a UI/tooling-oriented summary for a scaffold plan.
scaffold-plan-lines
Return display lines for a scaffold plan summary.
scaffold-conflict-lines
Return display lines for scaffold conflicts.
List -> List
safe-scaffold-script-step
Create a write step for a runnable safe scaffold script artifact. The artifact script refuses to overwrite existing scaffold targets.
with-safe-scaffold-script
Return a scaffold plan with a safe scaffold script artifact step attached.
scaffold-plan-file-steps
Return every file artifact step for a scaffold plan. Plans without an attached steps list default to their scaffold files.
save-scaffold-file
Save one scaffold file artifact. The returned step records written: true and preserves executable metadata.
save-scaffold-plan-files
Save every file artifact in a scaffold plan. This helper does not perform conflict checks; use the safe variant for project creation flows that should refuse to overwrite existing files.
save-scaffold-plan-files-safe
Save every scaffold plan file only when none of the target paths exists. The conflict check includes attached artifact steps such as the safe scaffold script, so no file is written when any target would be overwritten.
empty
Empty command queue.
List
clear
Clear the screen with a color.
circle
Draw a filled circle.
circle-outline
Draw a circle outline.
rect
Draw a filled rectangle.
rect-outline
Draw a rectangle outline.
rect-rounded
Draw a rounded rectangle.
line
Draw a line.
line-thick
Draw a line with thickness.
point
Draw a point.
triangle
Draw a triangle.
polygon
Draw a polygon.
ellipse
Draw an ellipse.
ellipse-outline
Draw an ellipse outline.
text
Draw text with the default size.
text-size
Draw text with a specific font size.
rect-rotated
Draw a rectangle with rotation and origin.
ring
Draw a ring.
sector
Draw a pie or sector.
sprite
Draw a sprite.
missing-asset
Draw a visible fallback for a missing or invalid asset path.
sprite-path
Build a sprite command from a cache-owned texture path. Returns {cache, command} so the caller keeps ownership of cache state.
sprite-tinted
Draw a tinted sprite.
sprite-path-tinted
Build a tinted sprite command from a cache-owned texture path. Returns {cache, command} so the caller keeps ownership of cache state.
sprite-ref
Describe a cache-owned sprite path draw for batch queue construction.
sprite-ref-tinted
Describe a cache-owned tinted sprite path draw for batch queue construction.
sprite-path-queue
Build render commands from sprite path refs while threading cache ownership. Returns {cache, commands}.
sprite-path-commands
Build only the command list from sprite path refs. Use sprite-path-queue when the updated cache needs to be kept.
sprite-ex
Draw a sprite with rotation and scale.
sprite-pro
Draw a sprite with explicit destination size.
animated-sprite
Draw an animated sprite frame.
animated-current
Draw an animated sprite's current animation frame.
animated-sprite-ex
Draw an animated sprite frame with rotation and scale.
tilemap
Draw a tilemap.
tilemap-layer
Draw one tilemap layer.
tilemap-in-bounds
Draw a tilemap through camera bounds.
particles
Draw particles as circles.
particles-rects
Draw particles as rectangles.
particles-faded
Draw particles with lifetime fade.
particles-textured
Draw textured particles.
render-target
Draw a render target at its native size.
render-target-tinted
Draw a tinted render target at its native size.
render-target-to-viewport
Draw a render target through a viewport's physical destination rectangle.
render-target-to-clipped-viewport
Draw a render target through a viewport and clip to the physical viewport.
render-target-to-letterboxed-viewport
Draw letterbox bars, then draw a render target through a clipped viewport.
render-target-presentation
Build a complete presentation queue for a logical render target followed by screen-space presentation commands such as overlays or screenshots.
render-target-pro
Draw a render target with explicit source and destination rectangles. Use a negative source height when drawing a target right-side-up.
screenshot
Capture the current framebuffer to a file when the queue executes.
debug
Draw the debug overlay.
camera-begin
Begin drawing through a camera.
camera-end
End camera drawing mode.
with-camera
Wrap a command list in camera begin/end commands.
scissor-begin
Begin drawing with a rectangular scissor/clip region.
scissor-end
End scissor/clip drawing mode.
with-scissor
Wrap a command list in scissor begin/end commands.
to-screen
Convert a logical-canvas command queue to physical screen coordinates through a viewport. clear becomes a rectangle over the viewport render area. Camera blocks keep world-space commands unchanged while scaling the camera offset and zoom to the viewport.
with-viewport
Alias for to-screen when building render queues.
viewport-scissor-begin
Begin clipping to the physical viewport rectangle.
with-viewport-scissor
Wrap already screen-space commands in a physical viewport scissor.
with-clipped-viewport
Convert logical commands through a viewport and clip them to the viewport.
letterbox-bars
Commands that cover the bars outside an aspect-fit or integer-fit viewport.
with-letterbox
Add letterbox bars and convert logical commands through a viewport.
with-clipped-letterbox
Add letterbox bars and clip logical commands to the viewport rectangle.
append
Append a command to a queue.
count
Count commands in a queue.
List -> Int
kinds
Return command kinds in order.
List -> List
of-kind
Return commands with the given kind.
List -> String -> List
inspect
Return a compact summary for debug overlays or tests.
watch-debug
Add render command count to a debug overlay state.
watch-debug-kinds
Add render command kinds to a debug overlay state.
execute-one
Execute one render command through the existing drawing modules. Unknown command kinds are ignored.
execute
Execute a command queue through the existing drawing modules.
List -> ()
default-metadata
Default release metadata.
metadata
Create release metadata from a partial config record.
debug-profile
Debug profile: fast local build output.
release-profile
Release profile: optimized binary plus assets.
distribution-profile
Distribution profile: optimized output intended for bundling.
profile
Create a profile from explicit fields.
profile-with
Create a profile from a partial config record.
bundle-root-path
Return the generic bundle root path for a profile.
bundle-bin-dir
Return the bundled executable directory for a profile.
bundle-assets-dir
Return the bundled asset directory for a profile.
bundle-metadata-dir
Return the bundled metadata directory for a profile.
executable-path
Return the profile output path for the executable.
asset-output-dir
Return the output asset directory for a profile.
asset-output-path
Return the output path for one asset entry.
icon-output-path
Return the output path for an application icon. Icons are copied to the profile output root rather than the asset directory.
asset
Create an asset entry whose destination matches its source path.
asset-to
Create an asset entry with an explicit destination path.
asset-from-root
Create an asset entry from a root directory and relative path. The copied destination remains relative to the package asset directory.
build-command
Return the kit build command for metadata and a release profile.
build-step
Create the build step record for a plan.
copy-step
Create one asset copy step record.
icon-step
Create an optional icon copy step for release metadata.
manifest
Generate a simple release manifest text.
manifest-path
Return the manifest output path for a profile.
bundle-layout
Return the generic distribution bundle layout for metadata and a profile. Non-bundled profiles return empty layout paths with enabled: false.
manifest-step
Create the manifest write step record for a plan.
plan
Create a complete release plan.
create-plan
Create a release plan from a config record. Optional fields: metadata, profile, assets.
step-label
Return a human-readable label for a release plan step.
step-view
Return a UI/tooling-oriented view record for one release step.
plan-step-views
Return view records for all release plan steps.
plan-view
Return a UI/tooling-oriented summary for a release plan.
plan-lines
Return display lines for a release plan summary.
step-script-lines
Return shell command lines for one release plan step. These are pure strings for a project script or future CLI to execute.
script-lines
Return a shell script as lines for a complete release plan.
script
Return a shell script for a complete release plan.
release-package-script-filename
File name for a generated release package script.
String
release-package-script-path
Return the generated release package script path for a profile.
release-package-script-step
Create a write step for a runnable release package script artifact. The artifact script contains the package commands for the original plan.
with-release-package-script
Return a plan with a package-script artifact step appended. The appended step writes a runnable script for the original plan.
step-package-actions
Return structured package actions for one release plan step.
package-actions
Return structured package actions for every release plan step.
package-action-label
Return a human-readable label for a package action.
package-action-view
Return a UI/tooling-oriented view record for one package action.
package-action-views
Return package action view records for a release plan.
launch-command
Return the shell command that runs the built release executable.
launch-action
Return structured launch data for future CLIs or project scripts.
package-plan
Create a structured package action plan from a release plan. The plan also carries generated shell script lines for external adapters.
package-plan-view
Return a UI/tooling-oriented summary for a package action plan.
package-plan-lines
Return display lines for a package action plan summary.
package-preflight-issue
Create one package preflight issue record.
package-preflight-with
Preflight a package action plan with caller-provided source/target predicates. Source checks apply to build-command sources and copy sources. Target checks report overwrite risk for command outputs, copy destinations, and write paths.
package-preflight-file
Preflight a package action plan against the current filesystem.
package-preflight-has-issues?
Return true when a package preflight issue list is non-empty.
List -> Bool
package-preflight-lines
Return display lines for package preflight issues.
List -> List
package-action-script-lines
Return shell command lines for one structured package action.
package-script-lines
Return shell script lines for a structured package action plan.
package-script
Return a shell script for a structured package action plan.
package-preflight-guard-lines
Return shell guard lines that fail on missing sources or existing targets.
package-safe-script-lines
Return guarded shell script lines for a structured package action plan.
package-safe-script
Return a guarded shell script for a structured package action plan.
release-safe-package-script-step
Create a write step for a guarded release package script artifact. The artifact script fails before missing sources or existing targets.
with-safe-release-package-script
Return a plan with a guarded package-script artifact step appended.
file-artifact-step?
Return whether a release plan step writes a file artifact. Build and copy steps are intentionally excluded because they must be run through generated shell commands or future CLI process execution.
plan-file-steps
Return only file artifact steps from a release plan.
save-step-file
Save one release file artifact step to disk. The returned step keeps mode metadata for a caller or CLI to apply.
save-plan-files
Save every file artifact in a release plan. Build and copy steps remain shell/CLI execution steps and are skipped.
plan-file-conflicts-with
Detect release file artifact conflicts using a caller-provided target predicate. Build and copy steps are skipped; only writable file artifacts are checked.
plan-file-conflicts-file
Detect release file artifact conflicts on disk using file read auth.
save-plan-files-safe
Save every release file artifact only when none of the target paths exists. Build and copy steps are still left to generated shell scripts or a future CLI.
default-profile-name
Conventional default action profile name.
String
empty-snapshot
Empty input snapshot for tests, replay, and synthetic input sources.
default-capture
Default set of inputs captured by capture. Override fields with record spread for game-specific inputs.
snapshot-key-down?
Check if a key is down in a snapshot.
snapshot-key-pressed?
Check if a key was pressed in a snapshot.
snapshot-key-released?
Check if a key was released in a snapshot.
snapshot-mouse-down?
Check if a mouse button is down in a snapshot.
snapshot-mouse-pressed?
Check if a mouse button was pressed in a snapshot.
snapshot-mouse-released?
Check if a mouse button was released in a snapshot.
snapshot-touches
Return touch points from a snapshot, defaulting missing legacy fields to [].
snapshot-gamepad-button-down?
Check if a gamepad button is down in a snapshot.
snapshot-gamepad-button-pressed?
Check if a gamepad button was pressed in a snapshot.
snapshot-gamepad-button-released?
Check if a gamepad button was released in a snapshot.
snapshot-gamepad-axis
Get a gamepad axis value from a snapshot.
snapshot-touch-count
Count touch points in a snapshot.
snapshot-touch-at
Get a touch point by list index from a snapshot.
snapshot-touch-by-id
Get a touch point by backend touch id from a snapshot.
snapshot-touch-active?
Check if a touch id is active in a snapshot.
touch-region
Create a rectangular touch region in logical or screen coordinates. Use the same coordinate space as the snapshot being queried.
touch-point-in-region?
Check whether a touch point lies inside a region.
snapshot-touch-in-region?
Check whether any touch point in a snapshot lies inside a region.
touch-region-pressed?
Check whether a touch region became active between snapshots.
touch-region-released?
Check whether a touch region stopped being active between snapshots.
touch-distance
Return the distance between two touch-like points.
touch-center
Return the center point between two touch-like points.
touch-delta
Return movement for a touch id between previous and current snapshots.
first-touch-delta
Return movement for the first current touch that existed previously.
touch-swipe
Return a swipe record when a touch moved at least min-distance.
first-touch-swipe
Return the first swipe from current touches that existed previously.
touch-pinch
Return pinch metrics for the first two current touches with previous matches.
infer-last-device
Infer the active input device from a snapshot. Edge events and movement win over held state because snapshots do not keep cross-frame device history.
snapshot-with
Capture a backend input snapshot using a complete capture config. Use {...Game.Input.default-capture, keys: [...]} for custom lists.
capture
Capture a backend input snapshot using Game.Input.default-capture.
key-binding
Create a digital key binding.
key-axis-binding
Create a key binding that contributes an axis value.
mouse-binding
Create a digital mouse button binding.
touch-region-binding
Create a digital touch-region binding for virtual buttons. Use action-down? for held state and action-started? / action-ended? for previous/current edge detection.
touch-swipe-binding
Create a touch swipe binding for previous/current action-started? queries. direction is "left", "right", "up", "down", or "any".
touch-pinch-binding
Create a touch pinch binding for previous/current action-started? queries. direction is "in", "out", or "any".
mouse-axis-binding
Create a mouse button binding that contributes an axis value.
gamepad-button-binding
Create a digital gamepad button binding.
gamepad-button-axis-binding
Create a gamepad button binding that contributes an axis value.
gamepad-axis-binding
Create an analog gamepad axis binding.
create-actions
Create an action map from binding records. Binding fields: action: String kind: "key", "mouse", "gamepad-button", or "gamepad-axis" input: String Axis bindings use value, gamepad, deadzone, and scale fields.
create-actions-with-deadzone
Create an action map with a default analog deadzone.
add-binding
Add a binding to an action map.
remove-action-bindings
Remove every binding for one action.
replace-action-bindings
Replace every binding for one action. Incoming bindings are assigned to the requested action name so saved UI choices cannot drift to another action.
rebind-key
Replace an action with one digital key binding.
rebind-key-axis
Replace an action with one key axis binding.
rebind-mouse
Replace an action with one digital mouse button binding.
rebind-gamepad-button
Replace an action with one digital gamepad button binding.
rebind-gamepad-axis
Replace an action with one analog gamepad axis binding.
bindings-for
Return all bindings for an action.
binding-source-key
Return a stable physical-source key for a binding. Values, deadzones, and action names are intentionally ignored so rebinding UIs can detect conflicting uses of the same key, button, axis, or region.
binding-same-source?
Check whether two bindings use the same physical source.
binding-conflict?
Check whether an existing binding conflicts with a candidate binding. Bindings on the same action are not conflicts; replace-action-bindings already replaces that action's bindings.
conflicts-for-binding
Return existing bindings that conflict with a candidate binding.
binding-conflicts?
Check whether a candidate binding conflicts with any existing binding.
binding-change
Create a rebinding preview record for UI conflict prompts. The candidate binding is assigned to action-name, regardless of the incoming binding's action field.
apply-binding-change
Apply a binding-change preview without removing conflicts from other actions.
apply-binding-change-clearing-conflicts
Apply a binding-change preview and remove conflicting bindings elsewhere. This supports the common "replace the other action's binding" prompt result.
action-names
Return unique action names in first-binding order.
binding-label
Return a display label for an action binding.
binding-view
Return a UI-oriented view record for an action binding.
action-binding-views
Return view records for one action's current bindings.
binding-change-view
Return a UI-oriented view record for a binding-change preview.
binding-to-json
Convert one action binding to a JSON value.
binding-from-json
Convert action binding JSON to a binding record. Missing optional fields use the same defaults as the action query helpers.
actions-to-json
Convert an action map to a JSON value.
actions-from-json
Convert action map JSON to an action map record.
stringify-actions
Convert an action map to JSON text.
parse-actions
Parse action map JSON text.
actions-path
Default input action map file path for a name.
String -> String
actions-path-in
Default input action map file path inside a directory.
String -> String -> String
save-actions-file
Save an action map to an explicit file path.
load-actions-file
Load an action map from an explicit file path.
exists-actions-file?
Check if an action map file exists.
FileReadAuth -> String -> Bool
delete-actions-file
Delete an action map file.
FileAuth -> String -> Result Bool String
create-profile
Create one named action profile.
create-profiles
Create a profile set with a default and active profile name.
create-default-profiles
Create a profile set containing one conventional default profile.
profile-names
Return the names in a profile set.
profile-view
Return a UI-oriented summary for one action profile.
profiles-view
Return a UI-oriented summary for a profile set.
profile-exists?
Check whether a profile exists.
get-profile
Get a profile by name.
default-profile
Get the configured default profile.
active-profile
Get the active profile.
active-actions
Return the active action map, falling back to the default profile or an empty action map when a settings file points at a missing profile.
set-active-profile
Switch the active profile when the requested profile exists. Missing names leave the profile set unchanged.
upsert-profile
Insert or replace one profile.
update-profile-actions
Replace the action map for one profile, creating it if needed.
update-active-actions
Replace the action map for the active profile.
rebind-active-key
Rebind a key in the active action profile.
rebind-active-mouse
Rebind a mouse button in the active action profile.
rebind-active-gamepad-button
Rebind a gamepad button in the active action profile.
rebind-active-gamepad-axis
Rebind a gamepad axis in the active action profile.
active-binding-change
Create a rebinding preview for the active action profile.
apply-active-binding-change
Apply a binding-change preview to the active action profile.
apply-active-binding-change-clearing-conflicts
Apply a binding-change preview to the active action profile and remove conflicting bindings from other actions in that profile.
profile-to-json
Convert one action profile to a JSON value.
profiles-to-json
Convert action profiles to a JSON value.
profiles-from-json
Convert profile JSON to an action profile set.
stringify-profiles
Convert action profiles to JSON text.
parse-profiles
Parse action profile JSON text.
profiles-path
Default input profile set file path for a name.
String -> String
profiles-path-in
Default input profile set file path inside a directory.
String -> String -> String
save-profiles-file
Save action profiles to an explicit file path.
load-profiles-file
Load action profiles from an explicit file path.
exists-profiles-file?
Check if an action profile file exists.
FileReadAuth -> String -> Bool
delete-profiles-file
Delete an action profile file.
FileAuth -> String -> Result Bool String
create-player-profiles
Create one player-to-profile-set entry.
create-player-profile-set
Create a multi-player profile set with an active player name.
player-names
Return the player names in a multi-player profile set.
player-profile-exists?
Check whether a player entry exists.
get-player-profiles
Get the profile set for a player.
active-player-profiles
Return the active player's profiles, falling back to the first player or an empty default profile set when the active player name is stale.
active-player-actions
Return the active player's action map.
set-active-player
Switch the active player when the requested player exists. Missing player names leave the set unchanged.
update-player-profiles
Insert or replace a player profile entry.
update-active-player-profiles
Replace the profiles for the active player.
set-player-active-profile
Switch one player's active profile when both player and profile exist.
active-player-binding-change
Create a rebinding preview for the active player's active profile.
apply-active-player-binding-change
Apply a binding-change preview to the active player's active profile.
apply-active-player-binding-change-clearing-conflicts
Apply a binding-change preview to the active player's active profile and clear conflicts in that profile.
player-profile-view
Return a UI-oriented summary for one player profile entry.
player-profile-set-view
Return a UI-oriented summary for a multi-player profile set.
player-profiles-to-json
Convert one player profile entry to a JSON value.
player-profile-set-to-json
Convert a multi-player profile set to a JSON value.
player-profile-set-from-json
Convert player profile JSON to a multi-player profile set.
stringify-player-profile-set
Convert a multi-player profile set to JSON text.
parse-player-profile-set
Parse multi-player profile JSON text.
player-profile-set-path
Default player profile set file path for a name.
String -> String
player-profile-set-path-in
Default player profile set file path inside a directory.
String -> String -> String
save-player-profile-set-file
Save a multi-player profile set to an explicit file path.
load-player-profile-set-file
Load a multi-player profile set from an explicit file path.
exists-player-profile-set-file?
Check if a multi-player profile set file exists.
FileReadAuth -> String -> Bool
delete-player-profile-set-file
Delete a multi-player profile set file.
FileAuth -> String -> Result Bool String
action-down?
Check if any binding for an action is currently down.
action-pressed?
Check if any binding for an action was pressed this frame.
action-released?
Check if any binding for an action was released this frame.
action-started?
Check if any binding for an action became active between snapshots. Touch-region bindings need previous/current snapshots for edge detection.
action-ended?
Check if any binding for an action stopped being active between snapshots. Touch-region bindings need previous/current snapshots for edge detection.
axis
Get an action axis value from keyboard, mouse, button, or analog bindings.
vector
Get a normalized 2D vector using <name>-x and <name>-y axes.
key-down?
Check if a key is currently held down
NonEmptyString -> Bool
key-pressed?
Check if a key was just pressed this frame
NonEmptyString -> Bool
key-released?
Check if a key was just released this frame
NonEmptyString -> Bool
key-up?
Check if a key is not being pressed
NonEmptyString -> Bool
get-key-pressed
Get the last key pressed (returns key code)
() -> Int
get-char-pressed
Get the last char pressed (for text input)
() -> Int
mouse-position
Get the current mouse position as a record {x, y}
mouse-x
Get the mouse X position
() -> Int
mouse-y
Get the mouse Y position
() -> Int
mouse-down?
Check if a mouse button is held down
NonEmptyString -> Bool
mouse-pressed?
Check if a mouse button was just pressed
NonEmptyString -> Bool
mouse-released?
Check if a mouse button was just released
NonEmptyString -> Bool
mouse-wheel
Get the mouse wheel movement (positive = up)
() -> Float
mouse-wheel-move
Backwards-compatible alias for mouse wheel movement
() -> Float
mouse-delta
Get mouse delta (movement since last frame)
touch-count
Get active touch point count from the backend.
() -> Int
touch-point-id
Get a backend touch point id by touch index.
Int -> Int
touch-position
Get a backend touch position by touch index.
touch-point
Get a backend touch point as {index, id, x, y}.
hide-cursor
Hide the mouse cursor
() -> ()
show-cursor
Show the mouse cursor
() -> ()
cursor-hidden?
Check if the cursor is hidden
() -> Bool
gamepad-connected?
Check if a gamepad is connected
Int -> Bool
gamepad-name
Get the name of a gamepad
Int -> String
gamepad-button-down?
Check if a gamepad button is held down
Int -> NonEmptyString -> Bool
gamepad-button-pressed?
Check if a gamepad button was just pressed
Int -> NonEmptyString -> Bool
gamepad-button-released?
Check if a gamepad button was just released
Int -> NonEmptyString -> Bool
gamepad-axis
Get a gamepad axis value (-1.0 to 1.0); 0.0 for unknown axis names
Int -> NonEmptyString -> Float
gamepad-left-stick
Get the left stick as a record {x, y}
gamepad-right-stick
Get the right stick as a record {x, y}
load-texture
Load a texture from a file
Returns:
unload-texture
Unload a texture from memory
is-texture-valid?
Check if texture is valid (loaded successfully)
load-sound
Load a sound from a file
Supported formats: WAV, OGG, MP3
NonEmptyString -> Ptr
unload-sound
Unload a sound from memory
Ptr -> ()
load-music
Load streaming music from a file
Supported formats: OGG, MP3, WAV, FLAC
NonEmptyString -> Ptr
unload-music
Unload music from memory
Ptr -> ()
load-font
Load a font from a file. Returns a FontHandle record {ptr, base-size}. Falls back to the default font when loading fails (use try-load-font to detect errors).
Supported formats: TTF, OTF, FNT
try-load-font
Load a font from a file with result handling. Ok carries a FontHandle record {ptr, base-size}.
NonEmptyString -> Result
load-font-size
Load a font with specific size. Returns a FontHandle record; falls back to the default font when loading fails.
unload-font
Unload a font from memory (takes the FontHandle record). Do not unload the default font.
default-font
Get the default font as a FontHandle record
load-image
Load an image from a file (CPU memory)
Use this when you need to process an image before creating a texture
NonEmptyString -> Ptr
unload-image
Unload an image from CPU memory
Ptr -> ()
texture-from-image
Create a texture from an image
join-path
Join path components
String -> String -> String
=> "assets/sprites/player.png"join-paths
Join multiple path components
List -> String
try-load-texture
Load texture with result handling
NonEmptyString -> Result
try-load-sound
Load sound with result handling
NonEmptyString -> Result
try-load-music
Load music with result handling
NonEmptyString -> Result
load-textures
Load multiple textures from a list of paths Returns a list of textures in the same order
List -> List
unload-textures
Unload multiple textures
List -> ()
load-sounds
Load multiple sounds from a list of paths
List -> List
unload-sounds
Unload multiple sounds
List -> ()
default
Default auto-save state (60 second interval, enabled). Override fields with record spread: auto = {...Game.AutoSave.default, interval: 30.0, slot: "quicksave"}
update
Update the auto-save timer. Call each frame with dt. Returns state with due flag set to true when timer reaches zero.
is-due?
Check if auto-save is due this frame.
is-enabled?
Check if auto-save is enabled.
time-remaining
Get seconds remaining until next save.
get-slot
Get the save slot name.
set-enabled
Enable or disable auto-save.
set-interval
Set the interval and reset the timer.
set-slot
Set the save slot name.
reset
Reset the timer to the full interval. Call after performing a save.
trigger-now
Trigger an immediate save on the next frame. Sets timer to zero.
save
Save game state to a slot The state is serialized to JSON and written to save-{slot}.json
FileWriteAuth -> String -> JSONValue -> Result Bool String
load
Load game state from a slot Returns the parsed JSON value. The caller must convert it to their state type.
FileReadAuth -> String -> Result JSONValue String
exists?
Check if a save slot exists
FileReadAuth -> String -> Bool
delete
Delete a save slot
FileAuth -> String -> Result Bool String
slot-path
Get the file path for a save slot
String -> String
slot-path-in
Get the file path for a save slot in a directory
String -> String -> String
save-versioned
Save game state with a version number. The state is wrapped in an envelope with version metadata.
FileWriteAuth -> String -> Int -> JSONValue -> Result Bool String
load-versioned
Load a versioned save, running migrations if needed. migrations: List of (JSONValue -> JSONValue) functions, where index i migrates from version i to i+1 Returns Ok state if successful, or Err if file missing, parse failed, or migration missing.
FileReadAuth -> String -> Int -> List -> Result JSONValue String
create-migrations
Create an empty migrations list.
() -> List
register-migration
Register a migration function (transforms JSONValue from version N to N+1). migrations is a list where index 0 migrates from v0->v1, index 1 from v1->v2, etc.
List -> (JSONValue -> JSONValue) -> List
get-version
Get the version from a raw loaded save (returns 0 for legacy saves).
JSONValue -> Int
create
Create a new scene manager with an initial scene
empty
Create an empty scene manager
active
Get the active (top) scene
active-state
Get the active scene's state
push
Push a new scene onto the stack (pauses current scene)
pop
Pop the current scene from the stack (returns to previous)
replace
Replace the current scene with a new one
switch-to
Switch to a completely new scene (clears stack)
update
Update the scene manager (updates active scene)
update-with-transition
Update with transition handling
draw
Draw the active scene
draw-all
Draw all scenes in stack (for overlay effects)
transition-to
Transition types fade-in: Fade from black fade-out: Fade to black fade: Fade out then fade in none: Instant switch
Start a fade transition to a new scene
transition-push
Start a push transition
transition-progress
Get the current transition progress (0.0 to 1.0)
is-transitioning?
Check if currently transitioning
update-transition
Update transition state
fade-alpha
Get fade alpha for current transition (0.0-1.0, where 1.0 is fully opaque)
update-state
Update the state of the active scene directly
scene-count
Get scene count in stack
has-scene?
Check if a scene with given name is in the stack
create
Create a 2D camera
Config fields (all required — records have no optional fields): target: {x: Float, y: Float} - Point the camera is looking at zoom: Float - Camera zoom (1.0 = normal) rotation: Float - Camera rotation in degrees (0.0 = none)
Camera.create {target: {x: 400.0, y: 300.0}, zoom: 1.0, rotation: 0.0}create-centered
Create a camera centered on the screen
create-for-screen
Create a camera with screen dimensions (auto-centered)
begin
Begin drawing with this camera
end
End camera drawing mode
() -> ()
set-target
Set the camera target directly
move
Move the camera target by a delta
follow
Smoothly follow a target position
smoothness is the fraction of the remaining distance RETAINED each frame: 0.0 = instant snap, 1.0 = no movement. For a smooth follow use 0.8-0.95 (e.g. 0.9 covers 10% of the distance per frame). Note: frame-rate dependent — call once per frame.
follow-with-deadzone
Follow with deadzone (camera doesn't move if target is within deadzone) smoothness works as in follow: 0.8-0.95 for smooth movement
clamp-to-bounds
Constrain camera within bounds
set-zoom
Set the camera zoom level
zoom-by
Adjust zoom by a factor
zoom-to
Smoothly zoom to a target level smoothness works as in follow: 0.8-0.95 for smooth zoom
clamp-zoom
Clamp zoom to min/max range
set-rotation
Set the camera rotation (in degrees)
rotate-by
Rotate the camera by an angle
rotate-to
Smoothly rotate to a target angle smoothness works as in follow: 0.8-0.95 for smooth rotation
shake
Start camera shake effect
intensity: Maximum shake offset in pixels duration: How long the shake lasts in seconds
update-shake
Update camera shake (call each frame)
is-shaking?
Check if camera is currently shaking
screen-to-world
Convert screen coordinates to world coordinates. Accounts for offset, zoom, and rotation (inverse of world-to-screen).
world-to-screen
Convert world coordinates to screen coordinates. Accounts for offset, zoom, and rotation (matches the begin transform).
update
Update camera (handles shake, call each frame)
create
Create a fixed-step clock.
with-max-steps
Set the maximum number of catch-up steps per rendered frame.
with-viewport
Replace the fixed clock viewport.
with-window
Replace the fixed clock window and resize its viewport to match.
with-window-viewport
Replace both fixed clock window and viewport.
context
Build a context for the current fixed tick.
interpolation-alpha
Return the normalized render interpolation factor for a clock. The value is clamped to [0, 1], so capped catch-up backlogs do not extrapolate render state.
interpolate-float
Interpolate between two floats.
Float -> Float -> Float -> Float
interpolate-point
Interpolate records with x and y fields.
interpolate-rect
Interpolate rectangle position and size.
interpolate-camera
Interpolate the numeric fields used by Game.Camera.
render-state
Interpolate a render state through a caller-supplied interpolation function.
step
Run exactly one fixed update. update receives (state, ctx) and returns the next state.
advance
Advance a clock by elapsed render time and run as many fixed updates as needed, capped by clock.max-steps.
run-snapshots
Run one fixed update per input snapshot. Useful for deterministic tests and future replay playback.