game

A LÖVE-inspired game development framework for Kit

Disclaimer

This project is still a work-in-progress and may not work correctly.

Files

FileDescription
.editorconfigEditor formatting configuration
.gitignoreGit ignore rules for build artifacts and dependencies
.tool-versionsasdf tool versions (Zig, Kit)
LICENSEMIT license file
README.mdThis file
examples/breakout.kitBreakout example with ball physics, bricks, and scoring
examples/cache-reload-polling.kitContext service cache/reload/debug render example
examples/camera.kitCamera example
examples/collision.kitCollision example
examples/context-debug.kitContext-owned debug overlay and watch example
examples/context-replay-session.kitContext-owned replay session service example
examples/dev-runner-plan.kitExternal dev runner script plan example
examples/dev-session-watch.kitSource/asset dev session watch example
examples/fixed-render-viewport.kitFixed-step render queue example with action maps, camera, and a logical viewport
examples/immediate-render-mix.kitMixed immediate-mode and render-command viewport example
examples/hybrid-test.kitHybrid package/import smoke example
examples/input-rebinding.kitLocal-player keyboard/controller profile switching and action rebinding example
examples/logical-render-viewport.kitAutomatic logical render target viewport example
examples/minimal-test.kitMinimal import smoke example
examples/particles.kitParticle system example
examples/platformer.kitPlatformer with tilemap collision, physics, camera, and debug overlay
examples/pong.kitPong example
examples/replay-export-plan.kitReplay browser/report/manifest export plan example
examples/replay-file-debug.kitReplay file persistence, deterministic verification, browser panel, and render/debug diagnostics
examples/replay-live.kitLive input recording and playback example using fixed ticks and render commands
examples/render-sprite-cache.kitRender command queue example with explicit sprite-path cache ownership
examples/render-target-screenshot.kitRender target and screenshot example
examples/scaffold-plan.kitStarter project scaffold plan and safe script artifact example
examples/shooter.kitShooter example
examples/simple.kitSimple moving-circle example
examples/tilemap.kitProcedural tilemap example
examples/topdown.kitTop-down collector with camera and high-score persistence
examples/touch-viewport.kitTouch and mouse input through a logical viewport
examples/viewport-scissor.kitLogical viewport example with backend scissor clipping
examples/support/basic-game.kitSupport facade for basic examples
examples/support/breakout-game.kitSupport facade for Breakout
examples/support/collision-game.kitSupport facade for collision examples
examples/support/particles-game.kitSupport facade for particle examples
examples/support/platformer-game.kitSupport facade for the platformer example
examples/support/shooter-game.kitSupport facade for the shooter example
examples/support/tilemap-game.kitSupport facade for tilemap examples
examples/support/topdown-game.kitSupport facade for the top-down example
kit.tomlPackage manifest with metadata, dependencies, and tasks
src/assets.kitTexture, sound, and font loading helpers
src/audio.kitSound effect and music helpers
src/auto-save.kitAuto-save timer utilities
src/backend/interface.kitBackend-facing texture handle interface
src/backend/raylib-slim.kitSlim raylib FFI facade used by the framework
src/backend/raylib.kitRaylib backend adapter
src/backend/select.kitBackend selection module
src/cache.kitAsset cache for textures, sounds, and fonts
src/camera.kit2D camera with follow, shake, and transforms
src/collision.kitCollision detection helpers
src/colors.kitPacked color constants and utilities
src/context.kitRuntime context helpers for opt-in context-aware loops
src/debug.kitDebug overlay and development tools
src/ecs.kitEntity Component System helpers
src/fixed-tick.kitDeterministic fixed-step simulation helpers
src/game.kitCore game loop implementation
src/graphics.kitDrawing primitives and text rendering
src/input.kitKeyboard, mouse, and gamepad input
src/math.kitVector, interpolation, angle, and easing helpers
src/package.kitPublic package entry point
src/particles.kitParticle emitters and effects
src/physics.kitBasic rigid body physics helpers
src/pool.kitObject pool utilities
src/quadtree.kitSpatial partitioning quadtree
src/render.kitOptional inspectable render command queue
src/replay.kitInput snapshot recording, JSON replay files, and deterministic playback
src/save.kitJSON-based save/load game state
src/scene.kitScene stack and transition helpers
src/sprite.kitStatic and animated sprite helpers
src/template.kitProject template generator
src/tilemap-procedural.kitProcedural tilemap helper surface for examples
src/tilemap.kitTilemap rendering, collision, JSON loading, and TMX loading
src/topdown-save.kitSmall high-score save helper for the top-down example
src/viewport.kitLogical canvas scaling and coordinate conversion helpers
tests/auto-save.test.kitTests for auto-save helpers
tests/cache.test.kitTests for the asset cache
tests/collision.test.kitTests for collision helpers
tests/compress.test.kitTests for compressed tile data helpers
tests/context.test.kitTests for runtime context helpers
tests/debug-console.test.kitTests for debug console helpers
tests/debug.test.kitTests for debug overlay helpers
tests/ecs.test.kitTests for ECS helpers
tests/fixed-tick.test.kitTests for fixed-step simulation helpers
tests/game.test.kitTests for core game helpers
tests/input.test.kitTests for input snapshots and action maps
tests/minimal-import.test.kitMinimal import smoke test
tests/module-structure.test.kitTests for public module structure
tests/physics.test.kitTests for physics helpers
tests/pool.test.kitTests for object pools
tests/render.test.kitTests for render command data and queue helpers
tests/replay.test.kitTests for replay recording and playback helpers
tests/save-versioned.test.kitTests for versioned saves
tests/save.test.kitTests for saves
tests/template.test.kitTests for template generation
tests/tmx.test.kitTests for TMX helpers
tests/viewport.test.kitTests for viewport scaling and coordinate conversion

Dependencies

Installation

kit add gitlab.com/kit-lang/packages/kit-game.git

Usage

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
  }

main

Game.run Configuration

FieldTypeDefaultDescription
titleString"Kit Game"Window title
widthInt800Window width
heightInt600Window height
fpsInt60Target frames per second
initStaterequiredInitial game state value
updatefn(State, Float) => StaterequiredUpdate state with delta time
drawfn(State) => ()requiredRender the game
resizableBoolfalseAllow window resizing
vsyncBooltrueEnable vertical sync
fullscreenBoolfalseStart in fullscreen

Available Modules

  • Game.Graphics - Shape drawing and text rendering
  • Game.Input - Keyboard, mouse, and gamepad input
  • Game.Audio - Sound effects and music
  • Game.Assets - Texture, sound, and font loading
  • Game.Sprite - Static and animated sprites
  • Game.Tilemap - Tile-based maps, Tiled JSON, and Tiled TMX XML
  • Game.Camera - 2D camera with follow and shake
  • Game.Collision - AABB, circle, line, and swept AABB collision helpers
  • Game.Particles - Particle emitters and effects
  • Game.ECS - Lightweight Entity Component System
  • Game.Scene - Scene stack management
  • Game.Save - JSON-based save/load game state
  • Game.Debug - Debug overlay, FPS counter, watches, pause/step, and profiling
  • Game.Dev - Development-time asset reload helpers
  • Game.Math - Vectors, interpolation, angles, and easing
  • Game.Menu - Data-first menu and pause-screen helpers
  • Game.Colors - Packed color constants and utilities
  • Game.Context - Runtime context helpers for opt-in context-aware loops
  • Game.FixedTick - Deterministic fixed-step simulation helpers
  • Game.Replay - Input snapshot recording, JSON replay files, and deterministic playback
  • Game.Render - Optional inspectable render command queue
  • Game.Viewport - Logical canvas scaling and coordinate conversion helpers
  • Game.Cache - Asset cache and preload helpers
  • Game.Release - Release packaging plan helpers
  • Game.Template - Project template generator
  • Game.Pool - Object pools for reusable entities
  • Game.Physics - Basic rigid body physics helpers
  • Game.AutoSave - Periodic auto-save state helpers

Architecture

Game Loop

flowchart LR A[Init] --> B[Load Assets] B --> C{Game Loop} C --> D[Process Input] D --> E[Update State] E --> F[Collision Detection] F --> G[Render] G --> C C --> H[Cleanup]

Module Structure

graph TD A[package.kit] --> B[game.kit] A --> C[graphics.kit] A --> D[audio.kit] A --> E[input.kit] A --> F[assets.kit] A --> G[sprite.kit] A --> H[tilemap.kit] A --> I[camera.kit] A --> J[collision.kit] A --> K[particles.kit] A --> L[scene.kit] A --> M[math.kit] A --> N[colors.kit] A --> Q[context.kit] A --> O[debug.kit] A --> R[cache.kit] A --> S[ecs.kit] A --> P[fixed-tick.kit] A --> AA[replay.kit] A --> T[pool.kit] A --> U[physics.kit] A --> V[auto-save.kit] A --> AB[viewport.kit] A --> AC[render.kit] AA --> P AA --> E Q --> AB P --> AB AB --> I AC --> C J --> W[quadtree.kit] B --> X[backend/raylib-slim.kit] C --> X D --> X E --> X F --> X H --> X I --> X K --> X X --> Y[kit-raylib]

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 debug3

Context-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 ctx3

See 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 ctx3

The 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 ctx3

See 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-ctx

See 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 path

For 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 change

View 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 profiles3

Active-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 change

For 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 path

Logical 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.y

Context-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.y

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-op

Game.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.commands

Wrap 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.cyan

Replay 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 10

Context-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-ctx

See 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-plan

See 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.command

For 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 path

For 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 runner2

For 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 plan

Use 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 packaged

Scaffold 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 packaged

Use 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 (.tsx files referenced via source="tileset.tsx") are loaded automatically.
  • Layer visible and solid custom 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 kit interpreter has a runtime conflict between the Raylib and libxml2 FFI modules, so load-tmx / from-tmx-xml will panic in interpreted tests. Use kit check and 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.kit

Compile 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-scissor

Running Tests

Run the test suite:

kit test

Run the test suite with coverage:

kit test --coverage

Running Parity Checks

Check interpreter/build parity for the examples:

kit parity --failures-only

Running kit dev

Run the standard development workflow (format, check, test):

kit dev

This will:

  1. Format and check source files in src/
  2. Run tests in tests/ with coverage

Generating Documentation

Generate API documentation from doc comments:

kit doc

Note: 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 --release

Cleaning Build Artifacts

Remove generated files, caches, and build artifacts:

kit task clean

Note: Defined in kit.toml.

Local Installation

To install this package locally for development:

kit install

This 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 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 file
  • tileset - 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 file
  • tileset - 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 app
  • path - 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 file
  • tileset - 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 file
  • tileset - 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 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.