// modules/utils/perlin.js — Classic Perlin noise for procedural generation export function createPerlinNoise() { const p = new Uint8Array(256); for (let i = 0; i < 256; i++) p[i] = i; let seed = 42; function seededRand() { seed = (seed * 1664525 + 1013904223) & 0xffffffff; return (seed >>> 0) / 0xffffffff; } for (let i = 255; i > 0; i--) { const j = Math.floor(seededRand() * (i + 1)); const tmp = p[i]; p[i] = p[j]; p[j] = tmp; } const perm = new Uint8Array(512); for (let i = 0; i < 512; i++) perm[i] = p[i & 255]; function fade(t) { return t * t * t * (t * (t * 6 - 15) + 10); } function lerp(a, b, t) { return a + t * (b - a); } function grad(hash, x, y, z) { const h = hash & 15; const u = h < 8 ? x : y; const v = h < 4 ? y : (h === 12 || h === 14) ? x : z; return ((h & 1) ? -u : u) + ((h & 2) ? -v : v); } return function noise(x, y, z) { z = z || 0; const X = Math.floor(x) & 255, Y = Math.floor(y) & 255, Z = Math.floor(z) & 255; x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z); const u = fade(x), v = fade(y), w = fade(z); const A = perm[X] + Y, AA = perm[A] + Z, AB = perm[A + 1] + Z; const B = perm[X + 1] + Y, BA = perm[B] + Z, BB = perm[B + 1] + Z; return lerp( lerp(lerp(grad(perm[AA], x, y, z ), grad(perm[BA], x-1, y, z ), u), lerp(grad(perm[AB], x, y-1, z ), grad(perm[BB], x-1, y-1, z ), u), v), lerp(lerp(grad(perm[AA + 1], x, y, z-1), grad(perm[BA + 1], x-1, y, z-1), u), lerp(grad(perm[AB + 1], x, y-1, z-1), grad(perm[BB + 1], x-1, y-1, z-1), u), v), w ); }; } export const perlin = createPerlinNoise();