C50BARZ commited on
Commit
c43b17d
·
verified ·
1 Parent(s): 01e6759

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +803 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Empathy Game
3
- emoji:
4
- colorFrom: purple
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: empathy-game
3
+ emoji: 🐳
4
+ colorFrom: red
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,803 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Empathy Connection Game</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/emoji-picker-element@1"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
12
+
13
+ body {
14
+ font-family: 'Poppins', sans-serif;
15
+ background-color: #f3f4f6;
16
+ height: 100vh;
17
+ overflow: hidden;
18
+ }
19
+
20
+ .message-container {
21
+ scrollbar-width: thin;
22
+ scrollbar-color: #9CA3AF #E5E7EB;
23
+ }
24
+
25
+ .message-container::-webkit-scrollbar {
26
+ width: 6px;
27
+ }
28
+
29
+ .message-container::-webkit-scrollbar-track {
30
+ background: #E5E7EB;
31
+ }
32
+
33
+ .message-container::-webkit-scrollbar-thumb {
34
+ background-color: #9CA3AF;
35
+ border-radius: 3px;
36
+ }
37
+
38
+ .typing-indicator::after {
39
+ content: "...";
40
+ animation: typing 1.5s infinite;
41
+ display: inline-block;
42
+ width: 0;
43
+ }
44
+
45
+ @keyframes typing {
46
+ 0% { content: "."; }
47
+ 33% { content: ".."; }
48
+ 66% { content: "..."; }
49
+ }
50
+
51
+ .pulse {
52
+ animation: pulse 2s infinite;
53
+ }
54
+
55
+ @keyframes pulse {
56
+ 0% { transform: scale(1); }
57
+ 50% { transform: scale(1.05); }
58
+ 100% { transform: scale(1); }
59
+ }
60
+
61
+ .emoji-picker {
62
+ position: absolute;
63
+ bottom: 60px;
64
+ right: 20px;
65
+ z-index: 10;
66
+ }
67
+
68
+ .confetti {
69
+ position: absolute;
70
+ width: 10px;
71
+ height: 10px;
72
+ background-color: #f00;
73
+ opacity: 0;
74
+ }
75
+ </style>
76
+ </head>
77
+ <body class="flex flex-col h-screen">
78
+ <!-- Header -->
79
+ <header class="bg-indigo-600 text-white p-4 shadow-md">
80
+ <div class="container mx-auto flex justify-between items-center">
81
+ <div class="flex items-center space-x-2">
82
+ <i class="fas fa-heart text-2xl"></i>
83
+ <h1 class="text-xl font-bold">Empathy Connection</h1>
84
+ </div>
85
+ <div id="user-count" class="flex items-center space-x-1">
86
+ <i class="fas fa-users"></i>
87
+ <span>1</span>
88
+ </div>
89
+ </div>
90
+ </header>
91
+
92
+ <!-- Game Area -->
93
+ <main class="flex-1 flex flex-col md:flex-row overflow-hidden">
94
+ <!-- Sidebar -->
95
+ <aside class="w-full md:w-64 bg-white p-4 border-r border-gray-200 flex flex-col">
96
+ <div class="mb-6">
97
+ <h2 class="font-bold text-lg text-indigo-700 mb-2">Game Rules</h2>
98
+ <ul class="text-sm space-y-2 text-gray-600">
99
+ <li class="flex items-start">
100
+ <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
101
+ <span>Share personal experiences when prompted</span>
102
+ </li>
103
+ <li class="flex items-start">
104
+ <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
105
+ <span>Respond with empathy and understanding</span>
106
+ </li>
107
+ <li class="flex items-start">
108
+ <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
109
+ <span>Be respectful and kind to others</span>
110
+ </li>
111
+ </ul>
112
+ </div>
113
+
114
+ <div class="mb-6">
115
+ <h2 class="font-bold text-lg text-indigo-700 mb-2">Players</h2>
116
+ <div id="players-list" class="space-y-2">
117
+ <div class="flex items-center space-x-2">
118
+ <div class="w-8 h-8 rounded-full bg-indigo-100 flex items-center justify-center text-indigo-600">
119
+ <i class="fas fa-user"></i>
120
+ </div>
121
+ <span class="text-sm">You</span>
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <div class="mt-auto">
127
+ <div id="game-status" class="p-3 rounded-lg bg-indigo-50 text-indigo-700 text-sm">
128
+ <p>Waiting for more players to join...</p>
129
+ </div>
130
+ </div>
131
+ </aside>
132
+
133
+ <!-- Main Chat Area -->
134
+ <section class="flex-1 flex flex-col bg-gray-50">
135
+ <!-- Prompt Area -->
136
+ <div id="prompt-area" class="p-4 bg-white border-b border-gray-200">
137
+ <div class="max-w-3xl mx-auto">
138
+ <div class="bg-indigo-50 p-4 rounded-lg">
139
+ <h3 class="font-bold text-indigo-700 mb-2">Today's Theme: Overcoming Challenges</h3>
140
+ <p class="text-gray-700">Share a time when you faced a difficult situation and how you handled it. Then respond to others with empathy and understanding.</p>
141
+ </div>
142
+ </div>
143
+ </div>
144
+
145
+ <!-- Messages Container -->
146
+ <div id="messages" class="message-container flex-1 overflow-y-auto p-4 space-y-4">
147
+ <div class="max-w-3xl mx-auto">
148
+ <div class="text-center py-8">
149
+ <div class="inline-block p-4 bg-indigo-100 rounded-full">
150
+ <i class="fas fa-heart text-indigo-500 text-3xl"></i>
151
+ </div>
152
+ <h3 class="text-xl font-bold text-indigo-700 mt-4">Welcome to Empathy Connection</h3>
153
+ <p class="text-gray-600 mt-2">Share your story and connect with others through empathy</p>
154
+ </div>
155
+ </div>
156
+ </div>
157
+
158
+ <!-- Input Area -->
159
+ <div class="p-4 bg-white border-t border-gray-200">
160
+ <div class="max-w-3xl mx-auto relative">
161
+ <div id="typing-indicator" class="text-xs text-gray-500 mb-1 hidden">
162
+ <span class="typing-indicator">Someone is typing</span>
163
+ </div>
164
+
165
+ <div class="flex space-x-2">
166
+ <button id="emoji-button" class="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center text-gray-500 hover:bg-gray-200">
167
+ <i class="far fa-smile"></i>
168
+ </button>
169
+
170
+ <div class="flex-1 relative">
171
+ <textarea id="message-input" rows="1" class="w-full p-3 pr-10 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 resize-none" placeholder="Share your experience..."></textarea>
172
+ <button id="send-button" class="absolute right-2 bottom-2 w-8 h-8 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center hover:bg-indigo-200 disabled:opacity-50" disabled>
173
+ <i class="fas fa-paper-plane"></i>
174
+ </button>
175
+ </div>
176
+ </div>
177
+
178
+ <emoji-picker id="emoji-picker" class="emoji-picker hidden"></emoji-picker>
179
+ </div>
180
+ </div>
181
+ </section>
182
+ </main>
183
+
184
+ <!-- Connection Modal -->
185
+ <div id="connection-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
186
+ <div class="bg-white rounded-lg p-6 max-w-md w-full mx-4">
187
+ <div class="text-center">
188
+ <div class="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mx-auto mb-4">
189
+ <i class="fas fa-plug text-indigo-500 text-2xl"></i>
190
+ </div>
191
+ <h3 class="text-xl font-bold text-gray-800 mb-2">Connecting to Game</h3>
192
+ <p class="text-gray-600 mb-6">Please wait while we connect you to other players...</p>
193
+ <div class="w-full bg-gray-200 rounded-full h-2">
194
+ <div id="connection-progress" class="bg-indigo-600 h-2 rounded-full w-0"></div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+ </div>
199
+
200
+ <!-- Welcome Modal -->
201
+ <div id="welcome-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
202
+ <div class="bg-white rounded-lg p-6 max-w-md w-full mx-4">
203
+ <div class="text-center">
204
+ <div class="w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mx-auto mb-4">
205
+ <i class="fas fa-heart text-indigo-500 text-2xl"></i>
206
+ </div>
207
+ <h3 class="text-xl font-bold text-gray-800 mb-2">Welcome to Empathy Connection</h3>
208
+ <p class="text-gray-600 mb-4">Practice empathy by sharing experiences and responding to others with understanding.</p>
209
+
210
+ <div class="mb-4">
211
+ <label for="username" class="block text-left text-sm font-medium text-gray-700 mb-1">Your Name</label>
212
+ <input type="text" id="username" class="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="Enter your name">
213
+ </div>
214
+
215
+ <button id="start-game" class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
216
+ Join the Game
217
+ </button>
218
+ </div>
219
+ </div>
220
+ </div>
221
+
222
+ <script>
223
+ // Game state
224
+ const gameState = {
225
+ players: {},
226
+ currentUser: null,
227
+ socket: null,
228
+ isTyping: false,
229
+ typingTimeout: null
230
+ };
231
+
232
+ // DOM elements
233
+ const elements = {
234
+ connectionModal: document.getElementById('connection-modal'),
235
+ welcomeModal: document.getElementById('welcome-modal'),
236
+ usernameInput: document.getElementById('username'),
237
+ startGameButton: document.getElementById('start-game'),
238
+ messageInput: document.getElementById('message-input'),
239
+ sendButton: document.getElementById('send-button'),
240
+ messagesContainer: document.getElementById('messages'),
241
+ playersList: document.getElementById('players-list'),
242
+ userCount: document.getElementById('user-count'),
243
+ typingIndicator: document.getElementById('typing-indicator'),
244
+ emojiButton: document.getElementById('emoji-button'),
245
+ emojiPicker: document.getElementById('emoji-picker'),
246
+ gameStatus: document.getElementById('game-status'),
247
+ connectionProgress: document.getElementById('connection-progress')
248
+ };
249
+
250
+ // Initialize the game
251
+ function initGame() {
252
+ // Show welcome modal
253
+ setTimeout(() => {
254
+ elements.connectionModal.classList.add('hidden');
255
+ elements.welcomeModal.classList.remove('hidden');
256
+ }, 2000);
257
+
258
+ // Simulate connection progress
259
+ let progress = 0;
260
+ const interval = setInterval(() => {
261
+ progress += 5;
262
+ elements.connectionProgress.style.width = `${progress}%`;
263
+
264
+ if (progress >= 100) {
265
+ clearInterval(interval);
266
+ }
267
+ }, 100);
268
+
269
+ // Set up event listeners
270
+ setupEventListeners();
271
+ }
272
+
273
+ // Set up all event listeners
274
+ function setupEventListeners() {
275
+ // Start game button
276
+ elements.startGameButton.addEventListener('click', () => {
277
+ const username = elements.usernameInput.value.trim();
278
+ if (username) {
279
+ joinGame(username);
280
+ }
281
+ });
282
+
283
+ // Message input events
284
+ elements.messageInput.addEventListener('input', handleMessageInput);
285
+ elements.messageInput.addEventListener('keydown', (e) => {
286
+ if (e.key === 'Enter' && !e.shiftKey) {
287
+ e.preventDefault();
288
+ sendMessage();
289
+ }
290
+ });
291
+
292
+ // Send button
293
+ elements.sendButton.addEventListener('click', sendMessage);
294
+
295
+ // Emoji picker
296
+ elements.emojiButton.addEventListener('click', toggleEmojiPicker);
297
+ elements.emojiPicker.addEventListener('emoji-click', (event) => {
298
+ const emoji = event.detail.unicode;
299
+ const input = elements.messageInput;
300
+ const startPos = input.selectionStart;
301
+ const endPos = input.selectionEnd;
302
+
303
+ input.value = input.value.substring(0, startPos) + emoji + input.value.substring(endPos);
304
+ input.focus();
305
+ input.selectionStart = startPos + emoji.length;
306
+ input.selectionEnd = startPos + emoji.length;
307
+
308
+ // Trigger input event to update send button state
309
+ input.dispatchEvent(new Event('input'));
310
+ });
311
+
312
+ // Close emoji picker when clicking outside
313
+ document.addEventListener('click', (e) => {
314
+ if (!elements.emojiButton.contains(e.target) && !elements.emojiPicker.contains(e.target)) {
315
+ elements.emojiPicker.classList.add('hidden');
316
+ }
317
+ });
318
+ }
319
+
320
+ // Toggle emoji picker visibility
321
+ function toggleEmojiPicker() {
322
+ elements.emojiPicker.classList.toggle('hidden');
323
+ }
324
+
325
+ // Handle message input changes
326
+ function handleMessageInput() {
327
+ const message = elements.messageInput.value.trim();
328
+ elements.sendButton.disabled = message === '';
329
+
330
+ // Update typing status
331
+ if (message && !gameState.isTyping) {
332
+ gameState.isTyping = true;
333
+ sendTypingStatus(true);
334
+ } else if (!message && gameState.isTyping) {
335
+ gameState.isTyping = false;
336
+ sendTypingStatus(false);
337
+ }
338
+
339
+ // Reset typing timeout
340
+ if (gameState.typingTimeout) {
341
+ clearTimeout(gameState.typingTimeout);
342
+ }
343
+
344
+ if (message) {
345
+ gameState.typingTimeout = setTimeout(() => {
346
+ gameState.isTyping = false;
347
+ sendTypingStatus(false);
348
+ }, 2000);
349
+ }
350
+
351
+ // Auto-resize textarea
352
+ autoResizeTextarea();
353
+ }
354
+
355
+ // Auto-resize textarea based on content
356
+ function autoResizeTextarea() {
357
+ const textarea = elements.messageInput;
358
+ textarea.style.height = 'auto';
359
+ textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;
360
+ }
361
+
362
+ // Send typing status to server
363
+ function sendTypingStatus(isTyping) {
364
+ if (gameState.socket) {
365
+ gameState.socket.send(JSON.stringify({
366
+ type: 'typing',
367
+ userId: gameState.currentUser.id,
368
+ isTyping: isTyping
369
+ }));
370
+ }
371
+ }
372
+
373
+ // Join the game
374
+ function joinGame(username) {
375
+ elements.welcomeModal.classList.add('hidden');
376
+
377
+ // Create user
378
+ gameState.currentUser = {
379
+ id: generateId(),
380
+ name: username,
381
+ color: getRandomColor(),
382
+ avatar: getRandomAvatar()
383
+ };
384
+
385
+ // Simulate WebSocket connection
386
+ setTimeout(() => {
387
+ connectWebSocket();
388
+ }, 500);
389
+
390
+ // Add user to players list
391
+ addPlayer(gameState.currentUser);
392
+
393
+ // Show welcome message
394
+ addSystemMessage(`Welcome, ${username}! Share your experience when you're ready.`);
395
+ }
396
+
397
+ // Connect to WebSocket (simulated in this demo)
398
+ function connectWebSocket() {
399
+ // In a real app, this would connect to your WebSocket server
400
+ console.log("Connecting to WebSocket server...");
401
+ gameState.socket = {
402
+ send: function(data) {
403
+ // Simulate receiving messages with a delay
404
+ setTimeout(() => {
405
+ const message = JSON.parse(data);
406
+ handleIncomingMessage(message);
407
+ }, 300);
408
+ }
409
+ };
410
+
411
+ // Simulate other players joining
412
+ simulateOtherPlayers();
413
+ }
414
+
415
+ // Simulate other players joining the game
416
+ function simulateOtherPlayers() {
417
+ const names = ["Alex", "Jordan", "Taylor", "Morgan", "Casey"];
418
+ const avatars = ["user", "user-tie", "user-graduate", "user-nurse", "user-astronaut"];
419
+
420
+ // Add 3-5 simulated players
421
+ const numPlayers = Math.floor(Math.random() * 3) + 3;
422
+
423
+ for (let i = 0; i < numPlayers; i++) {
424
+ setTimeout(() => {
425
+ const player = {
426
+ id: generateId(),
427
+ name: names[i],
428
+ color: getRandomColor(),
429
+ avatar: `fa-${avatars[i]}`
430
+ };
431
+
432
+ gameState.players[player.id] = player;
433
+ addPlayer(player);
434
+ addSystemMessage(`${player.name} has joined the game`);
435
+
436
+ // Update user count
437
+ updateUserCount();
438
+
439
+ // Simulate some messages from other players
440
+ if (i === 0) {
441
+ setTimeout(() => {
442
+ simulatePlayerMessage(player, "Hi everyone! I'm excited to share and listen today.");
443
+ }, 1500);
444
+ }
445
+
446
+ if (i === 1) {
447
+ setTimeout(() => {
448
+ simulatePlayerMessage(player, "This is my first time here. Looking forward to connecting!");
449
+ }, 3000);
450
+ }
451
+
452
+ if (i === 2) {
453
+ setTimeout(() => {
454
+ simulatePlayerTyping(player);
455
+ }, 4500);
456
+ }
457
+
458
+ }, i * 1000);
459
+ }
460
+
461
+ // Update game status
462
+ setTimeout(() => {
463
+ elements.gameStatus.innerHTML = `
464
+ <p class="font-medium">Game in progress</p>
465
+ <p class="text-xs mt-1">Share your story and respond to others</p>
466
+ `;
467
+ }, numPlayers * 1000);
468
+ }
469
+
470
+ // Simulate a player typing
471
+ function simulatePlayerTyping(player) {
472
+ // Show typing indicator
473
+ const typingEvent = {
474
+ type: 'typing',
475
+ userId: player.id,
476
+ isTyping: true
477
+ };
478
+ handleIncomingMessage(typingEvent);
479
+
480
+ // Send message after delay
481
+ setTimeout(() => {
482
+ simulatePlayerMessage(player, "I once faced a big challenge when I had to speak in front of a large audience. I was so nervous but I practiced a lot and it went better than I expected!");
483
+
484
+ // Hide typing indicator
485
+ const stopTypingEvent = {
486
+ type: 'typing',
487
+ userId: player.id,
488
+ isTyping: false
489
+ };
490
+ handleIncomingMessage(stopTypingEvent);
491
+ }, 2000);
492
+ }
493
+
494
+ // Simulate a message from another player
495
+ function simulatePlayerMessage(player, text) {
496
+ const message = {
497
+ type: 'message',
498
+ userId: player.id,
499
+ text: text,
500
+ timestamp: new Date().toISOString()
501
+ };
502
+ handleIncomingMessage(message);
503
+ }
504
+
505
+ // Handle incoming messages from WebSocket
506
+ function handleIncomingMessage(message) {
507
+ switch (message.type) {
508
+ case 'message':
509
+ addPlayerMessage(message.userId, message.text, message.timestamp);
510
+ break;
511
+ case 'typing':
512
+ handleTypingIndicator(message.userId, message.isTyping);
513
+ break;
514
+ case 'user-joined':
515
+ addPlayer(message.user);
516
+ addSystemMessage(`${message.user.name} has joined the game`);
517
+ updateUserCount();
518
+ break;
519
+ case 'user-left':
520
+ removePlayer(message.userId);
521
+ addSystemMessage(`${gameState.players[message.userId]?.name || 'A player'} has left the game`);
522
+ updateUserCount();
523
+ break;
524
+ }
525
+ }
526
+
527
+ // Send a message
528
+ function sendMessage() {
529
+ const text = elements.messageInput.value.trim();
530
+ if (!text || !gameState.socket) return;
531
+
532
+ // Create message
533
+ const message = {
534
+ type: 'message',
535
+ userId: gameState.currentUser.id,
536
+ text: text,
537
+ timestamp: new Date().toISOString()
538
+ };
539
+
540
+ // Add to chat
541
+ addPlayerMessage(gameState.currentUser.id, text, message.timestamp);
542
+
543
+ // Clear input
544
+ elements.messageInput.value = '';
545
+ elements.sendButton.disabled = true;
546
+ autoResizeTextarea();
547
+
548
+ // Send to server
549
+ gameState.socket.send(JSON.stringify(message));
550
+
551
+ // Stop typing
552
+ if (gameState.isTyping) {
553
+ gameState.isTyping = false;
554
+ sendTypingStatus(false);
555
+ }
556
+
557
+ // Simulate responses from other players
558
+ simulateEmpatheticResponses(text);
559
+ }
560
+
561
+ // Simulate empathetic responses from other players
562
+ function simulateEmpatheticResponses(text) {
563
+ const players = Object.values(gameState.players);
564
+ if (players.length === 0) return;
565
+
566
+ // Randomly select 1-2 players to respond
567
+ const numResponses = Math.floor(Math.random() * 2) + 1;
568
+ const responders = [];
569
+
570
+ for (let i = 0; i < numResponses && i < players.length; i++) {
571
+ let randomPlayer;
572
+ do {
573
+ randomPlayer = players[Math.floor(Math.random() * players.length)];
574
+ } while (randomPlayer.id === gameState.currentUser.id || responders.includes(randomPlayer));
575
+
576
+ responders.push(randomPlayer);
577
+
578
+ // Generate response based on message content
579
+ let response;
580
+ if (text.toLowerCase().includes("happy") || text.toLowerCase().includes("excited")) {
581
+ response = "That's wonderful to hear! I'm so happy for you!";
582
+ } else if (text.toLowerCase().includes("sad") || text.toLowerCase().includes("difficult")) {
583
+ response = "I'm really sorry to hear that. That must have been really hard.";
584
+ } else if (text.toLowerCase().includes("nervous") || text.toLowerCase().includes("anxious")) {
585
+ response = "I can relate to that feeling. It takes courage to face those situations.";
586
+ } else {
587
+ const responses = [
588
+ "Thank you for sharing that. I appreciate your openness.",
589
+ "That's really interesting. I hadn't thought about it that way before.",
590
+ "I can understand how that would feel. Thanks for helping me see your perspective.",
591
+ "That sounds like a meaningful experience. I appreciate you sharing it with us."
592
+ ];
593
+ response = responses[Math.floor(Math.random() * responses.length)];
594
+ }
595
+
596
+ // Delay the response
597
+ setTimeout(() => {
598
+ simulatePlayerTyping(randomPlayer);
599
+
600
+ setTimeout(() => {
601
+ simulatePlayerMessage(randomPlayer, response);
602
+
603
+ // Occasionally trigger confetti for positive messages
604
+ if (text.toLowerCase().includes("happy") || text.toLowerCase().includes("excited")) {
605
+ if (Math.random() > 0.7) {
606
+ triggerConfetti();
607
+ }
608
+ }
609
+ }, 1500);
610
+ }, Math.random() * 3000 + 1000);
611
+ }
612
+ }
613
+
614
+ // Add a player to the list
615
+ function addPlayer(player) {
616
+ gameState.players[player.id] = player;
617
+
618
+ const playerElement = document.createElement('div');
619
+ playerElement.className = 'flex items-center space-x-2';
620
+ playerElement.id = `player-${player.id}`;
621
+ playerElement.innerHTML = `
622
+ <div class="w-8 h-8 rounded-full flex items-center justify-center text-white" style="background-color: ${player.color}">
623
+ <i class="fas ${player.avatar}"></i>
624
+ </div>
625
+ <span class="text-sm">${player.name}</span>
626
+ `;
627
+
628
+ elements.playersList.appendChild(playerElement);
629
+ updateUserCount();
630
+ }
631
+
632
+ // Remove a player from the list
633
+ function removePlayer(playerId) {
634
+ const playerElement = document.getElementById(`player-${playerId}`);
635
+ if (playerElement) {
636
+ playerElement.remove();
637
+ }
638
+ delete gameState.players[playerId];
639
+ updateUserCount();
640
+ }
641
+
642
+ // Update the user count display
643
+ function updateUserCount() {
644
+ const count = Object.keys(gameState.players).length + 1; // +1 for current user
645
+ elements.userCount.querySelector('span').textContent = count;
646
+ }
647
+
648
+ // Add a system message to the chat
649
+ function addSystemMessage(text) {
650
+ const messageElement = document.createElement('div');
651
+ messageElement.className = 'text-center my-4';
652
+ messageElement.innerHTML = `
653
+ <span class="inline-block px-3 py-1 bg-gray-100 text-gray-600 rounded-full text-sm">
654
+ ${text}
655
+ </span>
656
+ `;
657
+ elements.messagesContainer.appendChild(messageElement);
658
+ scrollToBottom();
659
+ }
660
+
661
+ // Add a player message to the chat
662
+ function addPlayerMessage(userId, text, timestamp) {
663
+ const isCurrentUser = userId === gameState.currentUser?.id;
664
+ const player = isCurrentUser ? gameState.currentUser : gameState.players[userId];
665
+ if (!player) return;
666
+
667
+ const time = new Date(timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
668
+
669
+ const messageElement = document.createElement('div');
670
+ messageElement.className = `flex ${isCurrentUser ? 'justify-end' : 'justify-start'} mb-4`;
671
+
672
+ if (isCurrentUser) {
673
+ messageElement.innerHTML = `
674
+ <div class="max-w-xs md:max-w-md lg:max-w-lg">
675
+ <div class="bg-indigo-100 text-gray-800 p-3 rounded-lg rounded-tr-none">
676
+ <p>${text}</p>
677
+ <div class="text-right mt-1">
678
+ <span class="text-xs text-gray-500">${time}</span>
679
+ </div>
680
+ </div>
681
+ </div>
682
+ `;
683
+ } else {
684
+ messageElement.innerHTML = `
685
+ <div class="flex space-x-2 max-w-xs md:max-w-md lg:max-w-lg">
686
+ <div class="w-8 h-8 rounded-full flex items-center justify-center text-white" style="background-color: ${player.color}">
687
+ <i class="fas ${player.avatar}"></i>
688
+ </div>
689
+ <div>
690
+ <div class="font-medium text-xs text-gray-600 mb-1">${player.name}</div>
691
+ <div class="bg-white border border-gray-200 text-gray-800 p-3 rounded-lg rounded-tl-none">
692
+ <p>${text}</p>
693
+ <div class="text-right mt-1">
694
+ <span class="text-xs text-gray-500">${time}</span>
695
+ </div>
696
+ </div>
697
+ </div>
698
+ </div>
699
+ `;
700
+ }
701
+
702
+ elements.messagesContainer.appendChild(messageElement);
703
+ scrollToBottom();
704
+ }
705
+
706
+ // Handle typing indicator
707
+ function handleTypingIndicator(userId, isTyping) {
708
+ if (userId === gameState.currentUser?.id) return;
709
+
710
+ const player = gameState.players[userId];
711
+ if (!player) return;
712
+
713
+ if (isTyping) {
714
+ elements.typingIndicator.innerHTML = `
715
+ <span class="typing-indicator">${player.name} is typing</span>
716
+ `;
717
+ elements.typingIndicator.classList.remove('hidden');
718
+ } else {
719
+ elements.typingIndicator.classList.add('hidden');
720
+ }
721
+ }
722
+
723
+ // Scroll chat to bottom
724
+ function scrollToBottom() {
725
+ elements.messagesContainer.scrollTop = elements.messagesContainer.scrollHeight;
726
+ }
727
+
728
+ // Generate random ID
729
+ function generateId() {
730
+ return Math.random().toString(36).substr(2, 9);
731
+ }
732
+
733
+ // Get random color for player avatar
734
+ function getRandomColor() {
735
+ const colors = [
736
+ '#EF4444', '#F59E0B', '#10B981', '#3B82F6', '#6366F1', '#8B5CF6', '#EC4899'
737
+ ];
738
+ return colors[Math.floor(Math.random() * colors.length)];
739
+ }
740
+
741
+ // Get random avatar icon
742
+ function getRandomAvatar() {
743
+ const avatars = [
744
+ 'fa-user', 'fa-user-tie', 'fa-user-graduate', 'fa-user-nurse',
745
+ 'fa-user-astronaut', 'fa-user-secret', 'fa-user-md', 'fa-user-ninja'
746
+ ];
747
+ return avatars[Math.floor(Math.random() * avatars.length)];
748
+ }
749
+
750
+ // Trigger confetti effect
751
+ function triggerConfetti() {
752
+ const colors = ['#EF4444', '#F59E0B', '#10B981', '#3B82F6', '#6366F1', '#8B5CF6', '#EC4899'];
753
+
754
+ for (let i = 0; i < 50; i++) {
755
+ const confetti = document.createElement('div');
756
+ confetti.className = 'confetti';
757
+ confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
758
+ confetti.style.left = `${Math.random() * 100}%`;
759
+ confetti.style.transform = `rotate(${Math.random() * 360}deg)`;
760
+
761
+ // Random size
762
+ const size = Math.random() * 10 + 5;
763
+ confetti.style.width = `${size}px`;
764
+ confetti.style.height = `${size}px`;
765
+
766
+ document.body.appendChild(confetti);
767
+
768
+ // Animate
769
+ const animationDuration = Math.random() * 3 + 2;
770
+ const animationDelay = Math.random() * 0.5;
771
+
772
+ confetti.style.animation = `
773
+ confetti-fall ${animationDuration}s ease-in ${animationDelay}s forwards
774
+ `;
775
+
776
+ // Remove after animation
777
+ setTimeout(() => {
778
+ confetti.remove();
779
+ }, (animationDuration + animationDelay) * 1000);
780
+ }
781
+
782
+ // Add confetti animation styles
783
+ const style = document.createElement('style');
784
+ style.innerHTML = `
785
+ @keyframes confetti-fall {
786
+ 0% {
787
+ opacity: 1;
788
+ transform: translateY(-100vh) rotate(0deg);
789
+ }
790
+ 100% {
791
+ opacity: 0;
792
+ transform: translateY(100vh) rotate(360deg);
793
+ }
794
+ }
795
+ `;
796
+ document.head.appendChild(style);
797
+ }
798
+
799
+ // Initialize the game when the page loads
800
+ window.addEventListener('DOMContentLoaded', initGame);
801
+ </script>
802
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=C50BARZ/empathy-game" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
803
+ </html>