cosimotaiuti commited on
Commit
9fd3a67
·
verified ·
1 Parent(s): 22c7bef

Upload 109 files

Browse files
README.md CHANGED
@@ -3,8 +3,8 @@ title: The Last Message
3
  emoji: 📱
4
  colorFrom: gray
5
  colorTo: red
6
- sdk: docker
7
- sdk_version: 5.13.1
8
  app_file: app.py
9
  pinned: false
10
  ---
@@ -21,4 +21,4 @@ docker build -t p5js-game .
21
 
22
  # Run the container
23
 
24
- docker run -p 8000:8000 p5js-game
 
3
  emoji: 📱
4
  colorFrom: gray
5
  colorTo: red
6
+ sdk: gradio
7
+ sdk_version: "3.50.2"
8
  app_file: app.py
9
  pinned: false
10
  ---
 
21
 
22
  # Run the container
23
 
24
+ docker run -p 8000:8000 p5js-game
static/assets/.DS_Store CHANGED
Binary files a/static/assets/.DS_Store and b/static/assets/.DS_Store differ
 
static/assets/css/index-style.css CHANGED
@@ -83,10 +83,19 @@ main {
83
  }
84
 
85
  .logo img {
86
- width: 230px;
87
  height: auto;
88
  }
89
 
 
 
 
 
 
 
 
 
 
90
  .menu {
91
  display: flex;
92
  margin-top: 250px;
 
83
  }
84
 
85
  .logo img {
86
+ width: 400px;
87
  height: auto;
88
  }
89
 
90
+ .subtitle {
91
+ font-family: "HorrorBrush", cursive;
92
+ color: #fff;
93
+ font-size: 24px;
94
+ text-align: center;
95
+ margin-top: 10px;
96
+ letter-spacing: 2px;
97
+ }
98
+
99
  .menu {
100
  display: flex;
101
  margin-top: 250px;
static/assets/css/stress-animations.css CHANGED
@@ -127,8 +127,18 @@
127
  #chatSection.very-stress #chatHistory .ai-message {
128
  background-color: #e92626;
129
  color: #ffffff;
130
- animation: messageShake 0.8s infinite, messageRedPulse 2s infinite;
 
 
 
 
 
 
 
 
131
  border: 1px solid #ff0000;
 
 
132
  }
133
 
134
  #chatSection.very-stress #chatControls {
@@ -141,10 +151,6 @@
141
  border: 1px solid #ffffff;
142
  }
143
 
144
- #chatSection.very-stress .chat-name::before {
145
- content: "Bae ";
146
- }
147
-
148
  #chatSection.very-stress .chat-name::after {
149
  content: "💀💀";
150
  }
@@ -184,15 +190,17 @@
184
  }
185
 
186
  @keyframes messageShake {
187
- 0%,
188
- 100% {
189
- transform: translateX(0);
190
  }
191
  25% {
192
- transform: translateX(-2px) translateY(-1px);
 
 
 
193
  }
194
  75% {
195
- transform: translateX(2px) translateY(1px);
196
  }
197
  }
198
 
@@ -210,3 +218,18 @@
210
  box-shadow: 0 0 0 0 rgba(233, 38, 38, 0.4);
211
  }
212
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  #chatSection.very-stress #chatHistory .ai-message {
128
  background-color: #e92626;
129
  color: #ffffff;
130
+ animation: messageShake 0.8s infinite ease-in-out, messageRedPulse 1.5s infinite;
131
+ border: 2px solid #ff0000;
132
+ box-shadow: 0 0 15px rgba(255, 0, 0, 0.4);
133
+ transform-origin: center;
134
+ }
135
+
136
+ #chatSection.very-stress #chatHistory .assistant-message {
137
+ background-color: #2d2d2d;
138
+ color: #ff9999;
139
  border: 1px solid #ff0000;
140
+ animation: assistantMessageShake 1.5s infinite ease-in-out;
141
+ transform-origin: center;
142
  }
143
 
144
  #chatSection.very-stress #chatControls {
 
151
  border: 1px solid #ffffff;
152
  }
153
 
 
 
 
 
154
  #chatSection.very-stress .chat-name::after {
155
  content: "💀💀";
156
  }
 
190
  }
191
 
192
  @keyframes messageShake {
193
+ 0%, 100% {
194
+ transform: translate(0, 0) rotate(0deg);
 
195
  }
196
  25% {
197
+ transform: translate(-2px, 1px) rotate(-0.5deg);
198
+ }
199
+ 50% {
200
+ transform: translate(0, -1px) rotate(0.5deg);
201
  }
202
  75% {
203
+ transform: translate(2px, 1px) rotate(-0.25deg);
204
  }
205
  }
206
 
 
218
  box-shadow: 0 0 0 0 rgba(233, 38, 38, 0.4);
219
  }
220
  }
221
+
222
+ @keyframes assistantMessageShake {
223
+ 0%, 100% {
224
+ transform: translate(0, 0) rotate(0deg);
225
+ }
226
+ 25% {
227
+ transform: translate(-1px, 0.5px) rotate(-0.25deg);
228
+ }
229
+ 50% {
230
+ transform: translate(0, -0.5px) rotate(0.25deg);
231
+ }
232
+ 75% {
233
+ transform: translate(1px, 0.5px) rotate(-0.125deg);
234
+ }
235
+ }
static/assets/img/.DS_Store CHANGED
Binary files a/static/assets/img/.DS_Store and b/static/assets/img/.DS_Store differ
 
static/assets/img/logo.svg ADDED
static/assets/sounds/success.mp3 ADDED
Binary file (221 kB). View file
 
static/game/elmnts/clown.js CHANGED
@@ -24,9 +24,9 @@ class Clown extends Character {
24
 
25
  this.behaviorInterval = setInterval(() => {
26
  this.decideBehavior();
27
- // playSound(Math.random() < 0.5 ? 'clownSound1' : 'clownSound2');
28
 
29
- }, 3000);
30
  }
31
 
32
  decideBehavior() {
@@ -91,6 +91,7 @@ class Clown extends Character {
91
  this.path = this.findPath(this.characterPos, girlfriendPos);
92
  if (this.path.length > 0) {
93
  this.isChasing = true;
 
94
  this.moveCharacterAlongPath();
95
  }
96
  }
 
24
 
25
  this.behaviorInterval = setInterval(() => {
26
  this.decideBehavior();
27
+ playSound(Math.random() < 0.5 ? 'clownSound1' : 'clownSound2');
28
 
29
+ }, 6000);
30
  }
31
 
32
  decideBehavior() {
 
91
  this.path = this.findPath(this.characterPos, girlfriendPos);
92
  if (this.path.length > 0) {
93
  this.isChasing = true;
94
+ playSound('clownSeesYou');
95
  this.moveCharacterAlongPath();
96
  }
97
  }
static/game/elmnts/girlfriend.js CHANGED
@@ -9,8 +9,8 @@ class Girlfriend extends Character {
9
  this.stressLevel = 30;
10
  this.inventory = [];
11
  this.knows_about_dead_body = false;
12
- this.independance_rate = 3000;
13
- this.game_loops_before_deciding_for_herself = this.independance_rate;
14
  }
15
 
16
  update(){
@@ -58,6 +58,16 @@ class Girlfriend extends Character {
58
  }
59
 
60
  updateStressLevel(stressChange) {
 
 
 
 
 
 
 
 
 
 
61
  // Add or subtract the stress change while keeping within 0-100 range
62
  this.stressLevel = Math.max(
63
  0,
@@ -71,6 +81,7 @@ class Girlfriend extends Character {
71
  }
72
  switch (response.action) {
73
  case "go":
 
74
  this.moveToRoom(response.target);
75
  break;
76
  case "hide":
@@ -189,6 +200,7 @@ class Girlfriend extends Character {
189
  this.moveToPosition(deadBody.pos, () => {
190
 
191
  if (this.inventory.includes("Knife")) {
 
192
  addProgramaticMessage("No no no ew ew i can't believe im doing this...😭😭😭 ....the key was in here i got it!! I can get out!");
193
  deadBody.state = "unusable";
194
  this.inventory.push("Key");
 
9
  this.stressLevel = 30;
10
  this.inventory = [];
11
  this.knows_about_dead_body = false;
12
+ this.independance_rate = 2000;
13
+ this.game_loops_before_deciding_for_herself = 700;
14
  }
15
 
16
  update(){
 
58
  }
59
 
60
  updateStressLevel(stressChange) {
61
+
62
+ if (this.stressLevel <= 60) {
63
+ setStressLevel('no');
64
+ } else if (this.stressLevel > 40 && this.stressLevel <= 70) {
65
+ setStressLevel('low');
66
+ } else if (this.stressLevel > 70) {
67
+ setStressLevel('very');
68
+ }
69
+
70
+
71
  // Add or subtract the stress change while keeping within 0-100 range
72
  this.stressLevel = Math.max(
73
  0,
 
81
  }
82
  switch (response.action) {
83
  case "go":
84
+ playSound('gfMove');
85
  this.moveToRoom(response.target);
86
  break;
87
  case "hide":
 
200
  this.moveToPosition(deadBody.pos, () => {
201
 
202
  if (this.inventory.includes("Knife")) {
203
+ playSound('useKnife');
204
  addProgramaticMessage("No no no ew ew i can't believe im doing this...😭😭😭 ....the key was in here i got it!! I can get out!");
205
  deadBody.state = "unusable";
206
  this.inventory.push("Key");
static/game/game.js CHANGED
@@ -16,6 +16,9 @@ let gfMoveSnd;
16
  let loseSnd;
17
  let unlockDoorSnd;
18
  let useKnifeSnd;
 
 
 
19
 
20
 
21
 
@@ -41,6 +44,8 @@ function preload() {
41
  loseSnd = loadSound('/assets/sounds/lose.mp3');
42
  unlockDoorSnd = loadSound('/assets/sounds/unlockdoor.mp3');
43
  useKnifeSnd = loadSound('/assets/sounds/useknife.mp3');
 
 
44
  }
45
 
46
  async function initializeChat() {
@@ -61,6 +66,7 @@ async function initializeChat() {
61
  }
62
 
63
  async function setup() {
 
64
 
65
  baseMapImg = loadImage("/assets/img/appartment/basemap.png");
66
  girlfriendImg = loadImage("/assets/img/gf.png");
 
16
  let loseSnd;
17
  let unlockDoorSnd;
18
  let useKnifeSnd;
19
+ let messageSnd;
20
+
21
+ let successSnd;
22
 
23
 
24
 
 
44
  loseSnd = loadSound('/assets/sounds/lose.mp3');
45
  unlockDoorSnd = loadSound('/assets/sounds/unlockdoor.mp3');
46
  useKnifeSnd = loadSound('/assets/sounds/useknife.mp3');
47
+ messageSnd = loadSound('/assets/sounds/message.wav');
48
+ successSnd = loadSound('/assets/sounds/success.mp3');
49
  }
50
 
51
  async function initializeChat() {
 
66
  }
67
 
68
  async function setup() {
69
+ setStressLevel('no');
70
 
71
  baseMapImg = loadImage("/assets/img/appartment/basemap.png");
72
  girlfriendImg = loadImage("/assets/img/gf.png");
static/game/gameState.js CHANGED
@@ -7,18 +7,20 @@ class GameState {
7
  this.game_over = false;
8
  }
9
  endGame() {
 
10
  this.game_over = true;
11
  loseGameModal();
12
  }
13
 
14
  winGame() {
15
  this.game_over = true;
16
- unlockDoorSnd.play();
17
  setTimeout(() => {
18
  winGameModal();
 
 
19
  }, 3000);
20
  return;
21
- winGame();
22
  }
23
 
24
  update() {
 
7
  this.game_over = false;
8
  }
9
  endGame() {
10
+ playSound('lose');
11
  this.game_over = true;
12
  loseGameModal();
13
  }
14
 
15
  winGame() {
16
  this.game_over = true;
17
+ playSound('unlockDoor');
18
  setTimeout(() => {
19
  winGameModal();
20
+ bgMusic.pause();
21
+ playSound('success');
22
  }, 3000);
23
  return;
 
24
  }
25
 
26
  update() {
static/game/index.html CHANGED
@@ -1,8 +1,9 @@
1
  <!DOCTYPE html>
2
  <html>
3
  <head>
4
- <title>The Last Message - A text based horror game</title>
5
  <link rel="stylesheet" href="/static/assets/css/game-style.css" />
 
6
  <link rel="stylesheet" href="/static/assets/css/popup.css" />
7
  </head>
8
 
@@ -43,7 +44,7 @@
43
  <div id="chatSection">
44
  <div id="chatHeader">
45
  <div class="profile-picture">
46
- <!-- L'image sera ajoutée ici plus tard -->
47
  </div>
48
  <div class="chat-name">Bae 💖😘</div>
49
  </div>
@@ -54,7 +55,7 @@
54
  id="prompt"
55
  placeholder="Type your message..."
56
  />
57
- <button onclick="Message()">
58
  <svg
59
  width="683"
60
  height="683"
@@ -130,6 +131,39 @@
130
  location.reload(); // Reload the page to restart the game
131
  });
132
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  </script>
134
 
135
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
 
1
  <!DOCTYPE html>
2
  <html>
3
  <head>
4
+ <title>Text to Survive - A text based horror escape game</title>
5
  <link rel="stylesheet" href="/static/assets/css/game-style.css" />
6
+ <link rel="stylesheet" href="/static/assets/css/stress-animations.css" />
7
  <link rel="stylesheet" href="/static/assets/css/popup.css" />
8
  </head>
9
 
 
44
  <div id="chatSection">
45
  <div id="chatHeader">
46
  <div class="profile-picture">
47
+ <img src="/assets/img/profil_pictures/no_stress.webp" alt="Profile Picture">
48
  </div>
49
  <div class="chat-name">Bae 💖😘</div>
50
  </div>
 
55
  id="prompt"
56
  placeholder="Type your message..."
57
  />
58
+ <button onclick="sendMessage()">
59
  <svg
60
  width="683"
61
  height="683"
 
131
  location.reload(); // Reload the page to restart the game
132
  });
133
  });
134
+
135
+ // Global function to set stress level
136
+ function setStressLevel(level) {
137
+ const chatSection = document.getElementById('chatSection');
138
+ const profilePicture = chatSection.querySelector('.profile-picture img');
139
+
140
+ // Remove all existing stress classes
141
+ chatSection.classList.remove('no-stress', 'low-stress', 'very-stress');
142
+
143
+ // Add the appropriate class based on stress level
144
+ switch(level) {
145
+ case 'no':
146
+ chatSection.classList.add('no-stress');
147
+ if (profilePicture) {
148
+ profilePicture.src = '/assets/img/profil_pictures/no_stress.webp';
149
+ }
150
+ break;
151
+ case 'low':
152
+ chatSection.classList.add('low-stress');
153
+ if (profilePicture) {
154
+ profilePicture.src = '/assets/img/profil_pictures/low_stress.webp';
155
+ }
156
+ break;
157
+ case 'very':
158
+ chatSection.classList.add('very-stress');
159
+ if (profilePicture) {
160
+ profilePicture.src = '/assets/img/profil_pictures/very_stress.webp';
161
+ }
162
+ break;
163
+ default:
164
+ console.error('Invalid stress level:', level);
165
+ }
166
+ }
167
  </script>
168
 
169
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.min.js"></script>
static/game/utilities/chat.js CHANGED
@@ -129,27 +129,17 @@ function addMessageToChat(role, content) {
129
  chatMessages.push({ role, content });
130
 
131
  if (role === "assistant" && localStorage.getItem("isSoundOn") !== "false") {
132
- playMessageSound();
133
  }
134
  }
135
 
136
- // Update Message function to use girlfriend instance
137
- function Message() {
138
- if (girlfriend) {
139
- // Play message sound when sending a message
140
- if (localStorage.getItem("isSoundOn") !== "false") {
141
- playMessageSound();
142
- }
143
- sendMessage();
144
- }
145
- }
146
 
147
  // Allow sending message with Enter
148
  document.addEventListener("DOMContentLoaded", () => {
149
  document.getElementById("prompt").addEventListener("keypress", function (e) {
150
  if (e.key === "Enter") {
151
  e.preventDefault();
152
- Message();
153
  }
154
  });
155
 
@@ -157,11 +147,9 @@ document.addEventListener("DOMContentLoaded", () => {
157
  const bgMusic = document.getElementById("bgMusic");
158
  bgMusic.currentTime = 10;
159
  bgMusic.play().catch((error) => {
160
- console.log("Autoplay prevented:", error);
161
  isSoundOn = false;
162
  updateSoundIcon();
163
  });
164
  } catch (error) {
165
- console.error("Error playing audio:", error);
166
  }
167
  });
 
129
  chatMessages.push({ role, content });
130
 
131
  if (role === "assistant" && localStorage.getItem("isSoundOn") !== "false") {
132
+ playSound('message');
133
  }
134
  }
135
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  // Allow sending message with Enter
138
  document.addEventListener("DOMContentLoaded", () => {
139
  document.getElementById("prompt").addEventListener("keypress", function (e) {
140
  if (e.key === "Enter") {
141
  e.preventDefault();
142
+ sendMessage();
143
  }
144
  });
145
 
 
147
  const bgMusic = document.getElementById("bgMusic");
148
  bgMusic.currentTime = 10;
149
  bgMusic.play().catch((error) => {
 
150
  isSoundOn = false;
151
  updateSoundIcon();
152
  });
153
  } catch (error) {
 
154
  }
155
  });
static/game/utilities/sound.js CHANGED
@@ -1,7 +1,8 @@
1
-
2
  function playSound(sound) {
3
  if (isSoundOn) {
4
  let soundToPlay;
 
 
5
  switch (sound) {
6
  case 'clownSound1':
7
  soundToPlay = clownSound1Snd;
@@ -24,15 +25,30 @@ function playSound(sound) {
24
  case 'useKnife':
25
  soundToPlay = useKnifeSnd;
26
  break;
 
 
 
 
 
 
27
  }
28
- if (soundToPlay) {
29
- soundToPlay.stop(); // Stop any existing playback
30
- soundToPlay.loop(false); // Ensure looping is disabled
 
 
 
 
 
31
  soundToPlay.play(); // Play the sound once
 
 
32
  }
33
  }
34
  }
35
 
 
 
36
  function toggleSound() {
37
  isSoundOn = !isSoundOn;
38
  localStorage.setItem("isSoundOn", isSoundOn.toString());
@@ -42,9 +58,7 @@ function toggleSound() {
42
  bgMusic.currentTime = 10;
43
  }
44
  bgMusic.play();
45
- if (girlfriend && girlfriend.isMoving) {
46
- handleWalkingSound(true);
47
- }
48
  } else {
49
  bgMusic.pause();
50
  }
 
 
1
  function playSound(sound) {
2
  if (isSoundOn) {
3
  let soundToPlay;
4
+
5
+ // Determine which sound to play
6
  switch (sound) {
7
  case 'clownSound1':
8
  soundToPlay = clownSound1Snd;
 
25
  case 'useKnife':
26
  soundToPlay = useKnifeSnd;
27
  break;
28
+ case 'message':
29
+ soundToPlay = messageSnd;
30
+ break;
31
+ case 'success':
32
+ soundToPlay = successSnd;
33
+ break;
34
  }
35
+
36
+ // Play the sound if it's defined and loaded
37
+ if (soundToPlay && soundToPlay.isLoaded()) {
38
+ soundToPlay.setLoop(false); // Ensure looping is disabled
39
+ soundToPlay.playMode('restart'); // Set play mode to 'restart'
40
+ if (soundToPlay.isPlaying()) {
41
+ soundToPlay.stop(); // Stop any existing playback
42
+ }
43
  soundToPlay.play(); // Play the sound once
44
+ } else {
45
+ console.log('Sound file is not loaded or undefined.');
46
  }
47
  }
48
  }
49
 
50
+
51
+
52
  function toggleSound() {
53
  isSoundOn = !isSoundOn;
54
  localStorage.setItem("isSoundOn", isSoundOn.toString());
 
58
  bgMusic.currentTime = 10;
59
  }
60
  bgMusic.play();
61
+
 
 
62
  } else {
63
  bgMusic.pause();
64
  }
static/howto/how-to-play-2.html CHANGED
@@ -4,7 +4,8 @@
4
  <head>
5
  <meta charset="UTF-8" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Through Their Eyes - How to Play</title>
 
8
  <link rel="stylesheet" href="../assets/css/index-style.css" />
9
  <link rel="stylesheet" href="../assets/css/how-to-play.css" />
10
  </head>
 
4
  <head>
5
  <meta charset="UTF-8" />
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Text to Survive - A text based horror escape game</title>
8
+
9
  <link rel="stylesheet" href="../assets/css/index-style.css" />
10
  <link rel="stylesheet" href="../assets/css/how-to-play.css" />
11
  </head>
static/howto/how-to-play-3.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>Through Their Eyes - How to Play</title>
7
  <link rel="stylesheet" href="../assets/css/index-style.css" />
8
  <link rel="stylesheet" href="../assets/css/how-to-play.css" />
9
  </head>
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Text to Survive - A text based horror escape game</title>
7
  <link rel="stylesheet" href="../assets/css/index-style.css" />
8
  <link rel="stylesheet" href="../assets/css/how-to-play.css" />
9
  </head>
static/howto/how-to-play-4.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>Through Their Eyes - How to Play</title>
7
  <link rel="stylesheet" href="../assets/css/index-style.css" />
8
  <link rel="stylesheet" href="../assets/css/how-to-play.css" />
9
  </head>
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Text to Survive - A text based horror escape game</title>
7
  <link rel="stylesheet" href="../assets/css/index-style.css" />
8
  <link rel="stylesheet" href="../assets/css/how-to-play.css" />
9
  </head>
static/howto/how-to-play.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>Through Their Eyes - How to Play</title>
7
  <link rel="stylesheet" href="../assets/css/index-style.css" />
8
  <link rel="stylesheet" href="../assets/css/how-to-play.css" />
9
  </head>
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Text to Survive - A text based horror escape game</title>
7
  <link rel="stylesheet" href="../assets/css/index-style.css" />
8
  <link rel="stylesheet" href="../assets/css/how-to-play.css" />
9
  </head>
static/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>Through Their Eyes</title>
7
  <link rel="stylesheet" href="assets/css/index-style.css" />
8
  </head>
9
  <body>
@@ -19,7 +19,8 @@
19
 
20
  <main>
21
  <div class="logo">
22
- <img src="assets/img/logo.png" alt="Through Their Eyes" />
 
23
  </div>
24
 
25
  <nav class="menu">
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Text to Survive - A text based horror escape game</title>
7
  <link rel="stylesheet" href="assets/css/index-style.css" />
8
  </head>
9
  <body>
 
19
 
20
  <main>
21
  <div class="logo">
22
+ <img src="assets/img/logo.svg" alt="Through Their Eyes" />
23
+ <p class="subtitle">A text-based horror escape game</p>
24
  </div>
25
 
26
  <nav class="menu">