akhaliq HF Staff commited on
Commit
fc3f71a
·
verified ·
1 Parent(s): a225608

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +660 -19
index.html CHANGED
@@ -1,19 +1,660 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Lissajous Curve Visualization</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
14
+ }
15
+
16
+ :root {
17
+ --primary: #6c5ce7;
18
+ --secondary: #a29bfe;
19
+ --accent: #fd79a8;
20
+ --dark: #2d3436;
21
+ --light: #f7f7f7;
22
+ --success: #00b894;
23
+ }
24
+
25
+ body {
26
+ background: linear-gradient(135deg, #1a1a2e, #16213e);
27
+ color: var(--light);
28
+ min-height: 100vh;
29
+ overflow-x: hidden;
30
+ padding: 20px;
31
+ }
32
+
33
+ .container {
34
+ max-width: 1400px;
35
+ margin: 0 auto;
36
+ }
37
+
38
+ header {
39
+ text-align: center;
40
+ padding: 30px 0;
41
+ margin-bottom: 20px;
42
+ }
43
+
44
+ h1 {
45
+ font-size: 3.5rem;
46
+ margin-bottom: 10px;
47
+ background: linear-gradient(to right, var(--accent), var(--secondary));
48
+ -webkit-background-clip: text;
49
+ background-clip: text;
50
+ color: transparent;
51
+ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
52
+ }
53
+
54
+ .subtitle {
55
+ font-size: 1.2rem;
56
+ color: var(--secondary);
57
+ max-width: 700px;
58
+ margin: 0 auto 20px;
59
+ line-height: 1.6;
60
+ }
61
+
62
+ .content {
63
+ display: grid;
64
+ grid-template-columns: 1fr 1fr;
65
+ gap: 30px;
66
+ margin-bottom: 40px;
67
+ }
68
+
69
+ @media (max-width: 992px) {
70
+ .content {
71
+ grid-template-columns: 1fr;
72
+ }
73
+ }
74
+
75
+ .visualization-panel {
76
+ background: rgba(255, 255, 255, 0.05);
77
+ backdrop-filter: blur(10px);
78
+ border-radius: 20px;
79
+ padding: 25px;
80
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
81
+ border: 1px solid rgba(255, 255, 255, 0.1);
82
+ }
83
+
84
+ .panel-title {
85
+ font-size: 1.8rem;
86
+ margin-bottom: 20px;
87
+ color: var(--accent);
88
+ display: flex;
89
+ align-items: center;
90
+ gap: 10px;
91
+ }
92
+
93
+ .panel-title i {
94
+ background: linear-gradient(45deg, var(--primary), var(--accent));
95
+ -webkit-background-clip: text;
96
+ background-clip: text;
97
+ color: transparent;
98
+ }
99
+
100
+ .canvas-container {
101
+ position: relative;
102
+ width: 100%;
103
+ height: 500px;
104
+ background: rgba(0, 0, 0, 0.2);
105
+ border-radius: 15px;
106
+ overflow: hidden;
107
+ }
108
+
109
+ canvas {
110
+ display: block;
111
+ }
112
+
113
+ .controls {
114
+ display: grid;
115
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
116
+ gap: 20px;
117
+ margin-top: 30px;
118
+ }
119
+
120
+ .control-group {
121
+ background: rgba(255, 255, 255, 0.08);
122
+ padding: 20px;
123
+ border-radius: 15px;
124
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
125
+ }
126
+
127
+ .control-group:hover {
128
+ transform: translateY(-5px);
129
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
130
+ background: rgba(255, 255, 255, 0.12);
131
+ }
132
+
133
+ .control-group h3 {
134
+ margin-bottom: 15px;
135
+ color: var(--secondary);
136
+ display: flex;
137
+ align-items: center;
138
+ gap: 10px;
139
+ }
140
+
141
+ .slider-container {
142
+ margin-bottom: 15px;
143
+ }
144
+
145
+ label {
146
+ display: block;
147
+ margin-bottom: 8px;
148
+ font-weight: 500;
149
+ display: flex;
150
+ justify-content: space-between;
151
+ }
152
+
153
+ .value {
154
+ color: var(--accent);
155
+ font-weight: bold;
156
+ }
157
+
158
+ input[type="range"] {
159
+ width: 100%;
160
+ height: 8px;
161
+ border-radius: 4px;
162
+ background: rgba(255, 255, 255, 0.1);
163
+ outline: none;
164
+ -webkit-appearance: none;
165
+ }
166
+
167
+ input[type="range"]::-webkit-slider-thumb {
168
+ -webkit-appearance: none;
169
+ width: 20px;
170
+ height: 20px;
171
+ border-radius: 50%;
172
+ background: var(--accent);
173
+ cursor: pointer;
174
+ box-shadow: 0 0 10px rgba(253, 121, 168, 0.5);
175
+ }
176
+
177
+ .buttons {
178
+ display: flex;
179
+ gap: 15px;
180
+ margin-top: 20px;
181
+ flex-wrap: wrap;
182
+ }
183
+
184
+ button {
185
+ flex: 1;
186
+ min-width: 120px;
187
+ padding: 12px 20px;
188
+ border: none;
189
+ border-radius: 50px;
190
+ background: linear-gradient(45deg, var(--primary), var(--secondary));
191
+ color: white;
192
+ font-weight: 600;
193
+ cursor: pointer;
194
+ transition: all 0.3s ease;
195
+ box-shadow: 0 4px 15px rgba(108, 92, 231, 0.3);
196
+ }
197
+
198
+ button:hover {
199
+ transform: translateY(-3px);
200
+ box-shadow: 0 6px 20px rgba(108, 92, 231, 0.5);
201
+ }
202
+
203
+ button:active {
204
+ transform: translateY(1px);
205
+ }
206
+
207
+ button.reset {
208
+ background: linear-gradient(45deg, #e17055, #fdcb6e);
209
+ box-shadow: 0 4px 15px rgba(225, 112, 85, 0.3);
210
+ }
211
+
212
+ button.reset:hover {
213
+ box-shadow: 0 6px 20px rgba(225, 112, 85, 0.5);
214
+ }
215
+
216
+ .info-panel {
217
+ background: rgba(255, 255, 255, 0.05);
218
+ backdrop-filter: blur(10px);
219
+ border-radius: 20px;
220
+ padding: 25px;
221
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
222
+ border: 1px solid rgba(255, 255, 255, 0.1);
223
+ }
224
+
225
+ .info-content {
226
+ line-height: 1.8;
227
+ }
228
+
229
+ .info-content h2 {
230
+ color: var(--accent);
231
+ margin: 20px 0 15px;
232
+ font-size: 1.8rem;
233
+ }
234
+
235
+ .info-content p {
236
+ margin-bottom: 15px;
237
+ color: #ddd;
238
+ }
239
+
240
+ .formula {
241
+ background: rgba(0, 0, 0, 0.3);
242
+ padding: 20px;
243
+ border-radius: 10px;
244
+ margin: 20px 0;
245
+ font-family: 'Courier New', monospace;
246
+ font-size: 1.2rem;
247
+ text-align: center;
248
+ border-left: 4px solid var(--accent);
249
+ }
250
+
251
+ .examples {
252
+ display: grid;
253
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
254
+ gap: 15px;
255
+ margin-top: 20px;
256
+ }
257
+
258
+ .example {
259
+ background: rgba(255, 255, 255, 0.08);
260
+ padding: 15px;
261
+ border-radius: 10px;
262
+ text-align: center;
263
+ cursor: pointer;
264
+ transition: all 0.3s ease;
265
+ }
266
+
267
+ .example:hover {
268
+ background: rgba(108, 92, 231, 0.2);
269
+ transform: translateY(-3px);
270
+ }
271
+
272
+ .example h4 {
273
+ color: var(--secondary);
274
+ margin-bottom: 10px;
275
+ }
276
+
277
+ footer {
278
+ text-align: center;
279
+ padding: 30px 0;
280
+ color: var(--secondary);
281
+ font-size: 1rem;
282
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
283
+ margin-top: 20px;
284
+ }
285
+
286
+ @media (max-width: 768px) {
287
+ h1 {
288
+ font-size: 2.5rem;
289
+ }
290
+
291
+ .canvas-container {
292
+ height: 400px;
293
+ }
294
+
295
+ .controls {
296
+ grid-template-columns: 1fr;
297
+ }
298
+ }
299
+
300
+ @media (max-width: 480px) {
301
+ h1 {
302
+ font-size: 2rem;
303
+ }
304
+
305
+ .canvas-container {
306
+ height: 300px;
307
+ }
308
+
309
+ .buttons {
310
+ flex-direction: column;
311
+ }
312
+ }
313
+ </style>
314
+ </head>
315
+ <body>
316
+ <div class="container">
317
+ <header>
318
+ <h1><i class="fas fa-wave-square"></i> Lissajous Curve Visualization</h1>
319
+ <p class="subtitle">Explore the fascinating mathematical curves formed by the intersection of two harmonic motions at right angles. Adjust parameters to see how the curve changes in real-time.</p>
320
+ </header>
321
+
322
+ <div class="content">
323
+ <div class="visualization-panel">
324
+ <h2 class="panel-title"><i class="fas fa-chart-line"></i> Curve Visualization</h2>
325
+ <div class="canvas-container">
326
+ <canvas id="lissajousCanvas"></canvas>
327
+ </div>
328
+
329
+ <div class="controls">
330
+ <div class="control-group">
331
+ <h3><i class="fas fa-sliders-h"></i> Parameters</h3>
332
+ <div class="slider-container">
333
+ <label for="aSlider">
334
+ A Ratio: <span id="aValue" class="value">3</span>
335
+ </label>
336
+ <input type="range" id="aSlider" min="1" max="10" value="3" step="0.1">
337
+ </div>
338
+ <div class="slider-container">
339
+ <label for="bSlider">
340
+ B Ratio: <span id="bValue" class="value">2</span>
341
+ </label>
342
+ <input type="range" id="bSlider" min="1" max="10" value="2" step="0.1">
343
+ </div>
344
+ <div class="slider-container">
345
+ <label for="deltaSlider">
346
+ Phase Difference (δ): <span id="deltaValue" class="value">π/2</span>
347
+ </label>
348
+ <input type="range" id="deltaSlider" min="0" max="6.28" value="1.57" step="0.01">
349
+ </div>
350
+ </div>
351
+
352
+ <div class="control-group">
353
+ <h3><i class="fas fa-palette"></i> Appearance</h3>
354
+ <div class="slider-container">
355
+ <label for="speedSlider">
356
+ Animation Speed: <span id="speedValue" class="value">1.0</span>x
357
+ </label>
358
+ <input type="range" id="speedSlider" min="0.1" max="3" value="1" step="0.1">
359
+ </div>
360
+ <div class="slider-container">
361
+ <label for="trailSlider">
362
+ Trail Length: <span id="trailValue" class="value">500</span>
363
+ </label>
364
+ <input type="range" id="trailSlider" min="50" max="2000" value="500" step="10">
365
+ </div>
366
+ </div>
367
+ </div>
368
+
369
+ <div class="buttons">
370
+ <button id="pauseBtn"><i class="fas fa-pause"></i> Pause</button>
371
+ <button id="resetBtn" class="reset"><i class="fas fa-redo"></i> Reset</button>
372
+ <button id="clearBtn"><i class="fas fa-eraser"></i> Clear</button>
373
+ </div>
374
+ </div>
375
+
376
+ <div class="info-panel">
377
+ <h2 class="panel-title"><i class="fas fa-info-circle"></i> About Lissajous Curves</h2>
378
+ <div class="info-content">
379
+ <p>Lissajous curves, also known as Lissajous figures or Bowditch curves, are the graphs of a system of parametric equations that describe complex harmonic motion.</p>
380
+
381
+ <h2>Mathematical Formula</h2>
382
+ <div class="formula">
383
+ x = A × sin(a × t + δ)<br>
384
+ y = B × sin(b × t)
385
+ </div>
386
+
387
+ <p>Where:</p>
388
+ <ul>
389
+ <li><strong>A, B</strong>: Amplitudes of the waves</li>
390
+ <li><strong>a, b</strong>: Frequencies of the waves</li>
391
+ <li><strong>δ</strong>: Phase difference between the waves</li>
392
+ <li><strong>t</strong>: Time parameter</li>
393
+ </ul>
394
+
395
+ <h2>Common Examples</h2>
396
+ <div class="examples">
397
+ <div class="example" data-a="1" data-b="1" data-d="0">
398
+ <h4>Circle</h4>
399
+ <p>a=1, b=1, δ=0</p>
400
+ </div>
401
+ <div class="example" data-a="1" data-b="1" data-d="1.57">
402
+ <h4>Ellipse</h4>
403
+ <p>a=1, b=1, δ=π/2</p>
404
+ </div>
405
+ <div class="example" data-a="3" data-b="2" data-d="1.57">
406
+ <h4>Classic Curve</h4>
407
+ <p>a=3, b=2, δ=π/2</p>
408
+ </div>
409
+ <div class="example" data-a="5" data-b="4" data-d="1.57">
410
+ <h4>Complex Pattern</h4>
411
+ <p>a=5, b=4, δ=π/2</p>
412
+ </div>
413
+ </div>
414
+
415
+ <h2>Applications</h2>
416
+ <p>Lissajous curves have applications in physics, astronomy, and engineering:</p>
417
+ <ul>
418
+ <li>Oscilloscopes for signal analysis</li>
419
+ <li>Harmonic oscillators in mechanics</li>
420
+ <li>Optics and wave interference</li>
421
+ <li>Art and design patterns</li>
422
+ </ul>
423
+ </div>
424
+ </div>
425
+ </div>
426
+
427
+ <footer>
428
+ <p>Lissajous Curve Visualization | Mathematical Beauty in Motion</p>
429
+ </footer>
430
+ </div>
431
+
432
+ <script>
433
+ // Canvas setup
434
+ const canvas = document.getElementById('lissajousCanvas');
435
+ const ctx = canvas.getContext('2d');
436
+
437
+ // Set canvas dimensions
438
+ function resizeCanvas() {
439
+ const container = canvas.parentElement;
440
+ canvas.width = container.clientWidth;
441
+ canvas.height = container.clientHeight;
442
+ }
443
+
444
+ window.addEventListener('resize', resizeCanvas);
445
+ resizeCanvas();
446
+
447
+ // Initial parameters
448
+ let params = {
449
+ a: 3,
450
+ b: 2,
451
+ delta: Math.PI/2,
452
+ speed: 1,
453
+ trailLength: 500,
454
+ paused: false,
455
+ time: 0
456
+ };
457
+
458
+ // Trail points storage
459
+ let points = [];
460
+
461
+ // DOM elements
462
+ const aSlider = document.getElementById('aSlider');
463
+ const bSlider = document.getElementById('bSlider');
464
+ const deltaSlider = document.getElementById('deltaSlider');
465
+ const speedSlider = document.getElementById('speedSlider');
466
+ const trailSlider = document.getElementById('trailSlider');
467
+ const aValue = document.getElementById('aValue');
468
+ const bValue = document.getElementById('bValue');
469
+ const deltaValue = document.getElementById('deltaValue');
470
+ const speedValue = document.getElementById('speedValue');
471
+ const trailValue = document.getElementById('trailValue');
472
+ const pauseBtn = document.getElementById('pauseBtn');
473
+ const resetBtn = document.getElementById('resetBtn');
474
+ const clearBtn = document.getElementById('clearBtn');
475
+ const examples = document.querySelectorAll('.example');
476
+
477
+ // Update value displays
478
+ function updateValueDisplays() {
479
+ aValue.textContent = params.a.toFixed(1);
480
+ bValue.textContent = params.b.toFixed(1);
481
+ deltaValue.textContent = (params.delta/Math.PI).toFixed(2) + 'π';
482
+ speedValue.textContent = params.speed.toFixed(1);
483
+ trailValue.textContent = params.trailLength;
484
+ }
485
+
486
+ // Slider event listeners
487
+ aSlider.addEventListener('input', () => {
488
+ params.a = parseFloat(aSlider.value);
489
+ updateValueDisplays();
490
+ });
491
+
492
+ bSlider.addEventListener('input', () => {
493
+ params.b = parseFloat(bSlider.value);
494
+ updateValueDisplays();
495
+ });
496
+
497
+ deltaSlider.addEventListener('input', () => {
498
+ params.delta = parseFloat(deltaSlider.value);
499
+ updateValueDisplays();
500
+ });
501
+
502
+ speedSlider.addEventListener('input', () => {
503
+ params.speed = parseFloat(speedSlider.value);
504
+ updateValueDisplays();
505
+ });
506
+
507
+ trailSlider.addEventListener('input', () => {
508
+ params.trailLength = parseInt(trailSlider.value);
509
+ updateValueDisplays();
510
+ });
511
+
512
+ // Button event listeners
513
+ pauseBtn.addEventListener('click', () => {
514
+ params.paused = !params.paused;
515
+ pauseBtn.innerHTML = params.paused ?
516
+ '<i class="fas fa-play"></i> Play' :
517
+ '<i class="fas fa-pause"></i> Pause';
518
+ });
519
+
520
+ resetBtn.addEventListener('click', () => {
521
+ params.a = 3;
522
+ params.b = 2;
523
+ params.delta = Math.PI/2;
524
+ params.speed = 1;
525
+ params.trailLength = 500;
526
+ aSlider.value = params.a;
527
+ bSlider.value = params.b;
528
+ deltaSlider.value = params.delta;
529
+ speedSlider.value = params.speed;
530
+ trailSlider.value = params.trailLength;
531
+ updateValueDisplays();
532
+ });
533
+
534
+ clearBtn.addEventListener('click', () => {
535
+ points = [];
536
+ });
537
+
538
+ // Example click handlers
539
+ examples.forEach(example => {
540
+ example.addEventListener('click', () => {
541
+ params.a = parseFloat(example.dataset.a);
542
+ params.b = parseFloat(example.dataset.b);
543
+ params.delta = parseFloat(example.dataset.d);
544
+
545
+ aSlider.value = params.a;
546
+ bSlider.value = params.b;
547
+ deltaSlider.value = params.delta;
548
+
549
+ updateValueDisplays();
550
+ });
551
+ });
552
+
553
+ // Initialize value displays
554
+ updateValueDisplays();
555
+
556
+ // Animation function
557
+ function animate() {
558
+ if (!params.paused) {
559
+ params.time += 0.02 * params.speed;
560
+
561
+ // Calculate new point
562
+ const x = Math.sin(params.a * params.time + params.delta);
563
+ const y = Math.sin(params.b * params.time);
564
+
565
+ // Convert to canvas coordinates
566
+ const canvasX = canvas.width/2 + x * (canvas.width/2 - 50);
567
+ const canvasY = canvas.height/2 + y * (canvas.height/2 - 50);
568
+
569
+ // Add to points array
570
+ points.push({x: canvasX, y: canvasY});
571
+
572
+ // Remove old points if trail is too long
573
+ if (points.length > params.trailLength) {
574
+ points.shift();
575
+ }
576
+ }
577
+
578
+ // Clear canvas
579
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
580
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
581
+
582
+ // Draw grid
583
+ drawGrid();
584
+
585
+ // Draw trail
586
+ if (points.length > 1) {
587
+ ctx.beginPath();
588
+ ctx.moveTo(points[0].x, points[0].y);
589
+
590
+ for (let i = 1; i < points.length; i++) {
591
+ const alpha = i / points.length;
592
+ ctx.strokeStyle = `hsla(${240 + alpha * 120}, 100%, 70%, ${alpha})`;
593
+ ctx.lineWidth = 2;
594
+ ctx.lineTo(points[i].x, points[i].y);
595
+ ctx.stroke();
596
+ ctx.beginPath();
597
+ ctx.moveTo(points[i].x, points[i].y);
598
+ }
599
+
600
+ ctx.stroke();
601
+ }
602
+
603
+ // Draw current point
604
+ if (points.length > 0) {
605
+ const currentPoint = points[points.length - 1];
606
+ ctx.beginPath();
607
+ ctx.arc(currentPoint.x, currentPoint.y, 8, 0, Math.PI * 2);
608
+ ctx.fillStyle = '#fd79a8';
609
+ ctx.fill();
610
+ ctx.strokeStyle = '#fff';
611
+ ctx.lineWidth = 2;
612
+ ctx.stroke();
613
+ }
614
+
615
+ requestAnimationFrame(animate);
616
+ }
617
+
618
+ // Draw grid function
619
+ function drawGrid() {
620
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
621
+ ctx.lineWidth = 1;
622
+
623
+ // Vertical lines
624
+ for (let x = 0; x <= canvas.width; x += canvas.width/10) {
625
+ ctx.beginPath();
626
+ ctx.moveTo(x, 0);
627
+ ctx.lineTo(x, canvas.height);
628
+ ctx.stroke();
629
+ }
630
+
631
+ // Horizontal lines
632
+ for (let y = 0; y <= canvas.height; y += canvas.height/10) {
633
+ ctx.beginPath();
634
+ ctx.moveTo(0, y);
635
+ ctx.lineTo(canvas.width, y);
636
+ ctx.stroke();
637
+ }
638
+
639
+ // Center lines
640
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
641
+ ctx.lineWidth = 2;
642
+
643
+ // Vertical center
644
+ ctx.beginPath();
645
+ ctx.moveTo(canvas.width/2, 0);
646
+ ctx.lineTo(canvas.width/2, canvas.height);
647
+ ctx.stroke();
648
+
649
+ // Horizontal center
650
+ ctx.beginPath();
651
+ ctx.moveTo(0, canvas.height/2);
652
+ ctx.lineTo(canvas.width, canvas.height/2);
653
+ ctx.stroke();
654
+ }
655
+
656
+ // Start animation
657
+ animate();
658
+ </script>
659
+ </body>
660
+ </html>