API REFERENCE

Complete Lua API for the Dino8 retro game SDK.

GLOBALS

T number
Time in seconds since startup
DT number
Delta time between frames in seconds
PLATFORM table
.name ("desktop"|"mobile"|"web"), .os, .is_mobile, .is_web, .is_desktop
INPUT_GLYPH table
.UP .DOWN .LEFT .RIGHT .ACTION_A .ACTION_B .ESCAPE — context-aware input icons
GLYPH table
.ARROW_LEFT .ARROW_UP .ARROW_RIGHT .ARROW_DOWN .HEART .HEART_OUTLINE .STAR .STAR_OUTLINE .CHECK .CROSS .NOTE .NOTES .SPADE .CLUB .DIAMOND .TRI_UP .TRI_RIGHT .TRI_DOWN .TRI_LEFT .SQUARE .CIRCLE .BLOCK .PAUSE — symbol glyphs
CONFIG table
Read-only table of all conf.d8 values: .title, .version, .width, .height, .author, .assets, etc.

CALLBACKS

Define these functions in your game. The engine calls them automatically. Drawing is split into two passes: _draw runs in world space (affected by camera), while _ui runs in screen space (ignores camera). Use _draw for gameplay and _ui for HUD, menus, and overlays that should stay fixed on screen.
_init([kwargs])
Called once at startup for initialization. kwargs is a table of key-value pairs from CLI --key value args passed after the project path. Empty table if no args.
_update()
Called every frame to update game logic
_draw()
Called every frame to render in world space (affected by camera position, scale, rotation)
_ui()
Called every frame after _draw to render in screen space (ignores camera — stays fixed on screen)
_orientation_changed(orientation)
Called when device orientation changes. orientation: "portrait" | "landscape"
_input_changed(mode)
Called when input mode changes. mode: "keyboard" | "touch" | "gamepad"
main.d8
-- run with: dino8 run . --scene cave --debug

function _init(kwargs)
  -- kwargs = {scene="cave", debug="true"}
  local scene = kwargs.scene or "start"
  load_scene(scene)
end

function _update()
  -- game logic
end

function _draw()
  cls()
  -- render
end

CONFIGURATION

Every project has a conf.d8 that returns a table describing the game. This is where you set the title, resolution, assets, filters, and more. All values are available at runtime via the read-only CONFIG global — e.g. CONFIG.title, CONFIG.version, CONFIG.width.

Metadata

FieldDefaultDescription
title"dino8"Game title, shown in window title bar and used for save data.
author"Unknown"Creator name.
version"0.1.0"Semantic version string.
description"A retro game SDK"Short project description.
type"game"Project type: "game", "tool", or "data".
tagsnilArray of tag strings for categorization.
thumbnailnilPath to a thumbnail image file.
entry"main.d8"Entry script file, relative to the project directory.
enginenilTarget major engine version (integer). If the engine’s major version is lower, the project won’t run and will prompt you to update. If the engine is newer, a compatibility warning is shown. Omit to skip the check.

Display

FieldDefaultDescription
width128Canvas width in pixels.
height128Canvas height in pixels.
scale4Window scale multiplier.
fullscreenfalseStart in fullscreen mode.
speed1.0Game speed multiplier (0.5 = half speed, 2.0 = double).
gif_scale2Scale factor for GIF capture output.

Assets

FieldDefaultDescription
assets.spritesnilPath to sprite sheet PNG.
assets.mapnilPath to tilemap JSON file.
assets.musicnilArray of music file paths. Supports wildcards.

SFX Clips

Named sound effect clips with optional randomized pitch and volume.
FieldDefaultDescription
sfx_clips.<name>.pathWildcard path to sound files (e.g. "sfx/hit_*.wav").
sfx_clips.<name>.pitch1.0Fixed number or {min, max} range for random pitch.
sfx_clips.<name>.volume1.0Fixed number or {min, max} range for random volume.
sfx_clips.menu.navigatenilClip name to play for pause menu navigation.
sfx_clips.menu.selectnilClip name to play for pause menu selection.
sfx_clips.menu.backnilClip name to play for pause menu back/cancel.

Filters

Post-processing filters applied to the rendered frame. Filters can also be toggled and adjusted at runtime via the built-in settings screen.
FieldDefaultDescription
filters.upscale.typenoneUpscale filter: "scale2x", "hq2x", "hq3x", "hq4x", or "xbrz".
filters.scanline.enabledfalseEnable scanline effect.
filters.scanline.intensity0.2Scanline intensity (0.0–1.0).
filters.crt.enabledfalseEnable CRT screen effect.
filters.crt.curvature0.1CRT screen curvature amount.
filters.crt.glow0.2CRT glow intensity.
filters.chromatic.enabledfalseEnable chromatic aberration.
filters.chromatic.intensity0.5Chromatic aberration intensity.

Custom Palette

Replace the default Dawnbringer 16 palette with your own colors (max 254).
FieldDefaultDescription
paletteDawnbringer 16Array of colors in 0xRRGGBB format. Up to 254 entries.

Custom Fonts

Load additional font styles. Indices 1–2 are reserved for the built-in font, so the first user-defined entry starts at index 3: font_style(3).
FieldDefaultDescription
font_styles[n].fontPath to a TTF font file.
font_styles[n].size10Font size in pixels.
font_styles[n].line_height0Line height (0 = font default).
font_styles[n].kerning0Extra letter spacing in pixels.

Mobile

FieldDefaultDescription
orientation"landscape"Screen orientation: "landscape", "portrait", or "both".
mobile_controlstrueShow on-screen virtual touch controls.
render_offset0.5Vertical position of the game canvas (0 = top, 0.5 = center, 1 = bottom).

Publishing

Used by dino8 push to upload to itch.io.
FieldDefaultDescription
itch.usernilYour itch.io username.
itch.gamenilYour itch.io game slug.
itch.channel"html5"Upload channel.
FULL EXAMPLE
return {
  -- metadata
  title       = "dino-quest",
  author      = "doodleclan",
  version     = "1.2.0",
  description = "A tiny dino adventure",
  type        = "game",
  tags        = { "platformer", "retro" },
  thumbnail   = "assets/thumb.png",
  entry       = "main.d8",
  engine      = 0,

  -- display
  width      = 256,
  height     = 144,
  scale      = 3,
  fullscreen = false,
  speed      = 1.0,
  gif_scale  = 2,

  -- assets
  assets = {
    sprites = "assets/sprites.png",
    map     = "assets/world.json",
    music   = {
      "assets/music/title.ogg",
      "assets/music/level*.ogg",
    },
  },

  -- sound effects
  sfx_clips = {
    jump = {
      path   = "assets/sfx/jump_*.wav",
      pitch  = { 0.9, 1.1 },
      volume = 0.7,
    },
    land = {
      path   = "assets/sfx/land.wav",
      pitch  = 1.0,
      volume = { 0.4, 0.6 },
    },
    coin = {
      path   = "assets/sfx/coin*.wav",
      pitch  = { 0.95, 1.05 },
    },
    hurt = {
      path   = "assets/sfx/hurt.wav",
    },
    menu = {
      navigate = "coin",
      select   = "jump",
      back     = "hurt",
    },
  },

  -- filters
  filters = {
    upscale = {
      type = "hq2x",
    },
    scanline = {
      enabled   = true,
      intensity = 0.15,
    },
    crt = {
      enabled   = true,
      curvature = 0.1,
      glow      = 0.2,
    },
    chromatic = {
      enabled   = false,
      intensity = 0.5,
    },
  },

  -- custom palette (replaces default)
  palette = {
    0x140C1C, 0x442434,
    0x30346D, 0x4E4A4E,
    0x854C30, 0x346524,
    0xD04648, 0x757161,
    0x597DCE, 0xD27D2C,
    0x8595A1, 0x6DAA2C,
    0xD2AA99, 0x6DC2CA,
    0xDAD45E, 0xDEEED6,
  },

  -- custom fonts
  font_styles = {
    {
      font        = "assets/fonts/pixel.ttf",
      size        = 8,
      line_height = 10,
      kerning     = 0,
    },
    {
      font        = "assets/fonts/title.ttf",
      size        = 16,
      line_height = 20,
      kerning     = 1,
    },
  },

  -- mobile
  orientation     = "landscape",
  mobile_controls = true,
  render_offset   = 0.5,

  -- itch.io publishing
  itch = {
    user    = "doodleclan",
    game    = "dino-quest",
    channel = "html5",
  },
}

DRAWING

Colors can be a palette index (1-16) or raw 0xRRGGBB. Passing a color sets the pen color for subsequent calls.
cls([color])
Clear screen. Defaults to palette color 1.
pset(x, y, [color])
Set pixel at (x, y)
pget(x, y)
→ number
Get color of pixel at (x, y)
line([x0, y0], x1, y1, [color])
Draw line. Multiple argument patterns supported.
circ(cx, cy, [r], [color])
Draw circle outline. Default radius: 4
circf(cx, cy, [r], [color])
Draw filled circle
rect(x0, y0, x1, y1, [color])
Draw rectangle outline
rectf(x0, y0, x1, y1, [color])
Draw filled rectangle
rrect(x0, y0, x1, y1, r, [color])
Draw rounded rectangle outline. r = corner radius (clamped to half of smallest dimension)
rrectf(x0, y0, x1, y1, r, [color])
Draw filled rounded rectangle. r = corner radius (clamped to half of smallest dimension)
fillp([pattern, [color2]])
Set fill pattern for rectf/circf. pattern: 16-bit number (0b0101...) or glyph string ("#"). color2: secondary color index. No args resets to solid fill. Use PATTERN constants for presets.
PATTERN.CHECKER / PATTERN.STRIPE_H / PATTERN.STRIPE_V / ...
Preset fill pattern constants. Also: DOTS_SPARSE, DOTS_DENSE, DIAG_R, DIAG_L, BAR_H, LIGHT, HATCH
checker(x, y, w, h, cell_size, color1, [color2])
Draw checkerboard pattern
color([c])
→ number (when getting)
Set or get current pen color

PALETTE

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Default: Dawnbringer 16. Custom palettes can be set in conf.d8 or at runtime.
pal([c0, c1])
Map draw color c0 to appear as c1. No args resets.
pals([palette_table])
Enable shift mode: shapes remap existing pixels through the table. No args disables.
set_palette(colors)
Replace base 16-color palette. colors: array of 16 values in 0xRRGGBB format.
get_palette()
→ table
Get current base palette as array of 16 0xRRGGBB values

TEXT

Print text to screen. Font style, line height, and kerning are configurable at runtime.
print(text, x, y, [color], [bg_color])
Print text at position
printo(text, x, y, [color], [outline_color])
Print text with 1px outline. outline_color defaults to 1 (dark)
text_width(text)
→ number
Get pixel width of text string
font_style([index])
→ number (when getting)
Set or get current font style (1-based index)
font_style_count()
→ number
Number of available font styles
line_height()
→ number
Line height in pixels for current font
kerning()
→ number
Extra letter spacing in pixels for current font
chr(codepoint)
→ string
Convert a Unicode codepoint to a UTF-8 string. Use to access any glyph in the font by its codepoint (e.g. chr(0x2082) for subscript 2)

FONT

Dino8 includes a built-in pixel font (dino8.ttf) with broad multilingual coverage plus custom glyphs for input controls and symbols.

Supported Character Sets

Basic Latin + Western European

Full diacritic coverage for all standard ASCII characters plus accented and special letters used by English, French, German, Spanish, Italian, Portuguese, Dutch, Swedish, Norwegian, Danish, Finnish, Polish, Turkish, and other Latin-script languages.

LanguageExtra Characters
Frenché è ê ë î ï ô û ù ç à
Germanä ö ü ß
Spanishá é í ó ú ñ ¿ ¡
Nordicå ä ö

Japanese (Complete Syllabary)

Full support for modern game text with all 46 Hiragana, all 46 Katakana, dakuten (voiced) and handakuten (half-voiced) forms, all small/yōon combinations, and double-consonant support.

SetCoverage
Hiraganaあいうえお かきくけこ さしすせそ たちつてと なにぬねの はひふへほ まみむめも やゆよ らりるれろ わをん
Katakanaアイウエオ カキクケコ サシスセソ タチツテト ナニヌネノ ハヒフヘホ マミムメモ ヤユヨ ラリルレロ ワヲンー
Voiced (゛)がぎぐげご ざじずぜぞ だぢづでど ばびぶべぼ ガギグゲゴ ザジズゼゾ ダヂヅデド バビブベボ
Half-voiced (゚)ぱぴぷぺぽ パピプペポ
Small kanaぁぃぅぇぉ っゃゅょゎ ァィゥェォ ッャュョヮ
Kanji一三上下世 二人剣勝右 土大始小左 日星月死水 火王界終負 風魔
Punctuation、。「」!?

Custom Input Glyphs

Use these escape codes in print() strings to show input icons inline with text. Also accessible via the GLYPH table.

GlyphNameUsage
CursorGLYPH.CURSOR
MenuGLYPH.MENU
LeftGLYPH.LEFT
RightGLYPH.RIGHT
UpGLYPH.UP
DownGLYPH.DOWN
Action AGLYPH.ACTION_A
Action BGLYPH.ACTION_B
Bumper LGLYPH.BUMPER_L
Bumper RGLYPH.BUMPER_R

Symbol Glyphs

Custom pixel glyphs for common game symbols. Access via the GLYPH global table.

GlyphNameUsage
Left arrowGLYPH.ARROW_LEFT
Up arrowGLYPH.ARROW_UP
Right arrowGLYPH.ARROW_RIGHT
Down arrowGLYPH.ARROW_DOWN
Up triangleGLYPH.TRI_UP
Right triangle (play)GLYPH.TRI_RIGHT
Down triangleGLYPH.TRI_DOWN
Left triangleGLYPH.TRI_LEFT
Small up triangleGLYPH.TRI_UP_SM
Small right triangleGLYPH.TRI_RIGHT_SM
Small down triangleGLYPH.TRI_DOWN_SM
Small left triangleGLYPH.TRI_LEFT_SM
Filled square (stop)GLYPH.SQUARE
Outline squareGLYPH.SQUARE_OUTLINE
Filled circleGLYPH.CIRCLE
Outline circleGLYPH.CIRCLE_OUTLINE
Full blockGLYPH.BLOCK
Pause (double bar)GLYPH.PAUSE
StarGLYPH.STAR
Star outlineGLYPH.STAR_OUTLINE
Check markGLYPH.CHECK
Ballot XGLYPH.CROSS
Eighth noteGLYPH.NOTE
Beamed eighth notesGLYPH.NOTES
HeartGLYPH.HEART
Heart outlineGLYPH.HEART_OUTLINE
SpadeGLYPH.SPADE
ClubGLYPH.CLUB
DiamondGLYPH.DIAMOND
EXAMPLE
function _draw()
  -- Input glyphs via GLYPH table
  print(GLYPH.UP .. GLYPH.DOWN .. GLYPH.LEFT .. GLYPH.RIGHT .. " TO MOVE", 4, 10, 7)
  print(GLYPH.ACTION_A .. " JUMP  " .. GLYPH.ACTION_B .. " ATTACK", 4, 20, 7)

  -- Symbol glyphs via GLYPH table
  print(GLYPH.HEART .. " LIVES: 3", 4, 30, 8)
  print(GLYPH.STAR .. " SCORE: 1000", 4, 40, 10)
  print(GLYPH.TRI_RIGHT .. " PLAY", 4, 50, 7)
end

SPRITES

Load and draw images. Supports full-image, atlas sub-region, scaling, flipping, outlined, and quad-mapped drawing.
load_image(filename)
→ number | nil
Load image file (PNG, JPG). Returns image ID.
spr(id, dx, dy, [flip_x], [flip_y])
Draw full image at position
spr(id, sx, sy, sw, sh, dx, dy, [dw, dh, flip_x, flip_y, angle, scale_x, scale_y])
Draw sub-region of image (atlas-style) with optional scaling, flip, rotation, and per-axis scale. angle is in radians; scale_x/scale_y default to 1.0
spro(id, sx, sy, sw, sh, dx, dy, outline_color, [dw, dh, flip_x, flip_y])
Draw sprite with 1px outline. Draws 4 offset copies in outline_color then the sprite on top
sprq(id, src_quad, dst_quad)
Draw textured quad with affine mapping. Quads: {x1,y1, x2,y2, x3,y3, x4,y4}
unload_image(id)
Free image memory
fget(sprite_id, [flag])
→ number | boolean
Get sprite flag(s). Without flag: returns all 8 flags as bitmask. With flag (0-7): returns true/false
fset(sprite_id, flag, val)
Set sprite flag bit (0-7). With 2 args: sets all flags as bitmask number

CAMERA

Camera transforms apply to all drawing in _draw. Use _ui for elements that should ignore the camera.
cam_set(x, y)
Set camera position
cam_get()
→ x, y
Get camera position
cam_reset() / cam()
Reset camera to (0, 0)
cam_push() / cam_pop()
Save/restore transform state. See Transform.
cam_translate(x, y)
Move the origin by (x, y). See Transform.
cam_rotate(angle)
Rotate by angle (radians). See Transform.
cam_scale(sx, [sy])
Scale drawing. sy defaults to sx. See Transform.
cam_follow(target_x, target_y, [follow_time])
Smooth camera following. follow_time: seconds to reach target (default 1.0)
cam_offset(x, y)
Set offset from follow target
cam_shake(intensity, duration)
Screen shake. Decays over duration seconds.
cam_bounds(x1, y1, x2, y2)
Set camera movement boundaries
cam_deadzone(half_w, [half_h])
Set dead zone for cam_follow. Camera won't move until target exceeds this zone. half_h defaults to half_w

TRANSFORM

Matrix-based transform stack for positioning, rotating, and scaling anything you draw. Use cam_push/cam_pop to isolate transforms.
cam_push()
Save the current transform state onto the stack
cam_pop()
Restore the previous transform state from the stack
cam_translate(x, y)
Move the origin by (x, y)
cam_rotate(angle)
Rotate subsequent drawing by angle (radians)
cam_scale(sx, [sy])
Scale subsequent drawing. sy defaults to sx
ROTATE AROUND A POINT
-- rotate a house around its center
cam_push()
cam_translate(cx, cy)   -- move origin to pivot
cam_rotate(angle)       -- rotate around it
cam_translate(-cx, -cy) -- offset back
draw_house()
cam_pop()

SCALE FROM CENTER
-- scale a card from its center
cam_push()
cam_translate(cx, cy)   -- move origin to center
cam_scale(sx, sy)       -- scale around it
cam_translate(-ox, -oy) -- offset to top-left
draw_card()
cam_pop()

CLIPPING

Restrict drawing to a rectangular region of the screen.
clip([x, y, w, h])
Set clipping rectangle. No args resets to full screen.

RENDER TARGETS

Offscreen buffers (slots 1-8). Color -2 is transparent.
rt_create(slot, width, height)
Create render target in slot (1-8)
rt_destroy(slot)
Free render target
rt_clear(slot)
Clear to transparent
rt_target([slot])
Redirect drawing to slot. No args resets to screen.
rt_draw(slot, x, y)
Draw render target to current target
rt_save(slot, filename)
→ boolean
Save as PNG with alpha
rt_width(slot) / rt_height(slot)
→ number
Get dimensions (0 if not created)

SNAPSHOT

Capture the current screen to a buffer for later redrawing. Useful for transitions and effects.
snap()
Capture current screen to snapshot buffer
snap_draw(sx, sy, sw, sh, dx, dy)
Draw portion of snapshot (atlas-style)
snap_clear()
Clear snapshot and free memory

FILTERS

Available filters: "hqx", "crt", "chromatic"
filter_enable(name) / filter_disable(name) / filter_toggle(name)
Control filter state
filter_is_enabled(name)
→ boolean
Check if filter is active
filter_settings(opts)
Configure filter. hqx: {scale=2|3|4}, crt: {scanline, curvature}, chromatic: {intensity}
filter_get_settings(name)
→ table
Get current filter settings

CUSTOM SHADERS

Load and apply custom GLSL fragment shaders. Up to 8 shader slots. Auto-set uniforms: u_texture, u_resolution, u_time, u_mouse, u_game_resolution.
shader_load(name, source)
→ integer
Load shader from GLSL source or file path (if contains "/" or ends ".glsl"). Returns handle (1-8).
shader_enable(handle) / shader_disable(handle)
Enable or disable a shader by handle
shader_set(handle, name, v1, [v2, v3, v4])
Set a uniform on a shader. Supports float, vec2, vec3, vec4.
shader_unload(handle)
Unload a shader and free its slot

POLYGON

Draw triangles and arbitrary polygons.
tri(x1, y1, x2, y2, x3, y3, [color])
Draw outlined triangle
trif(x1, y1, x2, y2, x3, y3, [color])
Draw filled triangle
poly(points, [color])
Draw outlined polygon. points: flat array {x1,y1, x2,y2, ...}
polyf(points, [color])
Draw filled polygon. points: flat array {x1,y1, x2,y2, ...}

BEZIER CURVES

Create cubic bezier curve objects, then draw, sample, or subdivide them.
bezier(x1, y1, cx1, cy1, cx2, cy2, x2, y2)
→ id
Create a bezier curve. Returns curve ID.
bezier_draw(id, [color])
Draw curve outline
bezier_drawf(id, [color])
Draw filled closed curve shape
bezier_point(id, t)
→ x, y
Get point on curve at parameter t (0..1)
bezier_points(id, [segments])
→ table
Get subdivided points. segments defaults to 16. Returns flat array {x1,y1, x2,y2, ...}
bezier_set(id, {x1, y1, cx1, cy1, ...})
Update control points. Pass a table with only the fields you want to change. Also accepts all 8 values as flat args.
bezier_free(id)
Free a bezier curve

MASK

Draw a shape mask, then restrict subsequent drawing to inside or outside of the mask.
mask()
Begin capturing a mask. All drawing writes to the mask buffer instead of screen.
mask_apply([mode])
Apply the captured mask. mode: Mask.Inside (default) or Mask.Outside
mask_end()
End masking and return to normal drawing
Mask.Inside / Mask.Outside
Constants for mask_apply mode

KEYBOARD & BUTTONS

Check button and key state. btn/btnp use remappable bindings; key/keyp read physical keys directly. Up to 4 players supported.
btn(input, [player])
→ boolean
True if key/button is held. input: key name ("a", "space", "left") or player number (0-7). player: 0-3 (default 0)
btnp(input, [player])
→ boolean
True if just pressed (with auto-repeat). player: 0-3 (default 0). Default timing: 250ms initial, 100ms repeat.
get_btnp()
→ string | nil
Get any key pressed this frame
set_repeat_rates([initial_ms, repeat_ms])
Set btnp auto-repeat timing. No args resets to defaults.
get_repeat_rates()
→ initial_ms, repeat_ms
Get current repeat rates
consume(input)
Mark input as handled for this frame. Prevents the engine from acting on it (e.g., opening pause menu on escape). Resets each frame.
get_input_mode([player])
→ "keyboard" | "touch" | "gamepad"
Current input mode for player (auto-switches based on last device used). player: 0-3 (default 0)
key(key_name)
→ boolean
True if physical key is held. Bypasses key binding remapping. e.g. "a", "space", "enter"
keyp(key_name)
→ boolean
True if physical key was just pressed this frame. Bypasses key binding remapping.

MOUSE

Mouse position and button state in screen coordinates.
mouse_x() / mouse_y()
→ number
Current mouse position in screen pixels
mouse_btn(button)
→ boolean
True if mouse button held. 1=left, 2=right, 3=middle
mouse_btnp(button)
→ boolean
True if mouse button just pressed this frame
btn("mouse_left") / btn("mouse_right") / btn("mouse_middle")
Alternative: mouse buttons via btn/btnp (also "mouse1", "mouse2", "mouse3")
get_mouse()
→ x, y
Get current mouse position as two values (alternative to mouse_x/mouse_y)
get_hardware_mouse_visibility()
→ boolean
True if the hardware OS mouse cursor is currently visible
set_hardware_mouse_visibility(visible)
Show or hide the hardware OS mouse cursor (hidden while window is focused)

GAMEPAD

Up to 4 gamepads supported. Use btn/btnp with the player argument for per-controller input.
gamepad_count()
→ number
Number of connected gamepads (0-4)
gamepad_connected([player])
→ boolean
True if a gamepad is connected for player (default 0)
gamepad_name([player])
→ string | nil
Controller name for player, or nil (default player 0)

TOUCH & MOBILE

Touch input, on-screen keyboard, virtual controls, and mobile layout helpers.
open_keyboard() / close_keyboard()
Show/hide on-screen keyboard (no-op on desktop)
keyboard_height()
→ number
Keyboard height in pixels (0 on desktop or when hidden)
set_render_offset(offset)
Position game within black bars (0.0=top/left, 0.5=center, 1.0=bottom/right)
get_render_offset()
→ number
Get current render offset (0-1)
mobile_controls([enabled])
→ boolean
Enable/disable virtual on-screen controls (D-pad + buttons). If no arg, returns current state.
mobile_controls_config([config])
→ table
Configure virtual controls. config: {opacity, scale, enabled}. Returns current config.
touch_active()
→ boolean
True if any touch points are currently active on the screen
touch_pos()
→ x, y | nil, nil
First active touch position in game coordinates. Returns nil, nil if no touch.

SOUND EFFECTS

Load and play sound effects. Supports wildcards for random variations, pitch/volume randomization, and per-channel control.
load_sfx(filename, [pitch], [volume])
→ number | nil
Load sound. Supports wildcards ("*.wav"). pitch/volume: number or {min, max} for randomization.
sfx(sfx_id, [volume], [pitch])
Play sound effect. nil sfx_id is safely ignored.
stop_sfx([channel], [fade_time])
Stop sound effects. fade_time in seconds (0 = immediate).
set_sfx_volume(volume)
Set global SFX volume (0.0-1.0)
unload_sfx(sfx_id)
Free sound memory
get_sfx_count(sfx_id)
→ number
Number of loaded audio file variations for this sfx
pause_sfx([channel])
Pause a specific channel or all channels if omitted
resume_sfx([channel])
Resume a paused channel or all channels if omitted
is_channel_playing(channel)
→ boolean
True if the specified mixer channel is currently playing audio
sfx_channel(channel, sfx_id, [volume])
Play a sound effect on a specific mixer channel for explicit channel control

MUSIC

Background music playback with looping, volume, and fade control.
load_music(filename)
→ number | nil
Load music file (WAV, OGG, MP3)
music(music_id, [volume], [loop])
Play music. loop defaults to true.
stop_music([fade_time])
Stop music. fade_time in seconds.
pause_music() / resume_music()
Pause/resume music playback
is_music_playing()
→ boolean
Check if music is playing
set_music_volume(volume)
Set global music volume (0.0-1.0)
unload_music(music_id)
Free music memory

TABLE UTILITIES

PICO-8 style table helpers.
add(t, v, [i])
→ value
Append value (or insert at index i)
del(t, v)
→ value | nil
Delete first occurrence of value
deli(t, [i])
→ value | nil
Delete element at index (defaults to last)
count(t, [v])
→ number
Count elements, or occurrences of v
foreach(t, fn)
Call fn(v) for each element
all(t)
→ iterator
Iterator for use with for...in loops

MATH

Standard math functions. Trig uses radians. PICO-8 style naming (flr, rnd, mid).
sin(angle) / cos(angle)
→ number
Trig functions (radians)
atan2(y, x)
→ number
Arctangent of y/x in radians
sqrt(v) / abs(v)
→ number
Square root / absolute value
min(a, b) / max(a, b)
→ number
Minimum / maximum of two values
mid(a, b, c)
→ number
Middle value of three numbers
flr(v) / ceil(v)
→ number
Floor / ceiling
rnd([max])
→ number
Random number between 0 and max (default 1.0)
wrap(value, min, max)
→ number
Wrap value within [min, max] range (circular)
deg2rad(deg) / rad2deg(rad)
→ number
Angle conversion

COLLISION

Axis-aligned bounding box (AABB) and point-in-shape tests.
collides(x1, y1, w1, h1, x2, y2, w2, h2)
→ boolean
Check if two axis-aligned rectangles overlap (AABB)
point_in_rect(px, py, x, y, w, h)
→ boolean
Check if a point is inside a rectangle
point_in_circ(px, py, cx, cy, r)
→ boolean
Check if a point is inside a circle
rect_overlap(x1, y1, w1, h1, x2, y2, w2, h2)
→ x, y, w, h | nil
Get the overlap rectangle of two AABBs, or nil if no overlap

UTILITIES

Common helpers for interpolation, clamping, and movement.
lerp(a, b, t)
→ number
Linear interpolation: a + (b - a) * t
slerp(a, b, t)
→ number
Spherical interpolation for angles (radians). Takes shortest path
clamp(val, min, max)
→ number
Clamp value between min and max
sign(x)
→ number
Returns -1, 0, or 1
approach(current, target, step)
→ number
Move current toward target by step. Snaps if within step distance
distance(x1, y1, x2, y2)
→ number
2D Euclidean distance between two points

EASING

Easing functions accept an optional curve parameter from the Ease table. Default: Ease.Quad. Available curves: Quad, Cubic, Quart, Quint, Sine, Expo, Circ, Back, Elastic, Bounce
ease_in(t, [curve])
→ number
Ease-in (accelerating). e.g. ease_in(t, Ease.Bounce)
ease_out(t, [curve])
→ number
Ease-out (decelerating). e.g. ease_out(t, Ease.Elastic)
ease_in_out(t, [curve])
→ number
Ease-in-out (accelerate then decelerate). e.g. ease_in_out(t, Ease.Back)

PERSISTENCE

Data persists across sessions. Desktop: platform-specific app data directory. Web: localStorage.
dget(key)
→ string | nil
Get persistent value by key
dset(key, value)
Set persistent value (auto-saved)

FILE I/O

Read, write, and manage files relative to the project directory. Native builds only.
read_file(filename)
→ string | nil
Read text file (relative to project dir)
write_file(filename, content)
→ boolean
Write text file
append_file(filename, content)
→ boolean
Append to file
file_exists(filename) / dir_exists(path)
→ boolean
Check existence
delete_file(filename)
→ boolean
Delete a file
create_dir(path)
→ boolean
Create directory
list_dir(path)
→ table
List files in directory
get_project_dir()
→ string
Get project directory path
export_screen_png(filename)
→ boolean
Export current screen as PNG
export_palette(filename)
→ boolean
Export palette as JSON

LEVELS & TILEMAPS

Create and draw tile-based levels. Up to 16 levels, each with its own tileset and grid size.
create_level(level_data)
→ number
Create level from data table. Returns level ID (1–16). Tile values: 0 = empty, 1+ = sprite index in tileset. tileset_cols enables 2D grid tileset layout.
load_level_tiles(level_id, tiles_data)
Load tile data into existing level
get_tile(level_id, x, y)
→ number
Get tile ID at cell (x, y). 0-based coords.
set_tile(level_id, x, y, tile_id)
Set tile (0 = empty, 1+ = sprite index)
draw_level(level_id, cell_x, cell_y, screen_x, screen_y, cell_w, cell_h)
Draw level region to screen
get_level_info(level_id)
→ width, height, grid_size
Get level dimensions
destroy_level(level_id)
Free level memory
EXAMPLE
-- create a 4x3 level
local lvl = create_level({
  id           = 1,
  width        = 4,
  height       = 3,
  grid_size    = 16,
  tileset      = "assets/tiles.png",
  tileset_cols = 8,
  tiles = {
    0, 0, 0, 0,
    0, 0, 0, 0,
    1, 2, 2, 3,
  },
})

-- draw visible region
function _draw()
  draw_level(lvl,
    0,0,  -- cell origin
    0,0,  -- screen pos
    4,3)  -- cells w,h
end

-- swap a tile at runtime
set_tile(lvl, 1, 2, 5)

-- read it back
local t = get_tile(lvl, 1, 2)
-- t == 5

PHYSICS

Built-in 2D physics with automatic fixed-timestep simulation. Create bodies, apply forces, and detect collisions.
gravity(gx, gy)
Set global gravity (e.g., gravity(0, 200))
body(shape, x, y, w_or_r, [h])
→ integer
Create a physics body. shape: "circle", "box", or "static_box". Returns body handle.
body_pos(id)
→ x, y
Get body position
body_vel(id)
→ vx, vy
Get body velocity
body_angle(id)
→ number
Get body rotation angle in radians
body_set_pos(id, x, y)
Set body position
body_set_vel(id, vx, vy)
Set body velocity
body_set_angle(id, angle)
Set body rotation angle
body_push(id, fx, fy)
Apply continuous force to body
body_impulse(id, ix, iy)
Apply instant impulse to body
_on_collide(a, b)
Called when two bodies begin colliding. Define as a global function.
_on_separate(a, b)
Called when two bodies stop colliding. Define as a global function.
_on_sensor_enter(a, b)
Called when a sensor body begins overlapping another body. Define as a global function.
_on_sensor_exit(a, b)
Called when a sensor body stops overlapping another body. Define as a global function.
body_group(id, group)
Set collision group for a body
body_ignore(group_a, group_b)
Set two groups to ignore collisions with each other
body_at(x, y)
→ integer|nil
Query for a body at a point
body_raycast(x1, y1, x2, y2)
→ id, x, y | nil
Cast a ray and return the first body hit with hit point
body_destroy(id)
Destroy a physics body
physics_step(dt)
Manually advance the physics simulation by dt seconds — use when you need fixed-step control instead of automatic stepping
physics_draw()
Draw debug visualization of all physics bodies
EXAMPLE
-- set up gravity
gravity(0, 200)

-- create a ball and a floor
local ball = body("circle", 64, 32, 8)
local floor = body("static_box", 64, 120, 128, 8)

-- launch the ball to the right
body_push(ball, 500, 0)

function _draw()
  cls()
  local x, y = body_pos(ball)
  circfill(x, y, 8, 7)
end

PARTICLES

GPU-free particle system. Create emitters with a config table, then draw them each frame. Supports pixel and sprite particles, animated sprite sheets, color progression, sub-emitters, and emission shapes.
emitter(config)
→ emitter_id
Create a particle emitter from a config table.
fielddefaultdescription
spritenilImage ID for sprite particles. Omit for pixel particles.
framenilSource rect {sx, sy, sw, sh} within sprite sheet.
frame_rangenilAnimation frames {start, end} for sprite sheet animation.
anim_durationnilSeconds for one animation cycle.
anim_loopfalseLoop the sprite animation.
max256Particle pool size.
rate0Particles emitted per second. 0 = burst only.
life1Particle lifetime in seconds, or {min, max} for random range.
speed0Emission speed in px/sec, or {min, max} for random range.
direction0Emission angle in radians.
spread0Emission cone width in radians (6.28 = full circle).
gravity0Downward pull: number or {gx, gy} for directional.
damping1.0Velocity multiplier per frame. 1.0 = no damping.
colorsnilPalette indices for color progression over lifetime.
size1Particle scale, or {start, end} to animate over lifetime.
spin0Rotation speed in rad/sec, or {min, max} for random range.
areanilEmission shape: {"circ", r} or {"rect", w, h}.
emit(emitter_id, count)
→ emitter_id
Burst-emit particles. Returns emitter_id for chaining.
emitter_draw(emitter_id, x, y)
Update emitter position and draw all active particles. Call this every frame in _draw.
emitter_pos(emitter_id, x, y)
Set emitter position without drawing
emitter_set(emitter_id, config)
Update emitter properties at runtime (partial config table)
emitter_pause(emitter_id) / emitter_resume(emitter_id)
Pause/resume emission. Existing particles continue their life while paused.
emitter_stop(emitter_id)
Stop emission (alias for emitter_pause)
emitter_destroy(emitter_id)
Destroy emitter and free all its particles
emitter_sub(parent_id, child_id, mode)
Link a sub-emitter. mode: "life" (emit from each parent particle while alive) or "death" (burst on parent particle death)
EXAMPLE
-- fire sparks emitter
local sparks = emitter({
  rate   = 30,
  life   = {0.3, 0.8},
  speed  = {20, 60},
  spread = 6.28,
  colors = {10, 9, 8},
  size   = {2, 0},
  gravity = 40,
})

function _draw()
  cls()
  emitter_draw(sparks, 64, 64)
end

-- one-shot burst on click
local poof = emitter({
  rate = 0,
  life = 0.4,
  speed = {30, 80},
  spread = 6.28,
  colors = {7, 6},
})

emit(poof, 20)

TWEENS

Animate table properties over time with easing. Compose tweens into sequences (chain) or parallel groups (group). Also provides a simple timer for delayed/interval callbacks. All easing uses ease-in-out. Pass Ease constants (Ease.Quad, Ease.Bounce, etc.) as the ease parameter.
tween(target, duration, props, [ease], [opts])
→ handle
Animate properties on target table from current values to props values over duration seconds. ease: Ease constant (default Ease.Quad). opts: table with on_start, on_complete, on_pause, on_resume, on_interval, interval, delay — or a bare function for on_complete.
timer(duration, [interval], [opts])
→ handle
Callback-only timer (no property animation). interval: seconds between on_interval calls. opts: same as tween, or bare function for on_complete.
chain(..., [opts])
→ handle
Run tween/chain/group handles in sequence (each starts when the previous finishes). Optional trailing opts table or function.
group(..., [opts])
→ handle
Run tween/chain/group handles in parallel (all start together, completes when last finishes). Optional trailing opts table or function.
tween_pause(handle) / tween_resume(handle)
Pause or resume a tween, chain, or group (and all nested children). Accepts handle or integer ID.
tween_cancel(handle)
Cancel a tween, chain, or group without firing on_complete
Ease constants: Ease.Quad (default), Ease.Cubic, Ease.Quart, Ease.Quint, Ease.Sine, Ease.Expo, Ease.Circ, Ease.Back, Ease.Elastic, Ease.Bounce
All curves use ease-in-out (accelerate then decelerate)
TWEEN
local ball = { x=0, y=64 }

-- slide ball to x=120 over 1s
tween(ball, 1, { x=120 })

-- bounce ease with callback
tween(ball, 0.5, { y=32 },
  Ease.Bounce, function()
    print("landed!")
  end)
TIMER
-- do something after 2 seconds
timer(2, function()
  print("done!")
end)

-- tick every 0.5s for 3s
timer(3, 0.5, {
  on_interval = function(t)
    print("tick", t)
  end,
  on_complete = function()
    print("finished")
  end,
})
CHAIN
local p = { x=0, y=0 }

-- move right, then down
chain(
  tween(p, 0.5, { x=100 }),
  tween(p, 0.5, { y=80 }),
  function()
    print("path done")
  end
)
GROUP
local a = { x=0 }
local b = { x=0 }

-- animate both at once
group(
  tween(a, 1, { x=100 }),
  tween(b, 0.5, { x=50 }),
  function()
    print("both done")
  end
)

WINDOW

Screen dimensions and window control.
screen_size()
→ width, height
Get screen dimensions from conf.d8
get_fullscreen() / set_fullscreen(bool) / toggle_fullscreen()
Fullscreen control
get_window_title() / set_window_title(title)
Window title control

TIME

Timing and frame rate. See also the T and DT globals.
time()
→ string
Current system time as "HH:MM:SS"
t()
→ number
Seconds since engine start
fps()
→ number
Current frames per second

PLATFORM

Application lifecycle control.
quit()
Exit the application (native only, no-op on web)
restart()
Restart the game (returns to boot screen)

GIF CAPTURE

Record gameplay as animated GIFs. Also available via F9 hotkey.
gif_start([duration])
→ boolean
Start recording (default 10s). Also F9 hotkey.
gif_stop()
→ boolean
Stop and save GIF
gif_recording()
→ boolean
Check if recording
gif_remaining()
→ number
Seconds of recording remaining

SCREENSHOT

Save the current screen as a PNG image.
screenshot([filename])
→ boolean
Save screenshot as PNG. Uses timestamp if no filename given.

NOTIFICATIONS

Show brief slide-up messages to the player.
notify(message, [options])
Show slide-up notification. options: {value, col, vcol, bg}

CONSOLE & LOADING

Debug logging and loading screen control.
log(message)
Log message to console (not screen)
set_loading(enabled, [message])
Show/hide loading screen
is_loading()
→ boolean
Check if loading is active
sleep(ms)
Delay execution for milliseconds

WEBSOCKET

Connect to WebSocket servers for real-time multiplayer or live data. Tables sent via websocket_send are auto-encoded to JSON. Works on both native and web builds.
websocket_connect(url)
→ userdata | nil
Connect to a WebSocket server. Returns a handle, or nil on failure.
websocket_send(ws, data)
→ boolean
Send data through the connection. data can be a string or a table (auto-encoded to JSON).
websocket_receive(ws)
→ string | nil
Get next message from the queue, or nil if empty. Call each frame to drain incoming messages.
websocket_is_connected(ws)
→ boolean
Check if the connection is open.
websocket_close(ws)
Close the connection and release resources.

HTTP

Asynchronous HTTP requests. Callbacks fire on completion with (success, data). Tables sent via http_post are auto-encoded to JSON.
http_get(url, callback)
Perform async GET request. callback(success, data) fires on completion.
http_post(url, data, callback)
Perform async POST request. data can be a string or a table (auto-encoded to JSON). callback(success, data) fires on completion.

JSON

Encode and decode JSON strings. Tables, strings, numbers, and booleans are supported.
json_decode(json_string)
→ any
Parse a JSON string into a Lua value (table, string, number, boolean, or nil). Throws error on invalid JSON.
json_encode(value)
→ string
Encode a Lua value to compact JSON (no whitespace)
json_encode_pretty(value)
→ string
Encode a Lua value to formatted JSON with indentation

PREVIEW

Open a preview window for another Dino8 project. Useful for tools and editors that need to preview a game in real time.
preview_open(options)
→ handle
Open a preview window. options: {project, entry, title?, scale?, watch?}. Returns handle with :send(), :receive(), :is_open(), :close(), :focus().
preview_send(data)
Send a message from inside a preview script back to the editor