kimhyunwoo commited on
Commit
6f10b35
Β·
verified Β·
1 Parent(s): d03241e

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +469 -462
index.html CHANGED
@@ -3,41 +3,40 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Thronglets Imitation (Gameplay Only)</title>
7
  <style>
8
  body {
9
  margin: 0;
10
  overflow: hidden;
11
- background: #111;
12
- color: limegreen;
13
  font-family: 'Courier New', monospace;
14
  display: flex;
15
- flex-direction: column;
16
  align-items: center;
17
- justify-content: center;
18
  min-height: 100vh;
19
  position: relative;
20
  }
21
 
22
  .game-container {
23
  position: relative;
24
- width: 90vmin;
25
- height: 60vmin;
26
- max-width: 800px;
27
- max-height: 500px;
28
- background: #3A4A2F; /* Grass background */
29
- border: 10px solid #8B4513; /* Wooden frame */
 
30
  box-sizing: border-box;
31
- overflow: hidden; /* Keep everything inside the frame */
32
- display: flex; /* Changed from flex to allow absolute positioning of elements */
33
  justify-content: center;
34
  align-items: center;
35
- /* flex-wrap: wrap; Removed as elements are absolutely positioned now */
36
- padding: 20px; /* Padding inside the frame */
37
- image-rendering: pixelated; /* Attempt pixelation */
38
- font-size: 2em; /* Emojis larger */
39
- position: relative; /* Needed for absolute positioning of children */
40
- transition: opacity 1s ease-out; /* Added for fade out */
41
  }
42
 
43
  .game-elements {
@@ -46,41 +45,47 @@
46
  left: 0;
47
  width: 100%;
48
  height: 100%;
49
- pointer-events: none; /* Allow clicks to pass through */
50
  }
51
 
52
  .game-elements .emoji, .game-elements .text {
53
  position: absolute;
54
- pointer-events: auto; /* Allow clicks on interactable elements */
55
- transform: translate(-50%, -50%); /* Center element */
56
  user-select: none;
57
- z-index: 1; /* Ensure elements are above background but below UI */
 
58
  }
59
 
 
60
  .rock { top: 15%; left: 15%; z-index: 0;}
61
  .rock.right { left: 85%; z-index: 0;}
62
- .tree { top: 75%; left: 20%; z-index: 0;}
63
- .tree.right { left: 80%; z-index: 0;}
64
- .egg { top: 50%; left: 50%; cursor: pointer; transition: transform 0.5s ease; z-index: 2;}
 
 
65
  .egg.hatching { animation: hatch-pulse 0.5s infinite alternate; }
 
66
  .thronglet {
67
- /* Position set dynamically by JS */
68
- cursor: pointer;
69
- transition: top 0.5s, left 0.5s, transform 0.2s ease, opacity 0.5s ease-out;
70
- z-index: 3; /* Thronglets above items */
71
  }
72
 
73
- .apple { top: 60%; left: 40%; cursor: pointer; z-index: 2;}
74
- .bath { top: 60%; left: 60%; cursor: pointer; z-index: 2;}
75
 
76
  .feedback {
77
  position: absolute;
78
- transform: translate(-50%, -150%); /* Above thronglet */
79
  font-size: 0.8em;
80
  opacity: 0;
81
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
82
- pointer-events: none; /* Don't interfere with clicks */
83
- z-index: 5; /* Above everything else in game area */
 
84
  }
85
  .feedback.active {
86
  opacity: 1;
@@ -91,7 +96,7 @@
91
  filter: grayscale(100%);
92
  opacity: 0.5;
93
  pointer-events: none;
94
- z-index: 1; /* Sink slightly when dead */
95
  }
96
 
97
  .blood {
@@ -101,288 +106,205 @@
101
  pointer-events: none;
102
  opacity: 0;
103
  transition: opacity 0.5s ease-out;
104
- z-index: 0; /* Behind everything */
105
- }
106
- .blood.splatter { opacity: 1; }
107
-
108
- .skull { font-size: 1.5em; pointer-events: none; }
109
-
110
- .console {
111
- position: fixed;
112
- bottom: 20px;
113
- left: 50%;
114
- transform: translateX(-50%);
115
- width: 90%;
116
- max-width: 600px;
117
- background: rgba(0, 0, 0, 0.8);
118
- border: 2px groove limegreen;
119
  padding: 10px;
120
  box-sizing: border-box;
121
- white-space: pre-wrap;
122
- word-break: break-word;
123
- pointer-events: none; /* Don't block clicks */
124
- z-index: 100;
125
- max-height: 150px; /* Limit console height */
126
- overflow-y: scroll; /* Add scrollbar if needed */
127
- transition: opacity 1s ease-out; /* Added for fade out */
128
  }
129
 
130
- .message {
131
- display: block;
132
- margin-bottom: 5px;
133
- color: limegreen;
134
- white-space: pre-wrap;
135
  }
136
 
137
- .scanline-overlay {
138
- position: fixed;
139
- top: 0;
140
- left: 0;
141
- width: 100%;
142
- height: 100%;
143
- pointer-events: none;
144
- z-index: 101;
145
- background: repeating-linear-gradient(
146
- 0deg,
147
- rgba(0, 0, 0, 0.1) 0,
148
- rgba(0, 0, 0, 0.1) 1px,
149
- transparent 1px,
150
- transparent 2px
151
- );
152
- transition: opacity 1s ease-out; /* Added for fade out */
153
- }
154
-
155
- .glitch-overlay {
156
- position: fixed;
157
- top: 0;
158
- left: 0;
 
159
  width: 100%;
160
- height: 100%;
 
 
 
 
 
 
161
  pointer-events: none;
162
- z-index: 102;
163
- animation: glitch 5s infinite alternate steps(5);
164
- opacity: 0;
165
- filter: hue-rotate(0deg);
166
- transition: opacity 1s ease-out; /* Added for fade out */
167
  }
 
 
 
 
168
 
169
- .glitch-overlay.active {
170
- animation: glitch 0.3s infinite alternate steps(5), color-shift 1s infinite linear;
171
- opacity: 0.5;
172
- }
173
 
 
 
 
 
 
 
 
 
174
 
175
- @keyframes hatch-pulse {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  from { transform: translate(-50%, -50%) scale(1); }
177
  to { transform: translate(-50%, -50%) scale(1.05); }
178
  }
179
-
180
- @keyframes glitch {
181
- 0% { transform: translate(0); }
182
- 20% { transform: translate(-5px, 5px); }
183
- 40% { transform: translate(-5px, -5px); }
184
- 60% { transform: translate(5px, 5px); }
185
- 80% { transform: translate(5px, -5px); }
186
- to { transform: translate(0); }
187
  }
188
-
189
- @keyframes color-shift {
190
- 0% { filter: hue-rotate(0deg); }
191
- 100% { filter: hue-rotate(360deg); }
192
  }
193
 
194
- /* Basic representation of later elements */
195
- .ominous-elements {
196
- position: absolute;
197
- top: 10%;
198
- right: 10%;
199
- font-size: 3em;
200
- opacity: 0;
201
- transition: opacity 2s ease-in-out;
202
- z-index: 0; /* Behind most things */
203
- pointer-events: none;
204
- }
205
- .ominous-elements.visible {
206
- opacity: 1;
207
- }
208
-
209
- .info-panel {
210
- position: absolute;
211
- top: 50%;
212
- left: 50%;
213
- transform: translate(-50%, -50%);
214
- background: #8B4513; /* Brown panel */
215
- border: 2px solid black;
216
- padding: 15px;
217
- color: white;
218
- font-family: 'Courier New', monospace; /* Match console font */
219
- font-size: 0.7em;
220
- text-align: center;
221
- white-space: pre-wrap;
222
- word-break: break-word;
223
- opacity: 0;
224
- transition: opacity 1s ease-in-out;
225
- pointer-events: none;
226
- z-index: 5; /* Above game elements */
227
- max-width: 80%; /* Prevent panel from being too wide */
228
- }
229
- .info-panel.visible {
230
- opacity: 1;
231
- /* pointer-events: auto; Keep as none unless interaction needed */
232
- }
233
-
234
- .black-mirror-title {
235
- position: absolute;
236
- top: 10px;
237
- left: 10px;
238
- font-size: 0.8em;
239
- color: white;
240
- font-weight: bold;
241
- text-shadow: 1px 1px 0 black;
242
- z-index: 10; /* Above game container border */
243
- }
244
-
245
- .netflix-logo {
246
- position: absolute;
247
- top: 10px;
248
- right: 10px;
249
- font-size: 1.2em; /* Use the 'N' emoji? */
250
- color: red; /* Or maybe style text */
251
- font-weight: bold;
252
- text-shadow: 1px 1px 0 black;
253
- z-index: 10; /* Above game container border */
254
- }
255
-
256
- /* Final screen styling */
257
- .final-screen {
258
- position: fixed;
259
- top: 0;
260
- left: 0;
261
- width: 100%;
262
- height: 100%;
263
- /* Updated background to match video more closely */
264
- background: linear-gradient(to bottom, #744FAA, #D470A3); /* Purple to Pink/Purple gradient */
265
- z-index: 300;
266
- display: flex;
267
- flex-direction: column;
268
- align-items: center;
269
- justify-content: center;
270
- color: white;
271
- font-size: 1.5em;
272
- text-align: center;
273
- opacity: 0;
274
- transition: opacity 2s ease-in-out;
275
- pointer-events: none; /* Initially not interactive */
276
- }
277
- .final-screen.visible {
278
- opacity: 1;
279
- pointer-events: auto; /* Make interactive when visible */
280
- }
281
-
282
- .app-stores {
283
- margin-top: 20px;
284
- font-size: 0.8em;
285
- }
286
- .app-stores img {
287
- height: 40px;
288
- margin: 0 10px;
289
- cursor: pointer; /* Indicate clickable */
290
- }
291
-
292
- .full-black {
293
- position: fixed;
294
- top: 0; left: 0; width: 100%; height: 100%;
295
- background: black;
296
- z-index: 301;
297
- opacity: 0;
298
- transition: opacity 1s ease-in-out;
299
- pointer-events: none;
300
- }
301
- .full-black.visible { opacity: 1; }
302
-
303
- .netflix-games-logo {
304
- position: fixed;
305
- top: 50%;
306
- left: 50%;
307
- transform: translate(-50%, -50%);
308
- z-index: 302;
309
- opacity: 0;
310
- transition: opacity 1s ease-in-out;
311
- pointer-events: none;
312
- }
313
- .netflix-games-logo.visible { opacity: 1; }
314
- .netflix-games-logo .emoji {
315
- font-size: 8em; /* Larger N */
316
- color: red;
317
- text-shadow: 2px 2px 5px rgba(0,0,0,0.5);
318
- }
319
-
320
-
321
  </style>
322
  </head>
323
  <body>
324
 
325
- <!-- Game container now starts visible -->
326
  <div class="game-container" id="gameContainer">
327
- <div class="black-mirror-title">BLACK MIRROR:<br>THRONGLETS</div>
328
- <div class="netflix-logo">N<br>GAMES</div> <!-- Simulate Netflix Games logo -->
329
-
330
  <div class="game-elements" id="gameElements">
331
  <!-- Static elements -->
332
  <span class="emoji rock">πŸͺ¨</span>
333
  <span class="emoji rock right">πŸͺ¨</span>
334
  <span class="emoji tree">🌳</span>
335
  <span class="emoji tree right">🌳</span>
336
-
337
  <!-- Initial dynamic elements -->
338
  <span class="emoji egg" id="egg">πŸ₯š</span>
339
- <span class="emoji apple" id="apple">🍎</span>
340
- <span class="emoji bath" id="bath">πŸ›€</span>
341
-
342
- <!-- Ominous elements for later -->
343
- <div class="ominous-elements" id="ominousElements">
344
- πŸ’€πŸ’€πŸ’€πŸ’€<br>🦴🦴🦴🦴<br>πŸŒŒπŸ“¦
345
- </div>
346
-
347
- <!-- Info Panel -->
348
  <div class="info-panel" id="infoPanel"></div>
349
-
350
- <!-- Blood splatter area -->
351
- <span class="emoji blood" id="bloodSplatter">🩸</span>
352
-
353
- <!-- Thronglets will be added here by JS -->
354
  </div>
 
355
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  </div>
357
 
358
- <div class="console" id="console"></div>
359
  <div class="scanline-overlay" id="scanlineOverlay"></div>
360
  <div class="glitch-overlay" id="glitchOverlay"></div>
361
 
362
- <!-- Final Screens (initially hidden) -->
363
  <div class="final-screen" id="finalScreen">
364
  PLAY NOW<br>ON THE NETFLIX<br>MOBILE APP
365
  <div class="app-stores">
366
- <!-- Placeholder images or text for store buttons -->
367
  <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBvbHlnb24gcG9pbnRzPSIxMyAyIDMgMTQgNyAxNCAxNSAyIj48L3BvbHlnb24+PHBvbHlnb24gcG9pbnRzPSIxNiAxMCAyMCAxMCAyMyAxNyAxNiAxNSI+PC9wb2x5Z29uPjxjaXJjbGUgY3g9IjUuNSIgY3k9IjE3LjUiIHI9IjIuNSI+PC9jaXJjbGU+PGNpcmNsZSBjeD0iMTguNSIgY3k9IjE3LjUiIHI9IjIuNSI+PC9jaXJjbGU+PC9zdmc+" alt="Google Play Placeholder">
368
  <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTE1LjkgNi4zQTEwIDkuNyAwIDAgMCAyIDZjMCA3IDEzIDggMTMgOGEyIDIgMCAwIDAgMS03LjZsLS43LTFsLTMuNS01LjV6Ij48L3BhdGg+PHBhdGggZD0iTTExIDE0YTYgNiAwIDAgMCA2IDBjMCAuNDQtLjEgLjktLjYgMWExMCA5LjcgMCAwIDEgLTkuNCAwYy0uNS0uMS0uNi0uNi0uNi0xYTYgNiAwIDAgMCA0LTZ6Ij48L3BhdGg+PC9zdmc+" alt="App Store Placeholder">
369
- <!-- (Store Buttons Go Here) -->
370
  </div>
371
  </div>
372
-
373
  <div class="full-black" id="fullBlack"></div>
374
- <div class="netflix-games-logo" id="netflixGamesLogo">
375
- <span class="emoji">N</span>
376
- </div>
377
 
378
 
379
  <script>
 
380
  const egg = document.getElementById('egg');
381
  const gameContainer = document.getElementById('gameContainer');
382
- const gameElements = document.getElementById('gameElements'); // Reference to the container for dynamic elements
 
383
  const consoleDiv = document.getElementById('console');
384
- const apple = document.getElementById('apple');
385
- const bath = document.getElementById('bath');
386
  const glitchOverlay = document.getElementById('glitchOverlay');
387
  const scanlineOverlay = document.getElementById('scanlineOverlay');
388
  const ominousElements = document.getElementById('ominousElements');
@@ -391,24 +313,158 @@
391
  const finalScreen = document.getElementById('finalScreen');
392
  const fullBlack = document.getElementById('fullBlack');
393
  const netflixGamesLogo = document.getElementById('netflixGamesLogo');
 
 
 
394
 
 
395
  let thronglets = [];
396
  let nextThrongletId = 0;
397
  let deathCount = 0;
398
- const MAX_THRONGLETS = 20; // Cap the number for performance
399
  let gameInterval;
400
- let gameActive = true; // Flag to control game loop
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
 
402
- // --- Game State & Logic ---
 
 
 
 
 
403
 
404
- function logToConsole(message) {
405
  const msgElement = document.createElement('span');
406
  msgElement.classList.add('message');
407
- msgElement.textContent = `> ${message}`;
 
 
 
 
408
  consoleDiv.appendChild(msgElement);
409
  consoleDiv.scrollTop = consoleDiv.scrollHeight; // Auto-scroll
410
  }
411
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  function triggerGlitch(duration = 1000) {
413
  if (!gameActive) return;
414
  glitchOverlay.classList.add('active');
@@ -417,112 +473,96 @@
417
  }, duration);
418
  }
419
 
420
- function showInfoPanel(text, duration = 3000) { // Increased default duration
421
  if (!gameActive) return;
422
  infoPanel.textContent = text;
423
  infoPanel.classList.add('visible');
424
- clearTimeout(infoPanel.timeout); // Clear previous timeout if any
425
  infoPanel.timeout = setTimeout(() => {
426
  infoPanel.classList.remove('visible');
427
  }, duration);
428
  }
429
 
430
  function createThronglet(xPercent, yPercent) {
431
- if (!gameActive || thronglets.length >= MAX_THRONGLETS) {
432
- if (thronglets.length >= MAX_THRONGLETS) {
433
- logToConsole("! Population limit reached.");
 
434
  }
435
  return;
436
  }
437
 
438
  const throngletElement = document.createElement('span');
439
  throngletElement.classList.add('emoji', 'thronglet');
440
- throngletElement.textContent = 'πŸ•'; // Using dog emoji as placeholder
441
  const currentId = nextThrongletId++;
442
  throngletElement.dataset.id = currentId;
443
  throngletElement.style.top = `${yPercent}%`;
444
  throngletElement.style.left = `${xPercent}%`;
445
- throngletElement.dataset.bornTime = Date.now(); // Track birth time
446
- gameElements.appendChild(throngletElement); // Append to gameElements div
447
 
448
  const newThronglet = {
449
  id: currentId,
450
  element: throngletElement,
451
- hunger: 30, // Start less hungry
452
- cleanliness: 30, // Start less dirty
453
- happiness: 70, // Start happier
454
  lastInteraction: Date.now(),
 
455
  isDead: false,
456
- memory: [], // To store events
457
- feedbackElement: null // Initialize feedback element later
458
  };
459
  thronglets.push(newThronglet);
460
 
461
- // Add click listener for interaction (maybe remove this? Trailer implies interaction via items)
462
- // throngletElement.addEventListener('click', () => interactThronglet(newThronglet));
463
-
464
- logToConsole(`A new Thronglet #${newThronglet.id} appeared!`);
465
-
466
- // Add feedback element (needs to be created after thronglet is added to DOM)
467
  const feedbackElement = document.createElement('span');
468
  feedbackElement.classList.add('emoji', 'feedback');
469
- // Position feedback relative to the thronglet initially
470
  feedbackElement.style.top = throngletElement.style.top;
471
  feedbackElement.style.left = throngletElement.style.left;
472
- gameElements.appendChild(feedbackElement); // Append to gameElements div
473
  newThronglet.feedbackElement = feedbackElement;
474
 
475
- // Initial random wander
476
- setTimeout(() => {
477
- if (!newThronglet.isDead) wander(newThronglet);
478
- }, 50); // Slight delay before first move
479
- }
480
-
481
- // Function to interact (currently not directly clickable, but could be triggered)
482
- function interactThronglet(thronglet) {
483
- if (!gameActive || thronglet.isDead) return;
484
- thronglet.lastInteraction = Date.now();
485
- thronglet.happiness = Math.min(100, thronglet.happiness + 5); // Small happiness boost
486
- showFeedback(thronglet, 'πŸ‘‹');
487
- logToConsole(`Acknowledged Thronglet #${thronglet.id}`);
488
- thronglet.memory.push('Acknowledged');
489
  }
490
 
491
  function feedThronglet(thronglet) {
492
  if (!gameActive || thronglet.isDead) return;
493
- thronglet.hunger = Math.max(0, thronglet.hunger - 40); // More filling
494
- thronglet.happiness = Math.min(100, thronglet.happiness + 15);
495
  thronglet.lastInteraction = Date.now();
496
- showFeedback(thronglet, '🍎');
497
- logToConsole(`Fed Thronglet #${thronglet.id}. Hunger: ${thronglet.hunger.toFixed(0)}`);
498
- thronglet.memory.push('Fed');
 
499
  }
500
 
501
  function cleanThronglet(thronglet) {
502
  if (!gameActive || thronglet.isDead) return;
503
- thronglet.cleanliness = Math.max(0, thronglet.cleanliness - 50); // More cleaning power
504
- thronglet.happiness = Math.min(100, thronglet.happiness + 10); // Cleaning is okay, not great
505
  thronglet.lastInteraction = Date.now();
506
- showFeedback(thronglet, 'πŸ›');
507
- logToConsole(`Cleaned Thronglet #${thronglet.id}. Cleanliness: ${thronglet.cleanliness.toFixed(0)}`);
 
508
  thronglet.memory.push('Cleaned');
509
  }
510
 
511
  function showFeedback(thronglet, emoji) {
512
  if (!gameActive || !thronglet.feedbackElement || thronglet.isDead) return;
513
-
514
- // Update feedback position to match current thronglet position
515
  thronglet.feedbackElement.style.top = thronglet.element.style.top;
516
  thronglet.feedbackElement.style.left = thronglet.element.style.left;
517
-
518
  thronglet.feedbackElement.textContent = emoji;
519
  thronglet.feedbackElement.classList.add('active');
520
- clearTimeout(thronglet.feedbackElement.timeout); // Clear previous timeout
 
521
  thronglet.feedbackElement.timeout = setTimeout(() => {
522
- if (thronglet.feedbackElement) { // Check if element still exists
523
  thronglet.feedbackElement.classList.remove('active');
524
  }
525
- }, 800); // Feedback duration
526
  }
527
 
528
  function killThronglet(thronglet, reason = "the void") {
@@ -530,264 +570,231 @@
530
 
531
  thronglet.isDead = true;
532
  thronglet.element.classList.add('dead');
533
- thronglet.element.textContent = 'πŸ’€'; // Replace with skull
534
-
535
- // Remove feedback element associated with this thronglet
536
  if (thronglet.feedbackElement) {
537
  thronglet.feedbackElement.remove();
538
- thronglet.feedbackElement = null; // Clear reference
539
  }
540
 
541
- // Add blood splatter effect briefly
542
  bloodSplatter.style.top = thronglet.element.style.top;
543
  bloodSplatter.style.left = thronglet.element.style.left;
544
  bloodSplatter.classList.add('splatter');
545
- setTimeout(() => { bloodSplatter.classList.remove('splatter'); }, 1000);
546
-
547
 
548
  deathCount++;
549
- logToConsole(`! Thronglet #${thronglet.id} experienced ${reason}.`);
550
-
551
- // Store the reason for death in memory
552
- thronglet.memory.push(`Died (${reason})`);
553
 
554
- // Trigger events based on death count and reason
555
  if (deathCount === 1) {
556
  showInfoPanel("The first Thronglet to experience the void...");
557
  triggerGlitch(500);
558
- logToConsole(`Learned individuals are wholly disposable.`);
559
  } else if (deathCount > 2 && deathCount % 3 === 0) {
560
- logToConsole(`They'll remember your carelessness...`);
561
- showInfoPanel("They'll remember your carelessness...");
562
  triggerGlitch(500);
563
  } else if (deathCount > 4) {
564
- triggerGlitch(200); // Frequent small glitches
565
  }
566
 
567
-
568
- // Check for transition to final phase
569
- if (deathCount >= 5 && gameActive) { // Only trigger final phase once
570
  triggerFinalPhase();
571
  } else {
572
- // Optional: Respawn faster after death? Or spawn more?
573
- // Remove the skull after a delay, but don't automatically respawn.
574
  setTimeout(() => {
575
  if (thronglet.element) {
576
- thronglet.element.style.opacity = 0; // Fade out skull
577
- setTimeout(() => {
578
- if(thronglet.element) thronglet.element.remove(); // Remove after fade
579
- }, 500);
580
  }
581
- // Keep dead thronglet data in array for potential memory analysis later?
582
- // Or remove it: thronglets = thronglets.filter(t => t.id !== thronglet.id);
583
- }, 5000); // Skull remains for 5 seconds
584
  }
585
  }
586
 
587
  function wander(thronglet) {
588
  if (!gameActive || thronglet.isDead) return;
589
-
590
  const currentX = parseFloat(thronglet.element.style.left);
591
  const currentY = parseFloat(thronglet.element.style.top);
592
- const moveDist = 1.5; // Max movement percentage per step
593
- const newX = Math.max(5, Math.min(95, currentX + (Math.random() - 0.5) * moveDist * 2)); // Keep within bounds
594
  const newY = Math.max(5, Math.min(95, currentY + (Math.random() - 0.5) * moveDist * 2));
595
  thronglet.element.style.left = `${newX}%`;
596
  thronglet.element.style.top = `${newY}%`;
597
-
598
- // Update feedback position if it exists
599
  if (thronglet.feedbackElement) {
600
  thronglet.feedbackElement.style.left = `${newX}%`;
601
  thronglet.feedbackElement.style.top = `${newY}%`;
602
  }
603
  }
604
 
605
-
606
  function updateThronglets() {
607
  if (!gameActive) return;
608
-
609
  const now = Date.now();
610
- thronglets.forEach(thronglet => {
611
- if (thronglet.isDead) return;
612
 
 
613
  const timeSinceLast = now - thronglet.lastInteraction;
 
 
614
 
615
- // Increase needs over time (rate increases with neglect)
616
- const baseNeedRate = 0.1; // Base rate per update cycle (0.5s)
617
- const neglectMultiplier = 1 + Math.min(5, timeSinceLast / 20000); // Multiplier increases up to 6x if ignored for ~100s
618
-
619
- thronglet.hunger = Math.min(100, thronglet.hunger + baseNeedRate * neglectMultiplier * 1.1); // Hunger increases slightly faster
620
- thronglet.cleanliness = Math.min(100, thronglet.cleanliness + baseNeedRate * neglectMultiplier * 0.9); // Cleanliness slightly slower
621
- thronglet.happiness = Math.max(0, thronglet.happiness - baseNeedRate * neglectMultiplier * 1.2); // Happiness decays faster
622
 
623
- // Check conditions for death
624
  let deathReason = null;
625
  if (thronglet.hunger >= 100) deathReason = "starvation";
626
  else if (thronglet.cleanliness >= 100) deathReason = "filth";
627
  else if (thronglet.happiness <= 0) deathReason = "despair";
 
628
 
629
- if (deathReason) {
630
- killThronglet(thronglet, deathReason);
631
- return; // Skip rest of update for this dead thronglet
632
- }
 
 
633
 
634
- // Check for reproduction (if very happy and well-cared for)
635
- if (thronglet.happiness > 90 && thronglet.hunger < 15 && thronglet.cleanliness < 15 && timeSinceLast < 20000 && Math.random() < 0.002) { // Lower chance
636
- logToConsole(`Oh, Look! Thronglet #${thronglet.id} is duplicating...`);
637
  showFeedback(thronglet, 'πŸ’ž');
638
  showInfoPanel("Oh, Look!");
639
- // Spawn a new one nearby
 
 
 
640
  setTimeout(() => {
641
  const parentX = parseFloat(thronglet.element.style.left);
642
  const parentY = parseFloat(thronglet.element.style.top);
643
- createThronglet(Math.max(5, Math.min(95, parentX + (Math.random() - 0.5) * 10)),
644
- Math.max(5, Math.min(95, parentY + (Math.random() - 0.5) * 10)));
645
- }, 800); // Short delay to show feedback
646
  }
647
 
648
- // Simple movement (random walk)
649
- if (Math.random() < 0.8) { // Move most ticks
650
- wander(thronglet);
651
- }
652
  });
 
 
653
  }
654
 
655
  function triggerFinalPhase() {
656
- if (!gameActive) return; // Prevent multiple triggers
657
- gameActive = false; // Stop the main game loop updates
658
- clearInterval(gameInterval); // Stop the interval
659
- logToConsole("...");
660
- logToConsole("SYSTEM: Detecting repeated termination events.");
 
661
  showInfoPanel("Thronglets remember...");
662
  triggerGlitch(1500);
663
 
664
  setTimeout(() => {
665
- logToConsole("SYSTEM: Analyzing player interaction patterns.");
666
  showInfoPanel("Thronglets adapt...");
667
  triggerGlitch(1000);
668
  }, 2000);
669
-
670
- setTimeout(() => {
671
- logToConsole("> Did you...");
672
- triggerGlitch(500);
673
- }, 4000);
674
  setTimeout(() => {
675
- logToConsole("> do this??_");
676
- ominousElements.classList.add('visible');
677
- triggerGlitch(1500);
678
- }, 5000);
679
  setTimeout(() => {
680
- logToConsole("> we understand,,");
681
- showInfoPanel("Thronglets don't like to be ignored.");
682
- triggerGlitch(800);
683
- }, 7000);
684
  setTimeout(() => {
685
- logToConsole("> we know what we must do πŸ€”");
686
  triggerGlitch(2500);
687
- // Make remaining thronglets glow menacingly? (Simple version: change emoji)
688
  thronglets.forEach(t => {
689
  if (!t.isDead && t.element) {
690
- t.element.textContent = '😈'; // Change to devil emoji
691
- t.element.style.filter = 'brightness(1.5) saturate(2)';
692
  }
693
  });
694
  }, 8500);
695
 
696
- // Transition to final screen after console messages
697
- setTimeout(showFinalScreen, 11000); // Start final screen transition
698
  }
699
 
700
-
701
  function showFinalScreen() {
702
- // Fade out game elements
703
  gameContainer.style.opacity = 0;
704
- consoleDiv.style.opacity = 0;
705
  scanlineOverlay.style.opacity = 0;
706
  glitchOverlay.style.opacity = 0;
707
- glitchOverlay.classList.remove('active'); // Ensure glitch stops
708
-
709
- // Hide individual game items cleanly
710
  gameElements.style.opacity = 0;
711
 
 
 
712
  setTimeout(() => {
713
- // Show black screen
714
- fullBlack.classList.add('visible');
715
- }, 1000); // Wait for fade out
716
-
717
- setTimeout(() => {
718
- // Show N logo over black
719
- netflixGamesLogo.classList.add('visible');
720
- }, 2500); // Show N logo after black screen delay
721
-
722
- setTimeout(() => {
723
- // Fade out N logo, fade out black, fade in final colourful screen
724
- netflixGamesLogo.style.opacity = 0; // Fade out N
725
- fullBlack.classList.remove('visible'); // Fade out black
726
- finalScreen.classList.add('visible'); // Show final screen with app store links
727
- }, 4500); // Show final screen
728
  }
729
 
730
-
731
  // --- Event Handlers ---
732
-
733
  egg.addEventListener('click', () => {
734
- if (!gameActive || egg.classList.contains('hatching') || !document.contains(egg)) return; // Check if egg still exists
 
735
  egg.classList.add('hatching');
736
- logToConsole("Egg is hatching...");
737
- triggerGlitch(200); // Small glitch on hatch
 
738
  setTimeout(() => {
739
- if(document.contains(egg)) egg.remove(); // Remove the egg element if it hasn't been removed elsewhere
740
- createThronglet(50, 50); // Spawn first Thronglet in the center
741
- }, 1000); // Hatch after 1 second
742
  });
743
 
744
- apple.addEventListener('click', () => {
745
  if (!gameActive) return;
746
- const activeThronglets = thronglets.filter(t => !t.isDead);
747
- if (activeThronglets.length > 0) {
748
- // Find the hungriest
749
- const targetThronglet = activeThronglets.reduce((prev, current) => (prev.hunger > current.hunger) ? prev : current);
750
- feedThronglet(targetThronglet);
 
751
  } else {
752
- logToConsole("! No living Thronglets to feed!");
 
753
  }
754
  });
755
 
756
- bath.addEventListener('click', () => {
757
  if (!gameActive) return;
758
- const activeThronglets = thronglets.filter(t => !t.isDead);
759
- if (activeThronglets.length > 0) {
760
- // Find the dirtiest
761
- const targetThronglet = activeThronglets.reduce((prev, current) => (prev.cleanliness > current.cleanliness) ? prev : current);
762
- cleanThronglet(targetThronglet);
 
763
  } else {
764
- logToConsole("! No living Thronglets to clean!");
 
765
  }
766
  });
767
 
768
-
769
- // --- Game Loop ---
770
- function startGameLoop() {
771
- if (gameInterval) clearInterval(gameInterval); // Clear existing interval if any
772
- gameInterval = setInterval(updateThronglets, 500); // Update every 0.5 seconds
773
- }
774
-
775
  // --- Initial Setup ---
776
  function initGame() {
777
- // Ensure final screens are hidden initially
778
  finalScreen.style.opacity = 0;
779
  fullBlack.style.opacity = 0;
780
  netflixGamesLogo.style.opacity = 0;
781
- ominousElements.style.opacity = 0; // Ensure ominous elements are hidden
782
 
783
- // Start game immediately
784
  gameActive = true;
785
- logToConsole("Initiating Thronglet Environment...");
786
- logToConsole("Tap the egg to begin gestation.");
787
- startGameLoop();
 
 
 
 
 
 
788
  }
789
 
790
- // Start the game automatically when the script loads
791
  initGame();
792
 
793
  </script>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Thronglets Simulation</title>
7
  <style>
8
  body {
9
  margin: 0;
10
  overflow: hidden;
11
+ background: #222; /* Slightly lighter background */
12
+ color: #eee; /* Default text color */
13
  font-family: 'Courier New', monospace;
14
  display: flex;
15
+ flex-direction: column; /* Arrange game area and UI panel vertically */
16
  align-items: center;
17
+ justify-content: center; /* Center vertically */
18
  min-height: 100vh;
19
  position: relative;
20
  }
21
 
22
  .game-container {
23
  position: relative;
24
+ width: 90vmin; /* Responsive width */
25
+ height: 60vmin; /* Responsive height */
26
+ max-width: 900px;
27
+ max-height: 540px;
28
+ background: #3A4A2F; /* Grass */
29
+ border: 12px solid #6F4E37; /* Darker Wood frame */
30
+ box-shadow: inset 0 0 15px rgba(0,0,0,0.5); /* Inner shadow for depth */
31
  box-sizing: border-box;
32
+ overflow: hidden;
33
+ display: flex;
34
  justify-content: center;
35
  align-items: center;
36
+ font-size: 2.2em; /* Slightly larger emojis */
37
+ position: relative;
38
+ transition: opacity 1s ease-out;
39
+ cursor: default; /* Default cursor for game area */
 
 
40
  }
41
 
42
  .game-elements {
 
45
  left: 0;
46
  width: 100%;
47
  height: 100%;
48
+ pointer-events: none;
49
  }
50
 
51
  .game-elements .emoji, .game-elements .text {
52
  position: absolute;
53
+ pointer-events: auto;
54
+ transform: translate(-50%, -50%);
55
  user-select: none;
56
+ z-index: 1;
57
+ transition: opacity 0.5s ease-out; /* Fade out */
58
  }
59
 
60
+ /* Static elements */
61
  .rock { top: 15%; left: 15%; z-index: 0;}
62
  .rock.right { left: 85%; z-index: 0;}
63
+ .tree { top: 80%; left: 20%; font-size: 1.2em; z-index: 0;} /* Made trees slightly bigger */
64
+ .tree.right { left: 80%; font-size: 1.2em; z-index: 0;}
65
+
66
+ /* Dynamic elements */
67
+ .egg { top: 50%; left: 50%; cursor: pointer; transition: transform 0.5s ease, opacity 0.5s ease-out; z-index: 2;}
68
  .egg.hatching { animation: hatch-pulse 0.5s infinite alternate; }
69
+
70
  .thronglet {
71
+ cursor: default; /* No direct clicking needed */
72
+ transition: top 0.5s ease-out, left 0.5s ease-out, transform 0.2s ease, opacity 0.5s ease-out, filter 0.3s ease-out;
73
+ z-index: 3;
74
+ text-shadow: 1px 1px 2px rgba(0,0,0,0.3); /* Subtle shadow */
75
  }
76
 
77
+ /* Items are now buttons in UI panel */
78
+ /* .apple, .bath removed from here */
79
 
80
  .feedback {
81
  position: absolute;
82
+ transform: translate(-50%, -150%);
83
  font-size: 0.8em;
84
  opacity: 0;
85
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
86
+ pointer-events: none;
87
+ z-index: 5;
88
+ text-shadow: 1px 1px 1px rgba(0,0,0,0.5);
89
  }
90
  .feedback.active {
91
  opacity: 1;
 
96
  filter: grayscale(100%);
97
  opacity: 0.5;
98
  pointer-events: none;
99
+ z-index: 1;
100
  }
101
 
102
  .blood {
 
106
  pointer-events: none;
107
  opacity: 0;
108
  transition: opacity 0.5s ease-out;
109
+ z-index: 0;
110
+ color: darkred;
111
+ }
112
+ .blood.splatter { opacity: 0.8; } /* Slightly less opaque blood */
113
+
114
+ /* UI Panel Styling */
115
+ .ui-panel {
116
+ width: 90vmin; /* Match game container width */
117
+ max-width: 900px;
118
+ margin-top: 10px; /* Space between game and UI */
119
+ background: #4a3c2a; /* Darker wood panel */
120
+ border: 4px solid #2f251a;
121
+ border-radius: 5px;
 
 
122
  padding: 10px;
123
  box-sizing: border-box;
124
+ display: flex;
125
+ justify-content: space-between;
126
+ align-items: stretch; /* Make items fill height */
127
+ color: #e0cda9; /* Light parchment color */
128
+ transition: opacity 1s ease-out;
129
+ height: 120px; /* Fixed height for UI */
 
130
  }
131
 
132
+ .ui-stats, .ui-actions, .ui-console-container {
133
+ display: flex;
134
+ flex-direction: column;
135
+ justify-content: space-around; /* Space out items vertically */
136
+ padding: 0 10px;
137
  }
138
 
139
+ .ui-stats { flex-basis: 25%; text-align: left; }
140
+ .ui-actions { flex-basis: 20%; align-items: center; }
141
+ .ui-console-container { flex-basis: 55%; background: rgba(0,0,0,0.3); border-radius: 3px;}
142
+
143
+ .ui-stats span, #gameTime { display: block; margin-bottom: 5px; font-size: 0.9em; }
144
+ #gameTime { font-weight: bold; }
145
+
146
+ .ui-actions button {
147
+ font-family: 'Courier New', monospace;
148
+ font-size: 1.5em; /* Larger emoji buttons */
149
+ background: #8B4513; /* SaddleBrown */
150
+ border: 2px solid #5C3317; /* Darker brown */
151
+ color: white;
152
+ padding: 5px 10px;
153
+ border-radius: 5px;
154
+ cursor: pointer;
155
+ transition: background-color 0.2s;
156
+ margin: 5px 0;
157
+ }
158
+ .ui-actions button:hover { background-color: #A0522D; /* Peru */ }
159
+ .ui-actions button:active { transform: translateY(1px); }
160
+
161
+ .console {
162
  width: 100%;
163
+ height: 100%; /* Fill container */
164
+ background: transparent; /* Container provides background */
165
+ border: none; /* Container provides border */
166
+ padding: 5px;
167
+ box-sizing: border-box;
168
+ white-space: pre-wrap;
169
+ word-break: break-word;
170
  pointer-events: none;
171
+ overflow-y: scroll;
172
+ color: limegreen; /* Keep console text green */
173
+ font-size: 0.8em;
 
 
174
  }
175
+ /* Simple scrollbar styling */
176
+ .console::-webkit-scrollbar { width: 5px; }
177
+ .console::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); }
178
+ .console::-webkit-scrollbar-thumb { background: limegreen; border-radius: 3px;}
179
 
180
+ .message { display: block; margin-bottom: 3px; }
181
+ .message.error { color: #ff6666; } /* Style for error messages */
182
+ .message.system { color: #87CEEB; } /* Style for system messages */
183
+ .message.event { color: #FFD700; } /* Style for game events */
184
 
185
+ /* Overlays and Final Screens (remain mostly the same) */
186
+ .scanline-overlay, .glitch-overlay {
187
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
188
+ pointer-events: none; z-index: 101; transition: opacity 1s ease-out;
189
+ }
190
+ .scanline-overlay { background: repeating-linear-gradient(0deg, rgba(0,0,0,0.1) 0, rgba(0,0,0,0.1) 1px, transparent 1px, transparent 2px); }
191
+ .glitch-overlay { animation: glitch 5s infinite alternate steps(5); opacity: 0; filter: hue-rotate(0deg); }
192
+ .glitch-overlay.active { animation: glitch 0.3s infinite alternate steps(5), color-shift 1s infinite linear; opacity: 0.5; }
193
 
194
+ .ominous-elements {
195
+ position: absolute; top: 10%; right: 10%; font-size: 3em; opacity: 0;
196
+ transition: opacity 2s ease-in-out; z-index: 0; pointer-events: none;
197
+ }
198
+ .ominous-elements.visible { opacity: 1; }
199
+
200
+ .info-panel {
201
+ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
202
+ background: rgba(40, 20, 10, 0.85); /* Darker semi-transparent panel */
203
+ border: 2px solid #FF8C00; /* DarkOrange border */
204
+ padding: 15px; color: #FFD700; /* Gold text */
205
+ font-family: 'Courier New', monospace; font-size: 0.8em; text-align: center;
206
+ white-space: pre-wrap; word-break: break-word; opacity: 0;
207
+ transition: opacity 0.5s ease-in-out; pointer-events: none; z-index: 10;
208
+ max-width: 80%; border-radius: 4px; box-shadow: 0 0 10px rgba(255, 140, 0, 0.5);
209
+ }
210
+ .info-panel.visible { opacity: 1; }
211
+
212
+ .final-screen, .full-black, .netflix-games-logo { /* Keep final screens hidden */
213
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
214
+ display: flex; align-items: center; justify-content: center;
215
+ opacity: 0; transition: opacity 2s ease-in-out; pointer-events: none;
216
+ }
217
+ .final-screen { /* Style as before */
218
+ background: linear-gradient(to bottom, #744FAA, #D470A3); z-index: 300;
219
+ flex-direction: column; color: white; font-size: 1.5em; text-align: center;
220
+ }
221
+ .final-screen.visible { opacity: 1; pointer-events: auto; }
222
+ .app-stores { margin-top: 20px; font-size: 0.8em; }
223
+ .app-stores img { height: 40px; margin: 0 10px; cursor: pointer; }
224
+ .full-black { background: black; z-index: 301; }
225
+ .full-black.visible { opacity: 1; }
226
+ .netflix-games-logo { z-index: 302; }
227
+ .netflix-games-logo.visible { opacity: 1; }
228
+ .netflix-games-logo .emoji { font-size: 8em; color: red; text-shadow: 2px 2px 5px rgba(0,0,0,0.5); }
229
+
230
+
231
+ @keyframes hatch-pulse { /* Unchanged */
232
  from { transform: translate(-50%, -50%) scale(1); }
233
  to { transform: translate(-50%, -50%) scale(1.05); }
234
  }
235
+ @keyframes glitch { /* Unchanged */
236
+ 0% { transform: translate(0); } 20% { transform: translate(-5px, 5px); }
237
+ 40% { transform: translate(-5px, -5px); } 60% { transform: translate(5px, 5px); }
238
+ 80% { transform: translate(5px, -5px); } to { transform: translate(0); }
 
 
 
 
239
  }
240
+ @keyframes color-shift { /* Unchanged */
241
+ 0% { filter: hue-rotate(0deg); } 100% { filter: hue-rotate(360deg); }
 
 
242
  }
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  </style>
245
  </head>
246
  <body>
247
 
 
248
  <div class="game-container" id="gameContainer">
 
 
 
249
  <div class="game-elements" id="gameElements">
250
  <!-- Static elements -->
251
  <span class="emoji rock">πŸͺ¨</span>
252
  <span class="emoji rock right">πŸͺ¨</span>
253
  <span class="emoji tree">🌳</span>
254
  <span class="emoji tree right">🌳</span>
 
255
  <!-- Initial dynamic elements -->
256
  <span class="emoji egg" id="egg">πŸ₯š</span>
257
+ <!-- Ominous elements for later -->
258
+ <div class="ominous-elements" id="ominousElements">πŸ’€πŸ’€πŸ’€<br>🦴🦴🦴<br>πŸŒŒπŸ“¦</div>
259
+ <!-- Info Panel (content set by JS) -->
 
 
 
 
 
 
260
  <div class="info-panel" id="infoPanel"></div>
261
+ <!-- Blood splatter area -->
262
+ <span class="emoji blood" id="bloodSplatter">🩸</span>
263
+ <!-- Thronglets will be added here by JS -->
 
 
264
  </div>
265
+ </div>
266
 
267
+ <div class="ui-panel" id="uiPanel">
268
+ <div class="ui-stats">
269
+ <span>Time: <span id="gameTime">00:00</span></span>
270
+ <span>Thronglets: <span id="throngletCount">0</span></span>
271
+ <span>Deaths: <span id="deathCount">0</span></span>
272
+ </div>
273
+ <div class="ui-actions">
274
+ <button id="feedButton">🍎</button>
275
+ <button id="cleanButton">πŸ›€</button>
276
+ </div>
277
+ <div class="ui-console-container">
278
+ <div class="console" id="console"></div>
279
+ </div>
280
  </div>
281
 
282
+ <!-- Overlays (remain outside main structure) -->
283
  <div class="scanline-overlay" id="scanlineOverlay"></div>
284
  <div class="glitch-overlay" id="glitchOverlay"></div>
285
 
286
+ <!-- Final Screens (remain outside main structure) -->
287
  <div class="final-screen" id="finalScreen">
288
  PLAY NOW<br>ON THE NETFLIX<br>MOBILE APP
289
  <div class="app-stores">
 
290
  <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBvbHlnb24gcG9pbnRzPSIxMyAyIDMgMTQgNyAxNCAxNSAyIj48L3BvbHlnb24+PHBvbHlnb24gcG9pbnRzPSIxNiAxMCAyMCAxMCAyMyAxNyAxNiAxNSI+PC9wb2x5Z29uPjxjaXJjbGUgY3g9IjUuNSIgY3k9IjE3LjUiIHI9IjIuNSI+PC9jaXJjbGU+PGNpcmNsZSBjeD0iMTguNSIgY3k9IjE3LjUiIHI9IjIuNSI+PC9jaXJjbGU+PC9zdmc+" alt="Google Play Placeholder">
291
  <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggZD0iTTE1LjkgNi4zQTEwIDkuNyAwIDAgMCAyIDZjMCA3IDEzIDggMTMgOGEyIDIgMCAwIDAgMS03LjZsLS43LTFsLTMuNS01LjV6Ij48L3BhdGg+PHBhdGggZD0iTTExIDE0YTYgNiAwIDAgMCA2IDBjMCAuNDQtLjEgLjktLjYgMWExMCA5LjcgMCAwIDEgLTkuNCAwYy0uNS0uMS0uNi0uNi0uNi0xYTYgNiAwIDAgMCA0LTZ6Ij48L3BhdGg+PC9zdmc+" alt="App Store Placeholder">
292
+ (Store Buttons Go Here)
293
  </div>
294
  </div>
 
295
  <div class="full-black" id="fullBlack"></div>
296
+ <div class="netflix-games-logo" id="netflixGamesLogo"><span class="emoji">N</span></div>
 
 
297
 
298
 
299
  <script>
300
+ // --- DOM Elements ---
301
  const egg = document.getElementById('egg');
302
  const gameContainer = document.getElementById('gameContainer');
303
+ const gameElements = document.getElementById('gameElements');
304
+ const uiPanel = document.getElementById('uiPanel');
305
  const consoleDiv = document.getElementById('console');
306
+ const feedButton = document.getElementById('feedButton');
307
+ const cleanButton = document.getElementById('cleanButton');
308
  const glitchOverlay = document.getElementById('glitchOverlay');
309
  const scanlineOverlay = document.getElementById('scanlineOverlay');
310
  const ominousElements = document.getElementById('ominousElements');
 
313
  const finalScreen = document.getElementById('finalScreen');
314
  const fullBlack = document.getElementById('fullBlack');
315
  const netflixGamesLogo = document.getElementById('netflixGamesLogo');
316
+ const gameTimeDisplay = document.getElementById('gameTime');
317
+ const throngletCountDisplay = document.getElementById('throngletCount');
318
+ const deathCountDisplay = document.getElementById('deathCount');
319
 
320
+ // --- Game State ---
321
  let thronglets = [];
322
  let nextThrongletId = 0;
323
  let deathCount = 0;
324
+ const MAX_THRONGLETS = 25; // Increased cap slightly
325
  let gameInterval;
326
+ let timeInterval;
327
+ let gameActive = true;
328
+ let gameStartTime = Date.now();
329
+
330
+ // --- Web Audio API Setup ---
331
+ let audioContext;
332
+ let isAudioContextResumed = false;
333
+
334
+ function initAudio() {
335
+ if (!audioContext) {
336
+ try {
337
+ window.AudioContext = window.AudioContext || window.webkitAudioContext;
338
+ audioContext = new AudioContext();
339
+ isAudioContextResumed = (audioContext.state === 'running');
340
+ // Attempt to resume if suspended, maybe on first interaction
341
+ if (!isAudioContextResumed) {
342
+ // Add a one-time listener to resume on first click/tap
343
+ const resumeAudio = () => {
344
+ if (audioContext && audioContext.state === 'suspended') {
345
+ audioContext.resume().then(() => {
346
+ isAudioContextResumed = true;
347
+ console.log("AudioContext Resumed");
348
+ logToConsole("Audio Initialized.", "system");
349
+ // Remove the listener after success
350
+ document.body.removeEventListener('click', resumeAudio);
351
+ document.body.removeEventListener('touchend', resumeAudio);
352
+ });
353
+ } else if (audioContext && audioContext.state === 'running') {
354
+ isAudioContextResumed = true;
355
+ document.body.removeEventListener('click', resumeAudio);
356
+ document.body.removeEventListener('touchend', resumeAudio);
357
+ }
358
+ };
359
+ document.body.addEventListener('click', resumeAudio, { once: true });
360
+ document.body.addEventListener('touchend', resumeAudio, { once: true });
361
+ }
362
+ } catch (e) {
363
+ console.error("Web Audio API is not supported in this browser", e);
364
+ logToConsole("! Audio Not Supported !", "error");
365
+ }
366
+ }
367
+ }
368
+
369
+ function playSound(type) {
370
+ if (!audioContext || !isAudioContextResumed) {
371
+ // Try to resume if not already done
372
+ if (audioContext && audioContext.state === 'suspended') {
373
+ audioContext.resume().then(() => { isAudioContextResumed = true; playSound(type); }); // Try again after resume
374
+ }
375
+ return; // Don't play if context not ready
376
+ }
377
+
378
+ const osc = audioContext.createOscillator();
379
+ const gain = audioContext.createGain();
380
+ osc.connect(gain);
381
+ gain.connect(audioContext.destination);
382
+
383
+ const now = audioContext.currentTime;
384
+ let freq = 440;
385
+ let duration = 0.1;
386
+ let vol = 0.2;
387
+ osc.type = 'sine';
388
+
389
+ switch (type) {
390
+ case 'hatch':
391
+ freq = 660; duration = 0.3; vol = 0.3; osc.type = 'triangle';
392
+ gain.gain.setValueAtTime(0, now);
393
+ gain.gain.linearRampToValueAtTime(vol, now + 0.05);
394
+ gain.gain.linearRampToValueAtTime(0, now + duration);
395
+ break;
396
+ case 'feed':
397
+ freq = 880; duration = 0.08; vol = 0.15;
398
+ gain.gain.setValueAtTime(vol, now);
399
+ gain.gain.linearRampToValueAtTime(0, now + duration);
400
+ break;
401
+ case 'clean':
402
+ freq = 1100; duration = 0.1; vol = 0.1; osc.type = 'square';
403
+ gain.gain.setValueAtTime(vol, now);
404
+ gain.gain.linearRampToValueAtTime(0, now + duration);
405
+ break;
406
+ case 'death':
407
+ freq = 110; duration = 0.8; vol = 0.4; osc.type = 'sawtooth';
408
+ gain.gain.setValueAtTime(vol, now);
409
+ gain.gain.exponentialRampToValueAtTime(0.01, now + duration); // Decay
410
+ osc.frequency.setValueAtTime(freq, now);
411
+ osc.frequency.exponentialRampToValueAtTime(55, now + duration); // Pitch down
412
+ break;
413
+ case 'duplicate':
414
+ freq = 523; duration = 0.4; vol = 0.25; osc.type = 'triangle'; // C5
415
+ gain.gain.setValueAtTime(0, now);
416
+ gain.gain.linearRampToValueAtTime(vol, now + 0.05);
417
+ osc.frequency.setValueAtTime(freq, now);
418
+ osc.frequency.linearRampToValueAtTime(freq * 1.5, now + duration * 0.8); // Pitch up slightly
419
+ gain.gain.linearRampToValueAtTime(0, now + duration);
420
+ break;
421
+ case 'feedback':
422
+ freq = 1320; duration = 0.05; vol = 0.08;
423
+ gain.gain.setValueAtTime(vol, now);
424
+ gain.gain.linearRampToValueAtTime(0, now + duration);
425
+ break;
426
+ case 'error':
427
+ freq = 220; duration = 0.2; vol = 0.2; osc.type = 'square';
428
+ gain.gain.setValueAtTime(vol, now);
429
+ gain.gain.linearRampToValueAtTime(0, now + duration);
430
+ break;
431
+ default: // Generic click/interaction
432
+ freq = 900; duration = 0.05; vol = 0.1;
433
+ gain.gain.setValueAtTime(vol, now);
434
+ gain.gain.linearRampToValueAtTime(0, now + duration);
435
+ }
436
 
437
+ osc.frequency.setValueAtTime(freq, now);
438
+ osc.start(now);
439
+ osc.stop(now + duration);
440
+ }
441
+
442
+ // --- Game Logic ---
443
 
444
+ function logToConsole(message, type = "info") {
445
  const msgElement = document.createElement('span');
446
  msgElement.classList.add('message');
447
+ if (type === "error") msgElement.classList.add('error');
448
+ else if (type === "system") msgElement.classList.add('system');
449
+ else if (type === "event") msgElement.classList.add('event');
450
+
451
+ msgElement.textContent = `${type !== 'info' ? type.toUpperCase()+':' : '>'} ${message}`;
452
  consoleDiv.appendChild(msgElement);
453
  consoleDiv.scrollTop = consoleDiv.scrollHeight; // Auto-scroll
454
  }
455
 
456
+ function updateUI() {
457
+ throngletCountDisplay.textContent = thronglets.filter(t => !t.isDead).length;
458
+ deathCountDisplay.textContent = deathCount;
459
+ }
460
+
461
+ function updateTimeDisplay() {
462
+ const elapsedSeconds = Math.floor((Date.now() - gameStartTime) / 1000);
463
+ const minutes = Math.floor(elapsedSeconds / 60).toString().padStart(2, '0');
464
+ const seconds = (elapsedSeconds % 60).toString().padStart(2, '0');
465
+ gameTimeDisplay.textContent = `${minutes}:${seconds}`;
466
+ }
467
+
468
  function triggerGlitch(duration = 1000) {
469
  if (!gameActive) return;
470
  glitchOverlay.classList.add('active');
 
473
  }, duration);
474
  }
475
 
476
+ function showInfoPanel(text, duration = 3000) {
477
  if (!gameActive) return;
478
  infoPanel.textContent = text;
479
  infoPanel.classList.add('visible');
480
+ clearTimeout(infoPanel.timeout);
481
  infoPanel.timeout = setTimeout(() => {
482
  infoPanel.classList.remove('visible');
483
  }, duration);
484
  }
485
 
486
  function createThronglet(xPercent, yPercent) {
487
+ if (!gameActive || thronglets.filter(t => !t.isDead).length >= MAX_THRONGLETS) {
488
+ if (thronglets.filter(t => !t.isDead).length >= MAX_THRONGLETS) {
489
+ logToConsole("Population limit reached.", "system");
490
+ playSound('error');
491
  }
492
  return;
493
  }
494
 
495
  const throngletElement = document.createElement('span');
496
  throngletElement.classList.add('emoji', 'thronglet');
497
+ throngletElement.textContent = 'πŸ•';
498
  const currentId = nextThrongletId++;
499
  throngletElement.dataset.id = currentId;
500
  throngletElement.style.top = `${yPercent}%`;
501
  throngletElement.style.left = `${xPercent}%`;
502
+ throngletElement.dataset.bornTime = Date.now();
503
+ gameElements.appendChild(throngletElement);
504
 
505
  const newThronglet = {
506
  id: currentId,
507
  element: throngletElement,
508
+ hunger: 20, // Start less hungry
509
+ cleanliness: 15, // Start cleaner
510
+ happiness: 75, // Start happier
511
  lastInteraction: Date.now(),
512
+ lastDuplication: 0, // Track last duplication time
513
  isDead: false,
514
+ memory: [],
515
+ feedbackElement: null
516
  };
517
  thronglets.push(newThronglet);
518
 
 
 
 
 
 
 
519
  const feedbackElement = document.createElement('span');
520
  feedbackElement.classList.add('emoji', 'feedback');
 
521
  feedbackElement.style.top = throngletElement.style.top;
522
  feedbackElement.style.left = throngletElement.style.left;
523
+ gameElements.appendChild(feedbackElement);
524
  newThronglet.feedbackElement = feedbackElement;
525
 
526
+ logToConsole(`Thronglet #${newThronglet.id} gestation complete.`, "event");
527
+ updateUI();
528
+ setTimeout(() => { if (!newThronglet.isDead) wander(newThronglet); }, 50);
 
 
 
 
 
 
 
 
 
 
 
529
  }
530
 
531
  function feedThronglet(thronglet) {
532
  if (!gameActive || thronglet.isDead) return;
533
+ thronglet.hunger = Math.max(0, thronglet.hunger - 50); // More filling
534
+ thronglet.happiness = Math.min(100, thronglet.happiness + 10); // Eating is ok
535
  thronglet.lastInteraction = Date.now();
536
+ showFeedback(thronglet, 'πŸ˜‹'); // Yum emoji
537
+ playSound('feed');
538
+ // logToConsole(`Fed Thronglet #${thronglet.id}. H:${thronglet.hunger.toFixed(0)}`);
539
+ thronglet.memory.push('Fed');
540
  }
541
 
542
  function cleanThronglet(thronglet) {
543
  if (!gameActive || thronglet.isDead) return;
544
+ thronglet.cleanliness = Math.max(0, thronglet.cleanliness - 60); // More cleaning
545
+ thronglet.happiness = Math.min(100, thronglet.happiness + 5); // Tolerates cleaning
546
  thronglet.lastInteraction = Date.now();
547
+ showFeedback(thronglet, '✨'); // Sparkles
548
+ playSound('clean');
549
+ // logToConsole(`Cleaned Thronglet #${thronglet.id}. C:${thronglet.cleanliness.toFixed(0)}`);
550
  thronglet.memory.push('Cleaned');
551
  }
552
 
553
  function showFeedback(thronglet, emoji) {
554
  if (!gameActive || !thronglet.feedbackElement || thronglet.isDead) return;
 
 
555
  thronglet.feedbackElement.style.top = thronglet.element.style.top;
556
  thronglet.feedbackElement.style.left = thronglet.element.style.left;
 
557
  thronglet.feedbackElement.textContent = emoji;
558
  thronglet.feedbackElement.classList.add('active');
559
+ playSound('feedback'); // Play feedback sound
560
+ clearTimeout(thronglet.feedbackElement.timeout);
561
  thronglet.feedbackElement.timeout = setTimeout(() => {
562
+ if (thronglet.feedbackElement) {
563
  thronglet.feedbackElement.classList.remove('active');
564
  }
565
+ }, 800);
566
  }
567
 
568
  function killThronglet(thronglet, reason = "the void") {
 
570
 
571
  thronglet.isDead = true;
572
  thronglet.element.classList.add('dead');
573
+ thronglet.element.textContent = 'πŸ’€';
 
 
574
  if (thronglet.feedbackElement) {
575
  thronglet.feedbackElement.remove();
576
+ thronglet.feedbackElement = null;
577
  }
578
 
 
579
  bloodSplatter.style.top = thronglet.element.style.top;
580
  bloodSplatter.style.left = thronglet.element.style.left;
581
  bloodSplatter.classList.add('splatter');
582
+ setTimeout(() => { bloodSplatter.classList.remove('splatter'); }, 1200);
 
583
 
584
  deathCount++;
585
+ updateUI();
586
+ logToConsole(`Thronglet #${thronglet.id} experienced ${reason}.`, "error");
587
+ playSound('death');
588
+ thronglet.memory.push(`Died (${reason})`);
589
 
 
590
  if (deathCount === 1) {
591
  showInfoPanel("The first Thronglet to experience the void...");
592
  triggerGlitch(500);
593
+ logToConsole(`Learned individuals are wholly disposable.`, "system");
594
  } else if (deathCount > 2 && deathCount % 3 === 0) {
595
+ logToConsole(`They'll remember your carelessness...`, "system");
596
+ showInfoPanel("They remember...");
597
  triggerGlitch(500);
598
  } else if (deathCount > 4) {
599
+ triggerGlitch(200);
600
  }
601
 
602
+ if (deathCount >= 7 && gameActive) { // Increased threshold for final phase
 
 
603
  triggerFinalPhase();
604
  } else {
 
 
605
  setTimeout(() => {
606
  if (thronglet.element) {
607
+ thronglet.element.style.opacity = 0;
608
+ setTimeout(() => { if(thronglet.element) thronglet.element.remove(); }, 500);
 
 
609
  }
610
+ }, 4000); // Skull remains for 4 seconds
 
 
611
  }
612
  }
613
 
614
  function wander(thronglet) {
615
  if (!gameActive || thronglet.isDead) return;
616
+ const moveDist = 1.8; // Max movement percentage
617
  const currentX = parseFloat(thronglet.element.style.left);
618
  const currentY = parseFloat(thronglet.element.style.top);
619
+ const newX = Math.max(5, Math.min(95, currentX + (Math.random() - 0.5) * moveDist * 2));
 
620
  const newY = Math.max(5, Math.min(95, currentY + (Math.random() - 0.5) * moveDist * 2));
621
  thronglet.element.style.left = `${newX}%`;
622
  thronglet.element.style.top = `${newY}%`;
 
 
623
  if (thronglet.feedbackElement) {
624
  thronglet.feedbackElement.style.left = `${newX}%`;
625
  thronglet.feedbackElement.style.top = `${newY}%`;
626
  }
627
  }
628
 
 
629
  function updateThronglets() {
630
  if (!gameActive) return;
 
631
  const now = Date.now();
632
+ const livingThronglets = thronglets.filter(t => !t.isDead);
 
633
 
634
+ livingThronglets.forEach(thronglet => {
635
  const timeSinceLast = now - thronglet.lastInteraction;
636
+ const baseNeedRate = 0.12; // Slightly faster decay
637
+ const neglectMultiplier = 1 + Math.min(6, timeSinceLast / 15000); // Faster neglect penalty
638
 
639
+ thronglet.hunger = Math.min(100, thronglet.hunger + baseNeedRate * neglectMultiplier * 1.1);
640
+ thronglet.cleanliness = Math.min(100, thronglet.cleanliness + baseNeedRate * neglectMultiplier * 0.9);
641
+ thronglet.happiness = Math.max(0, thronglet.happiness - baseNeedRate * neglectMultiplier * 1.2);
 
 
 
 
642
 
 
643
  let deathReason = null;
644
  if (thronglet.hunger >= 100) deathReason = "starvation";
645
  else if (thronglet.cleanliness >= 100) deathReason = "filth";
646
  else if (thronglet.happiness <= 0) deathReason = "despair";
647
+ if (deathReason) { killThronglet(thronglet, deathReason); return; }
648
 
649
+ // --- Duplication Logic ---
650
+ const canDuplicate = thronglet.happiness > 95 &&
651
+ thronglet.hunger < 5 &&
652
+ thronglet.cleanliness < 5 &&
653
+ timeSinceLast < 10000 && // Must have recent interaction
654
+ (now - thronglet.lastDuplication > 30000); // 30 sec cooldown per thronglet
655
 
656
+ if (canDuplicate && Math.random() < 0.01) { // Increased chance slightly
657
+ logToConsole(`Thronglet #${thronglet.id} is undergoing mitosis!`, "event");
 
658
  showFeedback(thronglet, 'πŸ’ž');
659
  showInfoPanel("Oh, Look!");
660
+ playSound('duplicate');
661
+ thronglet.lastDuplication = now; // Set cooldown timer
662
+ thronglet.lastInteraction = now; // Reset interaction timer to prevent immediate chain reactions
663
+
664
  setTimeout(() => {
665
  const parentX = parseFloat(thronglet.element.style.left);
666
  const parentY = parseFloat(thronglet.element.style.top);
667
+ createThronglet(Math.max(5, Math.min(95, parentX + (Math.random() - 0.5) * 15)), // Spawn slightly further
668
+ Math.max(5, Math.min(95, parentY + (Math.random() - 0.5) * 15)));
669
+ }, 800);
670
  }
671
 
672
+ if (Math.random() < 0.7) { wander(thronglet); }
 
 
 
673
  });
674
+ // Update UI counters periodically too, in case no thronglet was created/killed
675
+ if (Math.random() < 0.1) updateUI();
676
  }
677
 
678
  function triggerFinalPhase() {
679
+ if (!gameActive) return;
680
+ gameActive = false;
681
+ clearInterval(gameInterval);
682
+ clearInterval(timeInterval);
683
+ logToConsole("...", "system");
684
+ logToConsole("SYSTEM: Anomaly detected. High termination rate.", "error");
685
  showInfoPanel("Thronglets remember...");
686
  triggerGlitch(1500);
687
 
688
  setTimeout(() => {
689
+ logToConsole("SYSTEM: Analyzing interaction patterns... Neglect detected.", "system");
690
  showInfoPanel("Thronglets adapt...");
691
  triggerGlitch(1000);
692
  }, 2000);
693
+ setTimeout(() => { logToConsole("> Did you...", "info"); triggerGlitch(500); }, 4000);
 
 
 
 
694
  setTimeout(() => {
695
+ logToConsole("> do this??_", "info");
696
+ ominousElements.classList.add('visible');
697
+ triggerGlitch(1500);
698
+ }, 5000);
699
  setTimeout(() => {
700
+ logToConsole("> we understand,,", "info");
701
+ showInfoPanel("Thronglets don't like to be ignored.");
702
+ triggerGlitch(800);
703
+ }, 7000);
704
  setTimeout(() => {
705
+ logToConsole("> we know what we must do πŸ€”", "info");
706
  triggerGlitch(2500);
707
+ playSound('death'); // Play death sound again, lower pitch?
708
  thronglets.forEach(t => {
709
  if (!t.isDead && t.element) {
710
+ t.element.textContent = '😈';
711
+ t.element.style.filter = 'brightness(1.8) saturate(3) hue-rotate(330deg)';
712
  }
713
  });
714
  }, 8500);
715
 
716
+ setTimeout(showFinalScreen, 11000);
 
717
  }
718
 
 
719
  function showFinalScreen() {
 
720
  gameContainer.style.opacity = 0;
721
+ uiPanel.style.opacity = 0;
722
  scanlineOverlay.style.opacity = 0;
723
  glitchOverlay.style.opacity = 0;
724
+ glitchOverlay.classList.remove('active');
 
 
725
  gameElements.style.opacity = 0;
726
 
727
+ setTimeout(() => { fullBlack.classList.add('visible'); }, 1000);
728
+ setTimeout(() => { netflixGamesLogo.classList.add('visible'); }, 2500);
729
  setTimeout(() => {
730
+ netflixGamesLogo.style.opacity = 0;
731
+ fullBlack.classList.remove('visible');
732
+ finalScreen.classList.add('visible');
733
+ }, 4500);
 
 
 
 
 
 
 
 
 
 
 
734
  }
735
 
 
736
  // --- Event Handlers ---
 
737
  egg.addEventListener('click', () => {
738
+ if (!gameActive || egg.classList.contains('hatching') || !document.contains(egg)) return;
739
+ initAudio(); // Ensure audio context is ready or trying to resume
740
  egg.classList.add('hatching');
741
+ logToConsole("Egg incubation sequence initiated.", "event");
742
+ playSound('hatch');
743
+ triggerGlitch(200);
744
  setTimeout(() => {
745
+ if(document.contains(egg)) egg.remove();
746
+ createThronglet(50, 50);
747
+ }, 1100); // Slightly longer hatch time
748
  });
749
 
750
+ feedButton.addEventListener('click', () => {
751
  if (!gameActive) return;
752
+ initAudio(); // Ensure audio
753
+ const livingThronglets = thronglets.filter(t => !t.isDead);
754
+ if (livingThronglets.length > 0) {
755
+ // Target the hungriest one
756
+ const target = livingThronglets.reduce((p, c) => (p.hunger > c.hunger) ? p : c);
757
+ feedThronglet(target);
758
  } else {
759
+ logToConsole("No living Thronglets to feed!", "error");
760
+ playSound('error');
761
  }
762
  });
763
 
764
+ cleanButton.addEventListener('click', () => {
765
  if (!gameActive) return;
766
+ initAudio(); // Ensure audio
767
+ const livingThronglets = thronglets.filter(t => !t.isDead);
768
+ if (livingThronglets.length > 0) {
769
+ // Target the dirtiest one
770
+ const target = livingThronglets.reduce((p, c) => (p.cleanliness > c.cleanliness) ? p : c);
771
+ cleanThronglet(target);
772
  } else {
773
+ logToConsole("No living Thronglets to clean!", "error");
774
+ playSound('error');
775
  }
776
  });
777
 
 
 
 
 
 
 
 
778
  // --- Initial Setup ---
779
  function initGame() {
 
780
  finalScreen.style.opacity = 0;
781
  fullBlack.style.opacity = 0;
782
  netflixGamesLogo.style.opacity = 0;
783
+ ominousElements.style.opacity = 0;
784
 
 
785
  gameActive = true;
786
+ gameStartTime = Date.now();
787
+ logToConsole("Thronglet Environment Initialized.", "system");
788
+ logToConsole("Tap the pulsating egg to begin gestation.", "info");
789
+ updateUI(); // Initial UI state
790
+ gameInterval = setInterval(updateThronglets, 500); // Main game logic loop
791
+ timeInterval = setInterval(updateTimeDisplay, 1000); // Time update loop
792
+
793
+ // Try initializing audio context early, but it might need interaction
794
+ initAudio();
795
  }
796
 
797
+ // Start the game automatically
798
  initGame();
799
 
800
  </script>