game

A LÖVE-inspired game development framework for Kit

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.kitExample: breakout with ball physics, bricks, scoring
examples/camera.kitExample: camera
examples/collision.kitExample: collision
examples/hybrid-test.kitExample: hybrid test
examples/minimal-test.kitExample: minimal test
examples/particles.kitExample: particles
examples/platformer.kitExample: platformer with tilemap, physics, camera, debug overlay
examples/pong.kitExample: pong
examples/simple.kitExample: simple
examples/tilemap.kitExample: tilemap
examples/topdown.kitExample: top-down coin collector with tilemap, camera, save/load
kit.tomlPackage manifest with metadata and dependencies
src/assets.kitModule for assets
src/audio.kitModule for audio
src/backend/interface.kitOpaque texture handle with dimensions
src/backend/raylib.kitModule for raylib
src/backend/select.kitModule for select
src/cache.kitAsset cache for textures, sounds, fonts
src/camera.kitModule for camera
src/collision.kitA rectangle for collision detection
src/colors.kitModule for colors
src/debug.kitDebug overlay and development tools
src/ecs.kitEntity Component System
src/game.kitMain module
src/graphics.kitModule for graphics
src/input.kitModule for input
src/math.kitPi (3.14159...)
src/package.kitKit Game - A LOVE-inspired game development framework
src/particles.kitModule for particles
src/quadtree.kitA quadtree node containing:
src/save.kitJSON-based save/load game state
src/scene.kitA scene manager holds the current scene stack and transition state
src/sprite.kitModule for sprite
src/template.kitProject template generator
src/tilemap.kitModule for tilemap
tests/cache.test.kitTests for cache module
tests/collision.test.kitTests for collision module
tests/debug.test.kitTests for debug module
tests/ecs.test.kitTests for ECS module
tests/game.test.kitTests for game
tests/minimal-import.test.kitTests for minimal import
tests/module-structure.test.kitTests for module-structure
tests/save.test.kitTests for save module
tests/template.test.kitTests for template module

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 --> O[debug.kit] J --> P[quadtree.kit] P[backend/select.kit] --> Q[backend/raylib.kit] Q --> R[raylib] B --> P C --> P D --> P E --> P F --> P

Dependencies

  • geometry
  • raylib

Installation

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

Usage

import Kit.Game as Game

# Define your game state
type State = {x: Float, y: Float, speed: Float}

# Initialize state
init = fn() => {x: 400.0, y: 300.0, speed: 200.0}

# Update state each frame (pure function)
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 the game
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

# Run the game
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
initfn() => StaterequiredInitialize game state
updatefn(State, Float) => StaterequiredUpdate state (receives delta time)
drawfn(State) => ()requiredRender the game
resizableBoolfalseAllow window resizing
vsyncBooltrueEnable vertical sync
fullscreenBoolfalseStart in fullscreen

Available Modules

  • Game.Graphics - Shape drawing, text rendering
  • Game.Input - Keyboard, mouse, gamepad
  • Game.Audio - Sound effects, music
  • Game.Assets - Load textures, sounds, fonts
  • Game.Sprite - Static and animated sprites
  • Game.Tilemap - Tile-based maps, Tiled JSON and TMX XML
  • Game.Camera - 2D camera with follow/shake
  • Game.Collision - AABB, circle, line detection, swept AABB (prevents tunneling)
  • 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, watch variables, pause/step, profiling
  • Game.Math - Vectors, lerp, easing
  • Game.Colors - Color constants
  • Game.Cache - Asset cache, preload and reuse textures/sounds
  • Game.Template - Project template generator

Debug Tools

The Game.Debug module provides development aids:

# In your init:
init = fn => {
  player: {x: 100.0, y: 100.0},
  debug: Game.Debug.create {enabled: false}
}

# In your update:
update = fn(state, dt) =>
  # Toggle pause with P key
  debug = if Game.Input.key-pressed? "p" then
    Game.Debug.toggle-pause state.debug
  else
    state.debug

  # Step one frame with N while paused
  debug2 = if Game.Input.key-pressed? "n" and Game.Debug.is-paused? debug then
    Game.Debug.step debug
  else
    debug

  # Only run game logic when not paused (or stepping)
  new-player = if Game.Debug.should-advance? debug2 then
    update-player state.player dt
  else
    state.player

  # Consume the step request after advancing
  debug3 = Game.Debug.consume-step debug2

  # Track frame time and clear watches
  debug4 = Game.Debug.update debug3 dt

  {...state, player: new-player, debug: debug4}

# In your draw:
draw = fn(state) =>
  # ... draw game ...

  # Profile a section
  debug = Game.Debug.profile-start state.debug "draw-world"
  # ... heavy drawing ...
  debug2 = Game.Debug.profile-end debug "draw-world"

  # Show watches on overlay
  debug3 = Game.Debug.watch debug2 "Player X" (Float.to-string state.player.x)

  # Draw overlay (shows FPS, frame time, pause status, profiles)
  Game.Debug.draw debug3

Asset Cache

The Game.Cache module prevents repeated disk loads:

init = fn => {
  cache: Game.Cache.create,
  player: {x: 100.0, y: 100.0}
}

# Load once, reuse everywhere
result = Game.Cache.get-texture state.cache "sprites/player.png"
texture = result.asset
cache2 = result.cache

# Preload a batch at level start
cache3 = Game.Cache.preload-textures cache2 ["bg.png", "enemy.png"]

Project Templates

Generate starter project files with Game.Template:

# Print starter main.kit content
print (Game.Template.main-file "My Game")

# Print kit.toml content
print (Game.Template.kit-toml "my-game" "0.1.0")

# Get all files at once
scaffold = Game.Template.scaffold "my-game" "My Game"
# scaffold.main, scaffold.kit-toml, scaffold.readme, scaffold.gitignore

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)

# Load a tileset texture separately
tileset = Game.Assets.load-texture "tiles.png"

# Load the map from JSON
match Game.Tilemap.load "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 (added automatically as a dependency).

See kit-xml docs.

# Load a tileset texture separately
tileset = Game.Assets.load-texture "tiles.png"

# Load the map from TMX XML
match Game.Tilemap.load-tmx "level1.tmx" tileset
  | Ok map ->
    # Same map structure as JSON loading
    no-op
  | Err e -> print "Failed: ${show e}"

TMX notes:

  • CSV, uncompressed Base64, zlib-compressed Base64, and gzip-compressed Base64 tile data are all 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.

Release Builds

Build a native binary for distribution:

# Development build (fast, larger binary)
kit build main.kit -o my-game

# Release build (slower compile, optimized binary)
kit build main.kit -o my-game --release

License

MIT License - see LICENSE for details.

Exported Functions & Types

rgb

Create a color from RGB values (0-255)

Int -> Int -> Int -> Int

rgba

Create a color from RGBA values (0-255)

Int -> Int -> Int -> Int -> Int

hex

Create a color from a hex value (e.g., 0xFF0000 for red)

Int -> Int

white

Pure white (255, 255, 255)

Int

black

Pure black (0, 0, 0)

Int

blank

Fully transparent (alpha = 0)

Int

light-gray

Light gray (200, 200, 200)

Int

gray

Medium gray (130, 130, 130)

Int

dark-gray

Dark gray (80, 80, 80)

Int

red

Pure red (230, 41, 55)

Int

green

Pure green (0, 228, 48)

Int

blue

Pure blue (0, 121, 241)

Int

yellow

Bright yellow (253, 249, 0)

Int

orange

Orange (255, 161, 0)

Int

pink

Pink (255, 109, 194)

Int

purple

Purple (200, 122, 255)

Int

violet

Violet (135, 60, 190)

Int

magenta

Magenta (255, 0, 255)

Int

gold

Gold (255, 203, 0)

Int

maroon

Maroon (190, 33, 55)

Int

lime

Lime green (0, 158, 47)

Int

dark-green

Dark green (0, 117, 44)

Int

sky-blue

Sky blue (102, 191, 255)

Int

dark-blue

Dark blue (0, 82, 172)

Int

beige

Beige (211, 176, 131)

Int

brown

Brown (127, 106, 79)

Int

dark-brown

Dark brown (76, 63, 47)

Int

cyan

Cyan (0, 255, 255)

Int

teal

Teal (0, 128, 128)

Int

coral

Coral (255, 127, 80)

Int

salmon

Salmon (250, 128, 114)

Int

Navy blue (0, 0, 128)

Int

olive

Olive (128, 128, 0)

Int

indigo

Indigo (75, 0, 130)

Int

with-alpha

Make a color transparent (alpha = 0-255)

Int -> Int -> Int

fade

Fade a color (factor 0.0-1.0)

Int -> Float -> Int

create

Create a new quadtree

Config fields: bounds: {x, y, width, height} - The region to cover max-objects: Int - Objects per node before split (default: 10) max-depth: Int - Maximum tree depth (default: 5)

Record -> Record

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)

Record -> Record -> Record

insert-all

Insert multiple objects

Record -> List -> Record

query

Query for all objects that could collide with a given bounds

Record -> Record -> List

query-point

Query for objects at a specific point

Record -> Float -> Float -> List

query-radius

Query for objects within a radius of a point

Record -> Float -> Float -> PositiveFloat -> List

clear

Clear all objects from the tree

Record -> Record

rebuild

Rebuild the tree with new objects (useful after many removals)

Quadtree -> List -> Quadtree

get-all

Get all objects in the tree

Record -> List

count

Count all objects in the tree

Record -> Int

find-collision-pairs

Find all pairs of potentially colliding objects

Record -> List

get-all-bounds

Get all node bounds for debug drawing

Record -> List

stats

Get tree statistics

Record -> Record

create-emitter

Create a particle emitter

Config fields: max-particles: Int - Maximum particles (default: 100) emission-rate: Float - Particles per second (default: 10.0) 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 (default: {x: 0, y: 0}) rotation-speed: {min: Float, max: Float} - Rotation speed range (optional)

Record -> Record

Particles.create-emitter {
  max-particles: 200,
  emission-rate: 50.0,
  lifetime: {min: 0.5, max: 1.5},
  speed: {min: 50.0, max: 150.0},
  angle: {min: 0.0, max: 360.0},
  size: {start: 8.0, end: 2.0},
  colors: [Colors.yellow, Colors.orange, Colors.red]
}

create-emitter-at

Create emitter at a specific position

Float -> Float -> Record -> Record

set-position

Set emitter position

Record -> Float -> Float -> Record

move

Move emitter by delta

Record -> Float -> Float -> Record

start

Start emitting

Record -> Record

stop

Stop emitting (existing particles continue)

Record -> Record

clear

Clear all particles

Record -> Record

has-particles?

Check if emitter has active particles

Record -> Bool

particle-count

Get particle count

Record -> Int

burst

Emit multiple particles at once

Record -> Int -> Record

update

Update emitter and all particles

Record -> Float -> Record

draw

Draw all particles as circles

Record -> ()

draw-rects

Draw particles as rectangles

Record -> ()

draw-faded

Draw particles with fade based on lifetime

Record -> ()

draw-textured

Draw particles with texture

Record -> Record -> ()

preset-fire

Create a fire effect emitter

Float -> Float -> Record

preset-smoke

Create a smoke effect emitter

Float -> Float -> Record

preset-sparks

Create a spark/explosion burst emitter

Float -> Float -> Record

preset-rain

Create a rain effect emitter

Int -> Record

preset-snow

Create a snow effect emitter

Int -> Record

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

Record -> Record

Tilemap.create {
  tile-width: 16,
  tile-height: 16,
  width: 50,
  height: 30,
  tileset: tileset-texture
}

add-layer

Add a layer to the tilemap

Record -> Record -> Record

create-layer

Create a layer with empty data

NonEmptyString -> Int -> Int -> Bool -> Record

create-layer-with-data

Create a layer with initial data

NonEmptyString -> List Int -> Bool -> Record

get-tile

Get tile index at position (in tile coordinates)

Record -> NonEmptyString -> Int -> Int -> Int

set-tile

Set tile at position (returns new tilemap)

Record -> NonEmptyString -> Int -> Int -> Int -> Record

get-tile-at

Get tile at world position (in pixels)

Record -> NonEmptyString -> Float -> Float -> Int

world-to-tile

Convert world position to tile position

Record -> Float -> Float -> Record

tile-to-world

Convert tile position to world position (top-left corner)

Record -> Int -> Int -> Record

get-layer

Get layer by name

Record -> NonEmptyString -> Option Record

set-layer-visible

Set layer visibility

Record -> NonEmptyString -> Bool -> Record

toggle-layer

Toggle layer visibility

Record -> NonEmptyString -> Record

draw

Draw all visible layers

Record -> Int -> ()

draw-layer

Draw a specific layer

Record -> Record -> Int -> ()

draw-in-bounds

Draw tilemap within camera bounds (optimized)

Record -> Float -> Float -> Float -> Float -> Int -> ()

is-solid?

Check if a tile position is solid

Record -> Int -> Int -> Bool

is-solid-at?

Check if a world position is solid

Record -> Float -> Float -> Bool

rect-collides?

Check if a rectangle collides with any solid tiles Returns true if any corner or edge touches a solid tile

Record -> Float -> Float -> Float -> Float -> Bool

get-colliding-tiles

Get all solid tiles that a rectangle overlaps with

Record -> Float -> Float -> Float -> Float -> List Record

resolve-collision

Resolve collision by pushing entity out of solid tiles Returns adjusted position {x, y}

Record -> Float -> Float -> Float -> Float -> Float -> Float -> Record

pixel-width

Get tilemap dimensions in pixels

Record -> Int

pixel-height

Record -> Int

fill-rect

Fill a rectangular region with a tile

Record -> NonEmptyString -> Int -> Int -> Int -> Int -> Int -> Record

clear-layer

Clear all tiles in a layer

Record -> String -> Record

TilemapError

Error type for tilemap loading

Variants

TilemapParseError {String}
TilemapMissingField {String}
TilemapInvalidFormat {String}

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

NonEmptyString -> Record -> Result Record TilemapError

  tileset = Assets.load-texture "tiles.png"
  match Tilemap.load "level1.tmj" tileset
    | Ok map -> use map
    | Err e -> print "Failed to load: ${show e}"

Note: This loads the map structure from JSON. 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

String -> Record -> Result Record TilemapError

get-tileset-info

Get tileset info from Tiled JSON (helper for loading tileset)

Parameters:

  • path - String - Path to the Tiled JSON file

Returns: Result {image: String, tile-width: Int, tile-height: Int} TilemapError

NonEmptyString -> Result Record TilemapError

match Tilemap.get-tileset-info "level1.tmj"
  | Ok info ->
    tileset = Assets.load-texture info.image
    Tilemap.load "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.

NonEmptyString -> Record -> Result Record TilemapError

tileset = Assets.load-texture "tiles.png"
match Tilemap.load-tmx "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.

String -> Record -> Result Record TilemapError

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.

String -> List Record

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.

NonEmptyString -> Result Record TilemapError

match Tilemap.get-tileset-info-tmx "level1.tmx"
  | Ok info ->
    tileset = Assets.load-texture info.image
    Tilemap.load-tmx "level1.tmx" tileset
  | Err e -> print "Error: ${show e}"

rect

A rectangle for collision detection Fields: x, y, width, height (all Float)

Create a rectangle

Float -> Float -> Float -> Float -> Record

rect-from

Create a rectangle from position and size records

Record -> Record -> Record

rect-centered

Create a rectangle centered at a point

Float -> Float -> Float -> Float -> Record

point-in-rect?

Check if a point is inside a rectangle

Float -> Float -> Record -> Bool

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)

Record -> Record -> Bool

rect-overlap

Get the overlap between two rectangles (returns None if no overlap)

Record -> Record -> Option

check-rects

Get collision info between two rectangles Returns Option with {overlap: {x, y}, normal: {x, y}, penetration: Float}

Record -> Record -> Option

rect-intersection

Get the intersection rectangle of two overlapping rectangles

Record -> Record -> Option

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}

Float -> Float -> Float -> Float -> Float -> Float -> Option

circle-rect-overlap?

Check if a circle and rectangle overlap

Float -> Float -> PositiveFloat -> Record -> Bool

check-circle-rect

Get collision info between circle and rectangle Returns Option with {closest: {x, y}, normal: {x, y}, penetration: Float}

Float -> Float -> PositiveFloat -> Record -> Option

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

Float -> Float -> Float -> Float -> Record -> Bool

expand-rect

Expand a rectangle by a margin

Record -> Float -> Record

shrink-rect

Shrink a rectangle by a margin

Record -> Float -> Record

rect-center

Get the center point of a rectangle

Record -> Record

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

Record -> Record -> Bool

rect-contains-circle?

Check if a rectangle contains a circle

Record -> Float -> Float -> PositiveFloat -> Bool

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

Int -> Int -> Record

filters-collide?

Check if two filters allow collision

Record -> Record -> Bool

filter-player

Player collision filter - collides with enemies, walls, pickups, triggers

Record

filter-enemy

Enemy collision filter - collides with player, bullets, walls

Record

filter-bullet

Bullet collision filter - collides with enemies, walls

Record

filter-wall

Wall collision filter - collides with player, enemies, bullets

Record

filter-pickup

Pickup collision filter - collides with player only

Record

filter-trigger

Trigger collision filter - collides with player only

Record

separate-circles

Separate two overlapping circles Returns new positions for both circles

Float -> Float -> Float -> Float -> Float -> Float -> Record

push-out-of-rect

Push an entity out of a static rectangle Returns the adjusted position

Float -> Float -> Float -> Float -> Record -> Record

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

Float -> Float -> Record -> Record

reflect-velocity-damped

Reflect with dampening (for bouncing) bounce: 0.0 = no bounce, 1.0 = perfect bounce

Float -> Float -> Record -> Float -> Record

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

Record -> Record -> Float -> Float -> Option

sweep-move

Move a rectangle with swept collision against a static rectangle. Returns the new position, collision time, hit flag, and normal.

Record -> Record -> Float -> Float -> Record

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}

Record -> List -> Float -> Float -> Record

Input

Input handling module - keyboard, mouse, gamepad

Module

Graphics

Graphics primitives module - drawing shapes, text

Module

Colors

Color constants and utilities module

Module

Audio

Audio module - sound effects and music

Module

Math

Math utilities module - vectors, angles, interpolation

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 -> ()

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

() -> ()

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

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 -> ()

create

Create a new empty ECS world

() -> Record

create-with-capacity

Create a world with initial capacity hint (for documentation only, functional lists don't pre-allocate)

Int -> Record

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}

Record -> Record -> Record

add-simple

Add an entity to the world (convenience, returns just world)

Record -> Record -> Record

add-many

Add multiple entities to the world Returns the new world and a list of assigned IDs

Record -> List -> Record

remove

Remove an entity by ID

Record -> Int -> Record

remove-where

Remove all entities matching a predicate

Record -> (Record -> Bool) -> Record

get

Get an entity by ID (returns Option)

Record -> Int -> Option

has?

Check if an entity with the given ID exists

Record -> Int -> Bool

query

Find all entities matching a predicate

Record -> (Record -> Bool) -> List

query-first

Find first entity matching a predicate (returns Option)

Record -> (Record -> Bool) -> Option

update

Update a single entity by ID Returns unchanged world if entity not found

Record -> Int -> (Record -> Record) -> Record

update-where

Update all entities matching a predicate

Record -> (Record -> Bool) -> (Record -> Record) -> Record

map-entities

Map a function over all entities

Record -> (Record -> Record) -> Record

count

Count all entities

Record -> Int

count-where

Count entities matching a predicate

Record -> (Record -> Bool) -> Int

sort-by

Sort entities by a key function (lowest first)

Record -> (Record -> Float) -> Record

create

Create an empty asset cache.

() -> Record

get-texture

Get a texture from the cache, loading it if not present. Returns {asset: Texture, cache: Record}

Record -> String -> Record

preload-textures

Preload multiple textures into the cache.

Record -> List -> Record

has-texture?

Check if a texture is already cached.

Record -> String -> Bool

unload-texture

Remove a texture from the cache and unload it.

Record -> String -> Record

get-sound

Get a sound from the cache, loading it if not present. Returns {asset: Ptr, cache: Record}

Record -> String -> Record

preload-sounds

Preload multiple sounds into the cache.

Record -> List -> Record

has-sound?

Check if a sound is already cached.

Record -> String -> Bool

unload-sound

Remove a sound from the cache and unload it.

Record -> String -> Record

get-font

Get a font from the cache, loading it if not present. Returns {asset: Ptr, cache: Record}

Record -> String -> Record

has-font?

Check if a font is already cached.

Record -> String -> Bool

get-music

Get music from the cache, loading it if not present. Returns {asset: Ptr, cache: Record}

Record -> String -> Record

has-music?

Check if music is already cached.

Record -> String -> Bool

preload-all

Preload textures, sounds, fonts, and music from asset lists.

Record -> Record -> Record

unload-all

Unload all cached assets and return an empty cache.

Record -> Record

size

Get the total number of cached assets.

Record -> Int

create

Create debug state with optional configuration. Config fields (all optional - provide only the ones you want to override): enabled: Bool (default: false) show-fps: Bool (default: true) show-frame-time: Bool (default: true) max-frame-history: Int (default: 60)

Record -> Record

empty

Default debug state. Use as Game.Debug.empty.

Record

toggle

Toggle overlay visibility

Record -> Record

enable

Enable the overlay

Record -> Record

disable

Disable the overlay

Record -> Record

watch

Add a watch variable to display on the overlay. The value should be a string; use interpolation for non-string values.

Record -> String -> String -> Record

update

Update debug state each frame. Records frame time and clears watches for the next frame. Call this in your update function.

Record -> Float -> Record

set-entity-count

Set entity count to display on overlay (0 to hide)

Record -> Int -> Record

set-scene-name

Set current scene name to display on overlay ("" to hide)

Record -> String -> Record

pause

Pause the game. When paused, is-paused? returns true and should-advance? returns false until step or unpause is called.

Record -> Record

unpause

Unpause the game.

Record -> Record

toggle-pause

Toggle pause state.

Record -> Record

step

Request a single frame advance while paused. Call this when the step key is pressed.

Record -> Record

is-paused?

Check if the game is currently paused.

Record -> Bool

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.

Record -> Bool

consume-step

Consume a step request. Call after advancing one paused frame.

Record -> Record

profile-start

Start timing a named profile marker.

Record -> String -> Record

profile-end

End timing a named profile marker. Finds the most recent un-ended marker with this name and records elapsed time.

Record -> String -> Record

profile-get

Get the elapsed time of the most recent completed profile marker. Returns 0.0 if no matching completed marker exists.

Record -> String -> Float

clear-profiles

Clear all profile markers.

Record -> Record

toggle-console

Toggle the debug console open/closed.

Record -> Record

console-open?

Check if the debug console is open.

Record -> Bool

register-command

Register a console command. name: command name (first word typed) handler: fn(String) -> String - receives args string, returns output

Record -> String -> (String -> String) -> Record

console-input-char

Append a character to the console input. Only works when console is open.

Record -> String -> Record

console-backspace

Remove the last character from console input. Only works when console is open.

Record -> () -> Record

console-submit

Submit the current console input, execute the command, and add to history. Returns updated state with cleared input.

Record -> Record

console-clear

Clear the console input and history.

Record -> Record

get-history

Get the console history as a list of {input, output} records.

Record -> List

get-console-input

Get the current console input string.

Record -> String

draw-console

Draw the debug console if open. Call this in your draw function after drawing the game.

Record -> ()

draw

Draw the debug overlay if enabled. Call this at the end of your draw function.

Record -> ()

draw-bounds

Draw a rectangle outline for visual debugging (e.g. collision bounds). Only draws if debug state is enabled.

Record -> Float -> Float -> Float -> Float -> Int -> ()

draw-vector

Draw a line representing a vector from a point. Only draws if debug state is enabled.

Record -> Float -> Float -> Float -> Float -> Int -> ()

draw-circle

Draw a circle for visual debugging. Only draws if debug state is enabled.

Record -> Float -> Float -> PositiveFloat -> Int -> ()

draw-point

Draw a point/crosshair for visual debugging.

Record -> Float -> Float -> Int -> ()

default-body

Default dynamic body. Override fields with record spread.

Record

default-world

Default physics world with gravity (0, 300).

Record

static-body

Create a static body (obstacle/wall).

Float -> Float -> Float -> Float -> Record

create-world

Create a world with custom gravity.

Float -> Float -> Record

add-body

Add a body to the world. Returns the updated world and the assigned id.

Record -> Record -> Record

get-body

Get a body by id (returns Option).

Record -> Int -> Option

set-body

Update a body by id.

Record -> Int -> Record -> Record

remove-body

Remove a body by id.

Record -> Int -> Record

body-count

Count bodies in the world.

Record -> Int

step

Step the physics simulation forward by dt seconds. Applies gravity, integrates velocity, applies friction. Only dynamic bodies are updated.

Record -> Float -> Record

step-with-collisions

Step with collision resolution between all bodies. Resolves overlaps and applies bounce (restitution).

Record -> Float -> Record

apply-force

Apply a force to a body (affects acceleration). Force is cleared after each step.

Record -> Float -> Float -> Record

apply-impulse

Apply an instantaneous impulse to a body (affects velocity directly).

Record -> Float -> Float -> Record

set-velocity

Set the body's velocity directly.

Record -> Float -> Float -> Record

set-position

Set the body's position directly.

Record -> Float -> Float -> Record

set-size

Set the body's size.

Record -> Float -> Float -> Record

stop

Zero out the velocity.

Record -> Record

scale-velocity

Scale the velocity (for time dilation / slow motion).

Record -> Float -> Record

get-position

Get the position as a {x, y} record.

Record -> Record

get-velocity

Get the velocity as a {x, y} record.

Record -> Record

get-bounds

Get the body's AABB bounds.

Record -> Record

point-in-body?

Check if a point is inside a body's bounds.

Float -> Float -> Record -> Bool

on-ground?

Check if a body is on the ground (has downward collision). Tests a small ray below the body against static bodies.

Record -> Record -> Bool

move-and-slide

Move a body and resolve collisions with static bodies in the world. Returns the updated world with the moved body.

Record -> Int -> Float -> Float -> Record

resolve-all-collisions

Resolve all body-vs-body collisions in the world. Static-static pairs are skipped. Dynamic-dynamic pairs get mutual separation.

Record -> Record

create

Create a pool from a list of pre-allocated objects. Each object is wrapped with an id and active flag.

List -> Record

create-with-factory

Create a pool with a factory function called N times.

Int -> (() -> Record) -> Record

acquire

Acquire an available object from the pool. Returns {pool: Record, data: Option, id: Int}. id is -1 if no object is available.

Record -> Record

release

Release an object back to the pool by id.

Record -> Int -> Record

release-all

Release all active objects back to the pool.

Record -> Record

is-active?

Check if an entry is active.

Record -> Int -> Bool

get

Get an active entry's data by id (returns None if inactive or missing).

Record -> Int -> Option

active-list

Get all active entries as a list of {id, data} records.

Record -> List

active-data

Get only the data of all active objects.

Record -> List

active-count

Count active objects.

Record -> Int

available-count

Count available (inactive) objects.

Record -> Int

capacity

Total pool capacity.

Record -> Int

has-available?

Check if pool has any available objects.

Record -> Bool

is-empty?

Check if pool is completely inactive.

Record -> Bool

update

Update an active object's data by id. Only updates if the entry is active.

Record -> Int -> (Record -> Record) -> Record

map-active

Map a function over all active objects' data. Inactive objects are left unchanged.

Record -> (Record -> Record) -> Record

filter-active

Filter active objects by predicate, releasing those that don't match.

Record -> (Record -> Bool) -> Record

grow

Resize the pool by adding new inactive objects. Preserves existing active entries.

Record -> List -> Record

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

Float -> Float -> Record

vec2-zero

Zero vector (0, 0)

Record

vec2-up

Unit vector pointing up (0, -1)

Record

vec2-down

Unit vector pointing down (0, 1)

Record

vec2-left

Unit vector pointing left (-1, 0)

Record

vec2-right

Unit vector pointing right (1, 0)

Record

vec2-add

Add two vectors

Record -> Record -> Record

vec2-sub

Subtract two vectors

Record -> Record -> Record

vec2-scale

Multiply a vector by a scalar

Record -> Float -> Record

vec2-div

Divide a vector by a scalar

Record -> Float -> Record

vec2-negate

Negate a vector

Record -> Record

vec2-length

Get the length of a vector

Record -> Float

vec2-length-squared

Get the squared length of a vector (faster than length)

Record -> Float

vec2-normalize

Normalize a vector to unit length

Record -> Record

vec2-dot

Dot product of two vectors

Record -> Record -> Float

vec2-cross

Cross product (returns scalar z-component)

Record -> Record -> Float

vec2-distance

Distance between two points

Record -> Record -> Float

vec2-distance-squared

Squared distance between two points

Record -> Record -> Float

vec2-lerp

Linear interpolation between two vectors

Record -> Record -> Float -> Record

vec2-rotate

Rotate a vector by an angle (in radians)

Record -> Float -> Record

vec2-angle

Get the angle of a vector (from positive x-axis)

Record -> Float

vec2-perpendicular

Get a perpendicular vector (90 degrees counter-clockwise)

Record -> Record

vec2-reflect

Reflect a vector off a surface with the given normal

Record -> Record -> Record

vec2-clamp-length

Clamp a vector to a maximum length

Record -> Float -> Record

vec2-from-angle

Create a unit vector from an angle (in radians)

Float -> Record

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

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

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 (called automatically by Game.run)

() -> ()

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

Ptr -> Bool -> ()

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

String -> String -> Record

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}

() -> Record

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)

() -> Record

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)

Int -> NonEmptyString -> Float

gamepad-left-stick

Get the left stick as a record {x, y}

Int -> Record

gamepad-right-stick

Get the right stick as a record {x, y}

Int -> Record

load-texture

Load a texture from a file

Returns:

NonEmptyString -> Record

unload-texture

Unload a texture from memory

Record -> ()

is-texture-valid?

Check if texture is valid (loaded successfully)

Record -> Bool

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

Supported formats: TTF, OTF, FNT

NonEmptyString -> Ptr

load-font-size

Load a font with specific size

NonEmptyString -> PositiveInt -> Ptr

unload-font

Unload a font from memory

Ptr -> ()

default-font

Get the default font

() -> Ptr

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

Ptr -> Record

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"}

Record

update

Update the auto-save timer. Call each frame with dt. Returns state with due flag set to true when timer reaches zero.

Record -> Float -> Record

is-due?

Check if auto-save is due this frame.

Record -> Bool

is-enabled?

Check if auto-save is enabled.

Record -> Bool

time-remaining

Get seconds remaining until next save.

Record -> Float

get-slot

Get the save slot name.

Record -> String

set-enabled

Enable or disable auto-save.

Record -> Bool -> Record

set-interval

Set the interval and reset the timer.

Record -> Float -> Record

set-slot

Set the save slot name.

Record -> String -> Record

reset

Reset the timer to the full interval. Call after performing a save.

Record -> Record

trigger-now

Trigger an immediate save on the next frame. Sets timer to zero.

Record -> Record

save

Save game state to a slot The state is serialized to JSON and written to save-{slot}.json

String -> Record -> Result () String

load

Load game state from a slot Returns the parsed JSON value. The caller must convert it to their state type.

String -> Result Record String

exists?

Check if a save slot exists

String -> Bool

delete

Delete a save slot

String -> Result () 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.

String -> Int -> Record -> Result () String

load-versioned

Load a versioned save, running migrations if needed. migrations: List of (Record -> Record) 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.

String -> Int -> List -> Result Record String

create-migrations

Create an empty migrations list.

() -> List

register-migration

Register a migration function (transforms Record from version N to N+1). migrations is a list where index 0 migrates from v0->v1, index 1 from v1->v2, etc.

List -> (Record -> Record) -> List

get-version

Get the version from a raw loaded save (returns 0 for legacy saves).

Record -> Int

create

Create a new scene manager with an initial scene

Record -> Record

empty

Create an empty scene manager

() -> Record

active

Get the active (top) scene

Record -> Option

active-state

Get the active scene's state

Record -> Option

push

Push a new scene onto the stack (pauses current scene)

Record -> Record -> Record

pop

Pop the current scene from the stack (returns to previous)

Record -> Record

replace

Replace the current scene with a new one

Record -> Record -> Record

switch-to

Switch to a completely new scene (clears stack)

Record -> Record -> Record

update

Update the scene manager (updates active scene)

Record -> Float -> Record

update-with-transition

Update with transition handling

Record -> Float -> Record

draw

Draw the active scene

Record -> ()

draw-all

Draw all scenes in stack (for overlay effects)

Record -> ()

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

Record -> Record -> Float -> Record

transition-push

Start a push transition

Record -> Record -> Float -> Record

transition-progress

Get the current transition progress (0.0 to 1.0)

Record -> Float

is-transitioning?

Check if currently transitioning

Record -> Bool

update-transition

Update transition state

Record -> Float -> Record

fade-alpha

Get fade alpha for current transition (0.0-1.0, where 1.0 is fully opaque)

Record -> Float

update-state

Update the state of the active scene directly

Record -> (a -> a) -> Record

scene-count

Get scene count in stack

Record -> Int

has-scene?

Check if a scene with given name is in the stack

Record -> NonEmptyString -> Bool

create

Create a 2D camera

Config fields: target: {x: Float, y: Float} - Point the camera is looking at zoom: Float - Camera zoom (1.0 = normal, default) rotation: Float - Camera rotation in degrees (default: 0.0)

Record -> Record

Camera.create {target: {x: 400.0, y: 300.0}, zoom: 1.0}

create-centered

Create a camera centered on the screen

Int -> Int -> Float -> Float -> Record

create-for-screen

Create a camera with screen dimensions (auto-centered)

Int -> Int -> Record

begin

Begin drawing with this camera

Record -> ()

end

End camera drawing mode

() -> ()

set-target

Set the camera target directly

Record -> Float -> Float -> Record

move

Move the camera target by a delta

Record -> Float -> Float -> Record

follow

Smoothly follow a target position

smoothness: 0.0 = instant, 1.0 = no movement (typically use 0.05-0.2)

Record -> Float -> Float -> Float -> Record

follow-with-deadzone

Follow with deadzone (camera doesn't move if target is within deadzone)

Record -> Float -> Float -> Float -> Float -> Float -> Record

clamp-to-bounds

Constrain camera within bounds

Record -> Float -> Float -> Float -> Float -> Record

set-zoom

Set the camera zoom level

Record -> Float -> Record

zoom-by

Adjust zoom by a factor

Record -> Float -> Record

zoom-to

Smoothly zoom to a target level

Record -> Float -> Float -> Record

clamp-zoom

Clamp zoom to min/max range

Record -> Float -> Float -> Record

set-rotation

Set the camera rotation (in degrees)

Record -> Float -> Record

rotate-by

Rotate the camera by an angle

Record -> Float -> Record

rotate-to

Smoothly rotate to a target angle

Record -> Float -> Float -> Record

shake

Start camera shake effect

intensity: Maximum shake offset in pixels duration: How long the shake lasts in seconds

Record -> Float -> Float -> Record

update-shake

Update camera shake (call each frame)

Record -> Float -> Record

is-shaking?

Check if camera is currently shaking

Record -> Bool

screen-to-world

Convert screen coordinates to world coordinates

Record -> Float -> Float -> Record

world-to-screen

Convert world coordinates to screen coordinates

Record -> Float -> Float -> Record

update

Update camera (handles shake, call each frame)

Record -> Float -> Record