Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# Wall of Entropy β€” GPU WebGL pack

This is a small GPU-powered WebGL shader version of the "wall of entropy" (lava-lamp wall). It runs in the browser (no build step), using p5.js to create a WebGL canvas and a GLSL fragment shader for the gooey blobs.
This is a small GPU-powered WebGL shader version of the "wall of entropy" (lava-lamp wall). It runs in the browser (no build step), using p5.js to create a WebGL canvas and a GLSL fragment shader for the gooey blobs. Features a 5x4 grid of lava lamps with truly random behavior using the Web Crypto API.

Files:
- index.html β€” entry page (contains shader sources and loads sketch.js)
- sketch.js β€” p5 sketch that sets up the shader and passes uniforms
- sketch.js β€” p5 sketch that sets up the shader and passes uniforms (including truly random seeds)
- run.bat β€” Windows batch file to easily run the application
- make_zip.ps1 β€” PowerShell script to make gpu_wall.zip on Windows
- make_zip.sh β€” bash script to make gpu_wall.zip on macOS/Linux

How to run locally:
1. Save all files in the same folder.
2. Open index.html in a modern browser (Chrome, Edge, Firefox). For best performance use Chrome/Edge.
1. **Windows (Easy Method)**: Double-click `run.bat` - This will start a local server and open your browser automatically.
2. **Manual Method**:
- Save all files in the same folder.
- Open index.html in a modern browser (Chrome, Edge, Firefox). For best performance use Chrome/Edge.
- Optionally serve with a simple static server (recommended for consistent behavior):
- Python 3: python -m http.server 8000
- Then visit http://localhost:8000/index.html
Expand All @@ -20,4 +23,12 @@ How to run locally:

Loop duration:
- Default loop duration is 12 seconds. To override, add ?loop=20.0 (seconds) to the URL:
index.html?loop=20
index.html?loop=20

Features:
- 5x4 grid of lava lamps (20 lamps total)
- Truly random initialization using Web Crypto API
- High-quality WebGL shader rendering
- Realistic lava lamp physics with organic blob motion
- Vibrant color palettes
- Smooth looping animation
33 changes: 20 additions & 13 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
uniform float u_time;
uniform float u_loop; // loop duration in seconds
uniform float u_pixel_ratio;
uniform float u_random_seeds[20]; // truly random seeds for each lamp (MUST match COLS*ROWS = 5*4 = 20)

// Hash / basic noise (IQ style)
float hash(vec2 p) {
Expand Down Expand Up @@ -96,6 +97,8 @@
// for each cell produce a soft lamp
for (int y = 0; y < ROWS; y++) {
for (int x = 0; x < COLS; x++) {
int lampIndex = y * COLS + x;

// compute cell center in uv-space
vec2 cellCenter = vec2(
-1.0 + (float(x) + 0.5) * cellW,
Expand All @@ -105,8 +108,8 @@
// small local coordinates
vec2 lp = (uv - cellCenter) / 0.9;

// seed per-lamp (deterministic)
float seed = float(x*31 + y*97);
// Use truly random seed for this lamp
float seed = u_random_seeds[lampIndex] * 1000.0;

// animate multiple blobs that rotate/oscillate; make motion depend on timeVec for loopability
float nblobs = 4.0 + mod(seed, 3.0);
Expand All @@ -116,29 +119,33 @@
float phase = seed*0.19 + fi * 2.3;
// angle for orbiting blob: combines global looping angle + seeded offsets
float ang = angle* (0.8 + 0.2*sin(seed*0.7+fi)) + phase;
float r = 0.14 + 0.10 * sin(seed*1.9 + fi*0.5);
float r = 0.16 + 0.12 * sin(seed*1.9 + fi*0.5);
vec2 center = vec2(cos(ang+fi)*r, sin(ang*0.9 - fi*0.6)*r) * (0.9 + 0.2*noise(vec2(seed,fi)));
// jitter with fbm for organic motion (but keep periodic by using timeVec in sample)
vec2 jitterInput = vec2(seed*13.1 + fi*7.3, dot(timeVec, vec2(1.0, -1.0))*0.5);
vec2 jitter = vec2(fbm(jitterInput + vec2(0.0, seed*0.01)), fbm(jitterInput + vec2(1.0, seed*0.01))) * 0.03;
vec2 jitter = vec2(fbm(jitterInput + vec2(0.0, seed*0.01)), fbm(jitterInput + vec2(1.0, seed*0.01))) * 0.04;
vec2 cpos = center + jitter;
float dist = length(lp - cpos);
// soft circular blob with a little noise modulation
float blob = smoothstep(0.45, 0.0, dist + 0.12*fbm((lp - cpos)*3.0 + vec2(seed,fi)));
local += blob * (0.6 + 0.4*sin(seed*1.3 + fi));
// Enhanced soft circular blob with more organic noise modulation for realism
float blobSize = 0.25 + 0.08 * sin(seed*1.1 + fi*0.7);
float noiseAmt = 0.15*fbm((lp - cpos)*4.0 + vec2(seed,fi) + timeVec*0.3);
float blob = smoothstep(blobSize + 0.1, 0.0, dist + noiseAmt);
// Add glow around blobs for realistic lava lamp effect
float glow = smoothstep(blobSize + 0.25, blobSize, dist) * 0.3;
local += (blob + glow) * (0.7 + 0.3*sin(seed*1.3 + fi));
}
local = clamp(local, 0.0, 1.5);
local = clamp(local, 0.0, 2.0);

// color per-lamp from palette seeds
vec3 a = vec3(0.8, 0.2, 0.12) * (0.6 + 0.4*sin(seed*0.3));
vec3 b = vec3(0.2, 0.7, 0.9) * (0.4 + 0.6*cos(seed*0.5));
// Enhanced color per-lamp from palette seeds for more vibrant, realistic lava lamp colors
vec3 a = vec3(0.9, 0.3, 0.15) * (0.7 + 0.3*sin(seed*0.3));
vec3 b = vec3(0.3, 0.8, 1.0) * (0.5 + 0.5*cos(seed*0.5));
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.0, 0.33, 0.67);

float palt = fract(seed*0.13 + 0.2 * sin(seed*0.7));
vec3 lampColor = mix(a, b, smoothstep(0.0, 1.0, palt));
// tint variation
lampColor *= 0.6 + 0.8 * smoothstep(0.0, 1.0, local);
// Enhanced tint variation for depth
lampColor *= 0.7 + 0.9 * smoothstep(0.0, 1.0, local);

// accumulate additive glow
color += lampColor * local * 0.9;
Expand Down
30 changes: 30 additions & 0 deletions run.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@echo off
REM Wall of Entropy - 5x4 Lava Lamp Wall Runner
REM This batch file starts a simple HTTP server and opens the lava lamp wall in your default browser

echo ========================================
echo Wall of Entropy - 5x4 Lava Lamp Wall
echo ========================================
echo.
echo Starting local web server...
echo.

REM Check if Python is available
where python >nul 2>nul
if %errorlevel% == 0 (
echo Using Python to start server on http://localhost:8000
echo.
echo Press Ctrl+C to stop the server when done.
echo.
timeout /t 2 >nul
start http://localhost:8000/index.html
python -m http.server 8000
) else (
echo ERROR: Python is not installed or not in PATH.
echo.
echo Please install Python 3 from https://www.python.org/
echo OR simply open index.html directly in your browser.
echo.
pause
exit /b 1
)
18 changes: 18 additions & 0 deletions sketch.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,29 @@
let theShader;
let loopDuration = 12.0; // seconds (changeable)
let paused = false;
let randomSeeds = []; // truly random seeds for each lamp

function preload() {
// grab shader source from DOM
const vert = document.getElementById('vert').textContent;
const frag = document.getElementById('frag').textContent;
theShader = new p5.Shader(this._renderer, vert, frag);

// Generate truly random seeds using crypto API
const numLamps = 5 * 4; // 5x4 grid
randomSeeds = new Array(numLamps);
if (window.crypto && window.crypto.getRandomValues) {
const randomBytes = new Uint32Array(numLamps);
window.crypto.getRandomValues(randomBytes);
for (let i = 0; i < numLamps; i++) {
randomSeeds[i] = randomBytes[i] / (0xFFFFFFFF + 1); // normalize to [0,1)
}
} else {
// Fallback to Math.random if crypto not available
for (let i = 0; i < numLamps; i++) {
randomSeeds[i] = Math.random();
}
}
}

function setup() {
Expand Down Expand Up @@ -37,6 +54,7 @@ function draw() {
theShader.setUniform('u_loop', loopDuration);
theShader.setUniform('u_resolution', [width, height]);
theShader.setUniform('u_pixel_ratio', window.devicePixelRatio || 1.0);
theShader.setUniform('u_random_seeds', randomSeeds);

rect(-width/2, -height/2, width, height);
}
Expand Down