Graphics API
gfx2d is a per-computer, layered 2D drawing API for terminal overlays.
It renders directly over the terminal text UI and is constrained to the terminal panel bounds.
Coordinate space
Coordinates are pixel-based with origin at the terminal canvas top-left.
xincreases to the right,yincreases downward.Any draw command outside bounds is clamped to current canvas size.
By default, commands are authored in a logical canvas and automatically scaled to the current terminal viewport.
Automatic UI scaling
Auto scaling is enabled by default.
On first render, the logical canvas is initialized from the current viewport size.
If the terminal viewport later changes (window resize/UI scale changes), existing draw coordinates are scaled automatically.
Mouse
inputuiX/uiYvalues are mapped back into the logical canvas for consistent hit-testing.
Use these methods to control behavior:
gfx2d.setAutoScale(enabled: Boolean)Enables/disables automatic render scaling.gfx2d.isAutoScaleEnabled()Returns current auto-scaling state.gfx2d.resetCanvasSize()Clears a custom logical canvas size set by script.gfx2d.getViewportWidth()/gfx2d.getViewportHeight()Returns current physical viewport size in pixels.gfx2d.getScaleX()/gfx2d.getScaleY()Returns logical-to-viewport scaling factors.
Layers
Layers let scripts separate background, content, and interaction visuals.
gfx2d.setLayer(name: String)Sets the active draw layer by name, creating it if it does not exist.gfx2d.createLayer(name: String, order: Integer)Creates or updates a layer with an explicit draworder. Lower values render first (behind higher layers).gfx2d.removeLayer(name: String)Removes the named layer and all its draw commands. The"default"layer cannot be removed.gfx2d.getLayers()Returns the names of all current layers as aString[].gfx2d.setLayerVisible(name: String, visible: Boolean)Shows (true) or hides (false) a layer without removing its draw commands.gfx2d.clearLayer(name: String)Discards all draw commands in the named layer.gfx2d.clear()Discards all draw commands in every layer.gfx2d.beginBatch()Begins a batch. All subsequentclearLayer,clear, and draw commands are staged in a private pending buffer instead of being applied immediately.gfx2d.commitBatch()Atomically applies all staged commands to the live buffers in a single lock acquisition. The render thread will either see the previous complete frame or the new complete frame — never a partially-cleared or partially-filled intermediate state. Use this pair to eliminate flicker when redrawing a dynamic UI:gfx2d.beginBatch() gfx2d.clearLayer("widgets") gfx2d.setLayer("widgets") -- ... all draw calls ... gfx2d.commitBatch()
Lower order draws first (behind higher layers).
Canvas
gfx2d.setCanvasSize(width, height)Overrides internal canvas dimensions. Usually automatic from terminal UI.gfx2d.getWidth()Current canvas width in pixels.gfx2d.getHeight()Current canvas height in pixels.
Drawing
gfx2d.point(x: Number, y: Number, r: Number, g: Number, b: Number, a: Number)Draws a single pixel. Color channels (r,g,b,a) are normalized floats in[0.0, 1.0].gfx2d.line(x1: Number, y1: Number, x2: Number, y2: Number, r: Number, g: Number, b: Number, a: Number)Draws a line from(x1, y1)to(x2, y2).gfx2d.line(x1, y1, x2, y2, r, g, b, a, thickness: Number)Draws a line with configurable stroke thickness (1..16, default1).
gfx2d.rect(x: Number, y: Number, width: Number, height: Number, r: Number, g: Number, b: Number, a: Number, filled: Boolean)
Draws a rectangle. filled = true draws a solid filled rect; false draws only the outline.
gfx2d.circle(x: Number, y: Number, radius: Number, r: Number, g: Number, b: Number, a: Number, filled: Boolean, segments: Integer)
Draws a circle centered at (x, y). segments controls smoothness (8..128, default 24).
gfx2d.circle(x, y, radius, r, g, b, a, filled, segments, thickness: Number)Draws a circle with configurable outline thickness whenfilled = false.gfx2d.polygon(points: Number[], r: Number, g: Number, b: Number, a: Number, filled: Boolean)Draws a polygon from a flat vertex list ({x1, y1, x2, y2, ...}). At least 3 points are required.gfx2d.polygon(points, r, g, b, a, filled, thickness: Number)Draws a polygon with configurable outline thickness whenfilled = false.gfx2d.text(x: Number, y: Number, text: String, r: Number, g: Number, b: Number, a: Number, scale: Integer)Draws text using a built-in pixel font.scalemultiplies glyph size (1..16, default1). Supports\nline breaks.gfx2d.text(x, y, text, r, g, b, a, scale, maxWidth: Integer, maxHeight: Integer, align: String, wrap: Boolean)Extended text rendering with optional clipping and layout:maxWidth/maxHeight: clip bounds in pixels (nildisables bound)align:"left"(default),"center", or"right"wrap: whentrue, wraps text to fitmaxWidth
gfx2d.bitmap(x: Number, y: Number, width: Integer, height: Integer, rgbaPixels: Integer[])Draws packed bitmap data.rgbaPixelsis row-major and uses0xRRGGBBAAper pixel.
Limits and config
Server config controls safety caps:
gfx2d_max_layersgfx2d_max_commands_per_layer
When limits are reached, additional commands/layers return false instead of growing unbounded.
Example: layered terminal HUD
gfx2d.clear()
gfx2d.createLayer("bg", 0)
gfx2d.createLayer("widgets", 10)
local w = gfx2d.getWidth()
local h = gfx2d.getHeight()
gfx2d.setLayer("bg")
gfx2d.rect(0, 0, w, h, 0.05, 0.05, 0.08, 0.85, true)
gfx2d.rect(8, 8, w - 16, h - 16, 0.3, 0.5, 1.0, 0.9, false)
gfx2d.setLayer("widgets")
gfx2d.line(16, 32, w - 16, 32, 0.2, 0.9, 0.8, 1.0, 2)
gfx2d.circle(w * 0.5, h * 0.5, 28, 1.0, 0.5, 0.2, 0.9, false, 32, 3)
gfx2d.text(20, h - 24, "gfx2d HUD", 1.0, 1.0, 1.0, 1.0, 2, w - 40, 24, "center", true)
Bitmap Helper Library (gfx2dlib)
gfx2dlib is a Lua helper module for creating bitmap payloads for gfx2d.bitmap.
local gfx2dlib = require("gfx2dlib")
local bmp = gfx2dlib.checkerBitmap(16, 16, 0xFFAA22FF, 0x223344CC, 2)
gfx2d.bitmap(8, 8, bmp.width, bmp.height, bmp.pixels)
Useful helpers:
gfx2dlib.pack(r, g, b, a)/gfx2dlib.unpack(color)gfx2dlib.newBitmap(width, height, fillColor)gfx2dlib.setPixel(bitmap, x, y, color)/gfx2dlib.getPixel(bitmap, x, y)gfx2dlib.checkerBitmap(width, height, colorA, colorB, cellSize)gfx2dlib.grayscaleBitmap(width, height, values, alpha)gfx2dlib.textMaskBitmap(rows, onColor, offColor, onChars)gfx2dlib.draw(gfx2d, x, y, bitmap)
Interactive UI pattern
Use input mouse events with uiX/uiY and insideCanvas for hit-testing and dragging.
input.clear()
input.consumeMouse()
local box = { x = 50, y = 40, w = 120, h = 70 }
local drag = nil
local function inside(x, y, r)
return x and y and x >= r.x and y >= r.y and x < (r.x + r.w) and y < (r.y + r.h)
end
while true do
gfx2d.clearLayer("widgets")
gfx2d.setLayer("widgets")
gfx2d.rect(box.x, box.y, box.w, box.h, 0.15, 0.75, 1.0, 0.95, true)
local e = input.waitFor(33)
if e and e.type == "mouse" then
if e.pressed and e.button == "left" and e.insideCanvas and inside(e.uiX, e.uiY, box) then
drag = { ox = e.uiX - box.x, oy = e.uiY - box.y }
elseif e.released and e.button == "left" then
drag = nil
elseif e.dragging and drag and e.uiX and e.uiY then
box.x = e.uiX - drag.ox
box.y = e.uiY - drag.oy
end
end
end