ludic/changes/render3d-hooks.md
Orkuncakilkaya 0c73287e35 feat(lang): functions are values (L2), and render3d takes its scene as callbacks
fn(int, float) -> bool is a type, fn name is any top-level function's value, and a call through
a local, a global, a record field, a slice element, a parameter or a result of a function type
is an indirect call; two function types mix only when equal, a call checks its argument count,
and a value may be null (examples/functions/values.ludic). Job.parallel_for keeps its worker
check.

render3d's scene is registered rather than required by name: r3d_on_draw, r3d_on_casters and
r3d_on_stream_fill (hooks.ludic). The two rendering examples register theirs - and had defined
scene_draw_casters with no parameter while the renderer passed one, which nothing checked.
render3d declares numbers float itself; smooth.ludic is converted to floats and returns when
r3d_init fails instead of running on into a segfault. Noise.* check their argument count (a call
one short crashed the compiler). selfhost-build says why it failed. The migration tool reads a
declared float as evidence. Seed regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 00:27:26 +03:00

10 lines
747 B
Markdown

bump: minor
type: feat
**render3d takes what a frame draws as callbacks.** A program used to have to define
`scene_draw`, `scene_draw_casters` and `stream_fill` by name - a contract only the linker
enforced, whose shape nothing checked (two examples defined `scene_draw_casters` with no
parameter while the renderer passed one), and one scene per program. It registers them now:
`r3d_on_draw(fn ...)`, `r3d_on_casters(fn ...)`, `r3d_on_stream_fill(fn ...)` (hooks.ludic).
render3d also declares `numbers float` itself, so a program that imports it without the line
still gets a working renderer. The Noise functions check their argument count: a call one
short crashed the compiler, or - where it happened to fit - put fbm2's octaves in its seed.