www.xbdev.net
xbdev - software development
Saturday April 19, 2025
Home | Contact | Support | JavaScript... so much power in such a few lines of code..
     
 

JavaScript...

so much power in such a few lines of code..

 


Noise Fields


The beauty and magic of generating noise field patterns lie in their ability to create intricate, organic visuals that evoke natural textures, landscapes, and even dreamlike worlds from pure mathematical randomness. Noise fields, like Perlin or simplex noise, introduce a controlled randomness that is both unpredictable and coherent, producing flowing gradients and patterns reminiscent of windblown sand dunes, cloud formations, or rippling water. As the algorithm weaves order into chaos, each pattern emerges with a sense of depth and continuity, giving rise to a stunning visual harmony that feels alive and infinitely varied.

The subtle unpredictability of these patterns captures a quality of nature itself—an aesthetic that is rich in complexity, yet serene in form. Whether applied in visual effects, procedural textures, or interactive art, noise fields open doors to endless creative exploration, celebrating both the power and elegance of algorithmic beauty.



Noise field output generated using the simple demo code below.
Noise field output generated using the simple demo code below.



Noise Field Code


The complete code for the noise field is given below for review. You can play around with the interactive demo and versions of the noise field in the xbdev notepad page (link at the bottom).


Noise field showing the
Noise field showing the 'field', 'partices' and 'particles without clear - leaves trail'.


You can create smooth noise using Perlin noise algorithm - this can be animated using a single timer - so the noise scrolls. You can do 1d, 2d, and 3d noise.

We add some random particles onto the screen - and use the noise as the 'direction' the particle should move. As the noise changes and the particles move around - you get a nice pattern.

Particles move in a pattern as if pushed around by an organic force, swirling and flowing.

You can adjust lots of things - the noise frequency, the number of particles, etc to create all sorts of different noise field patterns.

document.body.style.minHeight '600';
let canvas document.createElement('canvas');
document.body.appendChildcanvas );
canvas.width canvas.height 500;
canvas.id 'canvas';

// Helper function for fract (fractional part)
function myfract(x) {
    return 
Math.floor(x);
}

// Helper function indot product
function dot(v1v2) {
    return 
v1.v2.v1.v2.y;
}

// Random function
function random(uv) {
    return 
myfract(Math.sin(dot(uv, { x12.9898y78.233 })) * 43758.5453);
}

// Smooth random function
function randomsmooth(st) {
    
let freq 2.0;
    
// Integer grid coordinates
    
let i = { xMath.floor(st.freq), yMath.floor(st.freq) };
    
// Fractional coordinates within the grid cell
    
let f = { xmyfract(st.freq), ymyfract(st.freq) };

    
// Sample four corners of the cell using the random function
    
let a random(i);
    
let b random({ xi.1.0yi.});
    
let c random({ xi.xyi.1.0 });
    
let d random({ xi.1.0yi.1.0 });

    
// Smooth the interpolation factor `f` for smoother transition between values
    
f.f.f.* (3.0 2.0 f.x);
    
f.f.f.* (3.0 2.0 f.y);

    
// Bilinear interpolation between corners
    
let x1 * (1.0 f.x) + f.x;
    
let x2 * (1.0 f.x) + f.x;
    
let y1 x1 * (1.0 f.y) + x2 f.y;

    return 
y1;
}


const 
simplex3 = (abc) => {
  
  
// Sample noise values using randomsmooth
    
let vx randomsmooth({ xc*3.2390230
                            
yc*1.3923 });
  
    
let vy randomsmooth({ xc*2.19339023
                            
yc*0.19009323 });

    
let t Math.sin);
    return 
vx + (vy-vx)*t;
};

function 
valid(val)
{
  if ( 
val === undefined )  { throw 'invalid value'; }
  if ( 
isNaNval )      )  { throw 'NaN value'; }
  if ( 
val < -9999999)      { throw 'number warning range'; }
  if ( 
val >  9999999)      { throw 'number warning range'; }
}

// Constructor for vec2
function vec2(xy) {
    
this.x;
    
this.y;
    
valid(this.x);
    
valid(this.y);
    return 
this;
}

vec2.prototype.float32 = function() {
    
let r = new Float32Array(2);
    
r[0] = this.x;
    
r[1] = this.y;
    return 
r;
};

// vec2 operations
vec2.add = function(v0v1) { return new vec2(v0.v1.xv0.v1.y); };
vec2.sub = function(v0v1) { return new vec2(v0.v1.xv0.v1.y); };
vec2.scale = function(v0s) { return new vec2(v0.sv0.s); };
vec2.dot = function(v0v1) { return (v0.v1.v0.v1.y); };
vec2.dist = function(v0) { return Math.sqrt(v0.v0.v0.v0.y); };
vec2.norm = function(v0) {
    
let ln Math.sqrt(v0.v0.v0.v0.y);
    
valid(ln);
    return 
vec2.scale(v01.0 ln);
};
vec2.lerp = function(abt) {
    
let ti = (t);
    return new 
vec2(ti a.b.xti a.b.y);
};
vec2.fromAngle = function(angle) {
    return new 
vec2(Math.cos(angle), Math.sin(angle));
};


class 
Particle {
  
constructor(xy) {
    
this.pos = new vec2(xy);
    
this.vel = new vec2(Math.random()*2-1Math.random()*2-1);
    
this.acc = new vec2(00);
    
this.size 2;
  }
  
  
move(acc) {
    if(
acc) {
      
this.acc vec2.add(this.accacc);
    }
    
    
this.vel vec2.addthis.velthis.acc);
    
    
this.pos vec2.addthis.posvec2.scale(this.vel,1.0) );
    if( 
vec2.dist(this.vel) > 1.0 ) {
      
this.vel vec2.scalevec2.normthis.vel ), 1.0 );
    }
    
this.acc = new vec2(0,0);
  }
  
  
draw() {
    
let ss this.size;
    
//ss = 12.0;
    
ctx.fillRect(this.pos.xthis.pos.yssss);
  }
  
  
wrap() {
    if(
this.pos.w) {
      
this.pos.0;
    } else if(
this.pos.) { //  -this.size) {
      
this.pos.2;
    }
    
    if(
this.pos.h) {
      
this.pos.0;
    } else if(
this.pos.) { //  -this.size) {
      
this.pos.2;
    }
  }
}

let ctx;
let field;
let wh;
let size;
let columns;
let rows;
let noiseZ;
let particles;
let hue;

function 
setup() {
  
size 10;
  
hue 0;
  
noiseZ 0;
  
canvas document.querySelector("#canvas");
  
ctx canvas.getContext("2d");
  
reset();
  
window.addEventListener("resize"reset);  
}

function 
initParticles() {
  
particles = [];
  
let numberOfParticles 3000;
  for(
let i 0numberOfParticlesi++) {
    
let particle = new Particle(Math.random() * wMath.random() * h);
    
particles.push(particle);
  }
  
//console.log('init particles');
}

function 
initField() {
  
//console.log('init field');
  
field = new Array(columns);
  for(
let x 0columnsx++) {
    
field[x] = new Array(columns);
    for(
let y 0rowsy++) {
      
//field[x][y] = {};
      
let v = new vec2(00);
      
field[x][y] = v;
      
    }
  }
}

function 
calculateField() {
  
//console.log('calc field');
  
for(let x 0columnsx++) {
    for(
let y 0rowsy++) {
      
let angle simplex3(x/20y/20noiseZ) * Math.PI 2;
      
let len simplex3(x/40 40000y/40 40000noiseZ) * 0.5;
      
//field[x][y] = vec2.norm( field[x][y] );
      //field[x][y].angle = angle;
      
field[x][y] = vec2.fromAngleangle );
      
field[x][y].len   len;
      
field[x][y].angle angle;
    }
  }
}

function 
reset() {
  
canvas.width;// = window.innerWidth;
  
canvas.height;// = window.innerHeight;
  
ctx.strokeStyle "white";
  
columns Math.round(size) + 1;
  
rows Math.round(size) + 1;
  
initParticles();
  
initField();
  
  
//console.log('reset finished');
}

function 
draw(now) {
  
requestAnimationFrame(draw);
  
calculateField();
  
noiseZ += 0.01;//= now * 0.0002;
 // drawBackground();
 // drawFlowField();
  
drawParticles();
}

function 
drawBackground() {
  
ctx.fillStyle "black";
  
ctx.fillRect(00wh);
}

function 
drawParticles() {
  
hue += 0.5;
  
ctx.fillStyle = `hsla(${hue}, 50%, 50%, 0.5)`;
  
particles.forEach(=> {
    
p.draw();
    
    
let pos vec2.scalep.pos1.0 size );//.div(size);
    
let v= {x:1y:1};
    if(
pos.>= && pos.columns && pos.>= && pos.rows) {
      
field[Math.floor(pos.x)][Math.floor(pos.y)];
    }
    
    
p.move(v);
    
p.wrap();
  });
}

function 
drawFlowField() {
  
  for(
let x 0columnsx++) {
    for(
let y 0rowsy++) {
      
ctx.beginPath();
      
let x1 x*size;
      
let y1 y*size;
      
ctx.moveTo(x1y1);
      
ctx.lineTo(x1 field[x][y].x*sizey1 field[x][y].y*size);
      
ctx.stroke();
    }
  }
  
  
}

setup();
draw(performance.now());


Things to Try


• Use an overlay canvas with a pattern on to control the noise (e.g., large letters/text) so when the particles go over these areas that are 'black' with the text pixels - the noise increases or decreases. So you see a hidden pattern in the noise generated

• Try Other noise patterns - used a simple Perlin smooth noise but ohter noise patterns can produce other results (e.g., fractal brownian noise)

• Particles with different shapes - instead of just a point - they could be short lines or an x-shape - as it moves around and isn't cleared it creates a pen-like style

• Add user interaction - so the user can drag the mouse around on screen to add noise? Or control the noise directoin/pattern.

• Other colors - maybe take the color from a 'texture' instead of a hard coded value?




Resources & Links


• JavaScript Notepad (code/live demo) LINK

• Simplier (earlier) version with no options LINK














101 WebGPU Programming Projects. WebGPU Development Pixels - coding fragment shaders from post processing to ray tracing! WebGPU by Example: Fractals, Image Effects, Ray-Tracing, Procedural Geometry, 2D/3D, Particles, Simulations WebGPU Games WGSL 2d 3d interactive web-based fun learning WebGPU Compute WebGPU API - Owners WebGPU Development Cookbook - coding recipes for all your webgpu needs! WebGPU & WGSL Essentials: A Hands-On Approach to Interactive Graphics, Games, 2D Interfaces, 3D Meshes, Animation, Security and Production Kenwright graphics and animations using the webgpu api 12 week course kenwright learn webgpu api kenwright programming compute and graphics applications with html5 and webgpu api kenwright real-time 3d graphics with webgpu kenwright webgpu for dummies kenwright webgpu wgsl compute graphics all in one kenwright webgpu api develompent a quick start guide kenwright webgpu by example 2022 kenwright webgpu gems kenwright webgpu interactive compute and graphics visualization cookbook kenwright wgsl webgpu shading language cookbook kenwright WebGPU Shader Language Development: Vertex, Fragment, Compute Shaders for Programmers Kenwright WGSL Fundamentals book kenwright WebGPU Data Visualization Cookbook kenwright Special Effects Programming with WebGPU kenwright WebGPU Programming Guide: Interactive Graphics and Compute Programming with WebGPU & WGSL kenwright Ray-Tracing with WebGPU kenwright



 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2025 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.