ludic/docs/language/light/light-point.md
Orkuncakilkaya a71279a7b9
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 18s
ci / build-and-test (push) Successful in 1m13s
commit-lint / conventional-commits (push) Successful in 5s
docs / build-and-deploy (push) Successful in 18s
feat(rendering): add Light.* — deterministic 2D light accumulation with hard shadows (#4)
A software light pass over the framebuffer, run in a render phase after drawing
the scene: Light.ambient multiplies the scene toward a tint (night/cave mood),
Light.point additively accumulates a radial glow with linear falloff clamped per
channel, and Light.occlude / Light.clear_occluders cast hard shadows by blocking
a light's rays against rectangular occluders. Integer + Q16.16 fixed throughout,
so a scene lights identically every run and in a headless render (diffable).

Engine in runtime/native/light.ludic, spliced on demand (g_uses_light) like the
regex/query runtimes; namespace wired in emit_call.ludic. Ships issue #4 tiers 1
(ambient + additive radial lights) and 2 (hard shadows). Normal-mapped sprites,
soft shadows, a day/night directional light, and auto-consuming Light2D/Occluder
components are follow-ups (the auto-system hook is tracked by #43).

- runtime/native/light.ludic: the light-accumulation engine (isqrt falloff,
  segment/occluder shadow test, ambient modulate)
- examples/library/lighting.ludic: 14 pixel-readback assertions
- docs/language/light/: Light.ambient/point/occlude/clear_occluders
- tools/x/test.ludic: lighting.ludic in the regression suite

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-31 14:07:19 +03:00

1.4 KiB

id name category kind tokens sig tip order ns member
light-point Light.point light namespace-method Light.point Light.point(x, y, radius, color, energy) Add a radial glow that falls off with distance. 2 Light point

Additively accumulates a radial point light centred at (x, y). Brightness is full at the centre and falls off linearly to zero at radius pixels, scaled by energy (a fixed multiplier — 1.0 is full, 2.0 over-drives toward white, 0.5 is dim), and clamped per channel at 255 so overlapping lights add without wrapping. Only the light's bounding box is touched, and any Light.occlude rectangle between the centre and a pixel puts that pixel in shadow. Colours are 0x00RRGGBB.

Parameters:

  • x, y — the light centre, in screen pixels
  • radius — the reach in pixels; brightness is zero at and beyond it
  • color — the light colour, 0x00RRGGBB
  • energy — a fixed brightness multiplier (1.0 = full)
program Demo {
  property Torch { x: int = 0, y: int = 0 }
  model Lamp { Torch }
  handler Render phase Update {
    Screen.clear(0)
    Light.ambient(Color.rgb(32, 32, 48))
    Light.point(80, 60, 70, Color.rgb(255, 210, 130), 1.0)   # a warm torch
    Screen.show()
  }
}