Skip to main content

Modding overview

Phoenix Engine is built around two ways of modding, and tries to make both pleasant:

SoftmoddingHardmodding
Whata folder in mods/a fork of the engine
LanguageLua / Luau, Python, HScript, JSONHaxe
Needs a compilernoyes
Can replace assetsyesyes
Can change engine behaviourthrough the scripting APIanything
Distributionzip the foldership a build

Most mods only need softmodding. The scripting API exposes 275 Lua functions and 170 Python functions, and standalone HScript gets the engine classes directly, plus reflective getProperty/setProperty access to almost any field in the engine.

Compatibility​

Phoenix keeps the Psych Engine / JS Engine mod contract, so existing mods generally load unchanged: the same folder layout, the same callback names, the same chart format (including Psych 1.0 charts). Phoenix additions are strictly additive — Python scripting, extra callbacks, extra events.

What a build supports​

Scripting is compile-time gated. -DMODDING_LEVEL=0 disables both Lua and Python, and =1 keeps Lua but drops Python. HScript is controlled separately by HSCRIPT_ALLOWED, so it stays available at every modding level on targets that support it:

BuildMODS_ALLOWEDLuaPythonHScript
Desktop (default)✓✓✓✓
Mobile (default)✓✓✓✓
-DMODDING_LEVEL=1✓✓✗✓
-DMODDING_LEVEL=0✓✗✗✓
HTML5 / Flash / AIR✗✗✗web only

Getting started​

  1. Create the folder — mods/MyMod/ with the subfolders you need. See Mod folder structure.
  2. Enable it — add MyMod|1 to modsList.txt, or toggle it in the in-game Mods menu.
  3. Add content — charts in data/, audio in songs/, art in images/, characters in characters/, weeks in weeks/.
  4. Add behaviour — a .lua, .py or .hx/.hscript script in scripts/ (global) or data/<song>/ (per song). Start from docs/TemplateScript.lua / docs/TemplateScript.py / docs/TemplateScript.hx.
  5. Test — run the game, watch the on-screen debug text for script errors.
-- mods/MyMod/scripts/hello.lua
function onCreatePost()
debugPrint('Hello from MyMod!')
end

function onBeatHit()
if curBeat % 4 == 0 then
cameraShake('camGame', 0.005, 0.1)
end
end
# mods/MyMod/scripts/hello.py
def onCreatePost():
debugPrint('Hello from MyMod!')

def onBeatHit():
if curBeat % 4 == 0:
cameraShake('camGame', 0.005, 0.1)

The bundled example​

mods/bf-clicker/ is a shipped example mod written in Python:

mods/bf-clicker/
├── data/bf-clicker/bf-clicker.json # chart (normal)
├── data/bf-clicker/bf-clicker-easy.json
├── data/bf-clicker/bf-clicker-hard.json
├── data/bf-clicker/bf-clicker.py # the song script
├── songs/bf-clicker/Inst.ogg
└── weeks/bf-clicker-week.json

example_mods/ also contains modTemplate.zip and a script template.

Where to go next​

PageContents
Mod folder structureevery folder the engine looks for, pack.json, load order
Lua scriptinghow scripts are loaded, globals, patterns
Lua API referenceall 275 functions, generated from the engine
Python scriptingthe Hython runtime and its differences
Python API referenceall 170 functions
HScriptstandalone .hx/.hscript mods, plus running Haxe from a Lua script
Script hooksevery callback the engine fires
Custom events & notetypeschart-driven scripting
Transparent windowsee-through window, alpha and click-through