Skip to content

Lua Scripting API

SomeGuyWhoLovesCoding edited this page Mar 13, 2026 · 5 revisions

Note

Note: This document was AI-generated via claude sonnet 4.6 and is a work in progress. Things may change in the future.

FunkinView Lua Scripting System

A LuaJIT-powered scripting layer for Funkin' View that allows chart creators to hook into gameplay events, create custom visual elements, and manipulate the playfield at runtime.


Architecture Overview

The system is composed of three main classes:

Class Responsibility
FunkinViewLua Top-level manager. Loads .lua files, routes function calls to all active VM instances.
FunkinViewLuaScript Wraps a single Lua VM (llua.State). Handles callback registration.
CustomLuaSpriteComponent Exposes sprite/text/program/buffer APIs to Lua scripts.

Scripts are loaded from the chart's directory and, optionally, a stage-specific .lua file at stages/<stageName>.lua.


Lifecycle Callbacks

These are Lua functions your script can define. They are called automatically by the engine at the appropriate time.

Core

Function Arguments Notes
create() Called once on script load, before createPost.
createPost() Called after the playfield finishes initializing.
update(deltaTime) deltaTime: Float Called every frame before gameplay updates.
updatePost(deltaTime) deltaTime: Float Called every frame after gameplay updates. Also available as postUpdate.
render() Called every render frame.
renderPost() Called after the render pass. Also available as postRender.
dispose() Called when the playfield is being torn down.
disposePost() Called after disposal. Also available as postDispose.

Song Events

Function Arguments
startSong(title, difficulty) title: String, difficulty: String
startSongPost(title, difficulty) Also available as postStartSong
stopSong(title, difficulty) title: String, difficulty: String
stopSongPost(title, difficulty) Also available as postStopSong

Conductor

Function Arguments
stepHit(step) step: Float
beatHit(beat) beat: Float
measureHit(measure) measure: Float

Note Events

Function Arguments
hitNote(pos, index, duration, type, timing, notesInOne)
hitNotePost(...) Also available as postHitNote
missNote(pos, index, duration, type, notesInOne)
missNotePost(...) Also available as postMissNote
completeSustain(pos, index, duration, type)
completeSustainPost(...) Also available as postCompleteSustain
releaseSustain(pos, index, duration, type)
releaseSustainPost(...) Also available as postReleaseSustain

Pause / Resume

Function Arguments
pause()
pausePost() Also available as postPause
resume()
resumePost() Also available as postResume

Game Over

Function Arguments
gameOver()
gameOverPost() Also available as postGameOver

Lua API Reference

All functions below are callable from within any Lua script.

Utility

trace(message)
-- Prints a message to the console.

Buffers

Buffers hold collections of LuaSprite elements for batch rendering.

customBufferNew(bufferName, minSize, growSize, autoShrink)
-- Creates a new buffer.
-- bufferName: String (must not be empty)
-- minSize:    Int
-- growSize:   Int    (default: 0)
-- autoShrink: Bool   (default: false)
 
updateBuffer(bufferName)
-- Flushes and resubmits the buffer's data to the GPU.

Programs

A program links a buffer to a texture for rendering.

customProgramNew(programName, customBuffer)
-- Creates a new render program attached to an existing buffer.
 
addTextureToProgram(programName, texturePNG, disableAntialiasing)
-- Loads a PNG from the assets folder and binds it to the program.
-- texturePNG:          String  (relative asset path)
-- disableAntialiasing: Bool    (default: false)
 
wipeTextureFromProgram(programName)
-- Unbinds and removes the texture from the program.
 
addProgramToDisplay(programName, toDisplay, isBehind, atCustomProgram)
-- Adds the program to a named display (e.g. "display", "view", "roof").
-- isBehind:        Bool   (default: false) — render behind existing programs
-- atCustomProgram: String (optional) — insert relative to another program
 
removeProgramFromDisplay(programName, fromDisplay)
-- Removes the program from the specified display.

Elements (Sprites)

customElementNew(elem, x, y, w, h, color)
-- Creates a new sprite element.
-- color: String (color name or 0xAARRGGBB hex, default: "white")
 
addElementToBuffer(elemName, bufferName)
-- Adds the element to a buffer for rendering.
 
removeElementFromBuffer(elemName, bufferName)
-- Removes the element from a buffer.
 
updateElementToBuffer(elemName, bufferName)
-- Marks the element as dirty so the buffer re-uploads it.
 
-- Position
setElementPos(elemName, x, y)
getElementPosX(elemName) --> Float
getElementPosY(elemName) --> Float
 
-- Size (UV coordinates)
setElementCoordinate(elemName, w, h)
getElementCoordinateX(elemName) --> Float
getElementCoordinateY(elemName) --> Float
 
-- Color
setElementTint(elemName, color)
getElementTint(elemName) --> String  -- returns "0xAARRGGBB"
 
-- Alpha (0.0 – 1.0)
setElementAlpha(elemName, alpha)
getElementAlpha(elemName) --> Float
 
-- Rotation (degrees)
setElementAngle(elemName, rotation)
getElementAngle(elemName) --> Float
 
-- Centering
screenCenterElement(elemName, fromDisplay, axis)
-- axis: "X", "Y", or "XY"

Text Elements

Text elements automatically bind to a live gameplay value (e.g. score, combo).

customTextNew(textElem, x, y, toDisplay, text, font, color, outlineSize, outlineColor)
-- toDisplay:    String — a PlayField field name (e.g. "score", "combo", "accuracy")
-- font:         String (default: "vcr")
-- color:        String (default: "white")
-- outlineSize:  Int    (default: 0)
-- outlineColor: String (default: "black")
 
-- Position
setTextPos(textElem, x, y)
getTextPosX(textElem) --> Float
getTextPosY(textElem) --> Float
 
-- Content
setTextString(textElem, text)
getTextString(textElem) --> String
 
-- Color
setTextColor(textElem, color)
getTextColor(textElem) --> String
 
setTextOutlineColor(textElem, color)
getTextOutlineColor(textElem) --> String
 
setTextOutlineSize(textElem, size)
getTextOutlineSize(textElem) --> Float
 
-- Centering
screenCenterText(elemName, axis)
-- axis: "X", "Y", or "XY"
 
-- Visibility
hideText(elemName)
showText(elemName)

Display Utilities

setDisplayAngle(fromDisplay, rotation)
-- Rotates a named display (e.g. "display", "view").
 
getTextureCoordinateX(programName) --> Int  -- texture pixel width
getTextureCoordinateY(programName) --> Int  -- texture pixel height

Color Formats

Colors can be passed as:

  • Named colors — e.g. "white", "black", "red" (resolved via Color.defaultMap)
  • Hex strings — e.g. "0xFFFFFFFF" (AARRGGBB format)

Example Script

local mySprite = "box"
local myBuf    = "myBuffer"
local myProg   = "myProgram"
 
function create()
    customBufferNew(myBuf, 64)
    customProgramNew(myProg, myBuf)
    addTextureToProgram(myProg, "images/myTexture.png")
    addProgramToDisplay(myProg, "display")
 
    customElementNew(mySprite, 0, 0, 100, 100, "white")
    screenCenterElement(mySprite, "display", "XY")
    addElementToBuffer(mySprite, myBuf)
    updateElementToBuffer(mySprite, myBuf)
    updateBuffer(myBuf)
end
 
function beatHit(beat)
    setElementAngle(mySprite, beat * 15)
    updateElementToBuffer(mySprite, myBuf)
    updateBuffer(myBuf)
end
 
function dispose()
    removeProgramFromDisplay(myProg, "display")
end

Notes

  • Scripts are compiled and executed via LuaJIT using the linc_luajit bindings.
  • All callbacks silently no-op if the Lua function is not defined in the script.
  • Multiple .lua files in the chart directory are all loaded and called in sequence.
  • The ##FUNKINVIEWLUA_FUNCTION_STOP return value halts execution for that callback across subsequent VMs.
  • Stage scripts are loaded from stages/<stageName>.lua relative to the chart root.

Hello sidebar test.

Clone this wiki locally