Skip to content

Instantly share code, notes, and snippets.

@onetdev
Last active October 4, 2022 12:44
Show Gist options
  • Save onetdev/0d57891b02faf9805aceb1f3c82912d0 to your computer and use it in GitHub Desktop.
Save onetdev/0d57891b02faf9805aceb1f3c82912d0 to your computer and use it in GitHub Desktop.
3D noise map slice render supporting
import { createNoise3D } from 'simplex-noise';
// You will need an HTML with a `<cavas id="canvas" />` and `<span id='fps'>` and this ts file.
// This script only uses speed and doesn't care about frame draw time delta.
// Samples:
// - https://www.youtube.com/watch?v=ApI1m78MvAQ
// - https://www.youtube.com/watch?v=TPkWzFi1DrA
// - https://www.youtube.com/shorts/g-l_s-GkMCw (this is my favorite)
const config = {
// Clamping range (the smaller the value, the thinner the lines will be)
precission: 0.01,
// Slice distance per frame, lower number will result in smoother experience
speed: 0.01,
// Draw using hue wheel noise map or solid white
hueMode: false,
// Pixel shift/offset previous frame on Y axis each frame
decayShiftY: 0,
// Pixel shift/offset previous frame on X axis each frame
decayShiftX: 0,
// Fading out previous frame, use 0 to turn it off (esentially keeping previous frame and drawing on top of it)
decay: 0.05,
};
(async () => {
const canvas = document.getElementById('canvas') as HTMLCanvasElement | null;
const fpsCounter = document.getElementById('fps') as HTMLSpanElement | null;
if (!canvas || !fpsCounter) {
return console.error('Canvas or countet span not found');
}
const ctx = canvas.getContext('2d');
if (!ctx) {
console.error('Missing canvas context');
return;
}
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
const windowResize = () => {
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
};
window.addEventListener('resize', windowResize);
let time = 0;
const spaceNoise = createNoise3D();
const hueNoise = createNoise3D();
const clampMin = 1 - config.precission;
const clampMax = 1 + config.precission;
const draw = () => {
const start = new Date().getTime();
const width = ctx.canvas.width;
const height = ctx.canvas.height;
if (config.decayShiftX > 0 || config.decayShiftY > 0 ) {
const prevFrame = ctx.getImageData(0, 0, width, height);
ctx.putImageData(prevFrame, config.decayShiftX, config.decayShiftY);
}
if (config.decay > 0) {
ctx.fillStyle = `rgba(0,0,0,${config.decay})`;
ctx.fillRect(0, 0, width, height);
}
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
const value = spaceNoise(x / width, y / height, time) + 1;
if (value < clampMin || value > clampMax) {
continue;
}
if (config.hueMode) {
const hue = hueNoise(x / width, y / height, time);
const color = Math.round((hue + 1) * 180);
ctx.fillStyle = `hsl(${color},100%,50%)`;
ctx.fillRect(x, y, 1, 1);
} else {
ctx.fillStyle = `#ffffff`;
ctx.fillRect(x, y, 1, 1);
}
}
}
// Estimated FPS based on frame draw, not actual FPS
fpsCounter.innerText = `${Math.round(1000 / (new Date().getTime() - start))} fps`;
time += config.speed;
window.requestAnimationFrame(draw);
};
window.requestAnimationFrame(draw);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment