Changelog
Status: implemented (v0.1).
API 1.24 (2026-10-28): animation helpers
- Animations (VX1):
cl_ui_ease(enumcl_ui_easing:CL_EASE_SMOOTH,GENTLE,SNAPPY,BOUNCY,LINEAR),cl_ui_anim_step,cl_ui_anim_enabled,cl_ui_anim_duration; Luacl.ui.ease/anim_step/anim_enabled/anim_duration. The same curves as the client’s own HUD and menu animations, which the player turns on in Features > Animations (off by default). The UI Kit.
API 1.23 (2026-10-28): Features and the colour picker
- Features:
cl_ui_feature_register(cl_ui_feature_desc: id, name, description, icon,cl_ui_feature_category, keywords, option, page) andcl_ui_feature_remove; Luacl.ui.feature_register{...}. Mod features show as cards in the client’s Features screen (switch, pin, search over names, keywords and the rows of their page). Appearance Pages. - Colour picker:
cl_widget_color_picker_alpha(Luaw:color_picker_alpha(on)) adds an opacity bar. In the Fancy style the kit’s picker andcl_ui_page_colorrows are the client’s colour picker (wheel, brightness, opacity, hex typing, theme colour, presets, recent and saved colours);"#RRGGBBAA"options keep their opacity. The UI Kit.
API 1.22 (2026-10-27): React-style components, HTML/CSS overlays and panels
- Components (the
viewmodule):cl_view_open/cl_view_mountwithcl_view_desc(render, on_event, on_effect, on_unmount),cl_view_begin/cl_view_end/cl_view_node/cl_view_component, propscl_view_prop_num/cl_view_prop_strandcl_view_get_num/cl_view_get_str, named statecl_view_state_*/cl_view_set_state_*,cl_view_invalidate,cl_view_effect,cl_view_get_stats,cl_view_flush,cl_view_close/cl_view_is_open/cl_view_root, enumcl_view_kind. The engine keeps the tree, matches nodes by key or position, applies only changed props to the kit widgets, memoises child components with equal props and renders nothing while state is unchanged. Lua:cl.ui.component,cl.ui.open/mount,cl.ui.use_state/use_effect/use_ref/use_memo/use_callback, node constructors (cl.ui.column{...},cl.ui.button{...}, …),cl.ui.map. C++:clight_ui.hpp. Components. - RmlUi documents:
cl_rml_descgainsparent(a panel in the mod’s own open screen),anchor/x/y/width/height/id/label(a HUD overlay, placed like a HUD element, never taking input),modelandactionswithon_action;cl_rml_data_set_num/set_str/set_bool/set_json,cl_rml_data_get_json,cl_rml_shown. The theme sheetcelestial:theme.rcssand thecl-fancy/cl-vanillabody classes follow Appearance. Lua:doc:set(name, value)/doc:get(name),model/actionsas lists, anchors by name, actions with Lua arguments. HTML/CSS Overlays and Panels. - Sandbox for documents: documents, linked sheets and templates, and markup / attributes / properties set by code are checked; URLs, absolute paths,
.., percent-encoding,<script>, event attributes,<iframe>/<object>/<embed>,@importand other models are refused (CL_E_PERMISSION_DENIED); while a document loads onlymods/<id>/is readable. Document screens show the mod’s name. cl.has("rml.overlay"),cl.has("rml.data_model")andcl.has("ui.components")are true.- Example mods:
sdk/examples/react_settings_lua(Waypoint Settings),sdk/examples/html_hud_lua(Mana HUD).
API 1.21 (2026-10-25): the UI kit, theme tokens, HUD elements, Appearance pages
- Themed screens:
cl_screen_desc.themed; the screen and its widgets follow the player’s Appearance style (Vanilla / Fancy) and theme, live. The UI Kit. - Kit widgets:
cl_widget_toggle,cl_widget_icon_button,cl_widget_dropdown,cl_widget_tabs,cl_widget_list(+cl_widget_list_add/cl_widget_list_clear),cl_widget_panel,cl_widget_card,cl_widget_heading,cl_widget_color_picker; Luas:toggle(...)and so on. - Themed drawing:
cl_gui_panel,cl_gui_hud_panel,cl_gui_round_rect,cl_gui_ui_text,cl_gui_icon,cl_gui_control. - Theme tokens (read-only):
cl_ui_fancy,cl_ui_hud_fancy,cl_ui_theme,cl_ui_color,cl_ui_length,cl_ui_text_width,cl_ui_line_height,cl_ui_generation,cl_ui_has_icon. Theme Tokens. - HUD elements:
cl_hud_element_register(cl_hud_element_desc: id, label, icon, size, anchor, panel, cached, render, visible),cl_hud_element_remove/set_size/invalidate/shown; they appear in the HUD editor and Appearance > HUD, placements are saved. HUD Elements. - Appearance pages:
cl_ui_page_registerand rowscl_ui_page_group/note/option/choice/color/button/hud_element,cl_ui_page_open/remove; Luacl.ui.page_register{...}. Appearance Pages. - Manifest:
"screenshots"and"categories"(the Mods screen shows them). - Mods screen: the Mod Library (Fancy) with search, filters, details, permissions and the player’s on/off switch per mod (
config/clight/mods.json, applies at the next start);config/clight/updates.json(written by the launcher) shows available updates. - Example mod:
sdk/examples/ui_kit_lua(Compass Plus).
API 1.20 (2026-10-24): files, HTTP, typed attachments, equipment, entity events, emitters, WebAssembly hot reload
- Files (C10):
cl_fs_read/read_text/write/write_text/append_text/exists/stat/list/mkdir/remove/rename/data_used/data_quota; Luacl.fs(returnsnil, messagelikeio),cl.fs.read_json/write_json,cl.json.encode/decode. Reads reach the mod’s folder, writes onlydata/, atomic, 256 MiB quota, links and junctions never followed. Filesystem and HTTP. - HTTP (C10):
cl_http_requestwithcl_http_opts(method, body, headers, timeout, size limit,save_to),cl_http_cancel,cl_http_error,cl_http_header,cl_http_allowed; Luacl.http.get/post/request. Only hosts covered by a declared and allowednet.http:<host>(also*.<domain>), https only, redirects checked, no cookies, answers at the next tick on the side that asked. - Capabilities from code:
cl_cap_granted,cl_cap_request(opens the Permissions screen), eventmod.permission_changed; Luacl.permission,cl.request_permission. - Typed attachments:
cl_attachment_registerwithcl_attachment_desc(default_snbt,CL_ATTACH_SYNC,CL_ATTACH_COPY_ON_DEATH); Luacl.attachment(key, { default, sync, copy_on_death }). Data Attachments. - Equipment (C11):
cl_entity_equipment,cl_entity_set_equipment,cl_entity_set_drop_chance, enumcl_equip_slot. - Events (C11):
entity.spawn(cancellable,loaded),player.interact_entity(cancellable, result),entity.change_dimension. - Particle emitters (C11):
cl_render_emitter_add(on an entity or a bone, every N ticks),cl_render_emitter_remove,cl_render_emitter_set_active; Luae:emit(type, opts). - WebAssembly hot reload (C11): in dev mode a rebuilt
.wasmreplaces the running module;CLIGHT_MOD_HOT_STATE(var)/CLIGHT_MOD_SAVE_STATE(fn)/CLIGHT_MOD_RESTORE_STATE(fn)hand state over; a failing build rolls back.cl.has("hot_reload.wasm"),cl.has("fs"),cl.has("net.http")are true. Hot Reload. - Lua errors from API calls now carry the engine’s detail (
cl.fs_mkdir failed: permission_denied: fs_mkdir: path not allowed: ...). - Fixes:
e:set_casts_shadow(API 1.18) was not installed on entity handles in Lua; falling blocks cache their lighting per block position and light (the same picture, less work per frame).
API 1.19 (2026-10-24): the version layer
- The compatibility promise: a mod built against any API 1.x keeps loading and behaving the same on every later API 1 Celestial (ABI stability and API versioning). Golden mods built once against API 1.0, 1.4, 1.6 and 1.11 (Lua, C and C++) run in CI on every build.
- Stable names with a per-build map (
idl/generated/version_map.json);compat.idlrenames for events, accessors andcl.hasfeatures; deprecated functions forward to their replacement (@deprecated @forward) with a one-timeCLL-2010warning per mod. - Renamed vanilla ids keep working in the API’s lookups, per registry:
minecraft:grass/short_grass,chain/iron_chain,scute/turtle_scute,grass_path/dirt_path,zombie_pigman/zombified_piglinand the 1.20 pottery sherds. - Manifest:
"api_version"(a minimum minor,">=1.12"or"1.12") with clearCLL-2003messages;"former_ids"and"id_aliases"for renamed mods and content. - Lua: older spellings (
cl.net.buf_write_i32,cl.item_stack, …) warn once per mod; the API 1.0 method callsplayer:name(),player:health(),player:uuid()andplayer:level()work again (API 1.2’s properties had shadowed them).
API 1.18 (2026-10-24): entity lighting and shader pack entity shadows
- Without a shader pack: falling blocks and piston-moved blocks are lit like terrain (per-corner light and ambient occlusion, like vanilla), entities in the Nether use the Nether’s light directions, armor stand markers and block entities take their light like vanilla.
- With a shader pack: entities, block entities and mod models cast shadows into the pack’s shadow map (also off screen and the player’s own body in first person); Video Settings > Shader Entity Shadows (on by default).
- New:
cl_render_set_type_casts_shadow,cl_render_type_casts_shadow,cl_render_entity_shadows_setting,cl_render_entity_shadows_active,cl_entity_set_casts_shadow,cl_entity_casts_shadow, enumcl_shadow_mode; Luae:set_casts_shadow(true | false | nil).cl.has("render.entity_shadows"). Guide: Entity Lighting and Shadows.
API 1.17 (2026-10-24): world and data mixin targets
- 18 more mixin targets (C7): world generation (
chunk.generate.stage,worldgen.structure.start,worldgen.biome.fillwith a point per biome cell,worldgen.terrain.buildwith skip points before the noise fill, the surface and the carvers,worldgen.feature.place,worldgen.structure.place; WebAssembly mods only), chunks (chunk.load,chunk.unload,chunk.save), commands (command.execute,command.register,command.suggest), recipes, loot and tags (recipe.match,recipe.assemble,loot.table.roll,tag.contains) and data (data.reload,data.registry_freeze). See the mixin target appendix and Mixins.
API 1.16 (2026-10-24): client mixin targets
- 19 client mixin targets (C6) and the local player’s prediction variants; see the mixin target appendix.
API 1.15 (2026-10-24): item and block models, LOD
- Item models:
cl_render_item_model/cl.render.item_model(item, path, opts)draws an item with a glTF model in the hand (first and third person), the GUI, item frames, on the ground, on heads and shelves; vanilla itemdisplaytransforms (JSON or a Lua table; left-out contexts use the block item defaults),fitto a block,rotation,offset, a loopingdefault_clip, the enchantment glint. Guide: Item and Block Models. - Block models:
cl_render_block_model/cl.render.block_model(block, path, opts)for block entities (instead of the vanilla renderer, or withkeep_vanilla) and any other block (on top of its block model); the model turns withfacing/rotation. - LOD:
MSFT_lod(withMSFT_screencoverage) and_lodNnode / mesh names;cl_model_set_lod_distances,cl_model_lod_levels. - Materials: the glTF alpha mode and cutoff are honoured (also in shader packs); normal and metallic-roughness maps reach shader packs as LabPBR
normals/specular. cl.has:item.models,block.models,block_entity.models(now true),model.lod,model.alpha_mode,model.pbr_shaderpacks.
API 1.14 (2026-10-24): mixin targets
- 15 more game-logic mixin targets (C5b); see the mixin target appendix.
API 1.13 (2026-10-23): rendering extras and menus
- Model looks: glTF
KHR_materials_variants(cl_model_variants,cl_entity_set_material_variant/cl_entity_material_variant), per-entity render parameters (cl_entity_set_render_param,cl_entity_render_param,cl_entity_clear_render_param; synced numbers from the server, local values on a client) and custom fragment shaders per model (cl_model_set_shader: mod GLSL withcl_shade(), checked and compiled by the engine, up to 8 parameters and 4 textures). Guide: Post-processing, Fog, Sky and Camera. - Particles and decals: mod particle types from sprite sheets (
cl_render_particle_type),cl_level_particleon both sides (vanilla clients get the type’s vanilla fallback), decals clipped to block faces (cl_level_decal,cl_level_clear_decals). Payload channelclight:fx. Guide: Particles and Decals. - Post-processing:
cl_render_post_pass(mod GLSLcl_post(uv)over the world and the hand, up to 16 uniforms, 4 textures),cl_post_pass_set_uniform/set_enabled/is_enabled/remove; shader packs getuniform float <modid>_<name>(cl_render_set_uniform) and#define MOD_<ID>. - Fog, sky, light: event
render.fog(mutable), eventrender.frame,cl_render_set_sky_color,cl_render_set_lightmap_tint,cl_render_set_ambient_darkness,cl_render_clear_overrides. - Camera effects:
cl_camera_set_effects/clear_effects/get_effects(FOV multiplier, roll, view-bob scale, vignette, shake only with the player’s new Mod Camera Shake option), following FOV Effects, Distortion Effects and View Bobbing. - Menus:
cl_gui_set_title_background,cl_gui_set_panorama,cl_gui_set_sprite(per screen or global, keeps the sprite’s nine-slice scaling),cl_gui_clear_sprites; Lua alsocl.menu.*. Guide: Menus and Themes. - AI:
cl_entity_path_to_entity(re-plans when the target moves). - Lua:
level:particle(type, pos, vel, count, spread),level:decal(texture, pos, normal, size, rotation, lifetime), colours as"#RRGGBB", lists for comma-separated fields,cl.render.post_pass{ uniforms = function(pass, frame) ... end },model:variant_list(). cl.has:entity.render_params,model.variants,model.shaders,render.particles,render.decals,render.post,render.pack_uniforms,render.fog,render.sky,render.lightmap,camera.effects,camera.shake,gui.title_background,gui.panorama,gui.theme,ai.follow_entity.
API 1.12 (2026-10-23): AI, navigation and saved data
- Paths:
cl_level_find_path/level:find_path(from, to, opts)plans without moving (an ownedcl_path:cl_path_get_info,cl_path_nodes),cl_entity_path_to/e:path_to(pos, speed, opts)walks, pluscl_entity_follow_path,cl_entity_path,cl_entity_path_state,cl_entity_path_done,cl_entity_path_stop. Options: the body (default: the entity’s current hitbox), the node evaluator, doors (walking through adds vanilla’sOpenDoorGoal), climbing#climbableblocks, reach, the node budget, the drop height, the water malus and named path costs (cl_ai_path_cost_register; Luaavoid = function(pos)). The vanilla path finder with the mob’s own options; vanilla navigation is unchanged. Guide: AI and Pathfinding. - Looking and targets:
cl_entity_look_at,cl_entity_look_at_entity,cl_ai_set_target,cl_ai_target. - Goals: goal types (
cl_ai_goal_type_register: can use, can continue, start, tick, stop, removed, flags, target selector, interruptable, every tick),cl_ai_add_goalon mod mobs and vanilla mobs (brain mobs too),cl_ai_type_goalfor every mob of a type (also after loading),cl_ai_remove_goal,cl_ai_goal_running,cl_ai_goal_entity,cl_ai_goal_type,cl_ai_clear_goals. Lua:cl.ai.add_goal(e, priority, { can_use = fn, ... , state = {} }). Goal list changes apply at the end of the tick. - Data attachments:
cl_entity_data_*on every entity and player (saved asclight:data, players in their file;CL_DATA_SYNCsends a value to Celestial clients with CLight, evententity.data_changed),cl_level_chunk_data_*on loaded chunks (saved in the chunk),cl_level_saved_data_*per level (the world’sdata/<namespace>/<path>.dat). Values as SNBT text or binary NBT; Lua: plain Lua values,e:data/e:set_data,level:chunk_at(pos):data,level:saved_data(key)(a live table written at every save). Vanilla ignores all of it; data of removed mods stays. Guide: Saved Data. - C++:
clight::Pathis an RAII handle. cl.has:ai.paths,ai.find_path,ai.path_doors,ai.path_climb,ai.path_cost,ai.look_at,ai.goals,ai.type_goals,ai.target,data.entity,data.player,data.chunk,data.saved,data.sync,data.nbt.
API 1.11 (2026-10-23): world access and player control
- Ray casts:
cl_level_raycast/level:raycast(from, to, opts)with collision, outline, visual or no block shapes, fluids (none, source, any, water), entity hitboxes (margin, ignore, source entity), on the server and the client. Guide: World Access. - Bulk reads and snapshots:
cl_level_get_blocks(up to 128³ states in one call, x / z / y order,CL_BLOCK_UNLOADED),cl_level_snapshot(an owned copy readable from any thread;cl_snapshot_get/copy/get_info). - Block states and facts:
cl_block_state_property/_with/_properties/_property_values/_to_string/_parse,cl_level_set_block_property,cl_block_get_info(shape facts, hardness, friction, light, map colour),cl_block_sound_type("stone","wood", …) andcl_block_sound_event. Lua: typed values (cl.registry.state_property(s, "open")→true),"minecraft:x[prop=value]"wherever a state goes. - Light and height:
cl_level_light(block, sky, combined, sky darkening),cl_level_can_see_sky,cl_level_heightmap. - Containers and block entities (server):
cl_level_container_size/_get/_set(every data component kept),cl_level_block_entity_type/_get/_merge(SNBT, like/data). Item stacks taken from the world keep all their components inplayer_give,player_inventory_setandplayer_inventory_get. - Event
level.block_changedon both sides (server: end of the level tick, in order; client: right after the change; filter by the new block; free without subscribers). - Players:
cl.camera(client), stackable movement modifiers through vanilla attribute modifiers (speed, jump, step height, no sprinting, no jumping, camera sway), model part visibility and glTF part models, animation layers on the vanilla player model (cl_render_player_animations), disabled hands, locked slots, input overrides, food / saturation / exhaustion, air (cl_entity_air) and per-player natural regeneration. Synced to Celestial clients throughclight:entitiesops 3 and 4; vanilla clients get nothing and the server enforces locks itself. Guide: Player Control. - Lua: array results are no longer cut at 256 entries; the prelude loads faster.
cl.has:world.raycast,world.bulk_reads,world.snapshots,world.light,world.heightmaps,block.properties,block.info,block.sound_type,block.containers,block_entity.data,level.block_changed,camera,player.movement_modifiers,player.model_parts,player.part_models,player.animations,player.hand_locks,player.slot_locks,player.input_override,player.food,entity.air,player.natural_regen.
API 1.10 (2026-10-23): entity gameplay
- Queries:
cl_level_entities_in_box(type,#type tag, entity tag, category, exclude, limit, nearest first),cl_level_nearest_player,cl_level_entity_by_uuid,cl_entity_by_uuid,cl_entity_category, entity tags (cl_entity_has_tag/add_tag/remove_tag). Lua:level:entities_near(pos, radius, query), boolean flags,nilwhen nothing is found. Guide: Entity Gameplay. - Attributes and effects: value / base / set base, stackable modifiers by id; effects add / remove / has / info / clear.
- Synced data (
cl_entity_set_synced_*,cl_entity_synced_*, evententity.syncedon clients): only clients that registeredclight:entities(Celestial clients with CLight) receive it; saved with the entity. - Combat:
cl_entity_hurtwith damage types, attacker, direct entity, position and a knockback multiplier;cl_entity_knockback; the cancellableentity.knockbackevent; mod damage types (cl_damage_type_register,cl.damage_types.register) with vanilla-style death messages and an English fallback, damage type tags, a vanilla fallback for the damage event packet. - Natural spawning:
cl_spawn_rule_register/cl.registry.spawn_rule(biomes and tags, category, weight, packs, placement, base check, light, player distance, cap, condition callback) joins the biome spawn lists like a data pack entry. - Riding:
cl_entity_set_passenger(force, bone seats on the vehicle’s glTF model),dismount,eject_passengers,vehicle,passengers. - Lua commands:
ctx:level(). Manifests:limits.callback_ms(1-500, default 50) sets the Lua per-callback time limit. cl.has:entity.queries,entity.tags,entity.attributes,entity.effects,entity.synced,entity.combat,entity.knockback,damage_type.custom,spawn.rules,entity.riding,entity.bone_seats.
API 1.9 (2026-10-23): entity models and animation
- glTF 2.0 models for entity types (
cl_render_entity_model,cl.render.entity_model): skinned meshes with 4 weights, morph targets, PBR-lite materials (base colour, normal, roughness), linear mipmapped textures, vanilla light, overlays, outlines, shadows and shader packs; mod types draw the model instead of their fallback on Celestial clients with the mod, vanilla types can be restyled client-side. Sandboxed loading from the mod’s assets; clip sidecar<model>_clips.json. Guide: Entity Models and Animation. - Animation (
cl_entity_anim_*): clips on 8 layers with cross-fades, speed, weights, bone masks, additive layers, one-shots that fade out or hold, morph weights (cl_entity_set_morph), event markers (entity.anim_event, server and client), root motion, bone look-at with limits, bone transforms. The server’s state is synced to Celestial clients (clight:anim), late joiners included. cl.has:entity.models,entity.animation,entity.anim_layers,entity.anim_events,entity.root_motion,entity.look_at,entity.bone_transform,entity.anim_sync,model.gltf,model.skinning,model.morphs,model.pbr.- Mod mobs no longer burn in daylight because of a fallback in the
burn_in_daylighttag.
API 1.5 (2026-10-18): the first game mixin targets
- 41 targets for game logic on the server: entity damage and death (
entity.living.hurt,actually_hurt,damage_after_armor,damage_after_magic,heal,check_totem,die,knockback,cause_fall_damage), effects, ticks, movement and AI (entity.living.add_effect,tick_effects,tick,travel,jump_power,jump,entity.mob.ai_step,check_despawn,finalize_spawn,do_hurt_target,xp_reward,pick_up_items,spawn.check_rules), players (player.attack,attack_damage,interact_entity,food_tick,exhaust,give_xp,respawn,teleport,destroy_block), blocks and the level (block.player_destroy,place_item,use_without_item,use_with_item,random_tick,level.set_block,level.explode) and items (item.use,use_on,finish_using), with their points and values. The full list is Mixin targets; the frame structcl_damage_sourceis new. - Invokers:
entity.living.hurt,entity.living.heal,entity.living.knockback,player.exhaust,player.give_xp(cl.mixin.invoke,cl_mixin_invoke). /clight mixins [<target> | conflicts | stats]shows the ordered mixins, the conflicts and the call statistics; in dev modelogs/clight-mixins.txthas the full table.- A mod that hooks every target and passes everything through leaves the world bit-identical (tested on a deterministic server run).
C++ wrapper update (2026-10-17, no ABI change)
clight.hpp only; the C ABI, Lua and old C++ code keep working (except copying a clight::Buf, see below).
clight::Bufis move-only. The ABI has no retain for buffers, and a copy released the same buffer twice. Copying is now a compile error; passBuf&/const Buf&orstd::moveit.ItemStackandTextcopies still retain.[[nodiscard]]onSubscriptionandmixin::Handle(andmixin::inject): dropping one, which unsubscribes at once, now warns with a message.- Lambdas with captures everywhere, freed when the registration ends (unsubscribe, cancel, remove, a screen or menu closing, a one-shot that ran, mod unload):
clight::after/every/after_client,clight::keybind::add(id, key, fn)andKeybind::on_press,hud::add_layer(id, fn, {.above, .below, .visible})(returns theHudLayer),net::on_payload,screen::open(ScreenSpec)withScreen::button/checkbox/slider/text_field,menu::open(player, MenuSpec),registry::item/blockwith lambda behaviours. The engine only sees opaque ids, so a call queued for a removed lambda does nothing. - Command replies take plain strings:
CmdCtx::reply,send_success(string, broadcast = false),send_failure(string);send_success(text)no longer needs thefalse. CL_MIXINwithout options no longer warns under clang-Wall -Wextra(-Wmissing-designated-field-initializers).
API 1.4 (2026-10-17): beginner fixes 2
- Creative mode keeps items:
cl_player_inventory_consume(vanilla’sItemStack#consume: nothing is used up in creative) andcl_player_game_mode. Luaslot:shrink(n)and C++ / Cconsume_helduse it; Luaslot:remove(n)always removes;player.gamemode("survival","creative", …).player:takestill removes in every mode (like/clear). - Slot set keeps components:
cl_player_inventory_set/slot:set(id, n)with the item already in the slot only changes the count (name, enchantments, damage stay). block.breakxp in vanilla order: the value a handler reads is a preview rolled on a copy of the level random; the game still rolls the real amount after the loot, so the random sequence is exactly vanilla’s. An unchangedxpkeeps vanilla’s own roll; a changed one replaces it. (Fixes the 1.3 note above: the order no longer changes.)- Mod block properties are used:
destroy_time,friction,speed_factor,jump_factor,light_emission,sound_type(a SoundType name like"glass"or a block id). A field left at its default keeps the value ofcopy_properties_from, else of the base block. The server simulates them (mobs, items, mining, light, sounds) and Celestial clients predict the same (movement, mining, light, sounds). - Mod block loot tables:
<ns>:blocks/<path>from the mod’s data pack (26.3 format, mod items allowed), used for player breaks, explosions and/loot; without one the block drops itsitem. - Commands:
requires_permissionworks on any node (a name = operators, or a level 0 to 4); argument types"player","players","entity","entities"(names, UUIDs and selectors through the server’s EntityArgument),"string"reads"quoted phrases", selectors with spaces in[...]stay one argument. C ABI: the tree buildercl_cmd_literal/cl_cmd_argument/cl_cmd_then/cl_cmd_executes/cl_cmd_requires_level/cl_cmd_requires_permission/cl_cmd_register_tree, the getterscl_cmd_arg_str/_i32/_f64/_bool/_entities,cl_cmd_ctx_permission_level,cl_cmd_ctx_entities. C++: chainableliteral("x").then(...).executes([](CmdCtx c) { ... }).register_command(). C:cl_easy_arg_str/_int/_entity. Lua:ctx:arggives the entity (or a list),ctx:entities(name),ctx:permission_level(). - Text:
cl_text_set_style(bold, italic, underlined, strikethrough, obfuscated; on or explicitly off),cl_text_click(open_url,run_command,suggest_command,copy_to_clipboard),cl_text_hover,cl_text_add_arg(translation arguments). Titles:cl_player_send_title(with fade times),cl_player_clear_title. Client-only text:cl_client_show_message(chat or action bar) andcl_client_show_title. Lua:t:bold()… (chainable, alsocolorandappend),t:click(action, value),t:hover(text),cl.text.translatable(key, args...),player:send_title(title, subtitle, { fade_in, stay, fade_out }),player:clear_title(),cl.client.message/action_bar/title. C:cl_easy_send_title,cl_easy_show_message. - Keybinds in the Controls screen: mod keybinds are options
key.<ns>.<path>under their category (or the mod’s name), rebindable to keys and mouse buttons (key.mouse.*), saved inoptions.txt; clicks come from the real key events.cl_keybind_desc.label(appended field) names a key without a lang entry;cl_keybind_keyreturns the bound key. - Config:
cl_config_reload,cl_config_comment, the eventconfig.reloaded(Luaconfig:on_reload(fn)); edited files are read again within a second, a hot reload re-reads them,/clight reload-config(operators) reloads every mod’s files. The Mods screen has a Config page made from the definitions (toggle, slider, text box; the comment is the tooltip). - Lua typings:
clight.d.luamarks parameters the prelude fills in as optional (set_blockflags, title times, …).
API 1.3 (2026-10-17): beginner fixes
clight runloads the project folder itself (dev mode), so saving a Lua script hot-reloads it.bin/falls back tobuild/bin/; the mod’sdata/isbuild/run/<id>/data/. The old staged copy inbuild/run/<id>/is removed.set_blockwithout flags ="all"(neighbours + clients) in Lua (level:set_block(pos, id)) and C++ (Level::set_block(pos, state));cl_easy_set_blockalready did. The C ABI is unchanged (flags are explicit there).- Taking items:
cl_player_take,cl_player_count_item,cl_player_inventory_shrink,cl_player_inventory_set(C ABI, appended). Lua:player:take(id, n),player:count_item(id),player:has_item(id, n), live slotsplayer:slot(n)/player:held_item(hand)with.id/.count/.empty,:shrink(n),:set(id, n),:clear(),:stack(). C++:take,count_item,inventory_shrink,inventory_set,consume_held(n). C:cl_easy_take,cl_easy_count,cl_easy_consume_held. - Events that now fire:
tick.level_pre/tick.level_post(per level, on the tick thread around the parallel level tick),lifecycle.level_load/level_save/level_unload,lifecycle.data_reloaded(/reload),lifecycle.resources_reloaded(client resource reload),lifecycle.mod_reload(after a hot reload that worked). event:set_result(...)works: a result other thanpassonplayer.interact_block/player.interact_itemskips the vanilla handling.- Event filters work: the engine passes the filter key for
block.break/block.place/player.interact_block(block id),player.interact_item(item id),entity.damage/entity.death(entity type) andclient.screen_open(screen id). block.breakfillstool(and soevent.item) andxp(the experience the block drops; writable). With ablock.breakhandler the ore experience is rolled before the loot instead of after it (same amounts and odds; API 1.4 restores vanilla’s order).
API 1.2 (2026-10-17): the mixin core
- Mixins replace the old “no mixins” decision (user decision 2026-10-17). Mods attach sandboxed Lua or WASM callbacks to named engine targets:
head,return, namedpoints,values andcalls,wrapandoverwrite, plus accessors and invokers. See Mixins. This release shipped the core; the first game targets came with API 1.5 (cl.has("mixin:<name>")tells you which exist). - C ABI: module
mixin(cl_mixin_inject/remove/target_lookup/info,cl_mixin_cancel/set_return/call_original,cl_mixin_invoke,cl_accessor_lookup/get/set), the callback infocl_mixin_ci, and per target the generated frame structs and helpers. Static declarations:CL_MIXIN(...)/CL_MIXIN_SITE(...)(records read through the module’sclight_mixinsexport, whichCLIGHT_MOD_ENTRYadds). - Lua:
cl.mixin.inject(target, at, fn, opts)and the sugarhead/ret/wrap/overwrite/point/value/call,h:remove(),cl.mixin.info,cl.mixin.invoke,cl.accessor(name):get/set. Runtime mixins follow hot reload; manifest handlers are re-bound by name. - C++:
clight::mixin::inject<Traits>(clight::at::..., fn)with an RAII handle,clight::mx::Ci<T>,clight::accessor<V>. - Manifest: the
"mixins"block (schema andclight check, which also checks theCL_MIXINrecords of a built.wasm). The old"hooks"key is an error that names"mixins". - Conflicts: of two overwrites (or two
exclusivecall redirects) on one target, the mod that loads first wins; only the other mod’s mixin is off and the Mods screen and log say so (CLL-7005/7006). A failing mixin is turned off for the session, its changes dropped, and the game runs the vanilla behaviour exactly once (CLL-7009). New loader codes CLL-7001 to CLL-7012 (Error codes). - Cost: an unused target is one memory read and a branch; a mixin that passes everything through leaves the game bit-identical.
API 1.1 (2026-10-17): API cleanup
- Manifest:
"api": 1(the API major, an integer) replaces the"clight"range string. Old manifests still load: the range is mapped to a major with a deprecation warning, and0.xranges from the v0.1 drafts mean API 1. Templates, examples and the JSON schema use"api": 1;clight checkvalidates it. - Lua names mirror the C names:
cl.buf.*,cl.task.*,cl.widget.*,cl.player.*,cl.living.*,cl.music.*. The old spellings (cl.net.buf_*,cl.sched.task_*,cl.screen.widget_*,cl.entity.player_*/living_*,cl.sound.music_*,cl.item_stack) are the same functions and keep working.cl.stack(id, count)creates a stack;cl.versionreports the real API version. - New:
cl_core_has(name)/cl.has(name)for optional modules, functions, runtimes and features. - ABI guard: the shipped function table, events, structs, callbacks and enums are snapshotted in
client/clight/idl/abi/clight_abi.snapshot.json; a test fails if any entry is removed, reordered or changed. clight.d.luanow annotates the handle methods and the prelude helpers (cl.on,cl.cmd,cl.pos, …).- The easy layer (no ABI change). Lua:
player.name/uuid/pos/health/level/worldproperties (the shadowed getters areget_name()etc.;player:name()becameplayer.name),player:give(id, count),send_message/send_action_barwith any value, callablecl.log(...), the event fieldsevent.block/item/world/player, and id strings for block states, block ids and item ids. C++:player.give("id", n),send_message("text"),std::string name()(theExpectedform istry_name()),pos(),level.set_block(pos, "id"),clight::item/literal/broadcast. C: the new headerclight_easy.h(CL_ON,CL_EVENT,CL_LOG,cl_easy_give,cl_easy_send_message(f),cl_easy_player_name,cl_easy_set_block, …). The templates and examples use it.
CLight v0.1 (2026-10-05): first implementation
- User decisions: no mixins (events, registries and behaviour overrides only; replaced by the mixin design for API 1.2), no C#, and every mod sandboxed: C and C++ compile to WebAssembly (Wasmtime, AOT-cached), Lua runs in a sandboxed VM; a mod sees only
mods/<id>/(read) andmods/<id>/data/(read/write). No native DLL tier, no trust prompt; extra capabilities are allowed or denied per mod on the Permissions screen. - SDK in
clight-sdk/next to the game: theclightCLI (new,build,pack,check,run,setup,doctor), templates for C, C++ and Lua, the official wasi-sdk downloaded byclight setup, reproducible.clmodpackages. - Mod assets (
assets/) and data (datapack/) mount as packsmod/<id>; custom sounds and music through the sound API (cl_sound_*,cl_music_*, eventclient.sound_play). - The Mods screen lists mods with their errors; the Permissions screen per mod.
Spec v0.1 (2026-10-04): first documentation draft
- First complete design of the CLight modding platform documentation (
Mod_Docs/). - Languages: C (the stable C ABI
clight.h), C++ (the header-onlyclight.hpp) and Lua 5.4 (sandboxed VM with hot reload). C and C++ compile to WebAssembly; every mod is sandboxed. - Runtimes: data, Lua, and WebAssembly (Wasmtime). Every mod is sandboxed; there is no native-code tier.
- Single interface source
clight.idl, from which all bindings and the reference tables are generated. - Thread contexts
TICK/PARALLEL/RENDER/NET/ASYNCmatching the engine’s job system and parallel dimension ticking (ARCHITECTURE §2). - Events with priorities, cancellation and results. Behaviour overrides replace bytecode mixins (no hook sites, no patching).
- Registries (static and dynamic), vanilla fallbacks for vanilla clients, the configuration-phase handshake.
- APIs for worldgen, rendering (baked models, instanced entity models, render stages, shaders, post effects), RmlUi screens, immediate-mode GUI, HUD layers, input, sound, config, attachments, services, permissions, server plugins, filesystem and HTTP.
- Manifest schema 1 and the
.clmodpackage format. - Migration guides for hand-porting (Fabric, Forge/NeoForge, Paper/Bukkit). Java mods are not loaded, converted or translated.
Versioning policy
- Spec revisions (v0.x) can change anything until CLight 1.0 ships.
- From 1.0, the API follows the rules in ABI stability and API versioning: additions in minor versions, removals only in major versions after one major version of deprecation.