really bad game by corbun fixed

This sketch creates an interactive liquid-metal surface that responds to mouse movement with rippling shader effects and a generative techno soundscape. As you move your cursor, custom GLSL shaders render shimmering visuals while p5.sound synthesizes evolving tones with distortion, delay, and reverb.

🧪 Try This!

Experiment with the code by making these changes:

  1. Make the synth louder — The maximum volume the synth reaches when you move fastest will increase, making the sketch more aggressive sonically.
  2. Make glitches happen more often — Lowering the velocity thresholds means even gentle mouse movement will trigger the random frequency jumps.
  3. Add a deeper starting frequency — At zero mouse velocity, the synth will be in a lower, bassier register instead of mid-range.
  4. Make ripples fade faster — The liquid-metal surface will settle down more quickly after you stop moving the mouse, creating a snappier feel.
  5. Increase delay echo intensity — When moving fast, echoes will pile up more densely, creating a layered, chaotic sound.
Prefer the full editor? Open it there →

📖 About This Sketch

This sketch blends visual and audio synthesis into a single interactive experience. Move your mouse across the canvas to sculpt a shimmering, liquid-chrome surface rendered by a custom GLSL fragment shader. The faster you move, the more intense the visual ripples and the more glitchy and distorted the synthesized techno soundscape becomes—a perfect example of how p5.sound, WEBGL shaders, and mouse interaction can create immersive, gesture-driven art.

The code is organized into three main layers: a preload() function that loads custom shaders and fonts, a setup() function that initializes the p5.sound audio chain (oscillator, reverb, delay, and distortion), and a draw() loop that calculates mouse velocity every frame, maps that velocity to audio parameters, and passes shader uniforms to render the interactive surface. By studying this sketch, you will learn how to integrate GLSL shaders with p5.js, chain audio effects in real time, and create bidirectional feedback between gesture and sound.

⚙️ How It Works

  1. When the sketch loads, preload() loads two GLSL shader files (vertex.glsl and fragment.glsl) and a web font, then initializes mouse position tracking variables. setup() creates a fullscreen WEBGL canvas, starts a sawtooth-wave synthesizer routed through reverb, delay, and distortion effects, and calls userStartAudio() to enable audio in modern browsers.
  2. Every frame, draw() calculates the current mouse velocity by comparing the current mouse position to the previous frame's position, then dampens that velocity by 0.95 to create a settling-ripple effect.
  3. The velocity magnitude (the total speed regardless of direction) is calculated using the Pythagorean theorem and mapped to synthesizer frequency, amplitude, and distortion amount—faster movement triggers higher pitch, louder volume, and more glitch.
  4. Random frequency jumps are added when velocity exceeds 30 or 60 pixels per frame, creating unpredictable glitchy bursts when you move aggressively.
  5. Delay feedback is also randomized when velocity is high, adding echo instability that makes the sound feel chaotic and responsive.
  6. Finally, all this data is passed as uniforms to the GLSL shader (u_resolution, u_mouse, u_velocityMagnitude, u_time), which renders the liquid-chrome effect on a fullscreen rectangle, and the sketch draws 'made by corbun' text in the bottom-left corner.

🎓 Concepts You'll Learn

GLSL shaders and WEBGL renderingMouse velocity calculation and dampingReal-time audio parameter mappingp5.sound synthesis (oscillators, reverb, delay, distortion)Gesture-driven interaction designShader uniforms and fragment processing

📝 Code Breakdown

preload()

preload() runs before setup() and is the only place where loadShader() and loadFont() will work reliably. Use it to prepare all assets your sketch needs.

function preload() {
  // Load the custom shaders
  // Ensure 'vertex.glsl' and 'fragment.glsl' files are present and contain GLSL code
  myShader = loadShader('vertex.glsl', 'fragment.glsl');
  
  // Load a font for text in WEBGL mode
  // Using Fontsource CDN for reliable WEBGL-compatible fonts
  myFont = loadFont('https://unpkg.com/@fontsource/roboto@latest/files/roboto-latin-400-normal.woff');

  // Initialize velocity variables for the first frame
  prevMouseX = mouseX;
  prevMouseY = mouseY;
  velocityX = 0;
  velocityY = 0;
  velocityMagnitude = 0;
}
Line-by-line explanation (4 lines)

🔧 Subcomponents:

function-call Load Custom Shaders myShader = loadShader('vertex.glsl', 'fragment.glsl');

Loads the vertex and fragment shader files that will render the liquid-chrome effect

function-call Load Web Font myFont = loadFont('https://unpkg.com/@fontsource/roboto@latest/files/roboto-latin-400-normal.woff');

Loads a WEBGL-compatible font from a CDN so text renders correctly in 3D mode

initialization Initialize Velocity Tracking prevMouseX = mouseX; prevMouseY = mouseY; velocityX = 0; velocityY = 0;

Sets up variables to track mouse movement and calculate velocity on the first frame

myShader = loadShader('vertex.glsl', 'fragment.glsl');
Loads two GLSL shader files: vertex.glsl (handles geometry) and fragment.glsl (handles colors and effects). This must happen in preload() before setup() runs.
myFont = loadFont('https://unpkg.com/@fontsource/roboto@latest/files/roboto-latin-400-normal.woff');
Loads a font from a CDN. In WEBGL mode, regular fonts don't work, so p5.js needs a special WOFF font file loaded before setup().
prevMouseX = mouseX;
Stores the initial mouse X position so we can calculate velocity (change in position) on the next frame.
velocityX = 0;
Initializes horizontal velocity to zero so the first frame doesn't have a garbage value.

setup()

setup() runs once at startup. Create your canvas, set up audio chains, and initialize global variables here. Audio effects in p5.sound are chained by calling .process() on the effect with the source as the first argument—effects stack and all process the same signal.

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  noStroke(); // No p5.js strokes, shader handles all rendering

  // Set the loaded font and text size for the "made by corbun" text
  textFont(myFont);
  textSize(12);
  fill(255); // White text color

  // Initialize p5.sound components for techno music
  // Using a sawtooth wave for a typical techno synth sound
  technoSynth = new p5.Oscillator('sawtooth');
  technoSynth.amp(0); // Start silent
  technoSynth.freq(100); // Base frequency
  technoSynth.start();

  // Add reverb for a spacious, metallic sound
  technoReverb = new p5.Reverb();
  technoReverb.process(technoSynth, 3, 2); // 3 seconds decay, 2% dry/wet
  technoReverb.amp(0.1); // Subtle reverb volume

  // Add delay for a rhythmic echo effect
  technoDelay = new p5.Delay();
  technoDelay.process(technoSynth, 0.25, 0.5, 2300); // 0.25 delay time, 0.5 feedback, 2300 ms filter frequency
  technoDelay.amp(0.1); // Subtle delay volume

  // Add a distortion effect for the glitchy sound
  technoDistortion = new p5.Distortion(0.0); // Start with no distortion
  technoDistortion.process(technoSynth);
  technoDistortion.amp(0.1); // Subtle distortion volume

  // Start the Web Audio context. This is required for audio to play in modern browsers.
  userStartAudio();
}
Line-by-line explanation (10 lines)

🔧 Subcomponents:

initialization Create WEBGL Canvas createCanvas(windowWidth, windowHeight, WEBGL);

Creates a fullscreen 3D canvas using WEBGL mode, which is required to use custom shaders

initialization Build Audio Effect Chain technoSynth = new p5.Oscillator('sawtooth'); technoSynth.amp(0); technoSynth.freq(100); technoSynth.start(); technoReverb = new p5.Reverb(); technoReverb.process(technoSynth, 3, 2); technoDelay = new p5.Delay(); technoDelay.process(technoSynth, 0.25, 0.5, 2300); technoDistortion = new p5.Distortion(0.0); technoDistortion.process(technoSynth);

Creates a sound generator (sawtooth oscillator) and chains it through reverb, delay, and distortion effects so they all process the same signal

createCanvas(windowWidth, windowHeight, WEBGL);
Creates a fullscreen canvas in WEBGL mode. WEBGL is 3D graphics that allows custom shaders to run.
noStroke();
Disables outlines on shapes. The shader handles all visual rendering, so p5.js shape outlines aren't needed.
textFont(myFont);
Sets the font for any text() calls to use the WEBGL-compatible font we loaded in preload().
technoSynth = new p5.Oscillator('sawtooth');
Creates an oscillator that generates a sawtooth wave—a bright, buzzy waveform perfect for synth bass.
technoSynth.amp(0);
Starts the oscillator silent (amplitude 0) so it doesn't blare noise until draw() modulates its volume based on mouse speed.
technoSynth.start();
Begins the oscillator running. From this point on, it generates sound continuously.
technoReverb = new p5.Reverb(); technoReverb.process(technoSynth, 3, 2);
Creates a reverb effect and connects it to process the oscillator. The parameters set 3-second decay and 2% dry/wet mix, creating a spacious metallic room sound.
technoDelay = new p5.Delay(); technoDelay.process(technoSynth, 0.25, 0.5, 2300);
Creates a delay effect (echo) with 0.25-second delay time, 0.5 feedback (how much echo echoes), and 2300 Hz filter frequency for a lo-fi effect.
technoDistortion = new p5.Distortion(0.0); technoDistortion.process(technoSynth);
Creates a distortion effect starting at 0 (no distortion). This will be ramped up by draw() when the mouse moves fast.
userStartAudio();
Initializes the Web Audio API context. Modern browsers require user interaction before audio can play; this call happens at startup and enables audio to work.

draw()

draw() runs 60 times per second. Every frame, we calculate how fast the mouse moved, map that speed to audio parameters, and send data to the shader. The frame loop is where all real-time responsiveness happens. Notice how damping (multiplying by 0.95) creates inertia—velocity doesn't drop to zero instantly but decays smoothly, which is key to the liquid feel.

function draw() {
  // Calculate mouse velocity for this frame
  // Multiply by 0.5 to make the effect less aggressive and allow for smoother transitions
  velocityX = (mouseX - prevMouseX) * 0.5;
  velocityY = (mouseY - prevMouseY) * 0.5;

  // Store current mouse position for the next frame's velocity calculation
  prevMouseX = mouseX;
  prevMouseY = mouseY;

  // Smoothly decay velocity over time, making ripples settle
  // This gives the "liquid mercury" feel where movement creates ripples that fade
  velocityX *= 0.95;
  velocityY *= 0.95;

  // Calculate the magnitude (length) of the velocity vector
  velocityMagnitude = sqrt(velocityX * velocityX + velocityY * velocityY);

  // Modulate techno music based on velocityMagnitude
  // Map velocityMagnitude to frequency and amplitude of the synth
  // This makes the music more intense and glitchy as you move the mouse faster

  // Base frequency mapping
  let baseFreq = map(velocityMagnitude, 0, 100, 50, 400); // Map velocity (0-100) to frequency (50-400 Hz)
  let freq = baseFreq;

  // Add random frequency jumps for glitchiness when velocity is high
  if (velocityMagnitude > 30) {
    freq += random(-20, 20); // Add a small random offset
  }
  if (velocityMagnitude > 60) {
    freq += random(-50, 50); // Add a larger random offset
  }
  freq = constrain(freq, 50, 600); // Keep frequency within a reasonable range

  let amp = map(velocityMagnitude, 0, 100, 0, 0.2); // Map velocity (0-100) to amplitude (0-0.2 volume)

  technoSynth.freq(freq);
  technoSynth.amp(amp, 0.1); // Smooth amplitude change over 0.1 seconds

  // Modulate distortion amount based on velocityMagnitude
  // Faster movement = more distortion
  let distortionAmount = map(velocityMagnitude, 0, 100, 0, 0.5); // Map velocity to distortion amount (0-0.5)
  technoDistortion.amount.value = distortionAmount;

  // Randomize delay feedback slightly for glitchiness when velocity is high
  if (velocityMagnitude > 40) {
    let delayFeedback = map(velocityMagnitude, 0, 100, 0.5, 0.7); // Base feedback
    delayFeedback += random(-0.05, 0.05); // Add random variation
    delayFeedback = constrain(delayFeedback, 0.4, 0.8); // Keep feedback within a reasonable range
    technoDelay.feedback.value = delayFeedback;
  } else {
    technoDelay.feedback.value = 0.5; // Default feedback when calm
  }

  // Set the custom shader to be used for rendering
  shader(myShader);

  // Pass uniforms (variables) to the fragment shader
  myShader.setUniform('u_resolution', [width, height]); // Canvas resolution
  myShader.setUniform('u_mouse', [mouseX, mouseY]);     // Mouse position
  myShader.setUniform('u_velocityMagnitude', velocityMagnitude); // Mouse velocity magnitude
  myShader.setUniform('u_time', millis() / 1000.0);      // Time in seconds

  // Draw a rectangle that covers the entire canvas.
  // The shader will then render the liquid chrome effect on this rectangle.
  rect(0, 0, width, height);

  // Draw "made by corbun" text
  // In WEBGL, (0,0) is the center. To place in bottom-left, use negative width/2 and positive height/2.
  text("made by corbun", -width/2 + 10, height/2 - 10);
}
Line-by-line explanation (16 lines)

🔧 Subcomponents:

calculation Calculate Mouse Velocity velocityX = (mouseX - prevMouseX) * 0.5; velocityY = (mouseY - prevMouseY) * 0.5;

Subtracts the previous frame's mouse position from the current position to measure how far the mouse moved this frame

calculation Dampen Velocity Over Time velocityX *= 0.95; velocityY *= 0.95;

Reduces velocity by 5% each frame so ripples slow down and fade even if the mouse stops moving

calculation Calculate Velocity Magnitude velocityMagnitude = sqrt(velocityX * velocityX + velocityY * velocityY);

Computes the total speed regardless of direction using the Pythagorean theorem

calculation Map Velocity to Synth Frequency let baseFreq = map(velocityMagnitude, 0, 100, 50, 400); let freq = baseFreq;

Converts mouse speed into a synth frequency—faster movement = higher pitch

conditional Add Glitchy Frequency Jumps if (velocityMagnitude > 30) { freq += random(-20, 20); } if (velocityMagnitude > 60) { freq += random(-50, 50); }

When moving fast enough, adds random frequency offsets to create unpredictable pitch jumps that sound chaotic and digital

calculation Modulate Distortion Amount let distortionAmount = map(velocityMagnitude, 0, 100, 0, 0.5); technoDistortion.amount.value = distortionAmount;

Maps mouse speed to distortion intensity—faster movement adds more granular, gritty texture to the synth

conditional Modulate Delay Feedback if (velocityMagnitude > 40) { let delayFeedback = map(velocityMagnitude, 0, 100, 0.5, 0.7); delayFeedback += random(-0.05, 0.05); delayFeedback = constrain(delayFeedback, 0.4, 0.8); technoDelay.feedback.value = delayFeedback; }

When moving aggressively, increases and randomizes echo feedback so echoes become more intense and unstable

function-call Pass Data to Shader myShader.setUniform('u_resolution', [width, height]); myShader.setUniform('u_mouse', [mouseX, mouseY]); myShader.setUniform('u_velocityMagnitude', velocityMagnitude); myShader.setUniform('u_time', millis() / 1000.0);

Sends mouse position, velocity, canvas size, and elapsed time to the GLSL shader so it can render effects based on this data

velocityX = (mouseX - prevMouseX) * 0.5;
Calculates how far the mouse moved horizontally this frame by subtracting last frame's X from current X. Multiplying by 0.5 reduces jitter and makes the motion smoother.
velocityY = (mouseY - prevMouseY) * 0.5;
Calculates vertical movement the same way as horizontal movement.
prevMouseX = mouseX;
Saves the current mouse X position so we can use it to calculate velocity on the next frame.
velocityX *= 0.95;
Multiplies velocity by 0.95 each frame, shrinking it by 5%. This makes ripples settle over time and gives a fluid, decaying feel.
velocityMagnitude = sqrt(velocityX * velocityX + velocityY * velocityY);
Uses the Pythagorean theorem to calculate the total speed in any direction. This single number (magnitude) is what we use to modulate audio and visuals.
let baseFreq = map(velocityMagnitude, 0, 100, 50, 400);
Uses map() to convert velocity (expected range 0–100) to synth frequency (50–400 Hz). At zero velocity, frequency is 50 Hz; at velocity 100, it's 400 Hz.
if (velocityMagnitude > 30) { freq += random(-20, 20); }
When you're moving moderately fast, adds a random pitch jump up to ±20 Hz. This makes the synth sound less predictable and more glitchy.
freq = constrain(freq, 50, 600);
Clamps the frequency between 50 and 600 Hz so it never goes outside the audio range we want, preventing weird sounds.
technoSynth.freq(freq);
Actually sets the oscillator's frequency to the calculated value.
technoSynth.amp(amp, 0.1);
Sets the oscillator's amplitude (volume) and smooths the change over 0.1 seconds so the volume glide feels musical, not sudden.
technoDistortion.amount.value = distortionAmount;
Sets how much distortion to apply. Higher values make the sound grittier and more saturated.
shader(myShader);
Activates the loaded GLSL shader so all subsequent drawing uses this shader instead of the default p5.js rendering.
myShader.setUniform('u_resolution', [width, height]);
Passes the canvas width and height to the shader as a uniform (a constant value the shader can read). The shader uses this to map pixel coordinates.
myShader.setUniform('u_mouse', [mouseX, mouseY]);
Passes the current mouse position to the shader so the shader can draw ripples centered at the cursor.
rect(0, 0, width, height);
Draws a rectangle covering the entire canvas. The shader runs on every pixel of this rectangle, rendering the liquid-chrome effect.
text("made by corbun", -width/2 + 10, height/2 - 10);
In WEBGL, (0, 0) is the canvas center. This places the text 10 pixels from the left edge and 10 pixels from the bottom edge.

windowResized()

windowResized() is a special p5.js function that runs automatically whenever the window is resized. Always update shader uniforms here if they depend on canvas size or window dimensions. This keeps your shader in sync with the rendered output.

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
  // Update the resolution uniform in the shader when the canvas is resized
  myShader.setUniform('u_resolution', [width, height]);
}
Line-by-line explanation (2 lines)

🔧 Subcomponents:

function-call Resize Canvas resizeCanvas(windowWidth, windowHeight);

Adjusts the canvas dimensions whenever the browser window is resized

function-call Update Shader Resolution myShader.setUniform('u_resolution', [width, height]);

Tells the shader about the new canvas size so it can recalculate pixel positions correctly

resizeCanvas(windowWidth, windowHeight);
Automatically resizes the p5.js canvas to match the browser window size, keeping the sketch fullscreen.
myShader.setUniform('u_resolution', [width, height]);
Updates the u_resolution uniform in the shader with the new canvas dimensions. Without this, the shader would still think the old resolution was correct and render effects incorrectly at the new size.

📦 Key Variables

myShader p5.Shader

Holds the loaded GLSL shader program (vertex and fragment shaders). This is what renders the liquid-chrome visual effect.

myShader = loadShader('vertex.glsl', 'fragment.glsl');
prevMouseX number

Stores the mouse X position from the previous frame so we can calculate how far the mouse moved this frame.

prevMouseX = mouseX;
prevMouseY number

Stores the mouse Y position from the previous frame for vertical movement calculation.

prevMouseY = mouseY;
velocityX number

Stores the horizontal component of mouse velocity (pixels per frame). Damped by 0.95 each frame so it decays smoothly.

velocityX = (mouseX - prevMouseX) * 0.5;
velocityY number

Stores the vertical component of mouse velocity (pixels per frame).

velocityY = (mouseY - prevMouseY) * 0.5;
velocityMagnitude number

Stores the total speed (length of the velocity vector) regardless of direction. Used to modulate audio and visual intensity.

velocityMagnitude = sqrt(velocityX * velocityX + velocityY * velocityY);
technoSynth p5.Oscillator

The synthesizer that generates sound. A sawtooth wave oscillator whose frequency and amplitude are modulated by mouse velocity.

technoSynth = new p5.Oscillator('sawtooth');
technoReverb p5.Reverb

Audio effect that adds spacious, reflective quality to the synth—simulates sound bouncing in a room.

technoReverb = new p5.Reverb();
technoDelay p5.Delay

Audio effect that creates echoes of the synth. Feedback is randomized when moving fast to add glitch.

technoDelay = new p5.Delay();
technoDistortion p5.Distortion

Audio effect that adds gritty, saturated texture to the synth. Amount increases with mouse velocity to sound more chaotic when moving fast.

technoDistortion = new p5.Distortion(0.0);
myFont p5.Font

Stores a WEBGL-compatible font loaded from a CDN. Used to render the 'made by corbun' text.

myFont = loadFont('https://unpkg.com/@fontsource/roboto@latest/files/roboto-latin-400-normal.woff');

🔧 Potential Improvements (5)

Here are some ways this code could be enhanced:

PERFORMANCE draw() - shader uniform updates

u_resolution is recalculated and sent to the shader every frame even though the canvas size rarely changes

💡 Move myShader.setUniform('u_resolution', [width, height]); to windowResized() only. Only send it on resize, not every frame. This reduces unnecessary GPU communication.

BUG draw() - audio chain routing

The audio effects (reverb, delay, distortion) are all processing the synth, but the final audio output may be unclear about which effect dominates—all three are competing

💡 Chain effects serially instead of in parallel: route synth → reverb → delay → distortion. Currently reverb and delay both receive the synth directly. Use technoDelay.process(technoReverb) and technoDistortion.process(technoDelay) to create a serial chain.

STYLE preload() - velocity initialization

prevMouseX, prevMouseY, velocityX, velocityY, and velocityMagnitude are initialized in preload() but they are global variables that should ideally be declared at the top of the file

💡 Declare all global variables (including myShader, myFont, technoSynth, etc.) at the top of sketch.js with clear comments. Initialize them to null or 0. This makes the code structure clearer and easier to maintain.

FEATURE draw() - audio parameter mapping

The audio currently only responds to velocity magnitude. Touch pressure (if on a touch device) or audio input could add another dimension of control.

💡 Add optional controls: map mouseIsPressed to reverb dry/wet, or use the microphone (getAudioContext) to let ambient sound modulate synth pitch. This creates more immersive, multi-sensory feedback.

BUG draw() - text rendering

The 'made by corbun' text is drawn every frame, which is correct, but at very high resolutions or with certain fonts it may appear pixelated or jaggy

💡 Call textAlign(LEFT, BOTTOM) and textSmooth(true) before the text() call to ensure crisp, anti-aliased rendering. Also consider drawing text to a separate graphics buffer and scaling it for consistent quality.

🔄 Code Flow

Code flow showing preload, setup, draw, windowresized

💡 Click on function names in the diagram to jump to their code

graph TD start[Start] --> setup[setup] setup --> shaderload[shader-load] setup --> fontload[font-load] setup --> velocityinit[velocity-init] setup --> canvascreate[canvas-create] setup --> synthchain[synth-chain] setup --> draw[draw loop] click setup href "#fn-setup" click shaderload href "#sub-shader-load" click fontload href "#sub-font-load" click velocityinit href "#sub-velocity-init" click canvascreate href "#sub-canvas-create" click synthchain href "#sub-synth-chain" draw --> velocitycalculation[velocity-calculation] draw --> velocitydamping[velocity-damping] draw --> magnitudecalc[magnitude-calc] draw --> frequencymapping[frequency-mapping] draw --> glitchfrequency[glitch-frequency] draw --> distortionmodulation[distortion-modulation] draw --> delayfeedbackmodulation[delay-feedback-modulation] draw --> shaderuniforms[shader-uniforms] click draw href "#fn-draw" click velocitycalculation href "#sub-velocity-calculation" click velocitydamping href "#sub-velocity-damping" click magnitudecalc href "#sub-magnitude-calc" click frequencymapping href "#sub-frequency-mapping" click glitchfrequency href "#sub-glitch-frequency" click distortionmodulation href "#sub-distortion-modulation" click delayfeedbackmodulation href "#sub-delay-feedback-modulation" click shaderuniforms href "#sub-shader-uniforms" draw --> windowresized[windowresized] windowresized --> canvasresize[canvas-resize] windowresized --> uniformupdate[uniform-update] click windowresized href "#fn-windowresized" click canvasresize href "#sub-canvas-resize" click uniformupdate href "#sub-uniform-update" velocitycalculation --> velocitydamping velocitydamping --> magnitudecalc magnitudecalc --> frequencymapping frequencymapping --> glitchfrequency frequencymapping --> distortionmodulation distortionmodulation --> delayfeedbackmodulation shaderuniforms --> draw

❓ Frequently Asked Questions

What visual effects can users expect from the really bad game by corbun fixed sketch?

Users will see a shimmering, liquid-metal surface that responds to mouse movements with ripples and glitches, creating a dynamic and immersive visual experience.

How can users interact with the sketch to influence the sound and visuals?

Users can swirl their mouse across the canvas, which generates real-time ripples and glitches while simultaneously sculpting an evolving techno soundscape based on their gestures.

What creative coding techniques are showcased in this p5.js sketch?

The sketch demonstrates the use of shaders for visual effects, sound synthesis with p5.js, and real-time interaction to create a multisensory experience.

Preview

really bad game by corbun fixed - p5.js creative coding sketch preview
Sketch Preview
Code flow diagram showing the structure of really bad game by corbun fixed - Code flow showing preload, setup, draw, windowresized
Code Flow Diagram