awacke1's picture
Update app.py
91145e2 verified
import streamlit as st
def create_animation_app():
st.title("Bouncing Balls & Jellyfish in a Sphere")
html_content = """
<style>
.container {
position: relative;
width: 800px;
height: 600px;
margin: auto;
}
#animationCanvas, #p5Canvas {
position: absolute;
top: 0;
left: 0;
}
canvas {
background-color: transparent;
}
</style>
<div class="container">
<canvas id="animationCanvas"></canvas>
<div id="p5Container"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script>
// Jellyfish Animation
const jellyfishCanvas = document.getElementById('animationCanvas');
const ctx = jellyfishCanvas.getContext('2d');
jellyfishCanvas.width = 800;
jellyfishCanvas.height = 600;
let t = 0;
function mag(x, y) {
return Math.sqrt(x * x + y * y);
}
function a(x, y) {
const k = x/8 - 25;
const e = y/8 - 25;
const d = mag(k, e)**2 / 99;
const q = x/3 + k * 0.5 / Math.cos(y*5) * Math.sin(d*d - t);
const c = d/2 - t/8;
const xPos = q * Math.sin(c) + e * Math.sin(d + k - t) + 400;
const yPos = (q + y/8 + d*9) * Math.cos(c) + 300;
return [xPos, yPos];
}
function getColor(x, y, t) {
const hue = (Math.sin(t/2) * 360 + x/3 + y/3) % 360;
const saturation = 70 + Math.sin(t) * 30;
const lightness = 50 + Math.cos(t/2) * 20;
return `hsla(${hue}, ${saturation}%, ${lightness}%, 0.5)`;
}
function drawJellyfish() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
ctx.fillRect(0, 0, jellyfishCanvas.width, jellyfishCanvas.height);
ctx.lineWidth = 1.5;
for(let y = 99; y < 300; y += 4) {
for(let x = 99; x < 300; x += 2) {
const [px, py] = a(x, y);
const color = getColor(x, y, t);
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(px, py);
ctx.lineTo(px + 1, py + 1);
ctx.stroke();
}
}
t += Math.PI / 120;
requestAnimationFrame(drawJellyfish);
}
// Initialize jellyfish animation
drawJellyfish();
// Bouncing Balls Animation with p5.js
new p5((sketch) => {
let balls = [];
const numBalls = 100;
const sphereRadius = 200;
let rotation = {x: 0, y: 0};
class Ball {
constructor() {
this.pos = p5.Vector.random3D().mult(sphereRadius * 0.8);
this.vel = p5.Vector.random3D().mult(sketch.random(1, 3));
this.radius = 3;
}
update() {
// Update position
this.pos.add(this.vel);
// Sphere collision
let distance = this.pos.mag();
if (distance > sphereRadius - this.radius) {
let normal = this.pos.copy().normalize();
let reflection = this.vel.copy().reflect(normal);
this.vel.set(reflection);
this.pos = normal.mult(sphereRadius - this.radius);
}
}
display() {
sketch.push();
sketch.translate(this.pos.x, this.pos.y, this.pos.z);
sketch.fill(255, 255, 0);
sketch.noStroke();
sketch.sphere(this.radius);
sketch.pop();
}
}
function checkCollisions() {
for(let i = 0; i < balls.length; i++) {
for(let j = i+1; j < balls.length; j++) {
let b1 = balls[i];
let b2 = balls[j];
let d = b1.pos.dist(b2.pos);
let minDist = b1.radius + b2.radius;
if (d < minDist) {
let normal = p5.Vector.sub(b1.pos, b2.pos).normalize();
let overlap = (minDist - d) / 2;
// Position correction
b1.pos.add(p5.Vector.mult(normal, overlap));
b2.pos.sub(p5.Vector.mult(normal, overlap));
// Velocity adjustment
let velDiff = p5.Vector.sub(b1.vel, b2.vel);
let impulse = velDiff.dot(normal) / (1 + 1);
b1.vel.sub(p5.Vector.mult(normal, impulse));
b2.vel.add(p5.Vector.mult(normal, impulse));
}
}
}
}
sketch.setup = () => {
const p5Canvas = sketch.createCanvas(800, 600, sketch.WEBGL);
p5Canvas.parent('p5Container');
sketch.frameRate(30);
// Create balls
for(let i = 0; i < numBalls; i++) {
balls.push(new Ball());
}
};
sketch.draw = () => {
sketch.background(0, 0);
sketch.rotateX(rotation.x);
sketch.rotateY(rotation.y);
// Slowly rotate the sphere
rotation.x += 0.002;
rotation.y += 0.003;
// Draw wireframe sphere
sketch.push();
sketch.noFill();
sketch.stroke(255, 50);
sketch.sphere(sphereRadius);
sketch.pop();
// Update and display balls
balls.forEach(ball => {
ball.update();
ball.display();
});
checkCollisions();
};
}, 'p5Container');
</script>
"""
st.components.v1.html(html_content, height=600)
if __name__ == "__main__":
create_animation_app()