9.1 KiB
Changelog
All notable changes to the Ludic toolchain, newest first. Generated from the changesets under changes/ by x release; do not edit released sections by hand.
v0.2.0 — 2026-09-01
The types-and-systems release. Ludic grows a real type system — sum types,
option/result, exact and arbitrarily-big numbers, string-keyed containers and
packed 2D value types — alongside an engine that auto-runs animation, motion and
lighting over components a game merely declares, a full input stack from
rebindable action maps to native gamepads, out-of-band Audio / HTTP / Jobs
standard libraries, and a built-in test framework with line coverage. Every
addition is gated and additive: a program that never touches a feature compiles
byte-for-byte identically, and the C-free bootstrap fixpoint is untouched.
Language & types
- feat: Tagged-union enums (#56) — an
enumvariant may now carry a payload (enum Tile { Empty, Wall, Door(int), Portal(int, int) }), making it a sum type. Variants construct by name andmatchdestructures them, binding each payload, with exhaustiveness and arity checked so adding a variant surfaces every site to update. Plain enums keep their zero-cost ordinal representation, byte-for-byte unchanged. - feat:
result+try/else(#46) — a fallible function returnsok(payload)orerr(message), andtry EXPR else { … }recovers a value with the failure message bound toerror. A plain branch on the tag: no exceptions, no stack unwinding.is_ok/is_errclassify without unwrapping. - feat:
option(#53) —some(v)/none(), a maybe-a-value with no magic-1sentinel, read withis_some/is_none/unwrap_or. - feat:
panic(msg)+assert(cond, msg)(#8) — a clear, locatedfile:line: panic:/assertion failed:message and a clean exit 1 instead of a raw segfault; the source location is baked in at compile time. - feat:
IVec2+Rect2D value types (#1) — by-value spatial types that lower to packed integers, so they copy like scalars and never allocate: an integer 2D vector for grid coordinates and a Q16.16 axis-aligned rectangle for HUD boxes and hitboxes, both exact and platform-identical. - feat:
BigInt+Decimalexact numbers (#52) — arbitrary-precision integers and exact base-10 fixed-point for game economies, so an idle counter never overflows and0.10 + 0.20is exactly0.30. Nof32/f64; deterministic. - feat:
Huge+Angle+Percent(#55) — a display-scale idle/incremental big number (1.23e45), an auto-wrapping radian angle over deterministicMath.*trig, and a[0,1]-clamped fraction for health, volume and interpolationt. - feat:
Dict+Setcontainers (#54) — string-keyed lookups over one open-addressing hash table (FNV-1a, linear probing, tombstones), for resource counts, registries, tags and visited tiles; O(1) average instead of a linear scan. - feat: Value tree + reflection + JSON (#44) — a self-describing
Valuenode,Reflect.serialize/applyto walk an entity's whole component set to and from it bit-exactly, andJson.encode/parsefor compact, stable, diffable text. One-call save/load for entities and the backbone of data-driven tooling.
Engine, animation & lighting
- feat: Engine-owned systems (#43) — the ECS hook that auto-runs a system each frame over a component a game merely declares, no
handlerwired:SpriteAnimadvances sprite-sheet frames andMotionadvances value tweens for free. Built on the reflection ABI, so it costs nothing in a game that declares neither. - feat: Animation ergonomics (#48) — an ergonomic layer over those systems:
Anim.clip/Anim.playfor named spritesheet clips,Anim.on_frame/firedframe events,Motion.toone-call tweens, and fluent engine-advancedTweenhandles (to/chain/delay/parallel/stop). All integer and deterministic under replay. - feat:
Light.*2D lighting (#4) — a deterministic software light-accumulation pass over the framebuffer:ambienttinting, additive radialpointlights with linear falloff, and hard shadows cast against rectangular occluders. Integer + Q16.16, identical every run and headless. - feat: ECS-native lighting (#47) — a torch is now just an entity carrying
Light2D, a wall anOccluder, and oneAmbientsets the night tint; the engine runs the whole light pass at the end of the Render phase with noLight.*calls wired by hand. - feat: Lighting render-quality tiers (#49) — cone/flashlight
spotlights, afalloffexponent,softpenumbra shadows, colourgelcookies, normal-mapped surfaces (N·L) and atime_of_dayday/night ramp, all on the same deterministic accumulation core and consumable via optionalLight2Dfields.
Input
- feat: Action maps + record/replay (#7) — gameplay reads named, rebindable actions instead of physical keys, and the single per-frame
Input.pollmakes deterministic replay fall out for free:Input.recordcaptures the tape andInput.replayfeeds it back exactly — the seed of lockstep netcode. - feat: Device layer (#50) — multiple simultaneous held keys, analog axes and a normalized vector, the mouse (position/delta/buttons/wheel), gamepads and touch, all injectable on every target (
Input.press/set_mouse/set_pad/set_touch) and snapshotted whole into the replay tape. - feat: Native hardware bindings (#51) — the device layer's macOS side wired into cocoa.ll: live cursor position, per-frame GameController polling into gamepad buttons/axes (SDL button order), and NSTouch routing, all DCE'd out of a headless build. No API changes.
Standard library
- feat:
Audio.*(#22) — sound effects and music over a new AVAudioPlayer backend:load/play/play_music/stop/volume/pitch/is_playing. Out-of-band (real-time, not part of the simulation) but frame-driven, so a replay fires the same sounds at the same frames; headless builds carry it as dead-stripped no-ops. - feat:
Http.*(#6) — a poll-based HTTP/HTTPS client for out-of-band data (leaderboards, cloud saves, remote config) that never blocks the frame, over an NSURLConnection transport with system TLS on by default. Pairs withJson.parse; the response parser is pure Ludic and tested offline. - feat: Jobs, Promises & opt-in Sync (#14) — a layered concurrency library.
Job.*/Promise.*are the safe default: cooperative futures pumped a little each frame so heavy work spreads out, combined withPromise.all/race. The advancedSync.*tier adds mutexes, atomics and bounded channels. A deterministic cooperative scheduler — results are collected on the main thread and a Job never touches the world directly, so lockstep and replays stay bit-exact.
Testing & tooling
- feat: Built-in test framework (#12) — a
test "name" { … }block auto-discovered and run by a synthetic runner (noentryto write), withexpect/expect_eq/expect_nearassertions that report every failure and exit non-zero.expect_nearcarries the tolerance fixed-point game math needs. - feat: Line coverage (#45) — compile with
--coverageand the compiler instruments each statement with a per-line hit counter dumped at exit;bin/x test --coverageaggregates the dumps into a per-file report naming the unreached lines. Flag-gated and additive — an ordinary build stays byte-identical.
Fixes
- fix:
constof a non-int type is no longer miscompiled. Aconstreference lowered to its initializer's raw integer bits typed asint, soconst X: fixed = 10.0computed as the raw Q16.16 value655360instead of10.0— silently corrupting fixed-point math (and, in one case, spinning an infinite loop). Const references now emit their initializer with its real type. Every existing const is anintliteral, so the lowering there is byte-identical and the bootstrap fixpoint and golden renders are unchanged.
v0.1.0 — 2026-08-30
- ci: Continuous integration — Forgejo Actions workflows build the toolchain from the seed, run the regression + editor suites, assert the C-free bootstrap fixpoint, and lint commit messages on every push and pull request.
- feat: Editor tooling —
ludic-fmt(formatter) andludic-lsp(language server), plus VS Code and JetBrains integrations, all built by the toolchain. - feat: Namespaced standard library — Math, Text, List, Random, Time, Screen, Color, Ease, Collide, Memory, Vector, DateTime/Date/Duration/Clock, Unicode, Os, Fs/Path/Mime, Log, Noise, Hash, Crypto and Uuid, each deterministic where a game needs it.
- feat: Native 2D backend — an ECS core with a deterministic fixed-point (Q16.16) runtime, a windowed Cocoa target on macOS and a headless PPM renderer that runs anywhere.
- feat: Self-hosted, C-free toolchain — the compiler, runtime, task runner and editor tools are all written in Ludic and built from a checked-in LLVM-IR seed with clang alone;
x bootstrap-cfreeproves the compiler rebuilds itself byte-for-byte. - feat: Versioning and releases — SemVer with
ludicc --version, a changeset-drivenCHANGELOG.md, andx releaseto bump, tag, and publish a Forgejo release with source and toolchain artifacts.