Lua Documentation
Codetoy supports Lua 5.4 out of the box. The plan is to switch to Luau entirely or at least support luau powered linting as soon as possible, but for now Lua 5.4 is what is supported.
Canvas
State Stack
reset()
push()
pop()
Color State
fill(r, g, b, a = 1.0)
stroke(r, g, b, a = 1.0)
Line State
lineWidth(width: number)
lineJoin("round" | "bevel" | "miter")
lineMiterLimit(limit: number)
lineCap("butt" | "round" | "square")
Shape Drawing
rect(x, y, w, h, r = 0)
circle(x, y, radius)
line(x1, y1, x2, y2)
ellipse(x, y, w, h)
triangle(x1, y1, x2, y2, x3, y3)
polygon(number[] points) (eg. x1,y1, x2,y2, ...)
Transform
scale(x, y)
rotate(radians)
translate(x, y)
resetTransform()
Advanced Drawing
beginPath()
moveTo(x, y)
lineTo(x, y)
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
quadraticCurveTo(cpx, cpy, x, y)
closePath()
fillPath()
strokePath()
Text
font(family, size, weight = "normal")
text(text, x, y)
measureText(text) → number (returns width of text)
Input
Mouse
mouseX and mouseY → number
isMouseDown(button: number) → bool (0=left, 1=middle, 2=right)
function onMouseDown(key: string) if a global function with this signature exists it will be called
function onMouseUp(key: string) if a global function with this signature exists it will be called
Keyboard
isKeyDown(key: string) → bool (if the key is being held down)
function onKeyDown(key: string) if a global function with this signature exists it will be called
function onKeyUp(key: string) if a global function with this signature exists it will be called
Screen
width and height → number
centerX and centerY → number
Console
print(message: string)
API Examples
fill(r, g, b, a?)
Sets the fill color for subsequent drawing operations. Colors use RGBA format (0-255 for RGB, 0-1 for alpha).
Parameters:
r(number): Red channel (0-255)g(number): Green channel (0-255)b(number): Blue channel (0-255)a(number, optional): Alpha/opacity (0-1, default: 1.0)
Example:
function update()
fill(255, 0, 0, 0.8) -- Semi-transparent red
rect(50, 50, 100, 100)
end
rect(x, y, width, height, radius?)
Draws a rectangle at the specified position with optional rounded corners.
Parameters:
x(number): X coordinate of top-left cornery(number): Y coordinate of top-left cornerwidth(number): Width of rectangleheight(number): Height of rectangleradius(number, optional): Corner radius for rounding (default: 0)
Example:
function update()
fill(0, 150, 255)
rect(100, 100, 200, 150, 10) -- Blue rounded rectangle
end
circle(x, y, radius)
Draws a circle at the specified position.
Parameters:
x(number): X coordinate of circle centery(number): Y coordinate of circle centerradius(number): Circle radius
Example:
function update()
fill(100, 255, 100)
circle(width / 2, height / 2, 50) -- Green circle in center
end
ellipse(x, y, width, height)
Draws an ellipse at the specified position.
Parameters:
x(number): X coordinate of ellipse centery(number): Y coordinate of ellipse centerwidth(number): Horizontal radius (half-width)height(number): Vertical radius (half-height)
Example:
function update()
fill(255, 200, 0)
ellipse(width / 2, height / 2, 80, 40) -- Yellow ellipse
end
Global Variables
width
The current canvas width in pixels. Updates when the window is resized.
height
The current canvas height in pixels. Updates when the window is resized.
mouseX
The current X coordinate of the mouse in canvas space. Updated on mouse movement.
mouseY
The current Y coordinate of the mouse in canvas space. Updated on mouse movement.
deltaTime
The time elapsed since the last frame in seconds. Useful for smooth animations.
Example:
local speed = 100 -- pixels per second
local x = 0
function update()
x = x + speed * deltaTime
fill(255, 100, 200)
rect(x, 100, 50, 50)
end
Event Functions
update(deltaTime)
Called every frame. Use this for animations and game logic.
Parameters:
deltaTime(number): Time elapsed since last frame in seconds
Example:
function update()
fill(255, 100, 0)
circle(mouseX, mouseY, 20) -- Follow cursor
end
mouseDown(button)
Called when a mouse button is pressed.
Parameters:
button(number): 0 = left, 1 = middle, 2 = right
Example:
function mouseDown(button)
if button == 0 then
print("Left click at: " .. mouseX .. ", " .. mouseY)
end
end
mouseUp(button)
Called when a mouse button is released.
Parameters:
button(number): 0 = left, 1 = middle, 2 = right
resize()
Called when the canvas/window is resized.
Example:
function resize()
print("Canvas resized to: " .. width .. "x" .. height)
end
Math
The math library provides mathematical operations and trigonometric functions.
math.sin(x)
Returns the sine of x (in radians).
Example:
local xPos = 0
function update()
local halfHeight = height * 0.5
fill(255, 0, 0, 1)
rect(
xPos,
halfHeight + (halfHeight * math.sin(xPos / 10)),
10,
10
)
fill(0, 255, 255, 1)
rect(mouseX, mouseY, 10, 10)
xPos = xPos + (deltaTime * 50)
end
math.cos(x)
Returns the cosine of x (in radians).
Example:
local time = 0
function update()
fill(20, 20, 30)
rect(0, 0, width, height)
time = time + deltaTime
local x = width / 2 + math.cos(time) * 100
local y = height / 2 + math.sin(time) * 100
fill(100, 200, 255)
circle(x, y, 20)
end
math.abs(x)
Returns the absolute value of x.
Example:
function update()
local distX = math.abs(mouseX - width / 2)
local distY = math.abs(mouseY - height / 2)
fill(distX / 2, distY / 2, 200)
rect(0, 0, width, height)
fill(255, 100, 100)
rect(width / 2 - 50, height / 2 - 50, 100, 100)
end
math.sqrt(x)
Returns the square root of x.
Example:
function update()
fill(30, 30, 30)
rect(0, 0, width, height)
local distX = mouseX - width / 2
local distY = mouseY - height / 2
local distance = math.sqrt(distX * distX + distY * distY)
local radius = math.max(1, distance / 5)
fill(100 + (distance / 2) % 155, 150, 200)
circle(width / 2, height / 2, radius)
end
math.max(...)
Returns the largest number from the arguments provided.
Example:
function update()
local size = math.max(50, width / 4, height / 4)
fill(100, 200, 255)
rect(width / 2 - size / 2, height / 2 - size / 2, size, size)
end
math.min(...)
Returns the smallest number from the arguments provided.
Example:
function update()
fill(40, 40, 40)
rect(0, 0, width, height)
local maxRadius = math.min(width, height) / 4
local radiusPulse = maxRadius * (0.5 + 0.5 * math.sin(deltaTime))
fill(255, 100, 100)
circle(width / 2, height / 2, radiusPulse)
end
math.random()
Returns a random number between 0 and 1.
Example:
function update()
fill(30, 30, 30)
rect(0, 0, width, height)
for i = 1, 20 do
local x = math.random() * width
local y = math.random() * height
local r = math.random() * 255
local g = math.random() * 255
local b = math.random() * 255
fill(r, g, b)
circle(x, y, 5)
end
end
math.floor(x)
Returns x rounded down to the nearest integer.
Example:
function update()
fill(40, 40, 40)
rect(0, 0, width, height)
local gridSize = 40
local col = math.floor(mouseX / gridSize)
local row = math.floor(mouseY / gridSize)
fill(100, 200, 255)
rect(col * gridSize, row * gridSize, gridSize, gridSize)
end
math.floor(x) (alternative: rounding)
For rounding to nearest integer, use math.floor(x + 0.5).
Example:
function update()
fill(40, 40, 40)
rect(0, 0, width, height)
local gridSize = 40
local col = math.floor(mouseX / gridSize + 0.5) * gridSize
local row = math.floor(mouseY / gridSize + 0.5) * gridSize
local halfGridSize = 20
fill(100, 200, 255)
rect(col - halfGridSize, row - halfGridSize, gridSize, gridSize)
end
math.ceil(x)
Returns x rounded up to the nearest integer.
Example:
function update()
fill(40, 40, 40)
rect(0, 0, width, height)
local value = (mouseY / height) * 10
local ceiled = math.ceil(value)
local barHeight = ceiled * 20
fill(255, 100, 100)
rect(width / 2 - 50, height - barHeight, 100, barHeight)
end
math.pow(x, y) or ^ operator
Returns x raised to the power of y (x^y).
Example:
function update()
fill(20, 20, 30)
rect(0, 0, width, height)
local normalizedX = mouseX / width
local radius = math.pow(normalizedX, 2) * 150
fill(100, 200, 255)
circle(width / 2, height / 2, radius)
end
math.pi
The constant π (approximately 3.14159).
Example:
local time = 0
function update()
fill(30, 30, 30)
rect(0, 0, width, height)
time = time + deltaTime
for i = 0, 5 do
local angle = ((i / 6) * 2 * math.pi) + time
local x = width / 2 + math.cos(angle) * 100
local y = height / 2 + math.sin(angle) * 100
fill(100 + i * 30, 150, 200)
circle(x, y, 15)
end
end
math.atan2(y, x)
Returns the arctangent of y/x in radians, useful for calculating angles.
Example:
function update()
fill(40, 40, 40)
rect(0, 0, width, height)
local centerX = width / 2
local centerY = height / 2
local angle = math.atan2(mouseY - centerY, mouseX - centerX)
fill(255, 100, 100)
rect(centerX - 2, centerY - 2, 4, 4)
local endX = centerX + math.cos(angle) * 100
local endY = centerY + math.sin(angle) * 100
fill(100, 200, 255)
circle(endX, endY, 10)
end
Example Programs
Example 1: Interactive Circle Following Cursor
function update()
fill(200, 200, 200)
rect(0, 0, width, height) -- Clear background
fill(0, 150, 255)
circle(mouseX, mouseY, 30) -- Blue circle follows mouse
end
function mouseDown(button)
print("Clicked at " .. mouseX .. ", " .. mouseY)
end
Example 2: Animated Rectangle
local x = 0
local speed = 150 -- pixels per second
function update()
-- Clear background
fill(50, 50, 50)
rect(0, 0, width, height)
-- Bounce rectangle
x = x + speed * deltaTime
if x + 100 > width or x < 0 then
speed = -speed
end
fill(100, 200, 255)
rect(x, height / 2 - 50, 100, 100)
end
Example 3: Responsive Grid on Resize
local cols = 5
local rows = 4
function update()
fill(30, 30, 30)
rect(0, 0, width, height) -- Background
local cellWidth = width / cols
local cellHeight = height / rows
for row = 0, rows - 1 do
for col = 0, cols - 1 do
fill(100 + col * 30, 100 + row * 30, 200)
rect(col * cellWidth, row * cellHeight, cellWidth, cellHeight, 5)
end
end
end
function resize()
print("Resized to " .. width .. "x" .. height)
end
Example 4: Drawing with Mouse
local points = {}
function update()
fill(40, 40, 40)
rect(0, 0, width, height) -- Clear background
-- Draw all recorded points
fill(255, 100, 100)
for i, point in ipairs(points) do
circle(point.x, point.y, 5)
end
end
function mouseDown(button)
if button == 0 then
table.insert(points, { x = mouseX, y = mouseY })
end
end
function resize()
points = {} -- Clear points on resize
end
Example 5: Pulsing Ellipses
local time = 0
function update()
fill(20, 20, 30)
rect(0, 0, width, height) -- Background
time = time + deltaTime
for i = 1, 5 do
local delay = i * 0.2
local scale = 1 + math.sin(time * 3 - delay) * 0.5
fill(100 + i * 30, 150, 200)
ellipse(width / 2, height / 2, 40 * scale, 20 * scale)
end
end