// world-shared.jsx — shared noise GLSL + helpers used by all three worlds.

const TAU = Math.PI * 2;
const clamp01 = (x) => Math.min(1, Math.max(0, x));
const lerp = (a, b, t) => a + (b - a) * t;
const ease = (t) => t * t * (3 - 2 * t);
const easeOut = (t) => 1 - Math.pow(1 - t, 3);
const easeIn = (t) => t * t;

// ─── GLSL: value noise + fbm + ridged ──────────────────────────────────────
const NOISE_GLSL = `
float hash3(vec3 p){ return fract(sin(dot(p,vec3(127.1,311.7,74.7)))*43758.5453); }
float vnoise(vec3 p){
  vec3 i = floor(p); vec3 f = fract(p);
  f = f*f*(3.0-2.0*f);
  float n000 = hash3(i+vec3(0,0,0));
  float n100 = hash3(i+vec3(1,0,0));
  float n010 = hash3(i+vec3(0,1,0));
  float n110 = hash3(i+vec3(1,1,0));
  float n001 = hash3(i+vec3(0,0,1));
  float n101 = hash3(i+vec3(1,0,1));
  float n011 = hash3(i+vec3(0,1,1));
  float n111 = hash3(i+vec3(1,1,1));
  return mix(
    mix(mix(n000,n100,f.x), mix(n010,n110,f.x), f.y),
    mix(mix(n001,n101,f.x), mix(n011,n111,f.x), f.y),
    f.z
  );
}
float fbm(vec3 p){
  float v=0.0; float a=0.5;
  for(int i=0;i<6;i++){ v += a*vnoise(p); p = p*2.03 + vec3(13.1,7.7,3.3); a *= 0.5; }
  return v;
}
float fbm5(vec3 p){
  float v=0.0; float a=0.5;
  for(int i=0;i<5;i++){ v += a*vnoise(p); p = p*2.03 + vec3(13.1,7.7,3.3); a *= 0.5; }
  return v;
}
float ridged(vec3 p){
  float v=0.0; float a=0.5;
  for(int i=0;i<5;i++){ v += a*(1.0-abs(vnoise(p)*2.0-1.0)); p = p*2.04; a *= 0.5; }
  return v;
}
`;

// ─── JS: deterministic value-noise + fbm for CPU-side displacement ──────────
function jHash(x, y, seed){
  let s = Math.sin(x*127.1 + y*311.7 + seed*74.7) * 43758.5453;
  return s - Math.floor(s);
}
function jValueNoise(x, y, seed){
  const ix = Math.floor(x), iy = Math.floor(y);
  const fx = x - ix, fy = y - iy;
  const ux = fx*fx*(3-2*fx);
  const uy = fy*fy*(3-2*fy);
  const a = jHash(ix,   iy,   seed);
  const b = jHash(ix+1, iy,   seed);
  const c = jHash(ix,   iy+1, seed);
  const d = jHash(ix+1, iy+1, seed);
  return (a*(1-ux) + b*ux)*(1-uy) + (c*(1-ux) + d*ux)*uy;
}
function jFbm(x, y, seed, octaves){
  let v = 0, a = 0.5, fx = x, fy = y;
  for (let i = 0; i < (octaves || 5); i++){
    v += a * jValueNoise(fx, fy, seed);
    fx *= 2.03; fy *= 2.03; a *= 0.5;
  }
  return v;
}
function jRidged(x, y, seed, octaves){
  let v = 0, a = 0.5, fx = x, fy = y;
  for (let i = 0; i < (octaves || 4); i++){
    const n = jValueNoise(fx, fy, seed);
    v += a * (1 - Math.abs(n*2 - 1));
    fx *= 2.04; fy *= 2.04; a *= 0.5;
  }
  return v;
}

Object.assign(window, {
  TAU, clamp01, lerp, ease, easeOut, easeIn,
  NOISE_GLSL, jHash, jValueNoise, jFbm, jRidged,
});
