AI Synth Pad - Interactive Musical Grid Click the colorful pads to play musical tones! A 4x4 grid o
58 views ยท Dec 16, 2025
Create a Synth Pad with Visual Feedback! A 4x4 grid of colorful square pads on a dark background. Wh
๐ Embed Code
Copy this code to embed this sketch on your website:
<iframe src="https://p5js.ai/embed/72fee94d-dfd4-4009-8ee4-87a5a48517d5" width="400" height="400" frameborder="0" allow="autoplay" title="AI Synth Pad - Interactive Musical Grid Click the colorful pads to play musical tones! A 4x4 grid o"></iframe>
Adjust width and height as needed. Preview embed โ
โ About This Sketch 3 questions
What visual elements does the AI Synth Pad sketch feature?
The sketch displays a 4x4 grid of colorful square pads against a dark background, each pad illuminating with a glow effect when interacted with.
How can users interact with the AI Synth Pad to create music?
Users can click on the colorful pads to play different musical tones, corresponding to MIDI notes in a C major scale.
What creative coding concepts are showcased in the AI Synth Pad sketch?
The sketch demonstrates concepts like object-oriented programming through the Pad class and real-time audio generation using p5.js's oscillator features.
๐ฌ AI Chat History 2 messages
๐ค You
Create a Synth Pad with Visual Feedback! A 4x4 grid of colorful square pads on a dark background. When you click a pad, it plays a tone using p5.Oscillator and the pad visually pulses with a bright glow effect. Each pad should be a different color and play a different musical note. Show the grid clearly with visible borders. Make sure the canvas displays the pads!
๐ค AI
This is a fantastic idea for an interactive synth pad! We'll create a 4x4 grid of colorful pads, each playing a different musical note when clicked, and visually pulsing with a glow effect.
To achieve this, we'll use `p5.js` for drawing and interaction, and the `p5.sound` add-on for the audio synthesis. `p5.sound` is a PREFERRED library as it integrates seamlessly with p5.js and provides powerful audio capabilities like oscillators.
Here's how we'll set up your project:
1. **index.html**: We'll add the CDN links for `p5.js` and `p5.sound.min.js`. The load order is crucial: `p5.js` first, then `p5.sound`, then your `sketch.js`.
2. **style.css**: Your current CSS is perfect for making the canvas fill the window and removing default margins.
3. **sketch.js**:
* We'll define a `Pad` class to manage each individual synth pad's position, size, color, oscillator, and glow effect.
* The `setup()` function will initialize the canvas, set up the grid layout, create 16 `Pad` objects, and unlock the audio context.
* The `draw()` function will continuously update and display all the pads.
* `mousePressed()` will detect which pad was clicked and trigger its sound and glow.
* `windowResized()` will ensure the grid adjusts to different screen sizes.
---
### Understanding `p5.sound` Oscillators and Notes
We'll use `p5.Oscillator` to generate the sound for each pad. An oscillator creates a periodic waveform (like sine, square, saw, or triangle) at a specific frequency, which we perceive as a musical note.
To easily assign musical notes, we can use MIDI (Musical Instrument Digital Interface) numbers. MIDI 60 corresponds to C4 (middle C), 62 to D4, 64 to E4, and so on. `p5.sound` provides a handy function called `midiToFreq()` which converts a MIDI number directly into its corresponding frequency in Hertz (Hz). This makes assigning musical scales very straightforward.
When a pad is clicked, we'll use `oscillator.amp(targetLevel, fadeTime)` to smoothly fade the sound in and out, giving a more musical "pluck" or "pad" effect rather than an abrupt on/off. We'll also use `userStartAudio()` in `setup()` to ensure the web audio context is unlocked by a user gesture, which is a modern browser security requirement.
---
### Step-by-Step Code
Here are the updated files for your project:
#### `index.html`
We need to add the `p5.js` and `p5.sound` CDN links in the `<head>` section, before `sketch.js`. Remember, `p5.sound` must be loaded *after* `p5.js` because it extends the `p5` object.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Synth Pad with Visual Feedback</title>
<link rel="stylesheet" href="style.css">
<!-- Load p5.js core library -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/p5.min.js"></script>
<!-- Load p5.sound add-on library -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/addons/p5.sound.min.js"></script>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
```
#### `style.css`
Your current `style.css` is perfect for setting up the canvas to fill the window and remove default browser margins.
```css
body {
margin: 0;
padding: 0;
overflow: hidden; /* Prevents scrollbars */
}
canvas {
display: block; /* Removes extra space below the canvas */
}
```
#### `sketch.js`
This file contains the core logic for creating the pads, handling audio, and drawing the visuals.
```js
// Array to hold all the pad objects
let pads = [];
// Grid dimensions
const cols = 4;
const rows = 4;
// Size of each pad (calculated dynamically)
let padSize;
// Margins to center the grid on the canvas
let marginX, marginY;
// How fast the glow effect fades out (0.95 means it keeps 95% of its brightness each frame)
const glowDecay = 0.95;
// MIDI notes for a C major scale across a few octaves
// Starting from C4 (MIDI 60) up to D6 (MIDI 86)
// This array has 16 notes, matching our 4x4 grid.
const midiNotes = [
60, 62, 64, 65, // C4, D4, E4, F4
67, 69, 71, 72, // G4, A4, B4, C5
74, 76, 77, 79, // D5, E5, F5, G5
81, 83, 84, 86 // A5, B5, C6, D6
];
/**
* Class representing a single synth pad.
* Each pad has its own position, size, color, musical note, and oscillator.
*/
class Pad {
constructor(x, y, size, color, noteMIDI) {
this.x = x;
this.y = y;
this.size = size;
this.color = color;
this.note = noteMIDI;
this.freq = midiToFreq(noteMIDI); // Convert MIDI note number to frequency in Hz
// Create a p5.Oscillator (sine wave by default)
this.oscillator = new p5.Oscillator('sine');
this.oscillator.amp(0); // Start with 0 amplitude (silent)
this.oscillator.freq(this.freq); // Set the oscillator's frequency to the pad's note
this.oscillator.start(); // Start the oscillator, but it won't make sound until amp() is > 0
this.glowAlpha = 0; // Initial glow brightness (0 = fully transparent)
}
/**
* Displays the pad on the canvas, including its color, border, and glow effect.
*/
display() {
// Draw the pad base square
fill(this.color);
stroke(255); // White border
strokeWeight(2); // Border thickness
rect(this.x, this.y, this.size, this.size);
// Draw the glow effect if it's visible
if (this.glowAlpha > 0.1) {
noStroke(); // No border for the glow
fill(this.color, this.glowAlpha); // Use the pad's color with the glow's transparency
rect(this.x, this.y, this.size, this.size);
}
}
/**
* Plays the pad's musical note with a short fade-in and fade-out (attack/decay).
* Also triggers the visual glow effect.
*/
play() {
const attackTime = 0.05; // Time in seconds for the sound to fade in
const decayTime = 0.2; // Time in seconds for the sound to fade out after the attack
// Fade in to 0.5 amplitude
this.oscillator.amp(0.5, attackTime);
// Fade out to 0 amplitude after the attack and decay times
this.oscillator.amp(0, attackTime + decayTime);
this.glowAlpha = 200; // Set glow to a bright value
}
/**
* Updates the glow effect, making it fade out over time.
*/
pulse() {
this.glowAlpha *= glowDecay; // Multiply glowAlpha by decay factor each frame
}
/**
* Checks if a given mouse position (mx, my) is inside this pad.
* @param {number} mx - mouseX position
* @param {number} my - mouseY position
* @returns {boolean} True if the mouse is inside the pad, false otherwise.
*/
contains(mx, my) {
return mx > this.x && mx < this.x + this.size &&
my > this.y && my < this.y + this.size;
}
}
/**
* p5.js setup function: Initializes the canvas and pads.
*/
function setup() {
createCanvas(windowWidth, windowHeight);
// Set color mode to HSB for easier color variations (Hue, Saturation, Brightness)
colorMode(HSB, 360, 100, 100);
noStroke(); // By default, don't draw strokes for background
userStartAudio(); // Important for unlocking audio context in modern browsers on user interaction
initializePads(); // Set up the pad grid
}
/**
* Calculates the layout of the pads and creates Pad objects.
* This function is called in setup() and windowResized().
*/
function initializePads() {
pads = []; // Clear any existing pads
// Calculate total grid dimensions (e.g., 80% of canvas width/height)
const totalGridWidth = width * 0.8;
const totalGridHeight = height * 0.8;
// Determine pad size. We want square pads, so use the minimum of the two dimensions,
// divided by the number of columns/rows.
padSize = min(totalGridWidth / cols, totalGridHeight / rows);
// Recalculate actual grid dimensions based on the determined padSize
const actualGridWidth = padSize * cols;
const actualGridHeight = padSize * rows;
// Calculate margins to center the grid on the canvas
marginX = (width - actualGridWidth) / 2;
marginY = (height - actualGridHeight) / 2;
let noteIndex = 0; // Index to cycle through our midiNotes array
// Loop through rows and columns to create each pad
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
// Calculate pad position
const x = marginX + c * padSize;
const y = marginY + r * padSize;
// Generate a unique color using HSB color mode
// Hue ranges from 0 to 360, so we map our note index to this range
const hue = map(noteIndex, 0, midiNotes.length, 0, 360);
const saturation = 80;
const brightness = 90;
const padColor = color(hue, saturation, brightness);
// Get the MIDI note for this pad, cycling through midiNotes if needed
const note = midiNotes[noteIndex % midiNotes.length];
// Create a new Pad object and add it to our pads array
pads.push(new Pad(x, y, padSize, padColor, note));
noteIndex++;
}
}
}
/**
* p5.js draw function: Constantly updates and displays the pads.
*/
function draw() {
background(0); // Dark background
// Loop through all pads and update their glow and display them
for (let pad of pads) {
pad.pulse(); // Update the glow effect
pad.display(); // Draw the pad on the canvas
}
}
/**
* p5.js mousePressed function: Triggered when a mouse button is pressed.
* Checks if any pad was clicked and plays its note.
*/
function mousePressed() {
for (let pad of pads) {
if (pad.contains(mouseX, mouseY)) {
pad.play(); // Play the note and trigger glow for the clicked pad
// No 'break' here, as in some complex layouts, multiple pads might overlap
// For this simple grid, only one will be clicked at a time.
}
}
}
/**
* p5.js windowResized function: Triggered when the browser window is resized.
* Adjusts the canvas size and re-lays out the pads.
*/
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
initializePads(); // Re-initialize pads to adapt to the new window size
}
```
---
### How to Use:
1. **Save the files**: Make sure you have `index.html`, `style.css`, and `sketch.js` in the same folder.
2. **Open `index.html`**: Double-click `index.html` in your browser.
3. **Interact**: Click on the square pads to hear different musical tones and see them pulse!
4. **Resize**: Try resizing your browser window to see how the pads adjust their layout.
This setup provides a responsive and interactive synth pad experience right in your browser! Enjoy making some music!
To achieve this, we'll use `p5.js` for drawing and interaction, and the `p5.sound` add-on for the audio synthesis. `p5.sound` is a PREFERRED library as it integrates seamlessly with p5.js and provides powerful audio capabilities like oscillators.
Here's how we'll set up your project:
1. **index.html**: We'll add the CDN links for `p5.js` and `p5.sound.min.js`. The load order is crucial: `p5.js` first, then `p5.sound`, then your `sketch.js`.
2. **style.css**: Your current CSS is perfect for making the canvas fill the window and removing default margins.
3. **sketch.js**:
* We'll define a `Pad` class to manage each individual synth pad's position, size, color, oscillator, and glow effect.
* The `setup()` function will initialize the canvas, set up the grid layout, create 16 `Pad` objects, and unlock the audio context.
* The `draw()` function will continuously update and display all the pads.
* `mousePressed()` will detect which pad was clicked and trigger its sound and glow.
* `windowResized()` will ensure the grid adjusts to different screen sizes.
---
### Understanding `p5.sound` Oscillators and Notes
We'll use `p5.Oscillator` to generate the sound for each pad. An oscillator creates a periodic waveform (like sine, square, saw, or triangle) at a specific frequency, which we perceive as a musical note.
To easily assign musical notes, we can use MIDI (Musical Instrument Digital Interface) numbers. MIDI 60 corresponds to C4 (middle C), 62 to D4, 64 to E4, and so on. `p5.sound` provides a handy function called `midiToFreq()` which converts a MIDI number directly into its corresponding frequency in Hertz (Hz). This makes assigning musical scales very straightforward.
When a pad is clicked, we'll use `oscillator.amp(targetLevel, fadeTime)` to smoothly fade the sound in and out, giving a more musical "pluck" or "pad" effect rather than an abrupt on/off. We'll also use `userStartAudio()` in `setup()` to ensure the web audio context is unlocked by a user gesture, which is a modern browser security requirement.
---
### Step-by-Step Code
Here are the updated files for your project:
#### `index.html`
We need to add the `p5.js` and `p5.sound` CDN links in the `<head>` section, before `sketch.js`. Remember, `p5.sound` must be loaded *after* `p5.js` because it extends the `p5` object.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Synth Pad with Visual Feedback</title>
<link rel="stylesheet" href="style.css">
<!-- Load p5.js core library -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/p5.min.js"></script>
<!-- Load p5.sound add-on library -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/addons/p5.sound.min.js"></script>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
```
#### `style.css`
Your current `style.css` is perfect for setting up the canvas to fill the window and remove default browser margins.
```css
body {
margin: 0;
padding: 0;
overflow: hidden; /* Prevents scrollbars */
}
canvas {
display: block; /* Removes extra space below the canvas */
}
```
#### `sketch.js`
This file contains the core logic for creating the pads, handling audio, and drawing the visuals.
```js
// Array to hold all the pad objects
let pads = [];
// Grid dimensions
const cols = 4;
const rows = 4;
// Size of each pad (calculated dynamically)
let padSize;
// Margins to center the grid on the canvas
let marginX, marginY;
// How fast the glow effect fades out (0.95 means it keeps 95% of its brightness each frame)
const glowDecay = 0.95;
// MIDI notes for a C major scale across a few octaves
// Starting from C4 (MIDI 60) up to D6 (MIDI 86)
// This array has 16 notes, matching our 4x4 grid.
const midiNotes = [
60, 62, 64, 65, // C4, D4, E4, F4
67, 69, 71, 72, // G4, A4, B4, C5
74, 76, 77, 79, // D5, E5, F5, G5
81, 83, 84, 86 // A5, B5, C6, D6
];
/**
* Class representing a single synth pad.
* Each pad has its own position, size, color, musical note, and oscillator.
*/
class Pad {
constructor(x, y, size, color, noteMIDI) {
this.x = x;
this.y = y;
this.size = size;
this.color = color;
this.note = noteMIDI;
this.freq = midiToFreq(noteMIDI); // Convert MIDI note number to frequency in Hz
// Create a p5.Oscillator (sine wave by default)
this.oscillator = new p5.Oscillator('sine');
this.oscillator.amp(0); // Start with 0 amplitude (silent)
this.oscillator.freq(this.freq); // Set the oscillator's frequency to the pad's note
this.oscillator.start(); // Start the oscillator, but it won't make sound until amp() is > 0
this.glowAlpha = 0; // Initial glow brightness (0 = fully transparent)
}
/**
* Displays the pad on the canvas, including its color, border, and glow effect.
*/
display() {
// Draw the pad base square
fill(this.color);
stroke(255); // White border
strokeWeight(2); // Border thickness
rect(this.x, this.y, this.size, this.size);
// Draw the glow effect if it's visible
if (this.glowAlpha > 0.1) {
noStroke(); // No border for the glow
fill(this.color, this.glowAlpha); // Use the pad's color with the glow's transparency
rect(this.x, this.y, this.size, this.size);
}
}
/**
* Plays the pad's musical note with a short fade-in and fade-out (attack/decay).
* Also triggers the visual glow effect.
*/
play() {
const attackTime = 0.05; // Time in seconds for the sound to fade in
const decayTime = 0.2; // Time in seconds for the sound to fade out after the attack
// Fade in to 0.5 amplitude
this.oscillator.amp(0.5, attackTime);
// Fade out to 0 amplitude after the attack and decay times
this.oscillator.amp(0, attackTime + decayTime);
this.glowAlpha = 200; // Set glow to a bright value
}
/**
* Updates the glow effect, making it fade out over time.
*/
pulse() {
this.glowAlpha *= glowDecay; // Multiply glowAlpha by decay factor each frame
}
/**
* Checks if a given mouse position (mx, my) is inside this pad.
* @param {number} mx - mouseX position
* @param {number} my - mouseY position
* @returns {boolean} True if the mouse is inside the pad, false otherwise.
*/
contains(mx, my) {
return mx > this.x && mx < this.x + this.size &&
my > this.y && my < this.y + this.size;
}
}
/**
* p5.js setup function: Initializes the canvas and pads.
*/
function setup() {
createCanvas(windowWidth, windowHeight);
// Set color mode to HSB for easier color variations (Hue, Saturation, Brightness)
colorMode(HSB, 360, 100, 100);
noStroke(); // By default, don't draw strokes for background
userStartAudio(); // Important for unlocking audio context in modern browsers on user interaction
initializePads(); // Set up the pad grid
}
/**
* Calculates the layout of the pads and creates Pad objects.
* This function is called in setup() and windowResized().
*/
function initializePads() {
pads = []; // Clear any existing pads
// Calculate total grid dimensions (e.g., 80% of canvas width/height)
const totalGridWidth = width * 0.8;
const totalGridHeight = height * 0.8;
// Determine pad size. We want square pads, so use the minimum of the two dimensions,
// divided by the number of columns/rows.
padSize = min(totalGridWidth / cols, totalGridHeight / rows);
// Recalculate actual grid dimensions based on the determined padSize
const actualGridWidth = padSize * cols;
const actualGridHeight = padSize * rows;
// Calculate margins to center the grid on the canvas
marginX = (width - actualGridWidth) / 2;
marginY = (height - actualGridHeight) / 2;
let noteIndex = 0; // Index to cycle through our midiNotes array
// Loop through rows and columns to create each pad
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
// Calculate pad position
const x = marginX + c * padSize;
const y = marginY + r * padSize;
// Generate a unique color using HSB color mode
// Hue ranges from 0 to 360, so we map our note index to this range
const hue = map(noteIndex, 0, midiNotes.length, 0, 360);
const saturation = 80;
const brightness = 90;
const padColor = color(hue, saturation, brightness);
// Get the MIDI note for this pad, cycling through midiNotes if needed
const note = midiNotes[noteIndex % midiNotes.length];
// Create a new Pad object and add it to our pads array
pads.push(new Pad(x, y, padSize, padColor, note));
noteIndex++;
}
}
}
/**
* p5.js draw function: Constantly updates and displays the pads.
*/
function draw() {
background(0); // Dark background
// Loop through all pads and update their glow and display them
for (let pad of pads) {
pad.pulse(); // Update the glow effect
pad.display(); // Draw the pad on the canvas
}
}
/**
* p5.js mousePressed function: Triggered when a mouse button is pressed.
* Checks if any pad was clicked and plays its note.
*/
function mousePressed() {
for (let pad of pads) {
if (pad.contains(mouseX, mouseY)) {
pad.play(); // Play the note and trigger glow for the clicked pad
// No 'break' here, as in some complex layouts, multiple pads might overlap
// For this simple grid, only one will be clicked at a time.
}
}
}
/**
* p5.js windowResized function: Triggered when the browser window is resized.
* Adjusts the canvas size and re-lays out the pads.
*/
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
initializePads(); // Re-initialize pads to adapt to the new window size
}
```
---
### How to Use:
1. **Save the files**: Make sure you have `index.html`, `style.css`, and `sketch.js` in the same folder.
2. **Open `index.html`**: Double-click `index.html` in your browser.
3. **Interact**: Click on the square pads to hear different musical tones and see them pulse!
4. **Resize**: Try resizing your browser window to see how the pads adjust their layout.
This setup provides a responsive and interactive synth pad experience right in your browser! Enjoy making some music!