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

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +300 -250
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Thronglets Imitation</title>
7
  <style>
8
  body {
9
  margin: 0;
@@ -29,14 +29,15 @@
29
  border: 10px solid #8B4513; /* Wooden frame */
30
  box-sizing: border-box;
31
  overflow: hidden; /* Keep everything inside the frame */
32
- display: flex;
33
  justify-content: center;
34
  align-items: center;
35
- flex-wrap: wrap; /* Allow thronglets to wrap if many */
36
  padding: 20px; /* Padding inside the frame */
37
  image-rendering: pixelated; /* Attempt pixelation */
38
  font-size: 2em; /* Emojis larger */
39
- position: relative;
 
40
  }
41
 
42
  .game-elements {
@@ -53,25 +54,24 @@
53
  pointer-events: auto; /* Allow clicks on interactable elements */
54
  transform: translate(-50%, -50%); /* Center element */
55
  user-select: none;
 
56
  }
57
 
58
-
59
- .rock { top: 15%; left: 15%; }
60
- .rock.right { left: 85%; }
61
- .tree { top: 75%; left: 20%; }
62
- .tree.right { left: 80%; }
63
- .egg { top: 50%; left: 50%; cursor: pointer; transition: transform 0.5s ease;}
64
  .egg.hatching { animation: hatch-pulse 0.5s infinite alternate; }
65
  .thronglet {
66
- top: 50%;
67
- left: 50%;
68
  cursor: pointer;
69
- transition: top 0.5s, left 0.5s, transform 0.2s ease;
70
- z-index: 1; /* Ensure thronglets are above background elements */
71
  }
72
 
73
- .apple { top: 60%; left: 40%; cursor: pointer; }
74
- .bath { top: 60%; left: 60%; cursor: pointer; }
75
 
76
  .feedback {
77
  position: absolute;
@@ -79,6 +79,8 @@
79
  font-size: 0.8em;
80
  opacity: 0;
81
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
 
 
82
  }
83
  .feedback.active {
84
  opacity: 1;
@@ -89,6 +91,7 @@
89
  filter: grayscale(100%);
90
  opacity: 0.5;
91
  pointer-events: none;
 
92
  }
93
 
94
  .blood {
@@ -98,7 +101,7 @@
98
  pointer-events: none;
99
  opacity: 0;
100
  transition: opacity 0.5s ease-out;
101
- z-index: 0;
102
  }
103
  .blood.splatter { opacity: 1; }
104
 
@@ -119,6 +122,9 @@
119
  word-break: break-word;
120
  pointer-events: none; /* Don't block clicks */
121
  z-index: 100;
 
 
 
122
  }
123
 
124
  .message {
@@ -143,6 +149,7 @@
143
  transparent 1px,
144
  transparent 2px
145
  );
 
146
  }
147
 
148
  .glitch-overlay {
@@ -156,6 +163,7 @@
156
  animation: glitch 5s infinite alternate steps(5);
157
  opacity: 0;
158
  filter: hue-rotate(0deg);
 
159
  }
160
 
161
  .glitch-overlay.active {
@@ -170,24 +178,12 @@
170
  }
171
 
172
  @keyframes glitch {
173
- 0% {
174
- transform: translate(0);
175
- }
176
- 20% {
177
- transform: translate(-5px, 5px);
178
- }
179
- 40% {
180
- transform: translate(-5px, -5px);
181
- }
182
- 60% {
183
- transform: translate(5px, 5px);
184
- }
185
- 80% {
186
- transform: translate(5px, -5px);
187
- }
188
- to {
189
- transform: translate(0);
190
- }
191
  }
192
 
193
  @keyframes color-shift {
@@ -203,22 +199,23 @@
203
  font-size: 3em;
204
  opacity: 0;
205
  transition: opacity 2s ease-in-out;
206
- z-index: 0;
 
207
  }
208
  .ominous-elements.visible {
209
  opacity: 1;
210
  }
211
 
212
-
213
  .info-panel {
214
  position: absolute;
215
  top: 50%;
216
  left: 50%;
217
  transform: translate(-50%, -50%);
218
- background: #8B4513;
219
  border: 2px solid black;
220
  padding: 15px;
221
  color: white;
 
222
  font-size: 0.7em;
223
  text-align: center;
224
  white-space: pre-wrap;
@@ -226,11 +223,12 @@
226
  opacity: 0;
227
  transition: opacity 1s ease-in-out;
228
  pointer-events: none;
229
- z-index: 5;
 
230
  }
231
  .info-panel.visible {
232
  opacity: 1;
233
- pointer-events: auto;
234
  }
235
 
236
  .black-mirror-title {
@@ -241,7 +239,7 @@
241
  color: white;
242
  font-weight: bold;
243
  text-shadow: 1px 1px 0 black;
244
- z-index: 10;
245
  }
246
 
247
  .netflix-logo {
@@ -252,49 +250,18 @@
252
  color: red; /* Or maybe style text */
253
  font-weight: bold;
254
  text-shadow: 1px 1px 0 black;
255
- z-index: 10;
256
- }
257
-
258
- .thronglets-title-screen {
259
- position: fixed;
260
- top: 0;
261
- left: 0;
262
- width: 100%;
263
- height: 100%;
264
- background: linear-gradient(to bottom, #FFD700, #FFA500); /* Golden/Orange sky */
265
- color: #8B4513; /* Brown text */
266
- font-size: 3em;
267
- font-weight: bold;
268
- text-align: center;
269
- padding-top: 15vh;
270
- box-sizing: border-box;
271
- z-index: 200;
272
- transition: opacity 2s ease-out;
273
- display: flex;
274
- flex-direction: column;
275
- align-items: center;
276
- }
277
-
278
- .thronglets-title-screen .copyright {
279
- font-size: 0.4em;
280
- margin-top: 10px;
281
- }
282
-
283
- .thronglets-title-screen .creatures {
284
- margin-top: 5vh;
285
- }
286
- .thronglets-title-screen .creatures .emoji {
287
- font-size: 2em;
288
- margin: 0 20px;
289
  }
290
 
 
291
  .final-screen {
292
  position: fixed;
293
  top: 0;
294
  left: 0;
295
  width: 100%;
296
  height: 100%;
297
- background: radial-gradient(circle, rgba(148,187,233,1) 0%, rgba(238,174,202,1) 100%); /* Colorful background */
 
298
  z-index: 300;
299
  display: flex;
300
  flex-direction: column;
@@ -305,8 +272,12 @@
305
  text-align: center;
306
  opacity: 0;
307
  transition: opacity 2s ease-in-out;
 
 
 
 
 
308
  }
309
- .final-screen.visible { opacity: 1; }
310
 
311
  .app-stores {
312
  margin-top: 20px;
@@ -315,6 +286,7 @@
315
  .app-stores img {
316
  height: 40px;
317
  margin: 0 10px;
 
318
  }
319
 
320
  .full-black {
@@ -336,43 +308,34 @@
336
  z-index: 302;
337
  opacity: 0;
338
  transition: opacity 1s ease-in-out;
 
339
  }
340
  .netflix-games-logo.visible { opacity: 1; }
 
 
 
 
 
341
 
342
 
343
  </style>
344
  </head>
345
  <body>
346
 
347
- <div class="thronglets-title-screen" id="titleScreen">
348
- THRONGLETS
349
- <div class="copyright">(C) 1994 TUCKERSOFT LTD</div>
350
- <div class="creatures">
351
- <span class="emoji">πŸ₯š</span>
352
- <!-- Using a placeholder emoji that *could* look like a Thronglet -->
353
- <span class="emoji">🐻</span>
354
- <span class="emoji">🐻</span>
355
- <span class="emoji tree">🌳</span>
356
- </div>
357
- <div class="copyright" style="font-size: 0.3em; margin-top: 50px;">
358
- Tuckersoft is not responsible for strange noises, missing files, or dreams featuring Thronglets whispering your name.
359
- </div>
360
- </div>
361
-
362
-
363
  <div class="game-container" id="gameContainer">
364
  <div class="black-mirror-title">BLACK MIRROR:<br>THRONGLETS</div>
365
  <div class="netflix-logo">N<br>GAMES</div> <!-- Simulate Netflix Games logo -->
366
 
367
- <div class="game-elements">
 
368
  <span class="emoji rock">πŸͺ¨</span>
369
  <span class="emoji rock right">πŸͺ¨</span>
370
  <span class="emoji tree">🌳</span>
371
  <span class="emoji tree right">🌳</span>
372
 
 
373
  <span class="emoji egg" id="egg">πŸ₯š</span>
374
-
375
- <!-- Initial items -->
376
  <span class="emoji apple" id="apple">🍎</span>
377
  <span class="emoji bath" id="bath">πŸ›€</span>
378
 
@@ -386,41 +349,45 @@
386
 
387
  <!-- Blood splatter area -->
388
  <span class="emoji blood" id="bloodSplatter">🩸</span>
 
 
389
  </div>
390
 
391
  </div>
392
 
393
  <div class="console" id="console"></div>
394
- <div class="scanline-overlay"></div>
395
  <div class="glitch-overlay" id="glitchOverlay"></div>
396
 
 
397
  <div class="final-screen" id="finalScreen">
398
  PLAY NOW<br>ON THE NETFLIX<br>MOBILE APP
399
  <div class="app-stores">
400
  <!-- Placeholder images or text for store buttons -->
401
- <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" alt="Google Play Placeholder">
402
- <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=" alt="App Store Placeholder">
403
- (Store Buttons Go Here)
404
  </div>
405
  </div>
406
 
407
  <div class="full-black" id="fullBlack"></div>
408
  <div class="netflix-games-logo" id="netflixGamesLogo">
409
- <span class="emoji" style="font-size: 5em; color: red;">N</span>
410
  </div>
411
 
412
 
413
  <script>
414
  const egg = document.getElementById('egg');
415
  const gameContainer = document.getElementById('gameContainer');
 
416
  const consoleDiv = document.getElementById('console');
417
  const apple = document.getElementById('apple');
418
  const bath = document.getElementById('bath');
419
  const glitchOverlay = document.getElementById('glitchOverlay');
 
420
  const ominousElements = document.getElementById('ominousElements');
421
  const infoPanel = document.getElementById('infoPanel');
422
  const bloodSplatter = document.getElementById('bloodSplatter');
423
- const titleScreen = document.getElementById('titleScreen');
424
  const finalScreen = document.getElementById('finalScreen');
425
  const fullBlack = document.getElementById('fullBlack');
426
  const netflixGamesLogo = document.getElementById('netflixGamesLogo');
@@ -429,6 +396,8 @@
429
  let nextThrongletId = 0;
430
  let deathCount = 0;
431
  const MAX_THRONGLETS = 20; // Cap the number for performance
 
 
432
 
433
  // --- Game State & Logic ---
434
 
@@ -441,123 +410,133 @@
441
  }
442
 
443
  function triggerGlitch(duration = 1000) {
 
444
  glitchOverlay.classList.add('active');
445
  setTimeout(() => {
446
  glitchOverlay.classList.remove('active');
447
  }, duration);
448
  }
449
 
450
- function showInfoPanel(text, duration = 2000) {
 
451
  infoPanel.textContent = text;
452
  infoPanel.classList.add('visible');
453
- clearTimeout(infoPanel.timeout);
454
  infoPanel.timeout = setTimeout(() => {
455
  infoPanel.classList.remove('visible');
456
  }, duration);
457
  }
458
 
459
- function createThronglet(x, y) {
460
- if (thronglets.length >= MAX_THRONGLETS) {
461
- logToConsole("Too many Thronglets.");
 
 
462
  return;
463
  }
464
 
465
  const throngletElement = document.createElement('span');
466
  throngletElement.classList.add('emoji', 'thronglet');
467
- // Use a default emoji that could resemble the character
468
- throngletElement.textContent = 'πŸ•'; // Changed from 🐻 - maybe more ears?
469
- throngletElement.dataset.id = nextThrongletId++;
470
- throngletElement.style.top = `${y}%`;
471
- throngletElement.style.left = `${x}%`;
472
- gameContainer.querySelector('.game-elements').appendChild(throngletElement);
 
473
 
474
  const newThronglet = {
475
- id: throngletElement.dataset.id,
476
  element: throngletElement,
477
- hunger: 50, // 0-100, 100 is very hungry
478
- cleanliness: 50, // 0-100, 100 is very dirty
479
- happiness: 50, // 0-100, 0 is very unhappy
480
  lastInteraction: Date.now(),
481
  isDead: false,
482
  memory: [], // To store events
 
483
  };
484
  thronglets.push(newThronglet);
485
 
486
- // Add click listener for interaction
487
- throngletElement.addEventListener('click', () => interactThronglet(newThronglet));
488
 
489
  logToConsole(`A new Thronglet #${newThronglet.id} appeared!`);
490
 
491
- // Add feedback element
492
  const feedbackElement = document.createElement('span');
493
  feedbackElement.classList.add('emoji', 'feedback');
494
- feedbackElement.style.top = `${y}%`;
495
- feedbackElement.style.left = `${x}%`;
496
- gameContainer.querySelector('.game-elements').appendChild(feedbackElement);
 
497
  newThronglet.feedbackElement = feedbackElement;
 
 
 
 
 
498
  }
499
 
 
500
  function interactThronglet(thronglet) {
501
- if (thronglet.isDead) return;
502
-
503
- const now = Date.now();
504
- const timeSinceLast = now - thronglet.lastInteraction;
505
- thronglet.lastInteraction = now;
506
-
507
- // Simple interaction feedback
508
- thronglet.happiness = Math.max(0, thronglet.happiness - 10); // Interacting makes them slightly happy
509
- showFeedback(thronglet, 'πŸ‘‹'); // Wave emoji
510
-
511
- logToConsole(`Interacted with Thronglet #${thronglet.id}`);
512
-
513
- // Check for "tricks" (not implemented, but could be a mechanic)
514
- // If they have high stats, maybe they "learn" something?
515
- if (thronglet.hunger < 20 && thronglet.cleanliness < 20 && thronglet.happiness > 80 && timeSinceLast < 5000) {
516
- // This is a placeholder for a learning/trick mechanic
517
- logToConsole(`Thronglet #${thronglet.id} seems responsive...`);
518
- thronglet.memory.push('PositiveInteraction'); // Store positive memory
519
- showFeedback(thronglet, '✨');
520
- }
521
  }
522
 
523
-
524
  function feedThronglet(thronglet) {
525
- if (thronglet.isDead) return;
526
- thronglet.hunger = Math.max(0, thronglet.hunger - 30);
527
  thronglet.happiness = Math.min(100, thronglet.happiness + 15);
 
528
  showFeedback(thronglet, '🍎');
529
- logToConsole(`Fed Thronglet #${thronglet.id}. Hunger: ${thronglet.hunger}`);
530
  thronglet.memory.push('Fed');
531
  }
532
 
533
  function cleanThronglet(thronglet) {
534
- if (thronglet.isDead) return;
535
- thronglet.cleanliness = Math.max(0, thronglet.cleanliness - 40);
536
- thronglet.happiness = Math.min(100, thronglet.happiness + 20);
 
537
  showFeedback(thronglet, 'πŸ›');
538
- logToConsole(`Cleaned Thronglet #${thronglet.id}. Cleanliness: ${thronglet.cleanliness}`);
539
  thronglet.memory.push('Cleaned');
540
  }
541
 
542
-
543
  function showFeedback(thronglet, emoji) {
544
- if (thronglet.feedbackElement) {
545
- thronglet.feedbackElement.textContent = emoji;
546
- thronglet.feedbackElement.classList.add('active');
547
- clearTimeout(thronglet.feedbackElement.timeout);
548
- thronglet.feedbackElement.timeout = setTimeout(() => {
 
 
 
 
 
 
549
  thronglet.feedbackElement.classList.remove('active');
550
- }, 500);
551
- }
552
  }
553
 
554
- function killThronglet(thronglet) {
555
- if (thronglet.isDead) return;
556
 
557
  thronglet.isDead = true;
558
  thronglet.element.classList.add('dead');
559
  thronglet.element.textContent = 'πŸ’€'; // Replace with skull
560
- thronglet.feedbackElement.remove(); // Remove feedback icon
 
 
 
 
 
561
 
562
  // Add blood splatter effect briefly
563
  bloodSplatter.style.top = thronglet.element.style.top;
@@ -567,179 +546,250 @@
567
 
568
 
569
  deathCount++;
570
- logToConsole(`Thronglet #${thronglet.id} experienced the void.`);
571
- logToConsole(`Learned individuals are wholly disposable`); // From trailer
572
 
573
- thronglet.memory.push('Died'); // Remember death
 
574
 
575
- // Trigger events based on death count
576
  if (deathCount === 1) {
577
  showInfoPanel("The first Thronglet to experience the void...");
578
- triggerGlitch();
579
- } else if (deathCount > 3 && deathCount % 3 === 0) {
 
580
  logToConsole(`They'll remember your carelessness...`);
 
581
  triggerGlitch(500);
 
 
582
  }
583
 
584
- // Maybe respawn faster after death? Or spawn more?
585
- setTimeout(() => {
586
- // Simple respawn logic - replace the skull with a new egg/thronglet
587
- thronglet.element.remove(); // Remove the skull
588
- thronglets = thronglets.filter(t => t.id !== thronglet.id); // Remove from array
589
- const { top, left } = thronglet.element.style;
590
- createThronglet(parseFloat(left), parseFloat(top)); // Spawn a new one near where it died
591
- }, 5000); // Respawn after 5 seconds
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
  }
593
 
 
594
  function updateThronglets() {
 
 
595
  const now = Date.now();
596
  thronglets.forEach(thronglet => {
597
  if (thronglet.isDead) return;
598
 
599
- const timeAlive = now - thronglet.element.dataset.bornTime; // Track time alive
600
  const timeSinceLast = now - thronglet.lastInteraction;
601
 
602
- // Increase needs over time (faster if neglected)
603
- const needIncreaseRate = timeSinceLast / 10000; // Faster increase if ignored for 10s
604
- thronglet.hunger = Math.min(100, thronglet.hunger + needIncreaseRate);
605
- thronglet.cleanliness = Math.min(100, thronglet.cleanliness + needIncreaseRate * 0.8); // Cleaning slightly less critical
606
- thronglet.happiness = Math.max(0, thronglet.happiness - needIncreaseRate * 1.2); // Happiness decays faster
 
 
607
 
608
  // Check conditions for death
609
- if (thronglet.hunger >= 90 || thronglet.cleanliness >= 90 || thronglet.happiness <= 10) {
610
- killThronglet(thronglet);
 
 
 
 
 
 
611
  }
612
 
613
  // Check for reproduction (if very happy and well-cared for)
614
- if (thronglet.happiness > 85 && thronglet.hunger < 20 && thronglet.cleanliness < 20 && timeSinceLast < 30000 && Math.random() < 0.001) { // Small random chance
615
- logToConsole(`Thronglet #${thronglet.id} feels loved. Oh, Look!`); // From trailer
616
- showFeedback(thronglet, '❀️');
 
617
  // Spawn a new one nearby
618
  setTimeout(() => {
619
- createThronglet(parseFloat(thronglet.element.style.left) + (Math.random() - 0.5) * 10,
620
- parseFloat(thronglet.element.style.top) + (Math.random() - 0.5) * 10);
621
- }, 500); // Short delay to show feedback
 
 
622
  }
623
 
624
  // Simple movement (random walk)
625
- const currentX = parseFloat(thronglet.element.style.left);
626
- const currentY = parseFloat(thronglet.element.style.top);
627
- const moveDist = 2; // Max movement percentage
628
- const newX = Math.max(5, Math.min(95, currentX + (Math.random() - 0.5) * moveDist)); // Keep within bounds
629
- const newY = Math.max(5, Math.min(95, currentY + (Math.random() - 0.5) * moveDist));
630
- thronglet.element.style.left = `${newX}%`;
631
- thronglet.element.style.top = `${newY}%`;
632
-
633
-
634
- // Periodically show a status hint (optional, can clutter console)
635
- // if (Math.random() < 0.005) {
636
- // logToConsole(`#${thronglet.id}: H:${thronglet.hunger.toFixed(0)} C:${thronglet.cleanliness.toFixed(0)} P:${thronglet.happiness.toFixed(0)}`);
637
- // }
638
  });
 
639
 
640
- // Trigger final phase after significant events (e.g., high death count, many Thronglets)
641
- if (deathCount >= 5 && ! ominousElements.classList.contains('visible')) {
642
- logToConsole("Did you...");
643
- setTimeout(() => { logToConsole("do this??_"); triggerGlitch(1000); }, 1000);
644
- setTimeout(() => { ominousElements.classList.add('visible'); }, 2000);
645
- setTimeout(() => { logToConsole("we understand,,"); }, 3000);
646
- setTimeout(() => { logToConsole("we know what we must do πŸ€”"); triggerGlitch(2000); }, 4000);
 
647
 
648
- // Transition to final screen after console messages
649
- setTimeout(showFinalScreen, 8000);
650
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
  }
652
 
 
653
  function showFinalScreen() {
 
654
  gameContainer.style.opacity = 0;
655
  consoleDiv.style.opacity = 0;
656
  scanlineOverlay.style.opacity = 0;
657
  glitchOverlay.style.opacity = 0;
 
 
 
 
658
 
659
- fullBlack.classList.add('visible');
660
  setTimeout(() => {
 
 
 
 
 
 
661
  netflixGamesLogo.classList.add('visible');
662
- fullBlack.classList.remove('visible'); // Fade out black
663
- }, 2000); // Show N logo after black screen
664
 
665
  setTimeout(() => {
 
666
  netflixGamesLogo.style.opacity = 0; // Fade out N
 
667
  finalScreen.classList.add('visible'); // Show final screen with app store links
668
- }, 4000); // Show final screen
669
  }
670
 
671
 
672
  // --- Event Handlers ---
673
 
674
  egg.addEventListener('click', () => {
675
- if (egg.classList.contains('hatching')) return;
676
  egg.classList.add('hatching');
677
  logToConsole("Egg is hatching...");
 
678
  setTimeout(() => {
679
- egg.remove(); // Remove the egg element
680
  createThronglet(50, 50); // Spawn first Thronglet in the center
681
  }, 1000); // Hatch after 1 second
682
  });
683
 
684
  apple.addEventListener('click', () => {
 
685
  const activeThronglets = thronglets.filter(t => !t.isDead);
686
  if (activeThronglets.length > 0) {
687
- // Find the hungriest or a random one
688
- const targetThronglet = activeThronglets.reduce((prev, current) => (prev.hunger > current.hunger) ? prev : current, activeThronglets[0]);
689
  feedThronglet(targetThronglet);
690
  } else {
691
- logToConsole("No Thronglets to feed!");
692
  }
693
  });
694
 
695
  bath.addEventListener('click', () => {
 
696
  const activeThronglets = thronglets.filter(t => !t.isDead);
697
  if (activeThronglets.length > 0) {
698
- // Find the dirtiest or a random one
699
- const targetThronglet = activeThronglets.reduce((prev, current) => (prev.cleanliness > current.cleanliness) ? prev : current, activeThronglets[0]);
700
  cleanThronglet(targetThronglet);
701
  } else {
702
- logToConsole("No Thronglets to clean!");
703
  }
704
  });
705
 
706
 
707
  // --- Game Loop ---
708
- let gameInterval;
709
-
710
  function startGameLoop() {
 
711
  gameInterval = setInterval(updateThronglets, 500); // Update every 0.5 seconds
712
  }
713
 
714
  // --- Initial Setup ---
715
  function initGame() {
716
- // Hide game elements until title screen is gone
717
- gameContainer.style.opacity = 0;
718
- consoleDiv.style.opacity = 0;
719
- ominousElements.style.opacity = 0;
720
- finalScreen.style.opacity = 0;
721
- fullBlack.style.opacity = 0;
722
- netflixGamesLogo.style.opacity = 0;
723
-
724
- // Listen for title screen click to start
725
- titleScreen.addEventListener('click', () => {
726
- titleScreen.style.opacity = 0;
727
- setTimeout(() => {
728
- titleScreen.style.display = 'none';
729
- gameContainer.style.opacity = 1;
730
- consoleDiv.style.opacity = 1;
731
- logToConsole("Welcome to Thronglets!");
732
- logToConsole("Tap the egg to hatch your first Thronglet.");
733
- startGameLoop();
734
- }, 2000); // Fade out title screen
735
- });
736
- logToConsole("Click anywhere on the screen to start."); // Initial console message behind title
737
  }
738
 
739
- // Start the game
740
  initGame();
741
 
742
-
743
  </script>
744
  </body>
745
  </html>
 
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;
 
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 {
 
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;
 
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
  filter: grayscale(100%);
92
  opacity: 0.5;
93
  pointer-events: none;
94
+ z-index: 1; /* Sink slightly when dead */
95
  }
96
 
97
  .blood {
 
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
 
 
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 {
 
149
  transparent 1px,
150
  transparent 2px
151
  );
152
+ transition: opacity 1s ease-out; /* Added for fade out */
153
  }
154
 
155
  .glitch-overlay {
 
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 {
 
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 {
 
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;
 
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 {
 
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 {
 
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;
 
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;
 
286
  .app-stores img {
287
  height: 40px;
288
  margin: 0 10px;
289
+ cursor: pointer; /* Indicate clickable */
290
  }
291
 
292
  .full-black {
 
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
 
 
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');
389
  const infoPanel = document.getElementById('infoPanel');
390
  const bloodSplatter = document.getElementById('bloodSplatter');
 
391
  const finalScreen = document.getElementById('finalScreen');
392
  const fullBlack = document.getElementById('fullBlack');
393
  const netflixGamesLogo = document.getElementById('netflixGamesLogo');
 
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
 
 
410
  }
411
 
412
  function triggerGlitch(duration = 1000) {
413
+ if (!gameActive) return;
414
  glitchOverlay.classList.add('active');
415
  setTimeout(() => {
416
  glitchOverlay.classList.remove('active');
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") {
529
+ if (!gameActive || thronglet.isDead) return;
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;
 
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>
794
  </body>
795
  </html>