Lua API

Tangy exposes a small, intentional Lua 5.4 surface. Colon and dot call styles both work (sprite:load(...) or sprite.load(...)).

Lifecycle & timing

The entry script (main.lua) runs as a coroutine so wait works at top level. There is no engine-provided update or draw callback.

API Description
wait(ms) Yield the current coroutine for at least ms milliseconds.
engine:spawn(fn) Start fn as a new coroutine.
engine:yield() Pause until the next frame.
engine:time() Monotonic milliseconds since the scheduler started.
engine:spawn(function()
  while true do
    -- per-frame game logic
    engine:yield()
  end
end)

Input

API Description
input.button_pressed:connect(fn) Register a press handler: function(button, isGamepad).
input.button_released:connect(fn) Register a release handler with the same signature.

On desktop (Linux today), handlers receive SDL keyboard names (Left, Right, Space, …) with isGamepad=false — Tangy is meant for making desktop games with keyboard input as well as handheld titles. On the Nintendo 3DS family, buttons are A, B, X, Y, L, R, ZL, ZR, Start, Select, DPadLeft, DPadRight, DPadUp, DPadDown with isGamepad=true. Handlers are spawned as coroutines when they fire — use engine:spawn if you need wait from nested logic patterns you control yourself.

Sprites — sprite

Max loaded sprites defaults to 1024 (shared graphics budget with unique tileset tile types). Max sprite size is 64×64. Frame indices are 1-based.

API Description
id = sprite:load(path) Load a .tngspr; returns slot id.
ok = sprite:unload(id) Free a sprite slot.
x, y = sprite:getpos(id) Pixel position.
sprite:setpos(id, x, y) Set position (fractional values round to pixels).
sprite:flip(id, axis) Toggle flip; axis 1 = X, 2 = Y.
flipX, flipY = sprite:getflip(id) Current flip state (booleans).
sprite:setframe(id, frame) Set animation frame (1-based).
used, max = sprite:slots() Occupied loaded-sprite count and max slots.

Scene / tiles — scene

Four layers (1 = front, 4 = back). Tiles are 16×16.

API Description
scene:load(path) Load a .tngscn (replaces current scene; sprites untouched).
scene:unload([path]) Unload the scene; optional path string.
scene:reload() Restore pristine tile data after runtime edits.
scene:set_tile(tileId, tx, ty [, layer]) Set a cell; layer defaults to 1; tile 0 = empty.
tileId = scene:get_tile(tx, ty [, layer]) Read a cell; layer defaults to 1.
tx, ty = scene:spritepos_to_tilepos(x, y) Pixel → tile coords (uses layer-1 scroll).
scene:setscroll(x, y [, layer]) Pixel camera / parallax scroll; layer 1–4, default 1.

Palette — palette

API Description
palette:load(path) Load a .tngpal (15-bit, ≤256 colours). May swap anytime.

Screen — screen

API Description
screen:fill(palIndex) Background clear colour = palette index 0–255.

Effects — effect

API Description
effect:pixelate(amount) SNES-style mosaic; amount 1–4 (effect id 1).
effect:colourfade(colourIndex, durationMs) Fade toward a palette colour over milliseconds (effect id 2).
effect:clear([id]) Clear all effects, or one by id (1 = pixelate, 2 = colourfade).

Audio — sound

Up to 12 concurrent OGG streams.

API Description
id = sound:play(path [, loop]) Stream an OGG; optional loop; returns voice id 1–12.
sound:stop(id) Stop one voice.
sound:pause(id) Pause a playing voice.
sound:resume(id) Resume a paused voice.
sound:volume(id, level) / level = sound:volume(id) Set or get volume 0–1.
sound:kill() Stop all voices.

Standard Lua

Standard libraries are available (print, math, string, table, and so on). Example games use them heavily.