AI Xylophone - Rainbow Musical Bars Click the colorful bars to play musical notes! A playful xyloph
54 views Β· Dec 16, 2025
Create a Xylophone Instrument! Draw 8 colorful rectangular bars arranged horizontally like a real xy
π Embed Code
Copy this code to embed this sketch on your website:
<iframe src="https://p5js.ai/embed/d684fee9-854d-445d-8fa3-ff8a7ec8cf48" width="400" height="400" frameborder="0" allow="autoplay" title="AI Xylophone - Rainbow Musical Bars Click the colorful bars to play musical notes! A playful xyloph"></iframe>
Adjust width and height as needed. Preview embed β
β About This Sketch 3 questions
What visual elements can I expect from the AI Xylophone sketch?
This sketch features eight colorful rectangular bars arranged horizontally, each representing a musical note, set against a soft gradient background.
How can I interact with the AI Xylophone sketch?
Users can click on the colorful bars to play corresponding musical notes, while mallets visually follow the mouse cursor for a playful experience.
What creative coding techniques are showcased in this p5.js sketch?
The sketch demonstrates object-oriented programming through the creation of XyloBar objects, as well as audio interaction using the p5.sound library.
π¬ AI Chat History 2 messages
π€ You
Create a Xylophone Instrument! Draw 8 colorful rectangular bars arranged horizontally like a real xylophone - rainbow colors from red to violet. When you click on a bar, it plays a musical note (C, D, E, F, G, A, B, C) using p5.Oscillator and the bar bounces with a spring animation. Show mallets that follow the mouse. Wooden frame around the bars. Make it playful and fun!
π€ AI
Hereβs a complete xylophone sketch with 8 rainbow bars, springy bounce animation, mouse-following mallets, and p5.Oscillator notes (CβDβEβFβGβAβBβC).
Sound is made with [p5.Oscillator](https://p5js.org/reference/#/p5.Oscillator) and triggered in `mousePressed()` after `userStartAudio()` (p5.sound best practice).
---
```html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>p5.js Xylophone</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- p5.js core -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/p5.min.js"></script>
<!-- p5.sound addon (for p5.Oscillator) -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/addons/p5.sound.min.js"></script>
<!-- your sketch -->
<script src="sketch.js"></script>
</body>
</html>
```
```css
/* style.css */
body {
margin: 0;
padding: 0;
overflow: hidden;
background: #f0f3ff; /* soft background behind the canvas */
}
canvas {
display: block;
}
```
```js
// sketch.js
// p5.js 1.11.3 + p5.sound xylophone
let bars = [];
let frameRect = { x: 0, y: 0, w: 0, h: 0 };
let audioStarted = false;
// C major scale: C D E F G A B C
const NOTE_DATA = [
{ name: 'C', freq: 261.63 },
{ name: 'D', freq: 293.66 },
{ name: 'E', freq: 329.63 },
{ name: 'F', freq: 349.23 },
{ name: 'G', freq: 392.00 },
{ name: 'A', freq: 440.00 },
{ name: 'B', freq: 493.88 },
{ name: 'C', freq: 523.25 }
];
// rainbow colors from red to violet
const BAR_COLORS = [
'#ff4b4b', // red
'#ff8c3a', // orange
'#ffd93a', // yellow
'#6dd35e', // green
'#40b7ff', // light blue
'#6e5bff', // indigo-ish
'#c54bff', // violet
'#ff7bd5' // pinkish cap C
];
function setup() {
createCanvas(windowWidth, windowHeight);
noStroke();
textFont('sans-serif');
colorMode(RGB);
noCursor(); // hide mouse, we draw mallets instead
// create bars
for (let i = 0; i < NOTE_DATA.length; i++) {
const note = NOTE_DATA[i];
const col = BAR_COLORS[i % BAR_COLORS.length];
bars.push(new XyloBar(i, note.name, note.freq, col));
}
layoutBars();
}
function draw() {
// soft vertical gradient background
drawBackgroundGradient();
// wooden frame
drawFrame();
// update & draw each bar
for (let bar of bars) {
bar.update();
bar.draw();
}
// mallets follow the mouse
drawMallets();
}
function mousePressed() {
// start audio context on first user interaction
if (!audioStarted) {
userStartAudio();
audioStarted = true;
}
// check which bar was clicked
for (let bar of bars) {
if (bar.contains(mouseX, mouseY)) {
bar.hit(); // play note + bounce animation
break;
}
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
layoutBars();
}
// ---------- Layout & frame ----------
function layoutBars() {
if (bars.length === 0) return;
const num = bars.length;
const totalWidth = width * 0.8;
const spacing = totalWidth * 0.02;
const barWidth = (totalWidth - spacing * (num - 1)) / num;
const maxHeight = height * 0.35;
const minHeight = height * 0.18;
const startX = (width - totalWidth) / 2;
const topY = (height - maxHeight) / 2;
for (let i = 0; i < num; i++) {
const t = i / (num - 1); // 0..1, left to right
const h = lerp(maxHeight, minHeight, t); // left bars longer, right shorter
const x = startX + i * (barWidth + spacing);
const y = topY + (maxHeight - h); // align bottoms
const bar = bars[i];
bar.x = x;
bar.y = y;
bar.w = barWidth;
bar.h = h;
}
// wooden frame around bars
const padX = barWidth * 0.6;
const padY = maxHeight * 0.3;
frameRect.x = startX - padX;
frameRect.y = topY - padY * 0.5;
frameRect.w = totalWidth + padX * 2;
frameRect.h = maxHeight + padY;
}
function drawFrame() {
push();
rectMode(CORNER);
const r = min(width, height) * 0.03;
const strokeW = min(width, height) * 0.015;
// outer wooden frame
stroke(90, 60, 30);
strokeWeight(strokeW);
fill(181, 129, 80);
rect(frameRect.x, frameRect.y, frameRect.w, frameRect.h, r);
// inner panel
noStroke();
fill(210, 160, 110);
const inset = frameRect.w * 0.03;
rect(
frameRect.x + inset,
frameRect.y + inset,
frameRect.w - inset * 2,
frameRect.h - inset * 2,
r * 0.7
);
// little "screws" in the corners for fun
const screwR = strokeW * 0.4;
fill(140, 100, 60);
const sx1 = frameRect.x + strokeW * 0.7;
const sx2 = frameRect.x + frameRect.w - strokeW * 0.7;
const sy1 = frameRect.y + strokeW * 0.7;
const sy2 = frameRect.y + frameRect.h - strokeW * 0.7;
circle(sx1, sy1, screwR * 2);
circle(sx2, sy1, screwR * 2);
circle(sx1, sy2, screwR * 2);
circle(sx2, sy2, screwR * 2);
pop();
}
// soft background to keep it playful
function drawBackgroundGradient() {
const topColor = color(240, 245, 255);
const bottomColor = color(220, 235, 255);
noFill();
for (let y = 0; y < height; y++) {
const t = y / max(1, height - 1);
const c = lerpColor(topColor, bottomColor, t);
stroke(c);
line(0, y, width, y);
}
}
// ---------- Mallets ----------
function drawMallets() {
push();
const baseSize = min(width, height);
const headR = baseSize * 0.025;
const offsetX = headR * 2.2;
const headY = mouseY - headR * 0.5;
const handleLen = headR * 5.2;
stroke(120, 80, 40);
strokeWeight(headR * 0.4);
strokeCap(ROUND);
// left handle
line(
mouseX - offsetX,
headY + headR * 0.2,
mouseX - offsetX - handleLen * 0.3,
headY + handleLen
);
// right handle
line(
mouseX + offsetX,
headY + headR * 0.2,
mouseX + offsetX + handleLen * 0.3,
headY + handleLen
);
// mallet heads
noStroke();
fill(250);
circle(mouseX - offsetX, headY, headR * 2);
circle(mouseX + offsetX, headY, headR * 2);
// inner shading
fill(220);
circle(mouseX - offsetX, headY, headR * 1.2);
circle(mouseX + offsetX, headY, headR * 1.2);
pop();
}
// ---------- Bar class ----------
class XyloBar {
constructor(index, noteName, freq, col) {
this.index = index;
this.noteName = noteName;
this.freq = freq;
this.col = color(col);
// layout values (set in layoutBars)
this.x = 0;
this.y = 0;
this.w = 0;
this.h = 0;
// spring animation state
this.yOffset = 0;
this.vy = 0;
// sound
this.osc = new p5.Oscillator('sine');
this.osc.freq(this.freq);
this.osc.amp(0); // start silent
this.oscStarted = false;
}
contains(px, py) {
const yTop = this.y + this.yOffset;
return (
px >= this.x &&
px <= this.x + this.w &&
py >= yTop &&
py <= yTop + this.h
);
}
hit() {
// bounce upwards
this.vy = -4;
// ensure oscillator is started (after userStartAudio)
if (!this.oscStarted) {
this.osc.start();
this.osc.amp(0);
this.oscStarted = true;
}
// quick attack, smooth release
// https://p5js.org/reference/#/p5.Oscillator/amp
this.osc.amp(0.5, 0.02); // target amplitude, ramp time
this.osc.amp(0, 0.4); // fade out
}
update() {
// simple spring: a = -k * x - c * v
const k = 0.15; // spring stiffness
const damping = 0.1; // damping coefficient
const ay = -k * this.yOffset - damping * this.vy;
this.vy += ay;
this.yOffset += this.vy;
// stop tiny jitter
if (abs(this.vy) < 0.001 && abs(this.yOffset) < 0.001) {
this.vy = 0;
this.yOffset = 0;
}
}
draw() {
push();
rectMode(CORNER);
const yTop = this.y + this.yOffset;
// shadow
noStroke();
fill(0, 0, 0, 35);
const shadowOffset = this.h * 0.08;
rect(this.x, yTop + shadowOffset, this.w, this.h, this.w * 0.12);
// main bar
fill(this.col);
rect(this.x, yTop, this.w, this.h, this.w * 0.12);
// top highlight
fill(255, 255, 255, 80);
rect(
this.x,
yTop,
this.w,
this.h * 0.18,
this.w * 0.12,
this.w * 0.12,
0,
0
);
// note label in the center
fill(255);
textAlign(CENTER, CENTER);
const ts = min(this.w * 0.3, this.h * 0.45);
textSize(ts);
text(this.noteName, this.x + this.w / 2, yTop + this.h / 2);
pop();
}
}
```
You can paste these three files over your existing ones and run.
Click each colored bar to hear its note and see it bounce, and move the mouse to wave the mallets around the xylophone.
Sound is made with [p5.Oscillator](https://p5js.org/reference/#/p5.Oscillator) and triggered in `mousePressed()` after `userStartAudio()` (p5.sound best practice).
---
```html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>p5.js Xylophone</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- p5.js core -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/p5.min.js"></script>
<!-- p5.sound addon (for p5.Oscillator) -->
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.3/lib/addons/p5.sound.min.js"></script>
<!-- your sketch -->
<script src="sketch.js"></script>
</body>
</html>
```
```css
/* style.css */
body {
margin: 0;
padding: 0;
overflow: hidden;
background: #f0f3ff; /* soft background behind the canvas */
}
canvas {
display: block;
}
```
```js
// sketch.js
// p5.js 1.11.3 + p5.sound xylophone
let bars = [];
let frameRect = { x: 0, y: 0, w: 0, h: 0 };
let audioStarted = false;
// C major scale: C D E F G A B C
const NOTE_DATA = [
{ name: 'C', freq: 261.63 },
{ name: 'D', freq: 293.66 },
{ name: 'E', freq: 329.63 },
{ name: 'F', freq: 349.23 },
{ name: 'G', freq: 392.00 },
{ name: 'A', freq: 440.00 },
{ name: 'B', freq: 493.88 },
{ name: 'C', freq: 523.25 }
];
// rainbow colors from red to violet
const BAR_COLORS = [
'#ff4b4b', // red
'#ff8c3a', // orange
'#ffd93a', // yellow
'#6dd35e', // green
'#40b7ff', // light blue
'#6e5bff', // indigo-ish
'#c54bff', // violet
'#ff7bd5' // pinkish cap C
];
function setup() {
createCanvas(windowWidth, windowHeight);
noStroke();
textFont('sans-serif');
colorMode(RGB);
noCursor(); // hide mouse, we draw mallets instead
// create bars
for (let i = 0; i < NOTE_DATA.length; i++) {
const note = NOTE_DATA[i];
const col = BAR_COLORS[i % BAR_COLORS.length];
bars.push(new XyloBar(i, note.name, note.freq, col));
}
layoutBars();
}
function draw() {
// soft vertical gradient background
drawBackgroundGradient();
// wooden frame
drawFrame();
// update & draw each bar
for (let bar of bars) {
bar.update();
bar.draw();
}
// mallets follow the mouse
drawMallets();
}
function mousePressed() {
// start audio context on first user interaction
if (!audioStarted) {
userStartAudio();
audioStarted = true;
}
// check which bar was clicked
for (let bar of bars) {
if (bar.contains(mouseX, mouseY)) {
bar.hit(); // play note + bounce animation
break;
}
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
layoutBars();
}
// ---------- Layout & frame ----------
function layoutBars() {
if (bars.length === 0) return;
const num = bars.length;
const totalWidth = width * 0.8;
const spacing = totalWidth * 0.02;
const barWidth = (totalWidth - spacing * (num - 1)) / num;
const maxHeight = height * 0.35;
const minHeight = height * 0.18;
const startX = (width - totalWidth) / 2;
const topY = (height - maxHeight) / 2;
for (let i = 0; i < num; i++) {
const t = i / (num - 1); // 0..1, left to right
const h = lerp(maxHeight, minHeight, t); // left bars longer, right shorter
const x = startX + i * (barWidth + spacing);
const y = topY + (maxHeight - h); // align bottoms
const bar = bars[i];
bar.x = x;
bar.y = y;
bar.w = barWidth;
bar.h = h;
}
// wooden frame around bars
const padX = barWidth * 0.6;
const padY = maxHeight * 0.3;
frameRect.x = startX - padX;
frameRect.y = topY - padY * 0.5;
frameRect.w = totalWidth + padX * 2;
frameRect.h = maxHeight + padY;
}
function drawFrame() {
push();
rectMode(CORNER);
const r = min(width, height) * 0.03;
const strokeW = min(width, height) * 0.015;
// outer wooden frame
stroke(90, 60, 30);
strokeWeight(strokeW);
fill(181, 129, 80);
rect(frameRect.x, frameRect.y, frameRect.w, frameRect.h, r);
// inner panel
noStroke();
fill(210, 160, 110);
const inset = frameRect.w * 0.03;
rect(
frameRect.x + inset,
frameRect.y + inset,
frameRect.w - inset * 2,
frameRect.h - inset * 2,
r * 0.7
);
// little "screws" in the corners for fun
const screwR = strokeW * 0.4;
fill(140, 100, 60);
const sx1 = frameRect.x + strokeW * 0.7;
const sx2 = frameRect.x + frameRect.w - strokeW * 0.7;
const sy1 = frameRect.y + strokeW * 0.7;
const sy2 = frameRect.y + frameRect.h - strokeW * 0.7;
circle(sx1, sy1, screwR * 2);
circle(sx2, sy1, screwR * 2);
circle(sx1, sy2, screwR * 2);
circle(sx2, sy2, screwR * 2);
pop();
}
// soft background to keep it playful
function drawBackgroundGradient() {
const topColor = color(240, 245, 255);
const bottomColor = color(220, 235, 255);
noFill();
for (let y = 0; y < height; y++) {
const t = y / max(1, height - 1);
const c = lerpColor(topColor, bottomColor, t);
stroke(c);
line(0, y, width, y);
}
}
// ---------- Mallets ----------
function drawMallets() {
push();
const baseSize = min(width, height);
const headR = baseSize * 0.025;
const offsetX = headR * 2.2;
const headY = mouseY - headR * 0.5;
const handleLen = headR * 5.2;
stroke(120, 80, 40);
strokeWeight(headR * 0.4);
strokeCap(ROUND);
// left handle
line(
mouseX - offsetX,
headY + headR * 0.2,
mouseX - offsetX - handleLen * 0.3,
headY + handleLen
);
// right handle
line(
mouseX + offsetX,
headY + headR * 0.2,
mouseX + offsetX + handleLen * 0.3,
headY + handleLen
);
// mallet heads
noStroke();
fill(250);
circle(mouseX - offsetX, headY, headR * 2);
circle(mouseX + offsetX, headY, headR * 2);
// inner shading
fill(220);
circle(mouseX - offsetX, headY, headR * 1.2);
circle(mouseX + offsetX, headY, headR * 1.2);
pop();
}
// ---------- Bar class ----------
class XyloBar {
constructor(index, noteName, freq, col) {
this.index = index;
this.noteName = noteName;
this.freq = freq;
this.col = color(col);
// layout values (set in layoutBars)
this.x = 0;
this.y = 0;
this.w = 0;
this.h = 0;
// spring animation state
this.yOffset = 0;
this.vy = 0;
// sound
this.osc = new p5.Oscillator('sine');
this.osc.freq(this.freq);
this.osc.amp(0); // start silent
this.oscStarted = false;
}
contains(px, py) {
const yTop = this.y + this.yOffset;
return (
px >= this.x &&
px <= this.x + this.w &&
py >= yTop &&
py <= yTop + this.h
);
}
hit() {
// bounce upwards
this.vy = -4;
// ensure oscillator is started (after userStartAudio)
if (!this.oscStarted) {
this.osc.start();
this.osc.amp(0);
this.oscStarted = true;
}
// quick attack, smooth release
// https://p5js.org/reference/#/p5.Oscillator/amp
this.osc.amp(0.5, 0.02); // target amplitude, ramp time
this.osc.amp(0, 0.4); // fade out
}
update() {
// simple spring: a = -k * x - c * v
const k = 0.15; // spring stiffness
const damping = 0.1; // damping coefficient
const ay = -k * this.yOffset - damping * this.vy;
this.vy += ay;
this.yOffset += this.vy;
// stop tiny jitter
if (abs(this.vy) < 0.001 && abs(this.yOffset) < 0.001) {
this.vy = 0;
this.yOffset = 0;
}
}
draw() {
push();
rectMode(CORNER);
const yTop = this.y + this.yOffset;
// shadow
noStroke();
fill(0, 0, 0, 35);
const shadowOffset = this.h * 0.08;
rect(this.x, yTop + shadowOffset, this.w, this.h, this.w * 0.12);
// main bar
fill(this.col);
rect(this.x, yTop, this.w, this.h, this.w * 0.12);
// top highlight
fill(255, 255, 255, 80);
rect(
this.x,
yTop,
this.w,
this.h * 0.18,
this.w * 0.12,
this.w * 0.12,
0,
0
);
// note label in the center
fill(255);
textAlign(CENTER, CENTER);
const ts = min(this.w * 0.3, this.h * 0.45);
textSize(ts);
text(this.noteName, this.x + this.w / 2, yTop + this.h / 2);
pop();
}
}
```
You can paste these three files over your existing ones and run.
Click each colored bar to hear its note and see it bounce, and move the mouse to wave the mallets around the xylophone.