CLight modding documentation
Status: Implemented (API 1.24). Every page starts with its status: Implemented (it ships), Partly implemented (the page says what is missing) or Planned (not in the game yet; names may change). The SDK is in the
clight-sdkfolder next toCelestial.exe.
CLight is the official modding platform for the Celestial client. Mods add blocks and items, change gameplay through events and mixins, add HUD layers, screens, keybinds, sounds, commands and network payloads, ship data packs and resource packs, and run as server mods on Celestial’s dedicated server. They also add custom entities with glTF models, animation and AI, particles and decals, post-processing passes and camera effects, saved data and attachments, and their own UI with the UI kit, components and HTML overlays. Mixins reach rendering, the HUD, screens, world generation, chunks, recipes and loot. What is still to come (block entity types for mod blocks, dimensions and a worldgen API in code, services between mods) is marked Planned on its page.
You can write mods in three languages, and every mod runs in a sandbox: it can use the game API and its own folder, but it can’t touch your other files, start programs or download anything you didn’t allow.
| Language | How it runs |
|---|---|
| C | Against the C API clight.h, compiled to WebAssembly by the SDK (clight build). |
| C++ | Uses the header-only wrapper clight.hpp over the same C API, with RAII, std::expected and lambdas. Compiled to WebAssembly. |
| Lua | Lua 5.4 scripts in a per-mod sandboxed VM, with hot reload. No build step. |
Data-only mods (data packs, resource packs, CEM models, shader packs) need no code at all.
Java mods are not supported. Celestial does not load, convert or translate Fabric, Forge, NeoForge, Quilt or Bukkit/Paper plugin jars, and no such tool or compatibility runtime is planned. Mods must be written for CLight. Authors who want to port their own mods by hand will find concept mapping tables in Migration. Their data and assets (data packs, resource packs) work as they are.
Quick start
- Install the SDK (Installing the CLight SDK).
- Create a project:
clight new cpp ruby_tools(orc,lua). For C and C++, runclight setuponce to install the WebAssembly compiler. - Build and launch a dev instance:
clight run. It builds the mod, packs it into a.clmod, and starts Celestial with hot reload turned on. - Read Core concepts, then follow a guide in Guides.
The smallest complete Lua mod:
-- scripts/main.lua
-- When a player joins, give them a ruby and say hello.
cl.on("player.join", function(event)
local player = event.player
player:give("my_mod:ruby")
player:send_message("Welcome, " .. player.name .. "!")
end)
The same mod in C, with the helpers from clight_easy.h:
#include <clight_easy.h>
static void on_join(void* payload, void* user) {
(void)user;
cl_entity player = CL_EVENT(cl_ev_player, payload)->player;
char name[64];
cl_easy_player_name(player, name, sizeof name);
cl_easy_give(player, "my_mod:ruby", 1);
cl_easy_send_messagef(player, "Welcome, %s!", name);
}
static cl_result mod_main(void) { return CL_ON(CL_EV_PLAYER_JOIN, on_join); }
CLIGHT_MOD_ENTRY(mod_main)
And in C++:
#include <clight.hpp>
class MyMod final : public clight::Mod {
void on_construct() override {
clight::on<clight::ev::PlayerJoin>([](cl_ev_player& event) {
clight::Entity player = event.player;
player.give("my_mod:ruby");
player.send_message("Welcome, " + player.name() + "!");
}).detach();
}
};
CLIGHT_MOD(MyMod)
Reading order
| Folder | Contents |
|---|---|
| Getting started | What CLight is, installing the SDK, a first mod in each language, project templates, building, running and debugging. |
| Core concepts | Sides, lifecycle, identifiers and handles, registries, events, threading, events and overrides, mixins, data-driven content, capabilities, determinism. |
| API reference | One page per subsystem, plus generated tables of every function, event and type with C, Lua and C++ names. |
| Guides | Step-by-step tutorials: blocks, items, a shop menu, screens, HUD, commands, packets, keybinds, config, server plugins, client mods, recipes and loot, enchantments, custom entities with models and AI, world access, particles, post-processing, menus and themes, item and block models, UI components and HTML overlays (dimensions and worldgen features are still planned). |
| Language bindings | Per-language details for C, C++ and Lua: memory and ownership, errors, callbacks, performance, WASM toolchains, the IDL binding generator, and a language comparison. |
| Advanced | Event and override internals, performance rules, the job system, rendering internals, multi-version servers, the sandbox, hot reload, multiplayer sync, registry sync and vanilla clients, profiling, ABI stability, GPU access, attachment internals. |
| Publishing | Packaging .clmod files, the manifest, versioning and dependencies, trust, publishing on the Celestial website and installing with the launcher, server-required vs client-only, sharing sets of mods. |
| Migration | Guides for developers who port their own mods by hand from Fabric, Forge/NeoForge, Paper/Bukkit, data packs and OptiFine, with concept mapping tables. |
| Appendix | Glossary, full event list, registry list, value event list, error codes, manifest schema, permissions, FAQ, changelog. |
Design principles
- One API, three languages. A single interface description (
clight.idl) generatesclight.h,clight.hpp, the Lua binding, the WASM import table and the generated reference tables in these docs. A function has the same name and meaning everywhere (see Conventions). - A stable C ABI. Plain C functions, plain structs carrying
struct_size, and opaque 64-bit generational handles. No C++ classes cross the boundary, so a mod written for API 1 keeps loading on every 1.x engine. - Events and overrides first, mixins when you need them, never patching. Mods change behaviour through events (with priorities and cancellation), registries and per-content behaviour overrides, which is the simple path (Events, behaviours and mixins). The powerful path is mixins (93 targets across game logic, the client, world generation and data): sandboxed callbacks at the head, return, named points, values and calls of named, versioned engine targets (Mixins). No machine code is patched. All of these cost nothing when unused and compose between mods.
- Known threads, one at a time. Every callback states its thread context (
MAIN,TICK,RENDER,ANY), and one mod’s callbacks never run on two threads at once. - Unmodded Celestial stays exactly vanilla. With no mods installed, every event site is a single byte test, and visuals, physics and packets are identical to 26.3.
- Every mod is sandboxed. Lua and WebAssembly mods see only their own folder and the game API. Anything more is a capability the player allows or denies per mod on the Permissions screen. There is no unsandboxed native tier.
- Vanilla clients are first-class. Mod blocks and items are vanilla-backed, so unmodified clients can still join (see Registry sync and vanilla clients).
Versions
| Item | Value |
|---|---|
| Game version | 26.3 |
| CLight API | 1.24 |
| Manifest schema | 1 |
See Changelog.