Skip to content

Lua Scripting

Anthony Samms edited this page Jun 2, 2026 · 1 revision

Lua Scripting

Lua scripts live in Scripts/ and control dynamic behaviour such as the game background. The engine loads scripts from subdirectories: a folder named background containing background.lua becomes the background script.

Scripts/
└── background/
    ├── background.lua          (entry point, required name matches folder)
    └── bg_objects/
        ├── donbg.lua
        ├── bg_normal.lua
        ├── bg_fever.lua
        └── ...

Entry Point

The engine calls fixed methods on the returned script object. For the background script, the expected interface is:

Background = {}
Background.__index = Background

function Background.new(player_num, bpm, scene_preset)
    local self = setmetatable({}, Background)
    -- initialise
    return self
end

function Background:update(current_ms, bpm) end
function Background:handle_good(player_num) end
function Background:handle_ok(player_num) end
function Background:handle_bad(player_num) end
function Background:handle_drumroll(player_num) end
function Background:handle_balloon(player_num) end
function Background:handle_gauge(player_num, progress, is_clear, is_rainbow) end
function Background:draw_back() end
function Background:draw_fore() end
function Background:destroy() end

Global: tex

The tex table provides access to textures and the skin configuration.

Loading

tex.load_animations("background")
tex.load_folder("background", "bg_normal/bg_0")
tex.unload_folder("background", "bg_normal/bg_0")

Drawing

tex.draw_texture("background", "bg_normal/bg_0/background", {
    x = 0,
    y = 0,
    scale = 1.0,
    rotation = 0.0,
    fade = 1.0,
    frame = 0,
    index = 0,
    center = false,
    color = {255, 255, 255, 255},
    mirror = "horizontal",  -- "horizontal" or "vertical"
    origin = {0, 0},
    src = { x = 0, y = 0, width = 100, height = 100 },
    x2 = nil,
    y2 = nil,
})

You can also draw by numeric ID for performance:

local id = tex.get_id("background", "bg_normal/bg_0/background")
tex.draw_id(id, { x = 0, y = 0 })

Texture Info

local info = tex.get_texture_info("background", "bg_normal/bg_0/background")
-- info.x, info.y, info.width, info.height, info.name, info.frame_count

local keys = tex.get_texture_keys("background/bg_normal/bg_0")
-- returns an array of texture name strings

Screen Info

local w = tex.get_screen_width()
local h = tex.get_screen_height()
local s = tex.get_screen_scale()

Skin Config

local cfg = tex.get_skin_config("game_2p_offset")
if cfg then
    local y_offset = cfg.y
end
-- Returns table with x, y, width, height, font_size, or nil if not found.

Global: anim

The anim table creates animation objects. Animations defined in animation.json can be retrieved and copied; animations can also be created inline in Lua.

Retrieving from animation.json

local move_anim = tex.get_animation(0)          -- shared instance
local move_copy = tex.get_animation(0, true)    -- independent copy

Creating Inline

local fade = anim.fade(150, {
    initial_opacity = 0.0,
    final_opacity   = 1.0,
    loop            = false,
    delay           = 0.0,
    ease_in         = "quadratic",
    ease_out        = "quadratic",
    reverse_delay   = 0,
})

local move = anim.move(3000, {
    total_distance = -328,
    start_position = 0,
    loop           = true,
})

local tc = anim.texture_change(600, {
    {0, 100, 0},
    {100, 200, 1},
    {200, 300, 2},
}, { loop = true })

local resize = anim.texture_resize(200, {
    initial_size = 1.0,
    final_size   = 0.0,
})

local stretch = anim.text_stretch(300, { loop = false })

Animation Object Methods

All animation objects share these methods:

Method Description
anim:update(ms) Advance the animation by ms milliseconds; returns the current attribute value
anim:start() Start the animation
anim:restart() Restart from the beginning
anim:pause() Pause
anim:unpause() Resume
anim:reset() Reset to initial state without starting
anim.attribute Current value (opacity, position, scale, etc.)
anim.duration Total duration in ms
anim:is_finished() Returns true when the animation has completed
anim:is_started() Returns true if the animation has begun

Global: text

The text table creates outlined text objects that can be drawn with tex.draw_texture-style parameters.

local label = text.create_text(
    "free_play",            -- skin_config.json key (provides text string and font_size)
    {255, 255, 255, 255},   -- text color RGBA
    {0, 0, 0, 255},         -- outline color RGBA
    false,                  -- is_vertical
    2,                      -- outline thickness
    0.0                     -- letter spacing
)

if label.is_ready and not label.upload_pending then
    label:finish()
    label:draw({ x = 100, y = 200 })
end

OutlinedText exposes width, height, is_ready, and upload_pending properties.

Collab Backgrounds

Songs can specify a scene_preset that routes the background to a collab implementation. Built-in collab keys are:

PRACTICE, TUTORIAL, A3, ANIMAL, BUTTOBURST, DAN, FUNASSYI, IMAS, IMAS_CG, IMAS_ML, IMAS_SIDEM, OSHIRI

Collab scripts are placed in Scripts/background/bg_collabs/ and loaded via require. Each collab that needs unique graphics specifies a path under Graphics/background/collab/<name>/.

Clone this wiki locally