Veduta

Lua API Reference

API level 1 (Veduta v2.0). Everything a script can use besides the standard library. In VS Code the same reference appears as completion and hover text. Game Toolkit shows the timers, bodies, screens, UI and effects at work.

Conventions: positions and sizes are in units (metres), angles in degrees, HUD coordinates in pixels. A color is "#rrggbb", "#rrggbbaa" or an integer 0xrrggbb.

game

CallbackCalled
game.init()once, after the first scene is loaded
game.update()once per tick, before the entities' kinds
game.draw()once per frame shown, after the scene; the only place for hud.*
FunctionDoes
game.pause([on])stops the world (true or nothing) or starts it again (false): kinds, bodies, particles, on_touch and the game's timers, tweens and tasks wait; game.update, screens, dialogs and toasts go on
game.paused()whether the world is paused

kinds

kinds.<name> = { init = function(e) end, update = function(e) end }

FunctionCalled
init(e)when an entity of the kind is loaded with a scene or spawned
update(e)once per tick, in entity id order, after game.update
on_touch(e, other)once when e and other start to overlap (end of the tick), for each whose kind has it
on_despawn(e)inside e:despawn(), before the entity goes

Built-in kinds without behaviour: static, camera, light.

engine

FieldValue
engine.tickthe current tick: 0 in game.init, then 1, 2, …
engine.dtseconds per tick (0.05 at 20 ticks per second)
engine.width, engine.heightthe frame's size in pixels: the project's resolution, or in game.draw the frame being drawn
engine.headlesstrue when no window shows the game (tests, simulate, render)
engine.name, engine.titlefrom veduta.json
engine.apithe runtime's API level

Entity

Fields:

FieldAccessValue
idreadinteger
namereadstring
kindreadstring
alivereadfalse once despawned
x, y, zread/writeposition relative to the parent
visibleread/writeboolean
model, materialread/writeasset name or nil
layerread/writeinteger, draw order
frameread/writeinteger, the frame of a sprite sheet
animread/writethe clip it plays, or nil: another clip starts it, the same changes nothing, nil stops
anim_donereadtrue once a clip that does not loop has ended with no next
parentread/writeentity or nil; accepts an entity's name
hitboxread/write{{min x, y, z}, {max x, y, z}} or nil
colorread/writea tint ("#40a0ff", 0x40a0ff, nil for none); read back as 0xrrggbb; "#rrggbbaa" sets alpha too
alpharead/write0 (invisible) to 1 (default); below 1 it blends
bodyread/write{vx, vy, gravity, max_fall, solid, oneway} the engine moves each tick after the kinds, setting on_ground, on_ceiling, on_wall (−1, 0, 1); or nil
stateread/writetable of the entity's own values

Methods:

MethodReturns / does
e:position()x, y, z
e:set_position(x, y, z)
e:move(dx, dy, dz)adds to the position
e:world_position()x, y, z in the world
e:rotation()x, y, z in degrees
e:set_rotation(x, y, z)degrees
e:scale()x, y, z
e:set_scale(x, y, z)
e:has_tag(tag)boolean
e:add_tag(tag), e:remove_tag(tag)
e:tags()list of strings
e:overlapping([tag])list of live entities whose bounds overlap (last tick's bounds), id order
e:bounds()min x, y, z, max x, y, z; or nil
e:children()list of live child entities, id order
e:despawn()removed at the end of the tick, with its children; the kind's on_despawn runs first
e:play(clip)starts a clip from its first frame, even when it plays
e:clips()the clips its textures have, sorted
e:move_and_slide(dx, dy [, solid [, oneway]])moves in the x, y plane, stopped by entities and map cells tagged solid ("solid"), landing on oneway ("oneway") from above; returns stopped along x, along y
e:move_toward(x, y, speed [, solid]), e:move_toward(other, speed [, solid])one tick's step toward a point or entity; true once there
e:distance_to(x, y), e:distance_to(other)distance in the x, y plane
e:face(dx)mirrors the x scale to face the side dx points to; 0 keeps it
e:flash([color [, seconds]])paints it color (white) for seconds (0.1)
e:cooldown(name, seconds)true, and starts the wait, when the cooldown is over; false while it runs

scene

Available from game.init on.

FunctionReturns / does
scene.name()the loaded scene's name
scene.find(name)entity or nil
scene.tagged(tag)list of entities, id order
scene.entities()every live entity, id order
scene.spawn{...}the new entity; fields kind (default static), name, model, material, position, rotation, scale (each {x, y, z}), tags (list), visible, layer, frame, anim, parent (entity or name), hitbox ({{min}, {max}}), state (table)
scene.spawn_prefab(name, x, y, z [, rotation [, prefix]])a prefab's entities, footprint corner at (x, y, z), turned 0/90/180/270; the table lists them and holds each under its prefab name
scene.load(name [, {fade =, color =}])replaces the scene, as a reset; with fade (seconds) fades to color (black) and back, taking the input meanwhile. Cancels timers, tweens and tasks (but keep ones and the loading task), cooldowns, camera follow and shake, particles
scene.raycast(x, y, dx, dy, distance [, tag])the first entity or map cell tagged tag ("solid") along the ray: {x, y, distance, nx, ny, entity} (or cell = {x, y}), or nil
scene.nearest(x, y [, tag [, max]])the nearest live entity (with tag, within max) and its distance, or nil
scene.within(x, y, radius [, tag])the live entities within radius, nearest first

input

Buttons: "up", "down", "left", "right", "a", "b", "select", "cancel".

FunctionReturns
input.down(button)held this tick
input.pressed(button)went down this tick
input.released(button)went up this tick
input.dpad()x (−1, 0, 1: left to right), y (−1, 0, 1: down to up)
input.repeated(button [, delay [, rate]])true when it goes down, then every rate (0.1 s) once held delay (0.3 s)
input.held(button)seconds held, 0 when up

While a dialog is open, while a scene fades and on the tick a dialog closes, these read as nothing.

camera

FunctionReturns / does
camera.get(){position = {x, y, z}, target = {x, y, z}, ortho, fov, size, near, far}
camera.set{...}changes the fields given
camera.follow2d(x, y, height)orthographic camera looking down −Z at (x, y), height units visible
camera.follow(entity [, {bounds =, smooth =, deadzone =, offset =, snap =}])moves with the entity each tick; bounds "map" or {left, bottom, right, top}, smooth seconds, deadzone {w, h}, offset {x, y}, snap = false eases in; nil stops
camera.shake(strength [, seconds])shakes up to strength metres, fading over seconds (0.3); camera.get never sees it
camera.to_screen(x, y [, z])the frame pixel x, y of a world point, and whether it is on the frame

hud

Only inside game.draw. Pixels from the top left.

FunctionReturns / does
hud.text(x, y, text [, color [, scale]]), hud.text(x, y, text, {color =, scale =, align =, shadow =})draws with the 8 × 8 font (ASCII, Latin-1, Windows-1252's €‘’“”–—…); align "center" or "right" on x, shadow a color drawn one pixel down-right; returns the width drawn
hud.text_width(text [, scale])width in pixels; usable outside draw
hud.wrap(text, width [, scale])text with line breaks, and the number of lines; usable outside draw
hud.rect(x, y, w, h [, color])a filled rectangle
hud.outline(x, y, w, h [, color [, thickness]])a rectangle's border
hud.line(x1, y1, x2, y2 [, color [, width]])a line
hud.circle(x, y, r [, color [, fill]])a circle, a disc when fill
hud.bar(x, y, w, h, value, max [, options])a bar filled value / max; options color, back (false for none), border, low (color at low_at = 0.25 or less), vertical
hud.text_box(x, y, w, h, text [, options])text wrapped to w, cut to h; options color, scale, align, valign, spacing, shadow; returns lines drawn, lines total
hud.image(texture, x, y [, options])a texture or part of it; options src = {x, y, w, h}, w, h, color, flip_x, flip_y
hud.panel(texture, x, y, w, h, border [, options])nine-slice panel; border a number or {left, top, right, bottom}; options src, color
hud.image_size(texture)width, height in texels

world

FunctionReturns / does
world.load(name, cx, cz)replaces the scene with a streamed world around cell (cx, cz)
world.name()the loaded world or nil
world.focus(x, y, z)where chunks load; call every tick
world.height(x, z)ground height
world.water(x, z)water level or nil

map

The scene's tile map (see Maps). Cells are (x, y): columns right, rows down, from 0. layer is a layer's name.

FunctionReturns / does
map.name()the scene's map or nil
map.load(name)another map, as its file describes it (nil removes it); entities stay
map.size()columns, rows
map.tile()meters per cell
map.layers()layer names, bottom first
map.cell(x, y)the cell under a point of the world
map.center(x, y)the point at the center of a cell
map.inside(x, y)whether the cell is on the map
map.get(x, y [, layer])the terrain there (default the first layer), or nil
map.set(x, y, terrain [, layer])paints a cell; nil empties it
map.has(x, y, tag [, layer])a terrain with the tag paints the cell (any layer unless named)
map.tags(x, y [, layer])the tags there, sorted
map.objects([tag])objects {name, x, y, w, h, tags, props}, file order
map.object(name)one object or nil

mesh

FunctionReturns / does
mesh.new()an empty mesh
m:part([material])following faces use material (or the entity's)
m:quad(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4)a quad, counter-clockwise seen from the front
m:triangle(x1, y1, z1, x2, y2, z2, x3, y3, z3)a triangle
m:box(x, y, z, w, h, d [, faces])a box from (x, y, z); faces like "+x-x+y-y+z-z", default all
m:triangles()the triangle count
mesh.set(name, m)makes a copy of m the model name (must contain :, not start with world:); survives scene.load
mesh.remove(name)forgets the model
mesh.voxels(v, materials [, size])a mesh of a volume's visible faces, one part per block id, materials[id] names each; blocks size units wide (default 1)

volume

FunctionReturns / does
volume.new(x, y, z)a grid of block ids 0–255, all 0; at most 4 194 304 cells
v:get(x, y, z)the id; cells count from 0
v:set(x, y, z, id)
v:fill(x1, y1, z1, x2, y2, z2, id)every cell of the box
v:size()x, y, z

save

FunctionReturns / does
save.write(name, table)true, or nil and a message when the storage fails; errors on what a save cannot hold
save.read(name)a new table, or nil (and a message when it cannot be read)
save.remove(name)true, or nil and a message
save.list()the save names, sorted
save.best(key [, value [, "low"]])a record in the save best: with a value, stores it when it beats the record (higher, or lower with "low") and returns the record and whether it is new; without, the record or nil

settings, lang, T

FunctionReturns / does
settings.<key> = valuestores the value in the save settings at once; read back the same way
settings.defaults{...}values for keys never set
settings.reset(), settings.all()forgets every value; a copy of them all
T(key [, vars])the text of lang/<code>.lua in the current language, else English, else the key; {name} takes vars.name
lang.list(), lang.get(), lang.set(code)the languages; the current one; changes it (kept in settings.lang)

timer, tween, task

Count ticks; belong to the screen that made them and to an owner entity (cancelled when it is despawned); cancelled by a scene load unless made with keep.

FunctionReturns / does
timer.after(seconds, fn [, owner])calls fn once; a handle (h:cancel(), h:done()). owner: an entity or {owner =, keep = true}
timer.every(seconds, fn [, owner])calls fn every seconds until it returns false
timer.cancel(handle)stops a timer, tween or task
timer.cooldown(key, seconds)true, and starts the wait, when the cooldown is over
tween(target, values, seconds [, easing [, done]])moves numeric fields of an entity or table; easings linear, in_/out_/in_out_ + quad, cubic, quart, sine, expo, circ, back, elastic, bounce
tween.cancel(target or handle)
task.start(fn [, owner])runs fn until it waits; a handle
task.cancel(handle), task.current()
wait([seconds]), wait_for(button), wait_until(fn)inside a task: go on after that long (next tick), on a press, when fn() is true

screen, signal

FunctionReturns / does
screen.add(name, {enter =, update =, draw =, leave =, resume =})defines a screen; drawn after game.draw, bottom first; only the top updates, and game.update and kinds run only while at most one screen is on the stack
screen.go(name, ...), screen.push(name, ...), screen.pop(...)replace every screen; enter over the current one; back to the one below (its resume(...))
screen.current(), screen.depth()the top screen's name or nil; how many
signal.on(name, fn [, owner])a handle; fn(...) runs on every signal.emit(name, ...)
signal.emit(name, ...), signal.off(handle)

ui

FunctionReturns / does
ui.menu{items… [, x =, y =, w =, title =, index =, align =, scale =, wrap =, on_select =, on_cancel =, on_change =]}a menu; items are strings or {text =, disabled =, on_select =}. m:update() returns the index and item chosen this tick, or nil (nil, "cancel" on B or Cancel); m:draw(), m.index, m:select(i), m:size()
ui.dialog(speaker, text [, {choices =, speed =, on_done =}])a typed dialog box at the bottom, pages of three lines, then choices; in a task waits and returns the choice, else on_done(choice). Dialogs queue; the game's input reads as nothing while one is open
ui.toast(text [, {sec =, color =}])a short message at the top (2 s)
ui.busy()a dialog is open or a scene is fading
ui.box(x, y, w, h)a box in the style
ui.styleback, border, text, accent, dim; or panel (a texture, nine-slice) and panel_border

particles

FunctionReturns / does
particles.burst{x =, y = [, z =, count =, color =, color_end =, speed =, angle =, spread =, life =, gravity =, drag =, size =, size_end =, fade =]}count (8) squares from (x, y, z) at speed (a number or {min, max}), spread degrees (360) around angle (90), living life s; 512 at most
particles.clear(), particles.count()

Globals

FunctionDoes
trace(name [, fields])adds an event to the tick's trace; scenarios count events by name
invariant(name, predicate)registers a check; lists in veduta.json or a scenario enable it
require(module)runs module.lua once (dots are folders) and returns its result
print(...)writes to the tool's error output / VS Code's Debug Console

Standard library

string, table, math and utf8 as in Lua 5.4, with these additions:

FunctionReturns
math.clamp(x, lo, hi), math.lerp(a, b, t), math.sign(x)
math.round(x [, step])nearest integer (halves up), or multiple of step
math.approach(x, target, step)x moved toward target by at most step
math.distance(x1, y1, x2, y2), math.angle(x1, y1, x2, y2)distance; degrees from +x, counter-clockwise
random.int(a, b), random.float([a, b]), random.chance(p)from the seeded generator
random.choice(list), random.shuffle(list)an element (nil if empty); shuffles in place
random.weighted(t)a key of {gold = 3, rock = 1} or an item of {{"gold", 3}, {"rock", 1}}, by weight
table.find(list, value), table.remove_value(list, value)first index or nil; removes it, true if it was there
table.copy(t [, deep])a copy, nested tables too when deep

and these differences:

Veduta v2 (Lua games, release candidates). This wiki is built from wiki/ in the engine's repository, where its examples are tested, and published with every engine release on https://veduta.roomve.it/docs/.