Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
# @suaveplan/noise - Seeded spatial noise fields: Perlin, Simplex, Value, Worley, fBm and Blue-noise sampling for procedural generation
|
||||
|
||||
## Summary
|
||||
|
||||
Seeded spatial noise fields for procedural content generation. Provides six field types — Perlin, Simplex (2D/3D/4D), Value, Worley/cellular (F1/F2/F2-F1 modes), fBm (fractal Brownian motion compositor), and Poisson-disk Blue noise sampling — all seeded with `Sfc32Rng` for byte-identical, reproducible output. Every generator is available as both a functional API and a stateful class. Use this package for terrain heightmaps, texture generation, cloud simulation, vegetation scattering, and any procedural system that needs spatially-coherent randomness. For non-spatial random values (UUIDs, shuffles, distributions) use `@suaveplan/random`; for seeded integer/float sequences use `@suaveplan/pseudo-random`.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [blue](./src/blue/blue.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [blue](./src/blue/blue.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [errors](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [noise-error](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [utils](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [permutation](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
||||
<!-- end:auto-docs --> - [blue](./src/blue/blue.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [noise-error](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_- [utils](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_- [permutation](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_- [blue](./src/blue/blue.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [noise-error](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_- [utils](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_- [permutation](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_- [blue](./src/blue/blue.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [noise-error](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_- [utils](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_- [permutation](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_- [blue](./src/blue/blue.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_ - [noise-error](./src/errors/noise-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_ - [fbm](./src/fbm/fbm.md) — <!-- begin:auto-docs --> _(no submodules)_- [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_ - [perlin](./src/perlin/perlin.md) — <!-- begin:auto-docs --> _(no submodules)_- [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_ - [simplex](./src/simplex/simplex.md) — <!-- begin:auto-docs --> _(no submodules)_- [utils](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_ - [permutation](./src/utils/permutation.md) — <!-- begin:auto-docs --> _(no submodules)_- [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_ - [value](./src/value/value.md) — <!-- begin:auto-docs --> _(no submodules)_- [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_ - [worley](./src/worley/worley.md) — <!-- begin:auto-docs --> _(no submodules)_
|
||||
## Install
|
||||
|
||||
```sh
|
||||
bun add @suaveplan/noise
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **Perlin noise** — `perlin2` / `perlin3` (functional) + `PerlinNoise` (class)
|
||||
- **Simplex noise** — `simplex2` / `simplex3` / `simplex4` + `SimplexNoise`
|
||||
- **Value noise** — `value2` / `value3` + `ValueNoise`
|
||||
- **Worley/cellular noise** — `worley2` / `worley3` with `F1`/`F2`/`F2-F1` modes
|
||||
- **fBm compositor** — `fbm2` / `fbm3` wrap any base field into a multi-octave sum
|
||||
- **Blue noise sampler** — `blueNoiseSample` via Bridson's Poisson-disk algorithm
|
||||
- Every field is seeded with `Sfc32Rng` — byte-identical output for equal seeds
|
||||
- Zod schemas for every option bundle
|
||||
|
||||
## Quick start
|
||||
|
||||
```ts
|
||||
import { PerlinNoise, fbm2, blueNoiseSample } from "@suaveplan/noise";
|
||||
|
||||
const p = new PerlinNoise("terrain");
|
||||
const height = fbm2((x, y) => p.noise2(x, y), 10, 20, { octaves: 6 });
|
||||
const trees = blueNoiseSample({ width: 512, height: 512, radius: 16, seed: 1 });
|
||||
```
|
||||
|
||||
## Subpath exports
|
||||
|
||||
- `@suaveplan/noise/perlin`
|
||||
- `@suaveplan/noise/simplex`
|
||||
- `@suaveplan/noise/value`
|
||||
- `@suaveplan/noise/worley`
|
||||
- `@suaveplan/noise/fbm`
|
||||
- `@suaveplan/noise/blue`
|
||||
- `@suaveplan/noise/errors`
|
||||
|
||||
## Module docs
|
||||
|
||||
See the co-located `.md` next to each implementation.
|
||||
@@ -0,0 +1,53 @@
|
||||
# blue/blue
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `blue` module implements Robert Bridson's fast Poisson-disk sampling algorithm to generate an approximately blue-noise distribution of points in a 2D rectangle. Blue noise's defining property is that every pair of samples is at least `radius` apart, while their positions appear random — it is the gold standard for anti-aliased dithering, stippling, foliage placement, and any sampling application where regular grids produce visible artefacts.
|
||||
|
||||
## Features
|
||||
|
||||
- `blueNoiseSample({ width, height, radius, k?, maxSamples?, seed? })`
|
||||
- Seeded with `Sfc32Rng` for reproducible output
|
||||
- Bridson's spatial grid for O(n) amortised point insertion
|
||||
- `maxSamples` guard converts runaway parameters into a typed `NoiseError` instead of an out-of-memory crash
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { blueNoiseSample } from "@suaveplan/noise";
|
||||
|
||||
const dots = blueNoiseSample({ width: 400, height: 300, radius: 10, seed: 42 });
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { blueNoiseSample } from "@suaveplan/noise";
|
||||
|
||||
const trees = blueNoiseSample({
|
||||
width: 2048,
|
||||
height: 2048,
|
||||
radius: 32, // minimum canopy spacing
|
||||
k: 50, // higher k = denser packing
|
||||
maxSamples: 20_000,
|
||||
seed: "forest-2026-04-19",
|
||||
});
|
||||
for (const [x, y] of trees) plantTree(x, y);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `BlueNoiseOptions`:
|
||||
- `width`, `height`: rectangle size (must be positive finite)
|
||||
- `radius`: minimum spacing between samples (positive finite)
|
||||
- `k`: candidate neighbours per active sample (default 30)
|
||||
- `maxSamples`: hard ceiling (default 100 000) — throws `NoiseError.BLUE.MAX_SAMPLES_EXCEEDED` if exceeded
|
||||
- `seed`: `string | number` passed through to `Sfc32Rng` (default 0)
|
||||
- `blueNoiseSample(opts): Array<[number, number]>`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
A spatial background grid with `cellSize = radius / √2` guarantees at most one sample per cell, so the neighbour check only has to scan a 5×5 window (the 2-cell radius is the Bridson-recommended value). The `maxSamples` guard protects against the common user error of specifying a tiny radius relative to the rectangle — without it, `O(area/radius²)` can explode. `k` above 30 gives denser packing but longer runtimes; 30 is the paper's recommended value.
|
||||
@@ -0,0 +1,65 @@
|
||||
# noise-error
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `noise-error` module exports the `NoiseError` class and `NOISE_CODES` registry used by every public function in `@suaveplan/noise`. Centralising validation failures here keeps upstream error handling simple: callers only need to match on a single `NOISE.*` code prefix regardless of which noise function raised the error.
|
||||
|
||||
## Features
|
||||
|
||||
- Stable, namespaced error codes via `defineCodes("NOISE", [...])`
|
||||
- `NoiseError` extends `SuaveplanError<NoiseCode>` with the usual cause-chain, redaction, and OTel integrations
|
||||
- Coverage for argument validation, blue-noise termination guards and fBm octave validation
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { NoiseError, NOISE_CODES } from "@suaveplan/noise/errors";
|
||||
|
||||
throw new NoiseError(
|
||||
NOISE_CODES["ARG.INVALID"],
|
||||
"noise.arg.invalid",
|
||||
{ context: { field: "frequency" } },
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { NoiseError, NOISE_CODES } from "@suaveplan/noise/errors";
|
||||
|
||||
try {
|
||||
// ... sample blue noise over a huge radius ...
|
||||
} catch (err) {
|
||||
if (err instanceof NoiseError && err.code === NOISE_CODES["BLUE.MAX_SAMPLES_EXCEEDED"]) {
|
||||
// back off and retry with a larger spacing
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `NOISE_CODES` — frozen registry.
|
||||
- `NoiseError(code, messageKey, options?)` — structured error with `context`, `cause`, `traceId`, `clock` options.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
All codes sit under the `NOISE.*` namespace so they don't collide with `@suaveplan/pseudo-random` or `@suaveplan/random` codes. Adding new codes is strictly additive — removing them requires a major version bump.
|
||||
|
||||
### Subclasses & Codes
|
||||
|
||||
`NoiseError` is the `instanceof` pivot for every error thrown by `@suaveplan/noise`. Concrete subclasses cover invalid seed, invalid octave count, out-of-range frequency, and invalid amplitude. Every subclass carries a stable code from the `NOISE` namespace (`NOISE.INVALID_SEED`, `NOISE.OCTAVES.OUT_OF_RANGE`, etc.) so callers can type-narrow on `error.code` without string-matching the message. Inherits wire serialisation and OTel span-event support from `SuaveplanError`.
|
||||
|
||||
## Further Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { NoiseError } from "@suaveplan/noise/errors/noise-error";
|
||||
try {
|
||||
throw new NoiseError("invalid seed", { code: "NOISE.INVALID_SEED" });
|
||||
} catch (e) {
|
||||
if (e instanceof NoiseError) console.log(e.code);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,49 @@
|
||||
# fbm/fbm
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `fbm` module composes Fractional Brownian Motion on top of any base noise function. It layers `octaves` copies of the base at geometrically increasing frequencies (`lacunarity`) and geometrically decreasing amplitudes (`gain`), yielding the classical cloud/terrain/texture multi-scale roughness pattern that underlies most procedurally generated content.
|
||||
|
||||
Because `fbm2`/`fbm3` take the base function as a parameter, you can layer any of `perlin2`, `simplex2`, `value2`, or even Worley distances on top of fBm — the module has no coupling to a specific noise kind.
|
||||
|
||||
## Features
|
||||
|
||||
- `fbm2(base, x, y, opts?)` — 2D compositor
|
||||
- `fbm3(base, x, y, z, opts?)` — 3D compositor
|
||||
- Configurable `octaves`, `lacunarity`, `gain`, `frequency`, `amplitude`
|
||||
- Argument validation via `NoiseError.ARG.INVALID` / `FBM.INVALID_OCTAVES`
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { fbm2, PerlinNoise } from "@suaveplan/noise";
|
||||
|
||||
const p = new PerlinNoise("world");
|
||||
const h = fbm2((x, y) => p.noise2(x, y), 1.5, 2.3);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { fbm3, SimplexNoise } from "@suaveplan/noise";
|
||||
|
||||
const s = new SimplexNoise("clouds");
|
||||
const v = fbm3(
|
||||
(x, y, z) => s.noise3(x, y, z),
|
||||
0.1, 0.2, 0.3,
|
||||
{ octaves: 6, lacunarity: 2.0, gain: 0.5, frequency: 1, amplitude: 1 },
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `FbmOptions` — every field optional: `octaves` (default 4, must be an integer 1–32), `lacunarity` (default 2), `gain` (default 0.5, must be in (0, 1]), `frequency` (default 1), `amplitude` (default 1).
|
||||
- `fbm2(base, x, y, opts?): number`
|
||||
- `fbm3(base, x, y, z, opts?): number`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Clamping `octaves` to 1–32 avoids pathological input (negative or absurdly large numbers of loop iterations). `gain > 1` would diverge rather than converge, so it's rejected; `gain` exactly 1 means every octave contributes equally, which is useful for certain stylised effects but rejected here to keep the numeric output bounded — if you need that, call the base function manually in a loop.
|
||||
@@ -0,0 +1,50 @@
|
||||
# perlin/perlin
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `perlin` module implements Ken Perlin's classic gradient noise in two and three dimensions. Perlin noise is the de-facto standard for procedurally generated terrains, clouds, and texture dithering: it returns a smooth, pseudo-random-looking field in `[-1, 1]` whose value depends continuously on its coordinates.
|
||||
|
||||
This implementation uses the 12-gradient table from Perlin's "Improving Noise" paper (SIGGRAPH 2002), so both 2D and 3D variants share the same gradient space — useful when mixing them in a single shader-like pipeline.
|
||||
|
||||
## Features
|
||||
|
||||
- `PerlinNoise` class — holds a seeded permutation table you can reuse across many `noise2`/`noise3` calls
|
||||
- `perlin2(seed, x, y)` / `perlin3(seed, x, y, z)` — one-shot functional convenience
|
||||
- Deterministic per seed; `Sfc32Rng`-shuffled 256-byte permutation table
|
||||
- 2D and 3D outputs in roughly `[-1, 1]` (theoretical max is `√(N/4)` per Perlin, in practice values stay well within `[-0.86, 0.86]` for 2D)
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { perlin2 } from "@suaveplan/noise";
|
||||
|
||||
const v = perlin2("terrain-42", 1.5, 2.3);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { PerlinNoise } from "@suaveplan/noise";
|
||||
|
||||
const p = new PerlinNoise("world");
|
||||
for (let y = 0; y < 256; y += 1) {
|
||||
for (let x = 0; x < 256; x += 1) {
|
||||
const h = p.noise2(x * 0.05, y * 0.05); // [-1, 1]
|
||||
// ...paint tile height...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `class PerlinNoise(seed: string | number = 0)` — builds the permutation table once.
|
||||
- `noise2(x: number, y: number): number`
|
||||
- `noise3(x: number, y: number, z: number): number`
|
||||
- `perlin2(seed, x, y): number` / `perlin3(seed, x, y, z): number` — rebuild the table on every call; prefer `PerlinNoise` for hot loops.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Integer coordinates are masked with `& 0xff` — the permutation table is of length 512 with the second 256 entries mirroring the first, so `perm[(perm[xi] + yi) & 0x1ff]` can be written as `perm[perm[xi] + yi]` without risking out-of-bounds reads. Fractional coordinates run through Perlin's quintic fade (`6t^5 - 15t^4 + 10t^3`) for C² continuity.
|
||||
@@ -0,0 +1,54 @@
|
||||
# simplex/simplex
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `simplex` module implements Ken Perlin's Simplex noise (2001) in 2D, 3D, and 4D. Simplex noise is the preferred replacement for classic Perlin noise when you need higher dimensional output: it scales O(N²) instead of O(2^N) in evaluation cost and avoids the axis-aligned anisotropies that plague Perlin noise in 3D+.
|
||||
|
||||
Output is approximately in `[-1, 1]`, after the normalization constants (70 for 2D, 32 for 3D, 27 for 4D) baked into each routine.
|
||||
|
||||
## Features
|
||||
|
||||
- `SimplexNoise` class — reusable seeded permutation table
|
||||
- `simplex2` / `simplex3` / `simplex4` — one-shot functional APIs
|
||||
- Uses the 12-gradient table for 2D/3D and a 32-gradient table for 4D
|
||||
- Deterministic per seed
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { simplex2 } from "@suaveplan/noise";
|
||||
|
||||
const v = simplex2("world", 1.5, 2.3);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { SimplexNoise } from "@suaveplan/noise";
|
||||
|
||||
const s = new SimplexNoise("clouds");
|
||||
// Animated clouds: use the 4th dimension as time.
|
||||
for (let y = 0; y < 256; y += 1) {
|
||||
for (let x = 0; x < 256; x += 1) {
|
||||
const v = s.noise4(x * 0.01, y * 0.01, 0, performance.now() * 0.0001);
|
||||
// ... render ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `new SimplexNoise(seed)` — constructs the permutation table once.
|
||||
- `noise2(x, y) / noise3(x, y, z) / noise4(x, y, z, w): number`
|
||||
- `simplex2/3/4(seed, ...coords): number` — functional convenience.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The 4D simplex-corner selection uses rank-based selection from Gustavson's reference implementation. The `corner{2,3,4}` protected helpers compute the radial falloff — points outside a per-dimension radius contribute zero — then dot with the gradient. Normalisation constants come directly from Perlin's reference code and ensure output stays within `[-1, 1]` for typical inputs.
|
||||
|
||||
### Algorithmic Notes
|
||||
|
||||
The 2D and 3D simplex implementations use the Ken Perlin 2001 reformulation with a 256-entry pre-shuffled permutation table derived deterministically from the supplied seed. Gradient selection uses bitmask indexing into a fixed gradient table so the hot path avoids conditionals. Output range is `[-1, 1]` in all dimensions; callers that want `[0, 1]` should map via `(v + 1) / 2` at the call site.
|
||||
@@ -0,0 +1,53 @@
|
||||
# types/noise.types
|
||||
|
||||
## Purpose
|
||||
|
||||
The `noise.types` module re-exports every public option or mode type used across the `@suaveplan/noise` surface in one flat location. Consumers who only need the types (for instance, library authors publishing their own wrappers on top) can `import type { FbmOptions, WorleyMode, BlueNoiseOptions } from "@suaveplan/noise";` and never pay the runtime cost of loading the implementation modules.
|
||||
|
||||
## Features
|
||||
|
||||
- `FbmOptions` — every field optional (octaves, lacunarity, gain, frequency, amplitude)
|
||||
- `WorleyMode` — `"F1" | "F2" | "F2-F1"`
|
||||
- `BlueNoiseOptions` — rectangle size, radius, k, maxSamples, seed
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import type { WorleyMode } from "@suaveplan/noise";
|
||||
|
||||
function pickMode(kind: "crack" | "stone"): WorleyMode {
|
||||
return kind === "crack" ? "F2-F1" : "F1";
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import type { FbmOptions, BlueNoiseOptions } from "@suaveplan/noise";
|
||||
|
||||
interface TerrainRecipe {
|
||||
heightOpts: FbmOptions;
|
||||
treePlacement: BlueNoiseOptions;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
Re-exports from the corresponding implementation modules. There is zero runtime code in this file — it exists purely so downstream libraries can consume typings without importing functions.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
We keep the flat type barrel deliberately thin: adding more wrappers here invites drift. If a public option type ever gets added to a new noise family, extend this file at the same time as the new module lands.
|
||||
|
||||
### Shapes
|
||||
|
||||
`NoiseFunction2D` and `NoiseFunction3D` are the two canonical call shapes exported by every generator in the package. `NoiseOptions` aggregates seed, octaves, persistence, lacunarity, and amplitude multiplier so fractal / ridged / turbulent wrappers can be composed from a single options bundle. All shapes are type-only and free of runtime cost, consistent with the package-wide `src/types/` convention.
|
||||
|
||||
## Further Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import type { NoiseFunction2D, NoiseOptions } from "@suaveplan/noise/types/noise.types";
|
||||
const opts: NoiseOptions = { seed: 42, octaves: 4, persistence: 0.5, lacunarity: 2 };
|
||||
declare const fn: NoiseFunction2D;
|
||||
const sample = fn(0.1, 0.2);
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
# utils/permutation
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `permutation` module provides the seeded 512-byte permutation table plus the `fade` and `lerp` helpers used by every gradient-noise function in `@suaveplan/noise`. Centralising these shared utilities here keeps Perlin, Simplex, and Value noise consistent with one another: they all consume a table shuffled by `Sfc32Rng`.
|
||||
|
||||
## Features
|
||||
|
||||
- `buildPermutation(seed)` — seeded 512-byte Uint8Array; first 256 entries are a Fisher-Yates shuffle of `[0, 255]`, second 256 mirror the first (so hash wrap-around is free)
|
||||
- `fade(t)` — Perlin's quintic fade curve `6t^5 - 15t^4 + 10t^3`
|
||||
- `lerp(a, b, t)` — standard linear interpolation
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { buildPermutation, fade } from "@suaveplan/noise";
|
||||
|
||||
const p = buildPermutation("terrain-42");
|
||||
const f = fade(0.5); // 0.5
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { buildPermutation, fade, lerp } from "@suaveplan/noise";
|
||||
|
||||
const perm = buildPermutation(0);
|
||||
// Hash 2D integer coordinates through the table:
|
||||
function hash2(xi: number, yi: number): number {
|
||||
return perm[((perm[xi & 0xff] as number) + (yi & 0xff)) & 0x1ff] as number;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `buildPermutation(seed: string | number): Uint8Array` — deterministic 512-byte table.
|
||||
- `fade(t: number): number` — Perlin's quintic smoothing, returns 0 at t=0 and 1 at t=1.
|
||||
- `lerp(a: number, b: number, t: number): number` — returns `a + (b-a)*t`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Uint8Array uses one byte per entry, so the full table fits in 512 bytes of memory and stays in L1 cache during long noise evaluation loops. The Fisher-Yates shuffle runs 255 steps and uses `rng.nextUint32() % (i+1)` — the small modulo bias is statistically irrelevant for noise-table generation. The second-half mirror lets consumers do `perm[(a + b) & 0x1ff]` without branching or masking `a`/`b` first.
|
||||
@@ -0,0 +1,51 @@
|
||||
# value/value
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `value` module implements 2D and 3D Value noise — the simplest members of the noise family. At every integer lattice point it stores a random value in `[-1, 1]` and smoothly interpolates between them with the quintic fade curve. Value noise is cheaper to evaluate than Perlin noise (no gradient dot-products) but has a visibly axis-aligned structure; it is most useful as an inexpensive layer inside fBm or as a mask for other effects.
|
||||
|
||||
## Features
|
||||
|
||||
- `ValueNoise` class with reusable seeded permutation table
|
||||
- `value2(seed, x, y)` / `value3(seed, x, y, z)` functional APIs
|
||||
- Output normalised to `[-1, 1]`
|
||||
- Deterministic per seed
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { value2 } from "@suaveplan/noise";
|
||||
|
||||
const v = value2("layer", 2.5, 4.1);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { ValueNoise } from "@suaveplan/noise";
|
||||
|
||||
const n = new ValueNoise("rocks");
|
||||
let sum = 0;
|
||||
let weight = 1;
|
||||
for (let o = 0; o < 4; o += 1) {
|
||||
sum += weight * n.noise2(1.3 * o, 2.7 * o);
|
||||
weight *= 0.5;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `new ValueNoise(seed)` — one seeded permutation table, reusable.
|
||||
- `noise2(x, y)` / `noise3(x, y, z)`.
|
||||
- `value2(seed, x, y)` / `value3(seed, x, y, z)` — functional helpers.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The per-lattice-point value is derived from the 256-byte permutation table by reading `perm[(perm[xi] + yi) & 0x1ff]` and rescaling from `[0, 255]` to `[-1, 1]`. Quintic fade keeps the output C² continuous at lattice boundaries, matching the smoothness of our Perlin implementation.
|
||||
|
||||
### Algorithm
|
||||
|
||||
Value noise samples a lattice of pseudo-random values derived from the seed and interpolates with a quintic smoothstep (`6t^5 - 15t^4 + 10t^3`) for continuous first and second derivatives. Cheaper than gradient noise but produces a more block-like visual character — good for low-frequency base layers in a multi-octave stack. The permutation table is identical to the one used by `simplex` so both generators share a single precomputed lookup.
|
||||
@@ -0,0 +1,49 @@
|
||||
# worley/worley
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The `worley` module implements Steven Worley's cellular noise in 2D and 3D. At every point in space it computes the distance to the nearest (F1) and second-nearest (F2) feature point, where feature points are scattered per-cell according to a seeded PRNG. The resulting fields (F1, F2, F2-F1) give procedural cell structures used for lava rock, cracked surfaces, Voronoi textures, stone patterns, and biological cell walls.
|
||||
|
||||
## Features
|
||||
|
||||
- `WorleyNoise` class and `worley2` / `worley3` functional APIs
|
||||
- `WorleyMode`: `"F1" | "F2" | "F2-F1"`
|
||||
- 3×3 (2D) / 3×3×3 (3D) neighbourhood search — the canonical compromise between quality and performance
|
||||
- 1..3 feature points per cell, seeded per-cell so different seeds give completely different fields
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { worley2 } from "@suaveplan/noise";
|
||||
|
||||
const distance = worley2("stones", 0.25, 0.75); // F1 default
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { WorleyNoise } from "@suaveplan/noise";
|
||||
|
||||
const w = new WorleyNoise("cracks");
|
||||
for (let y = 0; y < 256; y += 1) {
|
||||
for (let x = 0; x < 256; x += 1) {
|
||||
const edge = w.noise2(x * 0.05, y * 0.05, "F2-F1");
|
||||
// Paint edges where two cells meet equidistantly.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `class WorleyNoise(seed: string | number = 0)` — one seeded field
|
||||
- `noise2(x, y, mode?): number` — `mode` defaults to `"F1"`
|
||||
- `noise3(x, y, z, mode?): number`
|
||||
- `worley2(seed, x, y, mode?): number`
|
||||
- `worley3(seed, x, y, z, mode?): number`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Feature points are _not_ cached between evaluations; we recreate the per-cell `Sfc32Rng` each time. This keeps the class stateless and thread-safe but makes repeated evaluation at nearby points slightly more expensive. For heavy workloads the simplest optimisation is to cache `featurePoints2/3` results by cell coordinate — feel free to subclass and override those protected methods.
|
||||
Reference in New Issue
Block a user