ludic/packages
Orkuncakilkaya df6ea046c3 render3d: VkAllocationCallbacks counted (R3D_ALLOC_VK), pipeline create infos freed, actor pool at init
Plan 25.1c: vk_mac.ll's @lvk_ac (posix_memalign under a 16-byte header of scope/offset/size, atomic
counters) passed at every render3d create/destroy (49 sites; the caps probe keeps its own null pair);
lvk_ac_bytes/_peak/_allocs/_scope_bytes for the fence, Vk.alloc_bytes. vk_win.ll: null and 0.
MoltenVK 1.4.2 counted 0 live bytes through them in steady. Fence findings: gvk_pipeline freed its 17
create infos (and reuses one bufs list); actor_init fills ac_spare with 512 records (actor_fresh,
m4_new, v3_new at first placement in play). Compiled, not run (the user's call).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 15:46:19 +03:00
..
ludic.aim feat(senses): walkers slide round still things, and lines of sight are the world's to answer 2026-09-27 00:59:39 +03:00
ludic.anim feat(ludic.anim): ozz-animation 0.17.0 underneath - a skin's skeleton and each clip built at load, sampled to 1e-4 of anim_mix (phase 19.1) 2026-09-28 12:44:49 +03:00
ludic.audio wip(0.S3): packages and examples migrated again from their pre-0.S sources in one run 2026-09-25 15:31:34 +03:00
ludic.base ludic.base: TextRing - a fixed ring of text buffers written in place, for a line made per event 2026-09-28 13:35:34 +03:00
ludic.character ludic.physics, ludic.character, ludic.vehicles: fact records reused, and phys_sink allocates nothing 2026-09-28 02:03:09 +03:00
ludic.clock refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
ludic.compass docs(compass): what a capture hands back lasts until the next one 2026-09-28 00:58:53 +03:00
ludic.core feat(engine): #90 atlas-aware Sprite component, #91 become from listeners, 0.3.x ergonomics batch 2026-09-04 01:36:08 +03:00
ludic.crafting refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
ludic.dungeon wip(0.S3): outside the runtime, its drawable size, scale, screen and tile size are read and set through its functions; a migration reports such a reference instead of threading the runtime's state 2026-09-25 15:47:21 +03:00
ludic.effects fix(leaks): effects_live_into / effects_live_count and hints_rail_into - a HUD's read-outs into lists it keeps 2026-09-28 01:21:53 +03:00
ludic.fire refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
ludic.fishing fix(ludic.fishing): fact records pooled (the ludic.wildlife idiom) - a record made per cast, bite and crossing was never given back 2026-09-28 13:17:12 +03:00
ludic.gameplay refactor(packages): 0.R5 - the rest of the lazy starts are defaults - hints' rail (sized by hints_config), lab's CRC table, rpg's crafting / items / inventory / quests / dialog, shooter's weapons, prefs, and npc's and gameplay's empty ensures gone; gameplay's faction table sits beside its state, since a default names only what is declared before it; --tighten over their tests and examples 2026-09-27 03:07:29 +03:00
ludic.gear refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
ludic.hints fix(leaks): effects_live_into / effects_live_count and hints_rail_into - a HUD's read-outs into lists it keeps 2026-09-28 01:21:53 +03:00
ludic.i18n wip(0.S3): packages and examples migrated again from their pre-0.S sources in one run 2026-09-25 15:31:34 +03:00
ludic.inventory refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
ludic.jobs ludic.jobs jobs_posted_count, ludic.steps steps_my_shares_into - a count and a kept list for what a party asks every tick 2026-09-28 15:12:24 +03:00
ludic.lab feat(render3d): 23.3 - a .dds beside a .png is uploaded BC-compressed with its whole mip chain 2026-09-28 01:23:45 +03:00
ludic.minimap fix(ludic.minimap): minimap_pins_near refills a list the state keeps - the compass asked every frame and got a new list each time 2026-09-28 13:16:05 +03:00
ludic.nativeecho feat(pkg): windows-x64 builds of ludic.physics (Jolt v5.6.0) and ludic.nativeecho, built on the PC by their native/build.sh 2026-09-27 13:29:55 +03:00
ludic.nav test(ludic.nav): an index loaded again twenty times, its tiles in each time, holds the heap (0 bytes), the open files and the tiles 2026-09-28 14:09:00 +03:00
ludic.needs refactor(packages): 0.R5 - the shop's week is rolled by its tick and asking reads it; needs start filled and vehicles start with their list; character, physics, vehicles and nativeecho's lazy starts are defaults; --tighten over all four 2026-09-27 13:25:57 +03:00
ludic.net ludic.net: a message's record, bytes and lists kept - queued ones back to a pool once sent or taken, the inbox's two drains on, a read text interned 2026-09-28 13:25:46 +03:00
ludic.npc ludic.base, ludic.wildlife, ludic.npc: fact records reused, not made per fact 2026-09-28 01:58:19 +03:00
ludic.npcai refactor(runtime,packages,examples): named constants, package enums, idiom sweep 2026-09-05 01:12:26 +03:00
ludic.photo merge lang/physics-senses: animals and people slide round still things, the aim's, photo's and animals' sight lines are one Jolt ray 2026-09-27 01:23:17 +03:00
ludic.physics fix(ludic.physics): a hull owns its box, so a boat called and sent away takes its shape with it 2026-09-28 13:59:25 +03:00
ludic.platformer refactor(runtime,packages,examples): named constants, package enums, idiom sweep 2026-09-05 01:12:26 +03:00
ludic.prefs refactor(packages): 0.R5 - the rest of the lazy starts are defaults - hints' rail (sized by hints_config), lab's CRC table, rpg's crafting / items / inventory / quests / dialog, shooter's weapons, prefs, and npc's and gameplay's empty ensures gone; gameplay's faction table sits beside its state, since a default names only what is declared before it; --tighten over their tests and examples 2026-09-27 03:07:29 +03:00
ludic.render3d render3d: VkAllocationCallbacks counted (R3D_ALLOC_VK), pipeline create infos freed, actor pool at init 2026-09-28 15:46:19 +03:00
ludic.rpg refactor(packages): 0.R5 - the rest of the lazy starts are defaults - hints' rail (sized by hints_config), lab's CRC table, rpg's crafting / items / inventory / quests / dialog, shooter's weapons, prefs, and npc's and gameplay's empty ensures gone; gameplay's faction table sits beside its state, since a default names only what is declared before it; --tighten over their tests and examples 2026-09-27 03:07:29 +03:00
ludic.save ludic.save, ludic.telemetry: a parsed tree they refuse is freed (23.2) 2026-09-27 22:51:06 +03:00
ludic.session refactor(packages): 0.R5 - jobs, session, settings, hints and net make their tables when the state is made, not on the first question (jobs__ensure, session__init and ply_init, sg_init, hn_mute_ensure, net__init gone); their questions read 2026-09-27 01:29:32 +03:00
ludic.settings refactor(packages): 0.R5 - jobs, session, settings, hints and net make their tables when the state is made, not on the first question (jobs__ensure, session__init and ply_init, sg_init, hn_mute_ensure, net__init gone); their questions read 2026-09-27 01:29:32 +03:00
ludic.shooter refactor(packages): 0.R5 - the rest of the lazy starts are defaults - hints' rail (sized by hints_config), lab's CRC table, rpg's crafting / items / inventory / quests / dialog, shooter's weapons, prefs, and npc's and gameplay's empty ensures gone; gameplay's faction table sits beside its state, since a default names only what is declared before it; --tighten over their tests and examples 2026-09-27 03:07:29 +03:00
ludic.shop refactor(packages): 0.R5 - the shop's week is rolled by its tick and asking reads it; needs start filled and vehicles start with their list; character, physics, vehicles and nativeecho's lazy starts are defaults; --tighten over all four 2026-09-27 13:25:57 +03:00
ludic.steps ludic.jobs jobs_posted_count, ludic.steps steps_my_shares_into - a count and a kept list for what a party asks every tick 2026-09-28 15:12:24 +03:00
ludic.telemetry ludic.save, ludic.telemetry: a parsed tree they refuse is freed (23.2) 2026-09-27 22:51:06 +03:00
ludic.things ludic.things: a fact's record kept, in two halves swapped when a fact finds the queue empty 2026-09-28 12:45:40 +03:00
ludic.tracks wip(tracks): phase 5 - a print names its maker, and a read print points at the next one (the chain); goes with maroon-lake phase-5 2026-09-27 21:31:14 +03:00
ludic.ui ludic.ui: an unmounted component is mounted again rather than made again - its record renewed (a generated renew), its props and model kept; an action's call answers into a ring 2026-09-28 15:25:55 +03:00
ludic.update refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
ludic.vehicles ludic.physics, ludic.character, ludic.vehicles: fact records reused, and phys_sink allocates nothing 2026-09-28 02:03:09 +03:00
ludic.wallet refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
ludic.weather refactor(packages): 0.R5 - a question no longer starts its state - 64 lazy starts ('if st.x == null { st.x = ... }' inside a getter) are the state's defaults, gear__ensure is gone, and ludic migrate state --tighten took mut off 208 package parameters: things_all, thing_find, gear_charge, gear_level, jobs_state and the rest read 2026-09-27 00:51:03 +03:00
ludic.wildlife ludic.base, ludic.wildlife, ludic.npc: fact records reused, not made per fact 2026-09-28 01:58:19 +03:00
README.md feat(ludic.anim): ozz-animation 0.17.0 underneath - a skin's skeleton and each clip built at load, sampled to 1e-4 of anim_mix (phase 19.1) 2026-09-28 12:44:49 +03:00

packages

The Ludic packages that ship with the toolchain, found by import "ludic.<name>" from $LUDIC_HOME/packages (or a project's ludic_modules). Each has a README of its own. ludic test packages runs every package's tests, each test block in a process of its own.

The mechanic packages

A mechanic says module ludic_<name> uses ludic_base and so reaches nothing else; it asks the game through ports (bind ClockWorld { ... }), reports through queues of facts, and saves its own section. The rules are in ludic.base.

ludic.base the shared vocabulary: Tick and phases, Queue<T>, rng streams, the save tree, the system runner (Systems, an open registry)
ludic.aim what the crosshair is on: a forgiving ray against cylinders, the ground in front, reach floors, which thing the use key means
ludic.anim glTF animation clips sampled and cross-faded onto a render3d Skin (uses ludic_render3d); ozz-animation underneath as a native library (phase 19)
ludic.character a third-person walking body: gait, steps and slopes, a jump, wading, swimming, sitting, a safe put-down, the orbit camera
ludic.audio world sounds with a gain, pan and pitch from a listener port, flat interface sounds, packed clips loaded, the one door to Audio.*
ludic.compass bearing marks on a strip: gathered from registered providers, gated by tier, sorted by priority, bearings, distances and a radar
ludic.clock the hour, the day, the moon and a calendar of seasons
ludic.crafting recipes: what goes in and out, where and how long, making, refunding, hold-to-make
ludic.effects timed modifiers that run down in game time (a meal's warmth, a drink's legs)
ludic.fire a camp fire: fuel, the rain on it, warmth at a distance, whether it will cook
ludic.fishing a rod at the water: cast, bite, the reel's fight, the landing; species as an open registry
ludic.hints a rail of what is true now, most urgent first, each a card that teaches it and can be muted by key
ludic.i18n a game in any language: gettext .po files, patterns with holes, plurals, a mod folder, a font per language
ludic.inventory a pack: a count per kind, with room the game decides
ludic.minimap a map's logic: the explored fog over a grid and its land share, the player's marks, and the view (world to map and back, zoom, pan, the camp, you, focus)
ludic.needs a body's warmth, food, water and energy, and the countdown to a collapse
ludic.npc the other people in a place: a routine by the hour, walking round what is in the way, facing a player who comes near, lines as data, a guest's copy
ludic.physics rigid bodies, removable still shapes, queries and buoyancy over Jolt Physics (a native library, phase 16)
ludic.nav a navmesh per kind of walker and the ways across it, over Recast & Detour (a native library, phase 17)
ludic.photo a camera's photographs: what is in the frame, a grade on size, framing, light and the moment, the roll, its worth, the best of each subject
ludic.save versioned save files: a migration chain the game declares, torn writes told apart, a backup, a newer file refused and read-only
ludic.settings a game's settings as data: one store, a fact per change, ranges, a safe set
ludic.shop vendors: prices by standing and weekly demand, stock, buying and selling
ludic.steps chapters of steps (kind, param, need), progress, and a party's shares pooled
ludic.telemetry events queued, batched to a PostHog-shaped endpoint, backed off when offline
ludic.things the placed things of a world and their kinds (an open registry), queries, facts, a save
ludic.tracks prints and sign animals leave, their age, and reading them
ludic.update a Velopack-installed game updating itself a frame at a time
ludic.vehicles each player's boat and horse: called to berths and bays, owner and rider, riding, getting off onto a safe spot
ludic.wallet money carried: earned, spent, lost, every change a fact
ludic.weather spells of weather described as data: odds, wetness, wind, storms, a forecast
ludic.wildlife a valley's animals: ranges, their day, senses and alert, feeding, lures, spawning

Engine and UI

ludic.render3d the physically based 3D renderer over OpenGL and Vulkan (named ludic_render3d under uses)
ludic.ui components: templates, stylesheets, layout, input and focus (module ludic_ui)
ludic.lab the visual lab: a scene on a lit plate, fixed cameras, PNG shots and a contact sheet
ludic.core the canonical engine-ABI components
ludic.prefs a small key=value store for preferences and records
ludic.nativeecho the worked example of a package carrying a native library: a C sum over a slice, callbacks drained as facts

Native libraries

A package may carry a C or C++ library (native lines in its package.ludic, docs/PACKAGES.md). The library is never bound directly: a thin C shim in the package's native/shim/ is, and every shim keeps the same shape so the Ludic side stays safe.

  • Only int, long, float and opaque handles cross. A Ludic float is a C float, a long an int64_t, a pointer a void *. No struct is passed by value, no C++ type, no exception: the shim catches and turns it into a return code.
  • A handle is the library's pointer, kept in the package's state and never exported. The game names what the package hands it - an int id - and the package maps it to the handle.
  • Nothing calls back into Ludic. No function pointer crosses the boundary. What a library reports through a callback (a contact, a finished path, a mixed buffer) the shim records in a buffer of its own, and the package drains it after the call returns (ne_scan then ne_drain), pushing each record onto its facts queue. A record that did not fit is counted, not dropped silently.
  • Bulk data crosses as a slice the package owns. A []float or []int passed where the shim takes a pointer is its data; the package makes it once and reuses it (L7), and passes its length beside it.
  • Errors are return codes. 0 is success and a negative number says what failed; nothing aborts, nothing prints.
  • Threads a library starts stay inside C (a job system, an audio device). The Ludic side is called on the game's thread only.
  • The symbols are prefixed with the package's short name (ne_, jph_), exported explicitly (__attribute__((visibility("default"))), __declspec(dllexport)), and everything else is hidden.

native/build.sh builds lib/<target>/ from the pinned upstream source and the shim through tools/native/lib.sh; run it on the Mac and, in Git Bash, on the PC. The package's tests run the real library - there is no fake for it.

The builtin controllers

ludic.gameplay the shared foundation of the builtin gameplay controllers
ludic.platformer the Platformer controller
ludic.shooter the top-down Shooter controller
ludic.rpg the RPG systems suite
ludic.dungeon arena rooms for a room-to-room roguelite
ludic.npcai NPC AI: perception, decision, action