Update app.py
Browse files
app.py
CHANGED
@@ -1,257 +1,153 @@
|
|
1 |
import streamlit as st
|
2 |
|
3 |
-
def
|
4 |
-
st.title("
|
5 |
-
|
6 |
-
# 1. p5.js (from a CDN)
|
7 |
-
# 2. a container div for our canvas
|
8 |
-
# 3. our p5.js sketch that simulates 100 bouncing yellow balls with collision detection
|
9 |
-
# and one bouncing jellyfish (using a spiral drawing similar to your jellyfish code)
|
10 |
-
# all inside a sphere (drawn as a circle) that slowly rotates.
|
11 |
html_code = r"""
|
12 |
<!DOCTYPE html>
|
13 |
<html>
|
14 |
<head>
|
15 |
<meta charset="UTF-8">
|
16 |
-
|
|
|
17 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>
|
18 |
<style>
|
19 |
-
/* Remove
|
20 |
-
body {
|
21 |
-
|
22 |
-
padding: 0;
|
23 |
-
overflow: hidden;
|
24 |
-
background: black;
|
25 |
-
}
|
26 |
-
#p5-container {
|
27 |
-
display: flex;
|
28 |
-
justify-content: center;
|
29 |
-
align-items: center;
|
30 |
-
}
|
31 |
</style>
|
32 |
</head>
|
33 |
<body>
|
34 |
-
<div id="
|
35 |
<script>
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
-
//
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
canvas.parent('p5-container');
|
49 |
-
sphereCenter = createVector(width/2, height/2);
|
50 |
-
|
51 |
-
// Set color mode to HSB for our jellyfish drawing.
|
52 |
-
colorMode(HSB, 360, 100, 100, 1);
|
53 |
-
|
54 |
-
// Create 100 balls. Each ball is given a random position (inside the sphere)
|
55 |
-
// and a random velocity.
|
56 |
-
for (let i = 0; i < numBalls; i++) {
|
57 |
-
balls.push(new Ball());
|
58 |
-
}
|
59 |
-
|
60 |
-
// Create one jellyfish object. (Its drawn “shape” is produced by the jellyA() and getJellyColor() functions below.)
|
61 |
-
jellyfish = new Jellyfish();
|
62 |
}
|
63 |
|
64 |
-
//
|
65 |
-
|
66 |
-
|
67 |
-
// (Note: using HSB mode so black is 0 saturation and 0 brightness.)
|
68 |
-
background(0, 0, 0, 0.1);
|
69 |
-
|
70 |
-
// Increment our rotation angle very slowly.
|
71 |
-
rotationAngle += 0.005;
|
72 |
-
|
73 |
-
// All drawing and physics is done in a coordinate system with origin at sphereCenter.
|
74 |
-
push();
|
75 |
-
translate(sphereCenter.x, sphereCenter.y);
|
76 |
-
// Slowly rotate the entire coordinate system.
|
77 |
-
rotate(rotationAngle);
|
78 |
-
|
79 |
-
// Draw the bounding sphere (a circle)
|
80 |
-
noFill();
|
81 |
-
stroke(255);
|
82 |
-
strokeWeight(2);
|
83 |
-
ellipse(0, 0, sphereRadius * 2, sphereRadius * 2);
|
84 |
-
|
85 |
-
// --- Update Physics ---
|
86 |
-
// 1. Update positions for all balls and the jellyfish.
|
87 |
-
for (let ball of balls) {
|
88 |
-
ball.update();
|
89 |
-
}
|
90 |
-
jellyfish.update();
|
91 |
-
|
92 |
-
// 2. Check and resolve ball-ball collisions.
|
93 |
-
for (let i = 0; i < balls.length; i++) {
|
94 |
-
for (let j = i + 1; j < balls.length; j++) {
|
95 |
-
balls[i].collide(balls[j]);
|
96 |
-
}
|
97 |
-
}
|
98 |
-
|
99 |
-
// 3. Check each ball for collisions with the sphere boundary and display them.
|
100 |
-
for (let ball of balls) {
|
101 |
-
ball.checkBoundaryCollision();
|
102 |
-
ball.display();
|
103 |
-
}
|
104 |
-
|
105 |
-
// 4. Check the jellyfish for sphere collisions and display it.
|
106 |
-
jellyfish.checkBoundaryCollision();
|
107 |
-
jellyfish.display();
|
108 |
-
|
109 |
-
pop();
|
110 |
}
|
|
|
|
|
|
|
|
|
111 |
|
112 |
-
//
|
113 |
-
|
114 |
-
|
115 |
-
this.r = 5; // radius of the ball
|
116 |
-
// Random position inside the sphere (by picking a random angle and radius)
|
117 |
-
let angle = random(TWO_PI);
|
118 |
-
let rad = random(sphereRadius - this.r);
|
119 |
-
this.pos = createVector(rad * cos(angle), rad * sin(angle));
|
120 |
-
// Random speed and direction
|
121 |
-
let speed = random(1, 3);
|
122 |
-
let vAngle = random(TWO_PI);
|
123 |
-
this.vel = createVector(speed * cos(vAngle), speed * sin(vAngle));
|
124 |
-
// Yellow color in HSB (hue=60, saturation=100, brightness=100)
|
125 |
-
this.col = color(60, 100, 100);
|
126 |
-
}
|
127 |
-
|
128 |
-
update() {
|
129 |
-
this.pos.add(this.vel);
|
130 |
-
}
|
131 |
-
|
132 |
-
// Check for collision with the circular (spherical) boundary.
|
133 |
-
checkBoundaryCollision() {
|
134 |
-
let d = this.pos.mag();
|
135 |
-
if (d + this.r > sphereRadius) {
|
136 |
-
// Compute the normal (pointing outward)
|
137 |
-
let normal = this.pos.copy().normalize();
|
138 |
-
// Reflect the velocity: v = v - 2*(v·normal)*normal
|
139 |
-
let dot = this.vel.dot(normal);
|
140 |
-
this.vel.sub(p5.Vector.mult(normal, 2 * dot));
|
141 |
-
// Ensure the ball is repositioned just inside the boundary.
|
142 |
-
this.pos = normal.mult(sphereRadius - this.r);
|
143 |
-
}
|
144 |
-
}
|
145 |
-
|
146 |
-
// Check for collisions with another ball (elastic collision for equal masses)
|
147 |
-
collide(other) {
|
148 |
-
let diff = p5.Vector.sub(other.pos, this.pos);
|
149 |
-
let distBetween = diff.mag();
|
150 |
-
if (distBetween < this.r + other.r) {
|
151 |
-
// Separate the overlapping balls by moving them apart equally.
|
152 |
-
let overlap = (this.r + other.r) - distBetween;
|
153 |
-
let displacement = diff.copy().normalize().mult(overlap / 2);
|
154 |
-
this.pos.sub(displacement);
|
155 |
-
other.pos.add(displacement);
|
156 |
-
|
157 |
-
// Compute collision response
|
158 |
-
let normal = diff.copy().normalize();
|
159 |
-
let relativeVelocity = p5.Vector.sub(this.vel, other.vel);
|
160 |
-
let dotProd = relativeVelocity.dot(normal);
|
161 |
-
// Only resolve if balls are moving toward each other.
|
162 |
-
if (dotProd > 0) {
|
163 |
-
// For equal masses, exchange the velocity components along the collision normal.
|
164 |
-
let impulse = normal.copy().mult(dotProd);
|
165 |
-
this.vel.sub(impulse);
|
166 |
-
other.vel.add(impulse);
|
167 |
-
}
|
168 |
-
}
|
169 |
-
}
|
170 |
-
|
171 |
-
display() {
|
172 |
-
noStroke();
|
173 |
-
fill(this.col);
|
174 |
-
ellipse(this.pos.x, this.pos.y, this.r * 2, this.r * 2);
|
175 |
-
}
|
176 |
-
}
|
177 |
|
178 |
-
//
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
}
|
224 |
-
pop();
|
225 |
}
|
|
|
226 |
}
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
}
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
|
|
|
|
|
|
248 |
}
|
|
|
249 |
</script>
|
250 |
</body>
|
251 |
</html>
|
252 |
"""
|
253 |
-
|
254 |
-
|
|
|
255 |
|
256 |
-
if __name__ ==
|
257 |
-
|
|
|
1 |
import streamlit as st
|
2 |
|
3 |
+
def create_app():
|
4 |
+
st.title("3D Python Snake Matrix Code ❤️🐍")
|
5 |
+
|
|
|
|
|
|
|
|
|
|
|
6 |
html_code = r"""
|
7 |
<!DOCTYPE html>
|
8 |
<html>
|
9 |
<head>
|
10 |
<meta charset="UTF-8">
|
11 |
+
<title>3D Python Snake Matrix Code ❤️</title>
|
12 |
+
<!-- Load p5.js (with WEBGL support) from a CDN -->
|
13 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>
|
14 |
<style>
|
15 |
+
/* Remove margins and set a black background */
|
16 |
+
body { margin: 0; padding: 0; overflow: hidden; background: black; }
|
17 |
+
#sketch-container { display: flex; justify-content: center; align-items: center; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
</style>
|
19 |
</head>
|
20 |
<body>
|
21 |
+
<div id="sketch-container"></div>
|
22 |
<script>
|
23 |
+
// ❤️ 3D Python Snake Matrix Code with Heart Emojis ❤️
|
24 |
+
// Global variables for the Matrix rain overlay
|
25 |
+
let matrixColumns = [];
|
26 |
+
let fontSize = 16;
|
27 |
+
let numColumns;
|
28 |
+
|
29 |
+
// Global variables for the snake
|
30 |
+
let snake = []; // Array to hold 3D positions of the snake segments
|
31 |
+
const maxSnakeLength = 50; // Maximum number of segments
|
32 |
+
let t = 0; // Time variable for snake movement
|
33 |
+
|
34 |
+
function setup() {
|
35 |
+
// Create a WEBGL canvas that fills the window and attach it to our container
|
36 |
+
let canvas = createCanvas(windowWidth, windowHeight, WEBGL);
|
37 |
+
canvas.parent('sketch-container');
|
38 |
+
textFont('monospace');
|
39 |
+
textSize(fontSize);
|
40 |
+
noStroke();
|
41 |
|
42 |
+
// Setup Matrix rain columns (we work in 2D for the overlay)
|
43 |
+
numColumns = floor(width / fontSize);
|
44 |
+
for (let i = 0; i < numColumns; i++) {
|
45 |
+
matrixColumns[i] = random(-1000, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
}
|
47 |
|
48 |
+
// Initialize the snake: start with all segments at the center (0,0,0)
|
49 |
+
for (let i = 0; i < maxSnakeLength; i++) {
|
50 |
+
snake.push(createVector(0, 0, 0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
}
|
52 |
+
}
|
53 |
+
|
54 |
+
function draw() {
|
55 |
+
background(0);
|
56 |
|
57 |
+
// Set up some lights for 3D shading
|
58 |
+
ambientLight(50);
|
59 |
+
directionalLight(255, 255, 255, 0, -1, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
+
// Rotate the entire 3D scene slowly for an extra cool effect
|
62 |
+
rotateY(frameCount * 0.005);
|
63 |
+
rotateX(frameCount * 0.003);
|
64 |
+
|
65 |
+
// Update and draw our snake in 3D
|
66 |
+
updateSnake();
|
67 |
+
drawSnake();
|
68 |
+
|
69 |
+
// Draw the Matrix rain overlay on top (in 2D)
|
70 |
+
drawMatrixRain();
|
71 |
+
}
|
72 |
+
|
73 |
+
// Update the snake's position using Perlin noise for a fluid, organic motion
|
74 |
+
function updateSnake() {
|
75 |
+
t += 0.01;
|
76 |
+
// Compute new head position using noise to vary x, y, and z independently
|
77 |
+
let x = map(noise(t, 0), 0, 1, -width/3, width/3);
|
78 |
+
let y = map(noise(t, 100), 0, 1, -height/3, height/3);
|
79 |
+
let z = map(noise(t, 200), 0, 1, -300, 300);
|
80 |
+
let newHead = createVector(x, y, z);
|
81 |
+
snake.push(newHead);
|
82 |
+
// Maintain a fixed length by removing the tail segment
|
83 |
+
if (snake.length > maxSnakeLength) {
|
84 |
+
snake.shift();
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
// Draw the snake: each segment is rendered as a Matrix-style character,
|
89 |
+
// and every 10th segment is rendered as a heart emoji for extra love ❤️.
|
90 |
+
function drawSnake() {
|
91 |
+
for (let i = 0; i < snake.length; i++) {
|
92 |
+
let pos = snake[i];
|
93 |
+
push();
|
94 |
+
translate(pos.x, pos.y, pos.z);
|
95 |
+
// Every 10th segment, show a heart emoji instead of a random character
|
96 |
+
if (i % 10 === 0) {
|
97 |
+
textSize(fontSize + 4);
|
98 |
+
fill(255, 0, 100);
|
99 |
+
text("❤️", 0, 0);
|
100 |
+
} else {
|
101 |
+
fill(0, 255, 70);
|
102 |
+
textSize(fontSize);
|
103 |
+
let matrixChars = "01ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
104 |
+
let char = matrixChars.charAt(floor(random(matrixChars.length)));
|
105 |
+
text(char, 0, 0);
|
|
|
|
|
106 |
}
|
107 |
+
pop();
|
108 |
}
|
109 |
+
}
|
110 |
+
|
111 |
+
// Draw a classic Matrix rain effect as a 2D overlay on top of the 3D scene
|
112 |
+
function drawMatrixRain() {
|
113 |
+
push();
|
114 |
+
// Reset to 2D drawing mode
|
115 |
+
resetMatrix();
|
116 |
+
// Shift the origin to the top-left corner
|
117 |
+
translate(0, 0);
|
118 |
+
textSize(fontSize);
|
119 |
+
fill(0, 255, 70);
|
120 |
+
for (let i = 0; i < numColumns; i++) {
|
121 |
+
let x = i * fontSize;
|
122 |
+
let y = matrixColumns[i];
|
123 |
+
let matrixChars = "01ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
124 |
+
let char = matrixChars.charAt(floor(random(matrixChars.length)));
|
125 |
+
text(char, x, y);
|
126 |
+
matrixColumns[i] += fontSize;
|
127 |
+
// If the drop goes off the screen, reset it to the top with a random offset
|
128 |
+
if (matrixColumns[i] > height) {
|
129 |
+
matrixColumns[i] = random(-100, 0);
|
130 |
+
}
|
131 |
}
|
132 |
+
pop();
|
133 |
+
}
|
134 |
+
|
135 |
+
// When the window is resized, adjust the canvas and recalc matrix columns
|
136 |
+
function windowResized() {
|
137 |
+
resizeCanvas(windowWidth, windowHeight);
|
138 |
+
numColumns = floor(width / fontSize);
|
139 |
+
matrixColumns = [];
|
140 |
+
for (let i = 0; i < numColumns; i++) {
|
141 |
+
matrixColumns[i] = random(-1000, 0);
|
142 |
}
|
143 |
+
}
|
144 |
</script>
|
145 |
</body>
|
146 |
</html>
|
147 |
"""
|
148 |
+
|
149 |
+
# Embed the HTML (with the p5.js sketch) into the Streamlit app.
|
150 |
+
st.components.v1.html(html_code, height=700, scrolling=True)
|
151 |
|
152 |
+
if __name__ == '__main__':
|
153 |
+
create_app()
|