pedromsfaria commited on
Commit
d9ec52c
·
verified ·
1 Parent(s): 01bc31a

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +519 -591
index.html CHANGED
@@ -1,649 +1,577 @@
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>ComfyUI Workflow</title>
7
  <style>
8
  * {
9
  margin: 0;
10
  padding: 0;
11
  box-sizing: border-box;
12
  }
 
13
  body {
14
- font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', system-ui, sans-serif;
15
- background-color: #000000;
16
- color: #f5f5f7;
17
- line-height: 1.6;
18
- padding: 20px;
19
  min-height: 100vh;
 
 
 
 
 
20
  }
21
- .container {
22
- max-width: 1200px;
23
- margin: 0 auto;
24
- }
25
  .header {
26
  text-align: center;
27
- margin-bottom: 40px;
28
- padding: 40px 20px;
29
  }
 
30
  .header h1 {
31
- font-size: 48px;
32
- font-weight: 600;
33
- color: #ffffff;
34
- margin-bottom: 12px;
35
- letter-spacing: -0.02em;
36
  }
37
- .header p {
38
- font-size: 18px;
39
- color: #86868b;
40
- font-weight: 400;
 
41
  }
42
- .controls {
 
 
 
 
 
 
 
 
 
 
 
 
43
  display: flex;
44
- gap: 12px;
45
- margin-bottom: 24px;
46
- justify-content: center;
 
 
47
  }
48
- .btn {
49
- padding: 12px 24px;
50
- border: none;
51
- border-radius: 24px;
52
- font-size: 14px;
53
- font-weight: 500;
54
- cursor: pointer;
55
- transition: all 0.2s;
56
- font-family: inherit;
 
57
  }
58
- .btn-primary {
59
- background: #ffffff;
60
- color: #000000;
61
  }
62
- .btn-primary:hover {
63
- background: #f5f5f7;
64
- transform: scale(0.98);
 
 
65
  }
66
- .btn-secondary {
67
- background: #1d1d1f;
68
- color: #f5f5f7;
69
- border: 1px solid #424245;
70
  }
71
- .btn-secondary:hover {
72
- background: #2d2d2f;
73
- transform: scale(0.98);
 
 
 
 
 
 
74
  }
75
- .json-container {
76
- background-color: #1d1d1f;
77
- border-radius: 16px;
78
- padding: 32px;
79
- overflow-x: auto;
80
- border: 1px solid #424245;
81
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
82
  }
83
- pre {
84
- margin: 0;
85
- font-family: 'SF Mono', 'Monaco', 'Menlo', 'Consolas', monospace;
86
- font-size: 13px;
87
- line-height: 1.6;
88
- white-space: pre-wrap;
89
- word-wrap: break-word;
 
 
90
  }
91
- .json-key {
92
- color: #9cdcfe;
 
 
 
 
 
 
 
 
 
93
  }
94
- .json-string {
95
- color: #ce9178;
 
 
 
 
 
 
 
 
96
  }
97
- .json-number {
98
- color: #b5cea8;
 
 
 
 
 
 
 
 
 
 
 
 
99
  }
100
- .json-boolean {
101
- color: #569cd6;
 
 
102
  }
103
- .json-null {
104
- color: #569cd6;
 
 
 
 
105
  }
106
- .success {
107
- color: #30d158;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  @media (max-width: 768px) {
 
 
 
 
110
  .header h1 {
111
- font-size: 32px;
 
 
 
 
112
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  .controls {
114
  flex-direction: column;
 
115
  }
116
- .json-container {
117
- padding: 20px;
 
118
  }
119
  }
120
  </style>
121
  </head>
122
  <body>
123
- <div class="container">
124
- <div class="header">
125
- <h1>ComfyUI Workflow</h1>
126
- <p>View and download your workflow JSON</p>
 
127
  </div>
128
-
129
- <div class="controls">
130
- <button class="btn btn-primary" onclick="downloadJSON()">Download JSON</button>
131
- <button class="btn btn-secondary" onclick="copyToClipboard()">Copy to Clipboard</button>
 
 
 
 
 
 
 
 
 
 
 
 
132
  </div>
133
-
134
- <div class="json-container">
135
- <pre id="json-content">{
136
- "last_node_id": 9,
137
- "last_link_id": 8,
138
- "nodes": [
139
- {
140
- "id": 1,
141
- "type": "CheckpointLoaderSimple",
142
- "pos": [
143
- 200,
144
- 100
145
- ],
146
- "size": {
147
- "0": 315,
148
- "1": 174
149
- },
150
- "flags": {},
151
- "order": 0,
152
- "mode": 0,
153
- "inputs": [
154
- {
155
- "name": "ckpt_name",
156
- "type": "COMBO",
157
- "link": null
158
- }
159
- ],
160
- "outputs": [
161
- {
162
- "name": "MODEL",
163
- "type": "MODEL",
164
- "links": [
165
- 2
166
- ],
167
- "slot_index": 0
168
- },
169
- {
170
- "name": "CLIP",
171
- "type": "CLIP",
172
- "links": [
173
- 3
174
- ],
175
- "slot_index": 0
176
- },
177
- {
178
- "name": "VAE",
179
- "type": "VAE",
180
- "links": [
181
- 4
182
- ],
183
- "slot_index": 0
184
- }
185
- ],
186
- "title": "Load Checkpoint",
187
- "properties": {
188
- "Node name for S&R": "CheckpointLoaderSimple_1"
189
- }
190
- },
191
- {
192
- "id": 2,
193
- "type": "CLIPTextEncode",
194
- "pos": [
195
- 200,
196
- 300
197
- ],
198
- "size": {
199
- "0": 422,
200
- "1": 180
201
- },
202
- "flags": {},
203
- "order": 1,
204
- "mode": 0,
205
- "inputs": [
206
- {
207
- "name": "clip",
208
- "type": "CLIP",
209
- "link": 3
210
- },
211
- {
212
- "name": "text",
213
- "type": "STRING",
214
- "link": null
215
- }
216
- ],
217
- "outputs": [
218
- {
219
- "name": "CONDITIONING",
220
- "type": "CONDITIONING",
221
- "links": [
222
- 5
223
- ],
224
- "slot_index": 0
225
- }
226
- ],
227
- "title": "CLIP Text Encode (Prompt)",
228
- "properties": {
229
- "Node name for S&R": "CLIPTextEncode_2"
230
- }
231
- },
232
- {
233
- "id": 3,
234
- "type": "CLIPTextEncode",
235
- "pos": [
236
- 200,
237
- 500
238
- ],
239
- "size": {
240
- "0": 422,
241
- "1": 180
242
- },
243
- "flags": {},
244
- "order": 2,
245
- "mode": 0,
246
- "inputs": [
247
- {
248
- "name": "clip",
249
- "type": "CLIP",
250
- "link": 3
251
- },
252
- {
253
- "name": "text",
254
- "type": "STRING",
255
- "link": null
256
- }
257
- ],
258
- "outputs": [
259
- {
260
- "name": "CONDITIONING",
261
- "type": "CONDITIONING",
262
- "links": [
263
- 6
264
- ],
265
- "slot_index": 0
266
- }
267
- ],
268
- "title": "CLIP Text Encode (Negative)",
269
- "properties": {
270
- "Node name for S&R": "CLIPTextEncode_3"
271
- }
272
- },
273
- {
274
- "id": 4,
275
- "type": "EmptyLatentImage",
276
- "pos": [
277
- 200,
278
- 700
279
- ],
280
- "size": {
281
- "0": 315,
282
- "1": 118
283
- },
284
- "flags": {},
285
- "order": 3,
286
- "mode": 0,
287
- "inputs": [
288
- {
289
- "name": "width",
290
- "type": "INT",
291
- "link": null
292
- },
293
- {
294
- "name": "height",
295
- "type": "INT",
296
- "link": null
297
- },
298
- {
299
- "name": "batch_size",
300
- "type": "INT",
301
- "link": null
302
- }
303
- ],
304
- "outputs": [
305
- {
306
- "name": "LATENT",
307
- "type": "LATENT",
308
- "links": [
309
- 7
310
- ],
311
- "slot_index": 0
312
- }
313
- ],
314
- "title": "Empty Latent Image",
315
- "properties": {
316
- "Node name for S&R": "EmptyLatentImage_4"
317
- }
318
- },
319
- {
320
- "id": 5,
321
- "type": "KSampler",
322
- "pos": [
323
- 600,
324
- 400
325
- ],
326
- "size": {
327
- "0": 315,
328
- "1": 262
329
- },
330
- "flags": {},
331
- "order": 4,
332
- "mode": 0,
333
- "inputs": [
334
- {
335
- "name": "model",
336
- "type": "MODEL",
337
- "link": 2
338
- },
339
- {
340
- "name": "seed",
341
- "type": "INT",
342
- "link": null
343
- },
344
- {
345
- "name": "steps",
346
- "type": "INT",
347
- "link": null
348
- },
349
- {
350
- "name": "cfg",
351
- "type": "FLOAT",
352
- "link": null
353
- },
354
- {
355
- "name": "sampler_name",
356
- "type": "COMBO",
357
- "link": null
358
- },
359
- {
360
- "name": "scheduler",
361
- "type": "COMBO",
362
- "link": null
363
- },
364
- {
365
- "name": "positive",
366
- "type": "CONDITIONING",
367
- "link": 5
368
- },
369
- {
370
- "name": "negative",
371
- "type": "CONDITIONING",
372
- "link": 6
373
- },
374
- {
375
- "name": "latent_image",
376
- "type": "LATENT",
377
- "link": 7
378
- }
379
- ],
380
- "outputs": [
381
- {
382
- "name": "LATENT",
383
- "type": "LATENT",
384
- "links": [
385
- 8
386
- ],
387
- "slot_index": 0
388
- }
389
- ],
390
- "title": "KSampler",
391
- "properties": {
392
- "Node name for S&R": "KSampler_5"
393
- }
394
- },
395
- {
396
- "id": 6,
397
- "type": "VAEDecode",
398
- "pos": [
399
- 1000,
400
- 400
401
- ],
402
- "size": {
403
- "0": 210,
404
- "1": 46
405
- },
406
- "flags": {},
407
- "order": 5,
408
- "mode": 0,
409
- "inputs": [
410
- {
411
- "name": "samples",
412
- "type": "LATENT",
413
- "link": 8
414
- },
415
- {
416
- "name": "vae",
417
- "type": "VAE",
418
- "link": 4
419
- }
420
- ],
421
- "outputs": [
422
- {
423
- "name": "IMAGE",
424
- "type": "IMAGE",
425
- "links": [
426
- 9
427
- ],
428
- "slot_index": 0
429
- }
430
- ],
431
- "title": "VAE Decode",
432
- "properties": {
433
- "Node name for S&R": "VAEDecode_6"
434
- }
435
- },
436
- {
437
- "id": 7,
438
- "type": "SaveImage",
439
- "pos": [
440
- 1300,
441
- 400
442
- ],
443
- "size": {
444
- "0": 210,
445
- "1": 258
446
- },
447
- "flags": {},
448
- "order": 6,
449
- "mode": 0,
450
- "inputs": [
451
- {
452
- "name": "images",
453
- "type": "IMAGE",
454
- "link": 9
455
- }
456
- ],
457
- "outputs": [],
458
- "title": "Save Image",
459
- "properties": {
460
- "Node name for S&R": "SaveImage_7"
461
- }
462
- },
463
- {
464
- "id": 8,
465
- "type": "Note",
466
- "pos": [
467
- 100,
468
- 50
469
- ],
470
- "size": {
471
- "0": 200,
472
- "1": 120
473
- },
474
- "flags": {},
475
- "order": 7,
476
- "mode": 0,
477
- "inputs": [
478
- {
479
- "name": "text",
480
- "type": "STRING",
481
- "link": null
482
- }
483
- ],
484
- "outputs": [],
485
- "title": "Note",
486
- "properties": {
487
- "Node name for S&R": "Note_8"
488
- }
489
- },
490
- {
491
- "id": 9,
492
- "type": "Note",
493
- "pos": [
494
- 100,
495
- 200
496
- ],
497
- "size": {
498
- "0": 200,
499
- "1": 120
500
- },
501
- "flags": {},
502
- "order": 8,
503
- "mode": 0,
504
- "inputs": [
505
- {
506
- "name": "text",
507
- "type": "STRING",
508
- "link": null
509
- }
510
- ],
511
- "outputs": [],
512
- "title": "Note",
513
- "properties": {
514
- "Node name for S&R": "Note_9"
515
- }
516
- }
517
- ],
518
- "links": [
519
- [
520
- 2,
521
- 1,
522
- 0,
523
- 5,
524
- 0
525
- ],
526
- [
527
- 3,
528
- 1,
529
- 1,
530
- 2,
531
- 0
532
- ],
533
- [
534
- 3,
535
- 1,
536
- 1,
537
- 3,
538
- 0
539
- ],
540
- [
541
- 4,
542
- 1,
543
- 2,
544
- 6,
545
- 1
546
- ],
547
- [
548
- 5,
549
- 2,
550
- 0,
551
- 5,
552
- 5
553
- ],
554
- [
555
- 6,
556
- 3,
557
- 0,
558
- 5,
559
- 6
560
- ],
561
- [
562
- 7,
563
- 4,
564
- 0,
565
- 5,
566
- 7
567
- ],
568
- [
569
- 8,
570
- 5,
571
- 0,
572
- 6,
573
- 0
574
- ],
575
- [
576
- 9,
577
- 6,
578
- 0,
579
- 7,
580
- 0
581
- ]
582
- ],
583
- "groups": [],
584
- "config": {},
585
- "extra": {},
586
- "version": 0.4
587
- }</pre>
588
  </div>
589
  </div>
590
 
 
 
 
 
 
 
591
  <script>
592
- function copyToClipboard() {
593
- const jsonContent = document.getElementById('json-content').textContent;
594
- navigator.clipboard.writeText(jsonContent).then(() => {
595
- const btn = event.target;
596
- const originalText = btn.textContent;
597
- btn.textContent = 'Copied!';
598
- btn.classList.add('success');
599
- setTimeout(() => {
600
- btn.textContent = originalText;
601
- btn.classList.remove('success');
602
- }, 2000);
603
- }).catch(err => {
604
- alert('Failed to copy to clipboard');
605
- });
606
- }
607
 
608
- function downloadJSON() {
609
- const jsonContent = document.getElementById('json-content').textContent;
610
- const blob = new Blob([jsonContent], { type: 'application/json' });
611
- const url = URL.createObjectURL(blob);
612
- const a = document.createElement('a');
613
- a.href = url;
614
- a.download = 'comfyui_workflow.json';
615
- document.body.appendChild(a);
616
- a.click();
617
- document.body.removeChild(a);
618
- URL.revokeObjectURL(url);
619
-
620
- const btn = event.target;
621
- const originalText = btn.textContent;
622
- btn.textContent = 'Downloaded!';
623
- btn.classList.add('success');
624
- setTimeout(() => {
625
- btn.textContent = originalText;
626
- btn.classList.remove('success');
627
- }, 2000);
628
- }
629
 
630
- // Add syntax highlighting
631
- function highlightJSON() {
632
- const content = document.getElementById('json-content');
633
- let html = content.innerHTML;
634
-
635
- // Highlight different JSON elements
636
- html = html.replace(/"([^"]+)":/g, '<span class="json-key">"$1":</span>');
637
- html = html.replace(/: "([^"]*)"/g, ': <span class="json-string">"$1"</span>');
638
- html = html.replace(/: (-?\d+\.?\d*)/g, ': <span class="json-number">$1</span>');
639
- html = html.replace(/: (true|false)/g, ': <span class="json-boolean">$1</span>');
640
- html = html.replace(/: null/g, ': <span class="json-null">null</span>');
641
-
642
- content.innerHTML = html;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
643
  }
644
 
645
- // Apply syntax highlighting after page load
646
- window.addEventListener('load', highlightJSON);
 
 
647
  </script>
648
  </body>
649
  </html>
 
1
  <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Jogo de Plinko</title>
7
  <style>
8
  * {
9
  margin: 0;
10
  padding: 0;
11
  box-sizing: border-box;
12
  }
13
+
14
  body {
15
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
16
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 
 
 
17
  min-height: 100vh;
18
+ display: flex;
19
+ flex-direction: column;
20
+ align-items: center;
21
+ padding: 20px;
22
+ color: white;
23
  }
24
+
 
 
 
25
  .header {
26
  text-align: center;
27
+ margin-bottom: 20px;
28
+ width: 100%;
29
  }
30
+
31
  .header h1 {
32
+ font-size: 2.5rem;
33
+ margin-bottom: 10px;
34
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
 
 
35
  }
36
+
37
+ .built-with {
38
+ margin-top: 10px;
39
+ font-size: 0.9rem;
40
+ opacity: 0.8;
41
  }
42
+
43
+ .built-with a {
44
+ color: #ffeb3b;
45
+ text-decoration: none;
46
+ transition: color 0.3s;
47
+ }
48
+
49
+ .built-with a:hover {
50
+ color: #fff;
51
+ text-decoration: underline;
52
+ }
53
+
54
+ .game-container {
55
  display: flex;
56
+ flex-direction: column;
57
+ align-items: center;
58
+ gap: 20px;
59
+ max-width: 800px;
60
+ width: 100%;
61
  }
62
+
63
+ .stats-panel {
64
+ background: rgba(255, 255, 255, 0.1);
65
+ backdrop-filter: blur(10px);
66
+ padding: 15px 25px;
67
+ border-radius: 15px;
68
+ display: flex;
69
+ justify-content: space-between;
70
+ width: 100%;
71
+ box-shadow: 0 8px 32px rgba(0,0,0,0.1);
72
  }
73
+
74
+ .stat {
75
+ text-align: center;
76
  }
77
+
78
+ .stat-value {
79
+ font-size: 1.8rem;
80
+ font-weight: bold;
81
+ color: #ffeb3b;
82
  }
83
+
84
+ .stat-label {
85
+ font-size: 0.9rem;
86
+ opacity: 0.8;
87
  }
88
+
89
+ .game-board {
90
+ position: relative;
91
+ width: 100%;
92
+ height: 500px;
93
+ background: rgba(255, 255, 255, 0.05);
94
+ border-radius: 15px;
95
+ overflow: hidden;
96
+ box-shadow: 0 10px 30px rgba(0,0,0,0.2);
97
  }
98
+
99
+ .peg-container {
100
+ position: absolute;
101
+ top: 0;
102
+ left: 0;
103
+ width: 100%;
104
+ height: 100%;
105
  }
106
+
107
+ .peg {
108
+ position: absolute;
109
+ width: 12px;
110
+ height: 12px;
111
+ background: #ffeb3b;
112
+ border-radius: 50%;
113
+ transform: translate(-50%, -50%);
114
+ box-shadow: 0 0 10px rgba(255, 235, 59, 0.5);
115
  }
116
+
117
+ .ball {
118
+ position: absolute;
119
+ width: 20px;
120
+ height: 20px;
121
+ background: #ff4081;
122
+ border-radius: 50%;
123
+ transform: translate(-50%, -50%);
124
+ box-shadow: 0 0 15px rgba(255, 64, 129, 0.7);
125
+ z-index: 10;
126
+ transition: transform 0.1s;
127
  }
128
+
129
+ .slot-container {
130
+ position: absolute;
131
+ bottom: 0;
132
+ left: 0;
133
+ width: 100%;
134
+ height: 60px;
135
+ display: flex;
136
+ justify-content: space-around;
137
+ padding: 0 10px;
138
  }
139
+
140
+ .slot {
141
+ flex: 1;
142
+ height: 100%;
143
+ margin: 0 5px;
144
+ background: rgba(255, 255, 255, 0.1);
145
+ border-radius: 10px 10px 0 0;
146
+ display: flex;
147
+ align-items: center;
148
+ justify-content: center;
149
+ font-weight: bold;
150
+ font-size: 1.2rem;
151
+ color: #ffeb3b;
152
+ transition: all 0.3s;
153
  }
154
+
155
+ .slot.active {
156
+ background: rgba(255, 235, 59, 0.3);
157
+ transform: scale(1.05);
158
  }
159
+
160
+ .controls {
161
+ display: flex;
162
+ gap: 15px;
163
+ flex-wrap: wrap;
164
+ justify-content: center;
165
  }
166
+
167
+ .btn {
168
+ padding: 12px 25px;
169
+ background: rgba(255, 255, 255, 0.2);
170
+ border: none;
171
+ border-radius: 25px;
172
+ color: white;
173
+ font-size: 1rem;
174
+ font-weight: 600;
175
+ cursor: pointer;
176
+ transition: all 0.3s;
177
+ backdrop-filter: blur(10px);
178
+ }
179
+
180
+ .btn:hover {
181
+ background: rgba(255, 255, 255, 0.3);
182
+ transform: translateY(-2px);
183
+ }
184
+
185
+ .btn:active {
186
+ transform: translateY(0);
187
  }
188
+
189
+ .btn-primary {
190
+ background: linear-gradient(45deg, #ff4081, #ff9800);
191
+ }
192
+
193
+ .btn-primary:hover {
194
+ background: linear-gradient(45deg, #f50057, #ff5722);
195
+ }
196
+
197
+ .message {
198
+ position: fixed;
199
+ top: 50%;
200
+ left: 50%;
201
+ transform: translate(-50%, -50%);
202
+ background: rgba(0, 0, 0, 0.8);
203
+ padding: 30px 50px;
204
+ border-radius: 15px;
205
+ text-align: center;
206
+ z-index: 100;
207
+ backdrop-filter: blur(10px);
208
+ display: none;
209
+ }
210
+
211
+ .message h2 {
212
+ margin-bottom: 15px;
213
+ color: #ffeb3b;
214
+ }
215
+
216
  @media (max-width: 768px) {
217
+ .game-board {
218
+ height: 400px;
219
+ }
220
+
221
  .header h1 {
222
+ font-size: 2rem;
223
+ }
224
+
225
+ .stat-value {
226
+ font-size: 1.5rem;
227
  }
228
+
229
+ .btn {
230
+ padding: 10px 20px;
231
+ font-size: 0.9rem;
232
+ }
233
+ }
234
+
235
+ @media (max-width: 480px) {
236
+ .game-board {
237
+ height: 350px;
238
+ }
239
+
240
+ .stats-panel {
241
+ flex-direction: column;
242
+ gap: 10px;
243
+ }
244
+
245
  .controls {
246
  flex-direction: column;
247
+ width: 100%;
248
  }
249
+
250
+ .btn {
251
+ width: 100%;
252
  }
253
  }
254
  </style>
255
  </head>
256
  <body>
257
+ <div class="header">
258
+ <h1>🎯 Jogo de Plinko</h1>
259
+ <p>Solte a bola e veja onde ela vai cair!</p>
260
+ <div class="built-with">
261
+ Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
262
  </div>
263
+ </div>
264
+
265
+ <div class="game-container">
266
+ <div class="stats-panel">
267
+ <div class="stat">
268
+ <div class="stat-value" id="score">0</div>
269
+ <div class="stat-label">Pontuação</div>
270
+ </div>
271
+ <div class="stat">
272
+ <div class="stat-value" id="balls-left">10</div>
273
+ <div class="stat-label">Bolas Restantes</div>
274
+ </div>
275
+ <div class="stat">
276
+ <div class="stat-value" id="multiplier">1x</div>
277
+ <div class="stat-label">Multiplicador</div>
278
+ </div>
279
  </div>
280
+
281
+ <div class="game-board" id="gameBoard">
282
+ <div class="peg-container" id="pegContainer"></div>
283
+ <div class="slot-container" id="slotContainer"></div>
284
+ </div>
285
+
286
+ <div class="controls">
287
+ <button class="btn btn-primary" id="dropBall">Soltar Bola</button>
288
+ <button class="btn" id="resetGame">Reiniciar Jogo</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  </div>
290
  </div>
291
 
292
+ <div class="message" id="gameOverMessage">
293
+ <h2>Fim de Jogo!</h2>
294
+ <p>Sua pontuação final: <span id="finalScore">0</span></p>
295
+ <button class="btn btn-primary" id="playAgain">Jogar Novamente</button>
296
+ </div>
297
+
298
  <script>
299
+ class PlinkoGame {
300
+ constructor() {
301
+ this.gameBoard = document.getElementById('gameBoard');
302
+ this.pegContainer = document.getElementById('pegContainer');
303
+ this.slotContainer = document.getElementById('slotContainer');
304
+ this.scoreElement = document.getElementById('score');
305
+ this.ballsLeftElement = document.getElementById('balls-left');
306
+ this.multiplierElement = document.getElementById('multiplier');
307
+ this.dropBallBtn = document.getElementById('dropBall');
308
+ this.resetGameBtn = document.getElementById('resetGame');
309
+ this.gameOverMessage = document.getElementById('gameOverMessage');
310
+ this.finalScoreElement = document.getElementById('finalScore');
311
+ this.playAgainBtn = document.getElementById('playAgain');
 
 
312
 
313
+ this.score = 0;
314
+ this.ballsLeft = 10;
315
+ this.multiplier = 1;
316
+ this.isDropping = false;
317
+ this.balls = [];
318
+ this.pegs = [];
319
+ this.slots = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
 
321
+ this.init();
322
+ this.setupEventListeners();
323
+ }
324
+
325
+ init() {
326
+ this.createPegs();
327
+ this.createSlots();
328
+ this.updateUI();
329
+ }
330
+
331
+ createPegs() {
332
+ const rows = 10;
333
+ const boardWidth = this.gameBoard.clientWidth;
334
+ const boardHeight = this.gameBoard.clientHeight - 60; // Subtract slot height
335
+
336
+ for (let row = 1; row <= rows; row++) {
337
+ const pegsInRow = row + 5;
338
+ const y = (row / (rows + 1)) * boardHeight + 50;
339
+
340
+ for (let col = 0; col < pegsInRow; col++) {
341
+ const x = (col + 0.5) / pegsInRow * boardWidth;
342
+
343
+ const peg = document.createElement('div');
344
+ peg.className = 'peg';
345
+ peg.style.left = `${x}px`;
346
+ peg.style.top = `${y}px`;
347
+
348
+ this.pegContainer.appendChild(peg);
349
+ this.pegs.push({
350
+ element: peg,
351
+ x: x,
352
+ y: y,
353
+ radius: 6
354
+ });
355
+ }
356
+ }
357
+ }
358
+
359
+ createSlots() {
360
+ const slotCount = 7;
361
+ const slotValues = [1, 2, 5, 10, 5, 2, 1];
362
+
363
+ for (let i = 0; i < slotCount; i++) {
364
+ const slot = document.createElement('div');
365
+ slot.className = 'slot';
366
+ slot.textContent = slotValues[i];
367
+ slot.dataset.value = slotValues[i];
368
+
369
+ this.slotContainer.appendChild(slot);
370
+ this.slots.push({
371
+ element: slot,
372
+ value: slotValues[i],
373
+ x: (i + 0.5) * (this.gameBoard.clientWidth / slotCount),
374
+ width: this.gameBoard.clientWidth / slotCount
375
+ });
376
+ }
377
+ }
378
+
379
+ dropBall() {
380
+ if (this.isDropping || this.ballsLeft <= 0) return;
381
+
382
+ this.isDropping = true;
383
+ this.ballsLeft--;
384
+
385
+ const startX = this.gameBoard.clientWidth / 2;
386
+ const ball = document.createElement('div');
387
+ ball.className = 'ball';
388
+ ball.style.left = `${startX}px`;
389
+ ball.style.top = '30px';
390
+
391
+ this.gameBoard.appendChild(ball);
392
+
393
+ const ballObj = {
394
+ element: ball,
395
+ x: startX,
396
+ y: 30,
397
+ vx: (Math.random() - 0.5) * 2,
398
+ vy: 0,
399
+ radius: 10,
400
+ active: true
401
+ };
402
+
403
+ this.balls.push(ballObj);
404
+ this.animateBall(ballObj);
405
+ this.updateUI();
406
+ }
407
+
408
+ animateBall(ball) {
409
+ const gravity = 0.2;
410
+ const friction = 0.99;
411
+ const bounce = 0.7;
412
+
413
+ const animate = () => {
414
+ if (!ball.active) return;
415
+
416
+ // Apply gravity
417
+ ball.vy += gravity;
418
+
419
+ // Update position
420
+ ball.x += ball.vx;
421
+ ball.y += ball.vy;
422
+
423
+ // Check collisions with pegs
424
+ this.checkPegCollisions(ball);
425
+
426
+ // Check wall collisions
427
+ if (ball.x <= ball.radius || ball.x >= this.gameBoard.clientWidth - ball.radius) {
428
+ ball.vx *= -bounce;
429
+ ball.x = Math.max(ball.radius, Math.min(this.gameBoard.clientWidth - ball.radius, ball.x));
430
+ }
431
+
432
+ // Check if ball reached bottom
433
+ if (ball.y >= this.gameBoard.clientHeight - 60 - ball.radius) {
434
+ this.handleBallLanded(ball);
435
+ return;
436
+ }
437
+
438
+ // Apply friction
439
+ ball.vx *= friction;
440
+ ball.vy *= friction;
441
+
442
+ // Update ball position
443
+ ball.element.style.left = `${ball.x}px`;
444
+ ball.element.style.top = `${ball.y}px`;
445
+
446
+ requestAnimationFrame(animate);
447
+ };
448
+
449
+ animate();
450
+ }
451
+
452
+ checkPegCollisions(ball) {
453
+ for (const peg of this.pegs) {
454
+ const dx = ball.x - peg.x;
455
+ const dy = ball.y - peg.y;
456
+ const distance = Math.sqrt(dx * dx + dy * dy);
457
+
458
+ if (distance < ball.radius + peg.radius) {
459
+ // Collision detected
460
+ const angle = Math.atan2(dy, dx);
461
+ const targetX = peg.x + Math.cos(angle) * (ball.radius + peg.radius);
462
+ const targetY = peg.y + Math.sin(angle) * (ball.radius + peg.radius);
463
+
464
+ const ax = (targetX - ball.x) * 0.1;
465
+ const ay = (targetY - ball.y) * 0.1;
466
+
467
+ ball.vx -= ax;
468
+ ball.vy -= ay;
469
+
470
+ // Add some random variation
471
+ ball.vx += (Math.random() - 0.5) * 0.5;
472
+
473
+ // Move ball outside peg
474
+ ball.x = targetX;
475
+ ball.y = targetY;
476
+ }
477
+ }
478
+ }
479
+
480
+ handleBallLanded(ball) {
481
+ ball.active = false;
482
+ this.isDropping = false;
483
+
484
+ // Find which slot the ball landed in
485
+ const slotIndex = this.findSlotForBall(ball.x);
486
+ if (slotIndex !== -1) {
487
+ const slotValue = this.slots[slotIndex].value;
488
+ const points = slotValue * this.multiplier;
489
+
490
+ this.score += points;
491
+ this.multiplier = Math.min(this.multiplier + 0.2, 5);
492
+
493
+ // Highlight the slot
494
+ this.slots[slotIndex].element.classList.add('active');
495
+ setTimeout(() => {
496
+ this.slots[slotIndex].element.classList.remove('active');
497
+ }, 1000);
498
+
499
+ // Remove ball after a delay
500
+ setTimeout(() => {
501
+ ball.element.remove();
502
+ this.balls = this.balls.filter(b => b !== ball);
503
+ }, 500);
504
+ }
505
+
506
+ this.updateUI();
507
+
508
+ // Check game over
509
+ if (this.ballsLeft === 0 && this.balls.length === 0) {
510
+ setTimeout(() => this.showGameOver(), 1000);
511
+ }
512
+ }
513
+
514
+ findSlotForBall(x) {
515
+ for (let i = 0; i < this.slots.length; i++) {
516
+ const slot = this.slots[i];
517
+ const slotLeft = slot.x - slot.width / 2;
518
+ const slotRight = slot.x + slot.width / 2;
519
+
520
+ if (x >= slotLeft && x <= slotRight) {
521
+ return i;
522
+ }
523
+ }
524
+ return -1;
525
+ }
526
+
527
+ updateUI() {
528
+ this.scoreElement.textContent = this.score;
529
+ this.ballsLeftElement.textContent = this.ballsLeft;
530
+ this.multiplierElement.textContent = `${this.multiplier.toFixed(1)}x`;
531
+
532
+ // Update button state
533
+ this.dropBallBtn.disabled = this.isDropping || this.ballsLeft <= 0;
534
+ }
535
+
536
+ showGameOver() {
537
+ this.finalScoreElement.textContent = this.score;
538
+ this.gameOverMessage.style.display = 'block';
539
+ }
540
+
541
+ resetGame() {
542
+ // Remove all balls
543
+ this.balls.forEach(ball => {
544
+ ball.element.remove();
545
+ });
546
+
547
+ this.balls = [];
548
+ this.score = 0;
549
+ this.ballsLeft = 10;
550
+ this.multiplier = 1;
551
+ this.isDropping = false;
552
+ this.gameOverMessage.style.display = 'none';
553
+ this.updateUI();
554
+ }
555
+
556
+ setupEventListeners() {
557
+ this.dropBallBtn.addEventListener('click', () => this.dropBall());
558
+ this.resetGameBtn.addEventListener('click', () => this.resetGame());
559
+ this.playAgainBtn.addEventListener('click', () => this.resetGame());
560
+
561
+ // Allow dropping ball by pressing spacebar
562
+ document.addEventListener('keydown', (e) => {
563
+ if (e.code === 'Space' && !this.isDropping && this.ballsLeft > 0) {
564
+ e.preventDefault();
565
+ this.dropBall();
566
+ }
567
+ });
568
+ }
569
  }
570
 
571
+ // Initialize the game when the page loads
572
+ document.addEventListener('DOMContentLoaded', () => {
573
+ new PlinkoGame();
574
+ });
575
  </script>
576
  </body>
577
  </html>