Pick random values on a coarse grid and linearly interpolate between them.
// random base values & linear interpolation
const width = 500, height = 200, grid = 10;
const base = Array.from({length:grid}, () => Math.random() * height);
const smooth = new Array(width);
const cellSize = width / (grid - 1);
for (let x = 0; x < width; x++) {
const fx = x / cellSize,
i0 = Math.floor(fx),
i1 = Math.min(i0 + 1, grid - 1),
t = fx - i0;
smooth[x] = base[i0] + (base[i1] - base[i0]) * t;
}
const canvas = document.getElementById("cnv2"),
ctx = canvas.getContext("2d");
ctx.clearRect(0,0,width,height);
ctx.strokeStyle = "#00FF00"; // ← vintage oscilloscope green
ctx.beginPath();
ctx.moveTo(0, height - smooth[0]);
for (let x = 1; x < width; x++) {
ctx.lineTo(x, height - smooth[x]);
}
ctx.stroke();
Cell 3: 1D Perlin Noise & Fade Curve
Perlin noise picks a random gradient (±1 here) at each integer,
computes dot‐products with the distance, and then blends via the
“fade” curve 6t⁵−15t⁴+10t³.
// fade, lerp, gradient, p‐array shuffle, 1D Perlin, plus plotting
function fade(t) { return t*t*t*(t*(t*6 - 15) + 10); }
function lerp(a,b,t) { return a + (b - a)*t; }
function grad1(hash,x) { return (hash & 1) === 0 ? x : -x; }
// build permutation table
const p = new Uint8Array(512);
(() => {
const perm = Array.from({length:256},(_,i)=>i);
for (let i = 255; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[perm[i], perm[j]] = [perm[j], perm[i]];
}
for (let i = 0; i < 256; i++) {
p[i] = p[i+256] = perm[i];
}
})();
function noise1D(x) {
const xi = Math.floor(x) & 255,
xf = x - Math.floor(x),
u = fade(xf),
a = grad1(p[xi], xf),
b = grad1(p[xi+1], xf-1);
return lerp(a, b, u);
}
// draw fade curve
const fadeC = document.getElementById("fadeC"),
fctx = fadeC.getContext("2d"),
Wf = fadeC.width, Hf = fadeC.height;
fctx.clearRect(0,0,Wf,Hf);
fctx.strokeStyle = "#00FF00"; // ← vintage oscilloscope green
fctx.beginPath();
for (let i=0; i<=Wf; i++) {
const t = i/Wf,
y = (1 - fade(t)) * Hf;
if (i===0) fctx.moveTo(i,y);
else fctx.lineTo(i,y);
}
fctx.stroke();
// draw noise
const canvas = document.getElementById("cnv3"),
ctx = canvas.getContext("2d"),
W = canvas.width, H = canvas.height;
ctx.clearRect(0,0,W,H);
ctx.strokeStyle = "#00FF00"; // ← vintage oscilloscope green
ctx.beginPath();
for (let x=0; x< W; x++) {
const v = noise1D(x/50),
y = (v*0.5 + 0.5)*H;
if (x===0) ctx.moveTo(x, H-y);
else ctx.lineTo(x, H-y);
}
ctx.stroke();
Cell 4: Interactive 2D Fractal Perlin Noise
Combine multiple octaves (fBm). Tweak sliders and watch the texture update.