MySafeCode commited on
Commit
42f531a
·
verified ·
1 Parent(s): b65c303

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +217 -171
app.py CHANGED
@@ -1,101 +1,248 @@
1
  #!/usr/bin/env python3
2
- # simple_animation_fixed.py - Working animation with no errors
3
- import numpy as np
4
  import time
5
- import threading
6
  import os
7
- from flask import Flask, Response
8
 
9
  PORT = int(os.getenv('PORT', 7860))
10
- WIDTH, HEIGHT = 400, 300
11
-
12
- print(f"🚀 Starting animation on port {PORT}")
13
-
14
- # Shared state
15
- shared = {
16
- "pixels": np.zeros((HEIGHT, WIDTH, 3), dtype=np.uint8),
17
- "frame_count": 0,
18
- "time": 0.0,
19
- "lock": threading.Lock()
20
- }
21
 
22
  app = Flask(__name__)
23
 
24
  HTML = '''<!DOCTYPE html>
25
  <html>
26
  <head>
27
- <title>Simple Animation</title>
28
  <style>
29
  body { margin: 0; padding: 20px; background: #111; color: white; font-family: Arial; text-align: center; }
30
  canvas { border: 3px solid #0af; background: black; display: block; margin: 20px auto; }
31
- .stats { background: #222; padding: 15px; border-radius: 8px; display: inline-block; margin: 10px; }
32
- .success { color: #0af; }
33
- .error { color: red; }
34
  </style>
35
  </head>
36
  <body>
37
- <h1> Simple Animation</h1>
38
- <canvas id="canvas" width="400" height="300"></canvas>
39
 
40
- <div class="stats">
41
- <div>Frames: <span id="frameCount">0</span></div>
42
- <div>Time: <span id="timeValue">0.0</span>s</div>
43
- <div>Status: <span id="status" class="success">Loading...</span></div>
 
 
 
 
 
 
 
44
  </div>
45
 
46
  <script>
47
  const canvas = document.getElementById('canvas');
48
  const ctx = canvas.getContext('2d');
49
- let framesReceived = 0;
 
 
50
 
51
- function loadFrame() {
52
- fetch('/frame')
53
- .then(response => {
54
- if (!response.ok) throw new Error('HTTP ' + response.status);
55
- return response.arrayBuffer();
56
- })
57
- .then(buffer => {
58
- framesReceived++;
59
-
60
- // Create ImageData
61
- const imageData = new ImageData(400, 300);
62
- const rgba = imageData.data;
63
- const rgb = new Uint8Array(buffer);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- // Convert RGB to RGBA
66
- for (let i = 0, j = 0; i < rgba.length; i += 4, j += 3) {
67
- [i] = rgb[j];
68
- rgba[i + 1] = rgb[j + 1];
69
- rgba[i + 2] = rgb[j + 2];
70
- rgba[i + 3] = 255;
71
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
- // Draw to canvas
74
- ctx.putImageData(imageData, 0, 0);
 
75
 
76
- // Update stats
77
- document.getElementById('frameCount').textContent = framesReceived;
78
- document.getElementById('status').textContent = 'Streaming ✓';
79
 
80
- // Get time from server
81
- fetch('/stats')
82
- .then(r => r.json())
83
- .then(data => {
84
- document.getElementById('timeValue').textContent = data.time.toFixed(2);
85
- });
86
- })
87
- .catch(error => {
88
- console.error('Error:', error);
89
- document.getElementById('status').textContent = 'Error: ' + error.message;
90
- document.getElementById('status').className = 'error';
91
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  }
93
 
94
- // Start streaming at 30 FPS
95
- setInterval(loadFrame, 33);
96
- loadFrame();
 
 
 
 
 
 
 
 
 
97
 
98
- console.log('Animation page loaded');
 
 
99
  </script>
100
  </body>
101
  </html>'''
@@ -104,114 +251,13 @@ HTML = '''<!DOCTYPE html>
104
  def index():
105
  return HTML
106
 
107
- @app.route('/stats')
108
- def stats():
109
- with shared['lock']:
110
- return {
111
- 'frame_count': shared['frame_count'],
112
- 'time': shared['time']
113
- }
114
-
115
- @app.route('/frame')
116
- def get_frame():
117
- """Generate a simple moving pattern"""
118
- with shared['lock']:
119
- # Update time
120
- shared['time'] += 1/30
121
- t = shared['time']
122
-
123
- # Create coordinate grids
124
- y, x = np.mgrid[:HEIGHT, :WIDTH]
125
-
126
- # Clear to dark blue
127
- pixels = shared['pixels']
128
- pixels[:, :, 0] = 20 # R
129
- pixels[:, :, 1] = 20 # G
130
- pixels[:, :, 2] = 40 # B
131
-
132
- # ===== ANIMATION 1: Moving rainbow circle =====
133
- center_x = 200 + 100 * np.sin(t)
134
- center_y = 150 + 80 * np.cos(t * 0.7)
135
- radius = 30 + 10 * np.sin(t * 2)
136
-
137
- distance = np.sqrt((x - center_x)**2 + (y - center_y)**2)
138
- circle_mask = distance < radius
139
-
140
- # Rainbow colors based on position and time
141
- pixels[circle_mask, 0] = (128 + 127 * np.sin(t + x[circle_mask]/100)).astype(np.uint8)
142
- pixels[circle_mask, 1] = (128 + 127 * np.sin(t * 1.3 + y[circle_mask]/100)).astype(np.uint8)
143
- pixels[circle_mask, 2] = (128 + 127 * np.sin(t * 1.7 + (x[circle_mask]+y[circle_mask])/200)).astype(np.uint8)
144
-
145
- # ===== ANIMATION 2: Pulsing grid =====
146
- grid_size = 20 + 10 * np.sin(t)
147
- grid_x = (x // grid_size).astype(int)
148
- grid_y = (y // grid_size).astype(int)
149
-
150
- # Pulsing checkerboard
151
- pulse = (np.sin(t * 3) + 1) * 0.5
152
- checker_mask = ((grid_x + grid_y) % 2 == 0)
153
-
154
- # Add pulsing grid lines
155
- grid_line_mask = ((x % grid_size < 2) | (y % grid_size < 2))
156
- pixels[grid_line_mask & checker_mask, 0] = 100 + int(155 * pulse)
157
- pixels[grid_line_mask & checker_mask, 1] = 200
158
- pixels[grid_line_mask & checker_mask, 2] = 100 + int(155 * pulse)
159
-
160
- # ===== ANIMATION 3: Moving wave =====
161
- wave = np.sin(x/20 + t * 2) * np.sin(y/30 + t * 1.5)
162
- wave_mask = wave > 0.5
163
-
164
- wave_color = np.zeros_like(pixels[wave_mask])
165
- wave_color[:, 0] = 200 # R
166
- wave_color[:, 1] = 100 # G
167
- wave_color[:, 2] = 200 # B
168
- pixels[wave_mask] = wave_color
169
-
170
- # ===== Add frame counter =====
171
- frame_text = f"Frame: {shared['frame_count']}"
172
-
173
- # Simple text using pixels
174
- if shared['frame_count'] < 1000:
175
- # Draw "FRAME" text
176
- text_pixels = [
177
- # F
178
- [(10, 10), (10, 25), (15, 10), (15, 15)],
179
- # R
180
- [(20, 10), (20, 25), (25, 10), (25, 15), (20, 15), (25, 25)],
181
- # A
182
- [(30, 25), (32, 10), (34, 10), (36, 25), (32, 17), (34, 17)],
183
- # M
184
- [(40, 25), (40, 10), (43, 20), (46, 10), (46, 25)],
185
- # E
186
- [(50, 10), (50, 25), (55, 10), (55, 17), (50, 17), (55, 25)]
187
- ]
188
-
189
- for char_pixels in text_pixels:
190
- for px, py in char_pixels:
191
- if 0 <= px < WIDTH and 0 <= py < HEIGHT:
192
- pixels[py, px] = [255, 255, 100]
193
-
194
- # Update frame count
195
- shared['frame_count'] += 1
196
-
197
- # Convert to bytes
198
- pixel_bytes = pixels.tobytes()
199
-
200
- print(f"📦 Frame {shared['frame_count']}, Time: {t:.2f}s")
201
-
202
- return Response(
203
- pixel_bytes,
204
- mimetype='application/octet-stream',
205
- headers={'Cache-Control': 'no-cache'}
206
- )
207
-
208
  def main():
209
  print("="*60)
210
- print(" SIMPLE ANIMATION SERVER")
211
  print("="*60)
212
  print(f"📡 Port: {PORT}")
213
- print(f"🎨 Resolution: {WIDTH}x{HEIGHT}")
214
- print("🎬 Animations: Rainbow circle + Pulsing grid + Wave")
215
  print("="*60)
216
 
217
  app.run(host='0.0.0.0', port=PORT, threaded=True, use_reloader=False)
 
1
  #!/usr/bin/env python3
2
+ # simple_canvas_animation.py - HTML5 Canvas + Minimal Flask
 
3
  import time
 
4
  import os
5
+ from flask import Flask
6
 
7
  PORT = int(os.getenv('PORT', 7860))
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  app = Flask(__name__)
10
 
11
  HTML = '''<!DOCTYPE html>
12
  <html>
13
  <head>
14
+ <title>Simple Canvas Animation</title>
15
  <style>
16
  body { margin: 0; padding: 20px; background: #111; color: white; font-family: Arial; text-align: center; }
17
  canvas { border: 3px solid #0af; background: black; display: block; margin: 20px auto; }
18
+ .controls { margin: 20px; }
19
+ button { background: #0af; color: white; border: none; padding: 10px 20px; margin: 5px; border-radius: 5px; cursor: pointer; }
20
+ button:hover { background: #08c; }
21
  </style>
22
  </head>
23
  <body>
24
+ <h1>🎨 HTML5 Canvas Animation</h1>
 
25
 
26
+ <canvas id="canvas" width="800" height="600"></canvas>
27
+
28
+ <div class="controls">
29
+ <button onclick="startAnimation()">Start</button>
30
+ <button onclick="stopAnimation()">Stop</button>
31
+ <button onclick="changePattern()">Change Pattern</button>
32
+ </div>
33
+
34
+ <div style="color: #888; margin-top: 20px;">
35
+ <p>Pure HTML5 Canvas + JavaScript - No Flask data transfer needed</p>
36
+ <p>Everything runs in your browser!</p>
37
  </div>
38
 
39
  <script>
40
  const canvas = document.getElementById('canvas');
41
  const ctx = canvas.getContext('2d');
42
+ let animationId = null;
43
+ let pattern = 1;
44
+ let time = 0;
45
 
46
+ // Bouncing balls
47
+ const balls[];
48
+ for (let i = 0; i < 10; i++) {
49
+ balls.push({
50
+ x: Math.random() * canvas.width,
51
+ y: Math.random() * canvas.height,
52
+ dx: (Math.random() - 0.5) * 8,
53
+ dy: (Math.random() - 0.5) * 8,
54
+ radius: 10 + Math.random() * 20,
55
+ color: `hsl(${Math.random() * 360}, 100%, 60%)`,
56
+ trail: []
57
+ });
58
+ }
59
+
60
+ function drawPattern1() {
61
+ // Clear with gradient
62
+ const gradient = ctx.createRadialGradient(
63
+ canvas.width/2, canvas.height/2, 0,
64
+ canvas.width/2, canvas.height/2, Math.max(canvas.width, canvas.height)/2
65
+ );
66
+ gradient.addColorStop(0, 'rgba(20, 20, 40, 0.8)');
67
+ gradient.addColorStop(1, 'rgba(0, 0, 20, 1)');
68
+ ctx.fillStyle = gradient;
69
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
70
+
71
+ // Update and draw balls
72
+ balls.forEach(ball => {
73
+ // Update position
74
+ ball.x += ball.dx;
75
+ ball.y += ball.dy;
76
+
77
+ // Bounce off walls
78
+ if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) {
79
+ ball.dx = -ball.dx;
80
+ }
81
+ if (ball.y - ball.radius < 0 || ball.y + ball.radius > canvas.height) {
82
+ ball.dy = -ball.dy;
83
+ }
84
+
85
+ // Add to trail
86
+ ball.trail.push({x: ball.x, y: ball.y});
87
+ if (ball.trail.length > 20) ball.trail.shift();
88
+
89
+ // Draw trail
90
+ ball.trail.forEach((pos, i) => {
91
+ const alpha = i / ball.trail.length;
92
+ ctx.beginPath();
93
+ ctx.arc(pos.x, pos.y, ball.radius * alpha, 0, Math.PI * 2);
94
+ ctx.fillStyle = ball.color.replace(')', `, ${alpha})`).replace('hsl', 'hsla');
95
+ ctx.fill();
96
+ });
97
+
98
+ // Draw ball
99
+ ctx.beginPath();
100
+ ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
101
+ ctx.fillStyle = ball.color;
102
+ ctx.fill();
103
+ ctx.strokeStyle = 'white';
104
+ ctx.lineWidth = 2;
105
+ ctx.stroke();
106
+ });
107
+ }
108
+
109
+ function drawPattern2() {
110
+ // Clear
111
+ ctx.fillStyle = 'rgba(0, 10, 20, 0.1)';
112
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
113
+
114
+ time += 0.05;
115
+
116
+ // Draw rotating pattern
117
+ const centerX = canvas.width / 2;
118
+ const centerY = canvas.height / 2;
119
+
120
+ for (let i = 0; i < 20; i++) {
121
+ const angle = time + i * Math.PI / 10;
122
+ const radius = 50 + i * 15;
123
+ const x = centerX + Math.cos(angle) * radius;
124
+ const y = centerY + Math.sin(angle) * radius;
125
+ const size = 10 + Math.sin(time * 2 + i) * 5;
126
+
127
+ // Gradient color
128
+ const hue = (time * 20 + i * 18) % 360;
129
+ ctx.fillStyle = `hsl(${hue}, 100%, 60%)`;
130
+
131
+ ctx.beginPath();
132
+ ctx.arc(x, y, size, 0, Math.PI * 2);
133
+ ctx.fill();
134
+
135
+ // Connecting lines
136
+ if (i > 0) {
137
+ const prevAngle = time + (i - 1) * Math.PI / 10;
138
+ const prevX = centerX + Math.cos(prevAngle) * radius;
139
+ const prevY = centerY + Math.sin(prevAngle) * radius;
140
 
141
+ ctx.beginPath();
142
+ ctx.moveTo(prevX, prevY);
143
+ ctx.lineTo(x, y);
144
+ ctx.strokeStyle = `hsla(${hue}, 100%, 60%, 0.5)`;
145
+ ctx.lineWidth = 2;
146
+ ctx.stroke();
147
+ }
148
+ }
149
+
150
+ // Draw center circle
151
+ ctx.beginPath();
152
+ ctx.arc(centerX, centerY, 30, 0, Math.PI * 2);
153
+ ctx.fillStyle = `hsl(${time * 50 % 360}, 100%, 60%)`;
154
+ ctx.fill();
155
+ ctx.strokeStyle = 'white';
156
+ ctx.lineWidth = 3;
157
+ ctx.stroke();
158
+ }
159
+
160
+ function drawPattern3() {
161
+ // Clear with subtle fade
162
+ ctx.fillStyle = 'rgba(10, 5, 20, 0.2)';
163
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
164
+
165
+ time += 0.03;
166
+
167
+ // Draw wave pattern
168
+ for (let x = 0; x < canvas.width; x += 20) {
169
+ for (let y = 0; y < canvas.height; y += 20) {
170
+ const wave = Math.sin(x * 0.02 + time) * Math.cos(y * 0.02 + time);
171
+ const size = 5 + wave * 10;
172
 
173
+ const hue = (x + y + time * 100) % 360;
174
+ const saturation = 70 + wave * 30;
175
+ const lightness = 40 + wave * 20;
176
 
177
+ ctx.fillStyle = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
 
 
178
 
179
+ ctx.beginPath();
180
+ ctx.arc(x, y, size, 0, Math.PI * 2);
181
+ ctx.fill();
182
+ }
183
+ }
184
+
185
+ // Draw moving text
186
+ ctx.font = 'bold 48px Arial';
187
+ ctx.textAlign = 'center';
188
+ ctx.textBaseline = 'middle';
189
+
190
+ const text = 'HTML5 CANVAS';
191
+ const textX = canvas.width / 2;
192
+ const textY = canvas.height / 2;
193
+
194
+ // Text shadow/glow
195
+ for (let i = 0; i < 10; i++) {
196
+ const offset = Math.sin(time + i) * 5;
197
+ ctx.fillStyle = `hsla(${i * 36}, 100%, 60%, 0.2)`;
198
+ ctx.fillText(text, textX + offset, textY + offset);
199
+ }
200
+
201
+ // Main text
202
+ ctx.fillStyle = `hsl(${time * 50 % 360}, 100%, 60%)`;
203
+ ctx.fillText(text, textX, textY);
204
+ }
205
+
206
+ function animate() {
207
+ switch(pattern) {
208
+ case 1: drawPattern1(); break;
209
+ case 2: drawPattern2(); break;
210
+ case 3: drawPattern3(); break;
211
+ }
212
+
213
+ // Add FPS counter
214
+ ctx.font = '16px monospace';
215
+ ctx.fillStyle = 'white';
216
+ ctx.textAlign = 'left';
217
+ ctx.fillText(`Pattern: ${pattern}`, 10, 20);
218
+ ctx.fillText(`Time: ${time.toFixed(1)}s`, 10, 40);
219
+
220
+ animationId = requestAnimationFrame(animate);
221
+ }
222
+
223
+ function startAnimation() {
224
+ if (!animationId) {
225
+ animate();
226
+ console.log('Animation started');
227
+ }
228
  }
229
 
230
+ function stopAnimation() {
231
+ if (animationId) {
232
+ cancelAnimationFrame(animationId);
233
+ animationId = null;
234
+ console.log('Animation stopped');
235
+ }
236
+ }
237
+
238
+ function changePattern() {
239
+ pattern = pattern % 3 + 1;
240
+ console.log(`Changed to pattern ${pattern}`);
241
+ }
242
 
243
+ // Initialize with pattern 1
244
+ drawPattern1();
245
+ console.log('Ready! Click Start to animate');
246
  </script>
247
  </body>
248
  </html>'''
 
251
  def index():
252
  return HTML
253
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  def main():
255
  print("="*60)
256
+ print("🎨 HTML5 Canvas Animation Server")
257
  print("="*60)
258
  print(f"📡 Port: {PORT}")
259
+ print(" Everything runs in browser - no data transfer needed!")
260
+ print("🎬 3 different animation patterns")
261
  print("="*60)
262
 
263
  app.run(host='0.0.0.0', port=PORT, threaded=True, use_reloader=False)