The ECS-native shape the 2D lighting follow-up asked for, built on the engine-owned-system hook from #43. A torch is just an entity carrying Light2D, a wall an entity carrying Occluder, and one Ambient entity sets the night tint — the engine runs the whole deterministic light pass at the end of the Render phase (ambient modulate -> carve occluder shadows -> accumulate additive radial lights) and presents. No Light.* calls wired. - runtime/native/systems_light.ludic: esys_light2d, consuming the components through the by-name reflection ABI and reusing the #4 accumulation core (light_ambient / light_occlude / light_point). Reads position from a Position component when present, else the light's own x/y. - Split from systems.ludic so a SpriteAnim/Motion-only game never links the light pass; spliced (with light.ludic) only when Light2D/Occluder declared. - emit_main now boots rt_init like the auto-loop/test runner, so an entry-driven game that renders has its framebuffer allocated (headless: allocate only, no window, byte-identical stdout for non-rendering games). Worked example + regression: examples/library/light_ecs.ludic (32 1 32 1). Full suite 74 passed, self-host C-free fixpoint intact, no golden drift. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 lines
715 B
Markdown
3 lines
715 B
Markdown
bump: minor
|
|
type: feat
|
|
ECS-native 2D lighting (#47) — a torch is now just an entity carrying `Light2D { x, y, radius, color, intensity }`, a wall an entity carrying `Occluder { x, y, w, h }`, and one `Ambient { color }` entity sets the night tint. The engine runs the whole deterministic light pass (ambient modulate → carve occluder shadows → accumulate each additive radial light) at the end of the Render phase and presents — no `Light.*` calls wired by hand. A `Light2D`/`Occluder` takes its position from a `Position { x, y }` component when the entity carries one, else from its own `x`/`y`. Built on the engine-owned-system hook, so it costs nothing in a game that declares none of these components.
|