ludic/docs/language/noise/_section.md
Orkuncakilkaya a4f1494a04
All checks were successful
docs / build-and-deploy (push) Successful in 2s
feat(stdlib): add Noise.* — deterministic fixed-point procedural noise (#3)
A Noise.* namespace for procedural generation, implemented entirely in Q16.16
fixed point over an integer permutation hash so a seed reproduces the exact same
field on every platform and run (native/headless/wasm) — the determinism edge
over float noise that drifts across CPUs.

  - value2 / perlin2 / simplex2  — value, gradient, and simplex noise -> [-1,1]
  - fbm2(x,y,seed,octaves)       — fractal Brownian motion (octaves of simplex)
  - cellular2 / cellular2_id     — Worley F1 distance + nearest-cell id
  - unit(n)                      — remap [-1,1] -> [0,1]

Covers issue phases 1–2 fully plus cellular from phase 3; domain warp, ridged/
billow, and sample1/sample3 remain as follow-ups. Pure integer IR, C-free;
cellular/fbm reuse the math prelude's fx_sqrt.

- examples/library/noise.ludic: asserts the invariants a fixed-point generator
  must hold (Perlin == 0 at lattice points, every sampler within [-1,1],
  reproducibility, seed sensitivity, non-negative cellular distance). Wired into
  `x test` (now 52 passed).
- docs: a new Noise section + per-symbol pages; inventory and coverage pass.
- seed regenerated; `x bootstrap-cfree` fixpoint holds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-30 21:50:50 +03:00

1.9 KiB

id title order
noise Noise 6

Procedural noise — the primitive that terrain, caves, biomes, textures, clouds, wind, and object placement are built on. Every generator is implemented in Q16.16 fixed point over an integer permutation hash seeded from an explicit seed, so a given seed reproduces the exact same field on every platform and every run: native, headless, and (later) wasm all agree bit-for-bit. That is a real edge over float-based engines, whose worlds can drift subtly across CPUs and break shared-seed multiplayer or replays.

Coordinates are fixed values. The integer part of a coordinate selects a lattice cell and the fraction interpolates within it, so you scale feature size by sampling at a fractional frequency (e.g. multiply coordinates by 1/64). Outputs are fixed normalised to [-1, 1]; Noise.unit remaps that to [0, 1] when you want a height or a probability.

Pick a generator by feel: value2 is cheap and blocky; perlin2 is the classic gradient noise; simplex2 is the organic default with fewer directional artifacts; fbm2 stacks octaves of simplex for natural, detailed fields; and cellular2 (Worley) gives Voronoi-cell structure for stone, cracks, and biome boundaries. Every sampler is a pure function of (x, y, seed) — no global state, no allocation — so it is safe to call across a whole worldgen pass or a per-pixel fill.

Seed worldgen from its own seed (or a dedicated Random stream), kept separate from gameplay RNG, so generating the world never desyncs the simulation.