-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
documentationImprovements or additions to documentationImprovements or additions to documentationenhancementNew feature or requestNew feature or request
Description
// p5.js — Bouncing Balloons
// Click to add balloons. Press 'r' to reset.
let balloons = [];
const NUM_START = 75;
let font;
let link;
let rainbow;
function preload() {
font = loadFont('TitanOne.ttf');
}
function setup() {
createCanvas(windowWidth, windowHeight);
angleMode(RADIANS);
resetBalloons(NUM_START);
textFont(font);
link = createA('https://forms.office.com/r/ZSd26JX5hN', 'Participate here!');
link.style("font-size", "75px");
link.style("font-family", "helvetica");
link.attribute("target", "_blank");
}
function draw() {
background(245);
// subtle confetti-like dots (optional vibe)
noStroke();
for (let i = 0; i < 30; i++) {
fill(0, 0, 0, 10);
circle((frameCount * 3 + i * 29) % width, (i * 61) % height, 2);
}
for (const b of balloons) {
b.update();
b.bounceEdges();
b.drawString();
b.drawBalloon();
}
// small instruction
fill(0, 120);
noStroke();
textSize(13);
text("click: add balloon | r: reset", 12, height - 14);
push();
textSize(100);
//colorMode(HSB);
fill(255, 193,110);
textAlign(CENTER);
textSize(180);
text("ICCIT", width/2 + 10, height/2 - 150);
textSize(100);
text("End of Year", width/2 + 10, height/2 - 50);
textSize(150);
text("Showcase", width/2 + 10, height/2 + 105 - 30);
textSize(50);
text("April 7th, 2026. 12-3:30pm.", width/2 + 10, height/2 + 125 );
fill(255, 230,25);
textSize(180);
text("ICCIT", width/2, height/2 - 150);
textSize(100);
textAlign(CENTER);
text("End of Year", width/2, height/2 - 55);
textSize(150);
text("Showcase", width/2, height/2 + 70);
textSize(50);
text("April 7th, 2026. 12-3:30pm.", width/2 + 5 , height/2 + 125 );
link.position(width/2 - 300, height/2 + 150)
pop();
}
function mouseMoved() {
balloons.push(new Balloon(mouseX, mouseY));
}
function keyPressed() {
if (key === "r" || key === "R") resetBalloons(NUM_START);
}
function resetBalloons(n) {
balloons = [];
for (let i = 0; i < n; i++) {
balloons.push(new Balloon(random(width), random(height)));
}
}
class Balloon {
constructor(x, y) {
this.pos = createVector(x, y);
// randomized size & "mass"
this.r = random(22, 52);
this.mass = map(this.r, 22, 52, 0.8, 1.8);
// randomized velocity (a little floaty)
this.vel = p5.Vector.random2D().mult(random(1.0, 2.6));
this.vel.y -= random(0.6, 1.4); // bias upward
// slight "wind" drift
this.wind = random(-0.02, 0.02);
// color
this.base = color(random(60, 255), random(60, 255), random(60, 255));
// random(60, 255), random(60, 255), random(60, 255)
this.highlight = color(255, 255, 255, 90);
// wobble animation
this.phase = random(TWO_PI);
this.wobbleSpeed = random(0.015, 0.035);
this.wobbleAmt = random(0.10, 0.22);
// string length
this.stringLen = random(55, 105);
// "knot" size
this.knot = random(6, 10);
}
update() {
// buoyancy (gentle upward), plus mild gravity to avoid shooting upward
const buoyancy = -0.03 * this.mass;
const gravity = 0.012 * this.mass;
this.vel.y += buoyancy + gravity;
// slight horizontal wind + tiny noise for life
this.vel.x += this.wind + (noise(frameCount * 0.01 + this.phase) - 0.5) * 0.03;
// limit speed so it stays calm
this.vel.limit(3.5);
this.pos.add(this.vel);
this.phase += this.wobbleSpeed;
}
bounceEdges() {
// balloon body is an ellipse; use r as rough radius
const pad = this.r * 0.7;
if (this.pos.x < pad) {
this.pos.x = pad;
this.vel.x *= -1;
} else if (this.pos.x > width - pad) {
this.pos.x = width - pad;
this.vel.x *= -1;
}
if (this.pos.y < pad) {
this.pos.y = pad;
this.vel.y *= -1;
} else if (this.pos.y > height - pad) {
this.pos.y = height - pad;
this.vel.y *= -1;
}
}
drawBalloon() {
push();
translate(this.pos.x, this.pos.y);
// wobble: scale + rotate slightly
const wob = sin(this.phase) * this.wobbleAmt;
const rot = sin(this.phase * 0.9) * 0.18;
rotate(rot);
scale(1 + wob * 0.25, 1 - wob * 0.15);
// body
noStroke();
fill(this.base);
const w = this.r * 1.05;
const h = this.r * 1.25;
ellipse(0, 0, w * 2, h * 2);
// highlight
fill(this.highlight);
ellipse(-this.r * 0.25, -this.r * 0.25, w * 0.6, h * 0.7);
// knot (little triangle-ish)
fill(0, 0, 0, 35);
triangle(-this.knot * 0.5, h * 1.05, this.knot * 0.5, h * 1.05, 0, h * 1.25);
pop();
}
drawString() {
// string starts at bottom of balloon; wobble makes it feel tethered
const wobX = sin(this.phase * 1.2) * this.r * 0.25;
const wobY = cos(this.phase * 1.1) * 3;
const startX = this.pos.x + wobX;
const startY = this.pos.y + this.r * 1.0 + wobY;
const endX = this.pos.x - wobX * 0.8;
const endY = startY + this.stringLen;
stroke(40, 110);
strokeWeight(2);
noFill();
// curvy string
const c1x = lerp(startX, endX, 0.35) + wobX * 1.2;
const c1y = lerp(startY, endY, 0.35) + 10;
const c2x = lerp(startX, endX, 0.75) - wobX * 1.1;
const c2y = lerp(startY, endY, 0.75) - 10;
bezier(startX, startY, c1x, c1y, c2x, c2y, endX, endY);
// tiny tail dot
noStroke();
fill(40, 110);
circle(endX, endY, 4);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.11/lib/p5.js"></script>
<script src="https://cdn.jsdelivr.net/npm/p5@1.11.11/lib/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<main>
</main>
<script src="sketch.js"></script>
</body>
</html>
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
documentationImprovements or additions to documentationImprovements or additions to documentationenhancementNew feature or requestNew feature or request