Преглед на файлове

Add Games web app with 5 playable mini games

Introduce a new `Games` module under `src/web/Games` with an AGI registration script and a landing page that links to Minesweeper, Tetris, Snake, Memory, and Pong. Each game is implemented as a standalone HTML app with in-page styling, controls, scoring/state handling, and restart/back navigation. Also update `.gitignore` to exclude `/.kilo`.
Toby Chui преди 1 ден
родител
ревизия
3a67d37827
променени са 8 файла, в които са добавени 2881 реда и са изтрити 0 реда
  1. 1 0
      .gitignore
  2. 257 0
      src/web/Games/index.html
  3. 23 0
      src/web/Games/init.agi
  4. 431 0
      src/web/Games/memory.html
  5. 557 0
      src/web/Games/minesweeper.html
  6. 454 0
      src/web/Games/pong.html
  7. 496 0
      src/web/Games/snake.html
  8. 662 0
      src/web/Games/tetris.html

+ 1 - 0
.gitignore

@@ -48,3 +48,4 @@ src/system/telegram_conf.json
 # AES key that encrypts the stored git credentials — generated per install,
 # must never be committed
 src/system/git/
+/.kilo

+ 257 - 0
src/web/Games/index.html

@@ -0,0 +1,257 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Games - ArozOS</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+
+        body {
+            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+            background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0f0f0f 100%);
+            color: #e0e0e0;
+            min-height: 100vh;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            justify-content: center;
+        }
+
+        .header {
+            text-align: center;
+            margin-bottom: 40px;
+        }
+
+        .header h1 {
+            font-size: 2.5rem;
+            background: linear-gradient(90deg, #ffd700, #ffcc00, #ffb300);
+            -webkit-background-clip: text;
+            -webkit-text-fill-color: transparent;
+            background-clip: text;
+            margin-bottom: 10px;
+        }
+
+        .header p {
+            font-size: 1rem;
+            color: #888888;
+        }
+
+        .header-icon {
+            width: 48px;
+            height: 48px;
+            margin: 0 auto 12px;
+        }
+
+        .header-icon svg {
+            width: 100%;
+            height: 100%;
+        }
+
+        .game-grid {
+            display: grid;
+            grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
+            gap: 20px;
+            max-width: 800px;
+            width: 100%;
+            padding: 0 20px;
+        }
+
+        .game-card {
+            background: rgba(255, 255, 255, 0.03);
+            border: 1px solid rgba(255, 215, 0, 0.15);
+            border-radius: 12px;
+            padding: 24px;
+            text-align: center;
+            cursor: pointer;
+            transition: transform 0.2s, box-shadow 0.2s;
+        }
+
+        .game-card:hover {
+            transform: translateY(-4px);
+            box-shadow: 0 8px 24px rgba(255, 215, 0, 0.2);
+            border-color: rgba(255, 215, 0, 0.5);
+        }
+
+        .game-icon {
+            width: 48px;
+            height: 48px;
+            margin: 0 auto 12px;
+        }
+
+        .game-icon svg {
+            width: 100%;
+            height: 100%;
+        }
+
+        .game-card h3 {
+            font-size: 1rem;
+            margin-bottom: 6px;
+            color: #ffffff;
+        }
+
+        .game-card p {
+            font-size: 0.8rem;
+            color: #888888;
+        }
+
+        .hello-banner {
+            background: rgba(255, 215, 0, 0.08);
+            border: 1px solid rgba(255, 215, 0, 0.25);
+            border-radius: 8px;
+            padding: 16px 24px;
+            margin-bottom: 30px;
+            text-align: center;
+            max-width: 500px;
+        }
+
+        .hello-icon {
+            width: 32px;
+            height: 32px;
+            margin: 0 auto 8px;
+        }
+
+        .hello-icon svg {
+            width: 100%;
+            height: 100%;
+        }
+
+        .hello-banner p {
+            font-size: 1.1rem;
+            color: #ffd700;
+        }
+
+        .game-card.available {
+            border-color: rgba(255, 215, 0, 0.4);
+        }
+
+        .game-card.available:hover {
+            box-shadow: 0 8px 24px rgba(255, 215, 0, 0.3);
+            border-color: rgba(255, 215, 0, 0.7);
+        }
+
+        .badge {
+            display: inline-block;
+            background: rgba(255, 215, 0, 0.15);
+            color: #ffd700;
+            font-size: 0.65rem;
+            padding: 2px 6px;
+            border-radius: 3px;
+            margin-top: 4px;
+        }
+    </style>
+</head>
+<body>
+    <div class="header">
+        <div class="header-icon">
+            <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <rect x="6" y="14" width="36" height="20" rx="10" stroke="#ffd700" stroke-width="2" fill="none"/>
+                <circle cx="16" cy="24" r="3" fill="#ffd700"/>
+                <circle cx="32" cy="24" r="3" fill="#ffd700"/>
+                <line x1="10" y1="32" x2="14" y2="34" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <line x1="34" y1="34" x2="38" y2="32" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <line x1="18" y1="18" x2="14" y2="12" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <line x1="30" y1="18" x2="34" y2="12" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+            </svg>
+        </div>
+        <h1>ArozOS Mini Games</h1>
+        <p>Select a game to start playing!</p>
+    </div>
+
+    <div class="hello-banner">
+        <div class="hello-icon">
+            <svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M16 2L19 12L28 12L21 18L24 28L16 22L8 28L11 18L4 12L13 12Z" stroke="#ffd700" stroke-width="1.5" fill="none"/>
+            </svg>
+        </div>
+        <p>Hello World! Welcome to the Games collection. More games coming soon!</p>
+    </div>
+
+    <div class="game-grid">
+        <div class="game-card available" onclick="window.location.href='minesweeper.html'">
+            <div class="game-icon">
+                <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                    <rect x="8" y="10" width="32" height="28" rx="2" stroke="#ffd700" stroke-width="2" fill="none"/>
+                    <line x1="8" y1="18" x2="40" y2="18" stroke="#ffd700" stroke-width="1.5"/>
+                    <rect x="12" y="22" width="6" height="6" rx="1" fill="#ffd700" opacity="0.3"/>
+                    <rect x="20" y="22" width="6" height="6" rx="1" fill="#ffd700" opacity="0.6"/>
+                    <rect x="28" y="22" width="6" height="6" rx="1" fill="#ffd700"/>
+                    <rect x="12" y="30" width="6" height="6" rx="1" fill="#ffd700" opacity="0.6"/>
+                    <rect x="20" y="30" width="6" height="6" rx="1" fill="#ffd700" opacity="0.3"/>
+                    <rect x="28" y="30" width="6" height="6" rx="1" fill="#ffd700" opacity="0.9"/>
+                    <circle cx="34" cy="34" r="2" fill="#ff4444"/>
+                </svg>
+            </div>
+            <h3>Minesweeper</h3>
+            <p>Find all the mines</p>
+            <span class="badge">PLAYABLE</span>
+        </div>
+        <div class="game-card available" onclick="window.location.href='tetris.html'">
+            <div class="game-icon">
+                <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                    <rect x="6" y="6" width="8" height="8" rx="1" fill="#ffd700"/>
+                    <rect x="18" y="6" width="8" height="8" rx="1" fill="#ffd700" opacity="0.7"/>
+                    <rect x="30" y="6" width="8" height="8" rx="1" fill="#ffd700" opacity="0.4"/>
+                    <rect x="12" y="18" width="8" height="8" rx="1" fill="#ffd700" opacity="0.7"/>
+                    <rect x="24" y="18" width="8" height="8" rx="1" fill="#ffd700" opacity="0.4"/>
+                    <rect x="6" y="30" width="8" height="8" rx="1" fill="#ffd700" opacity="0.4"/>
+                    <rect x="18" y="30" width="8" height="8" rx="1" fill="#ffd700" opacity="0.7"/>
+                    <rect x="30" y="30" width="8" height="8" rx="1" fill="#ffd700" opacity="0.4"/>
+                </svg>
+            </div>
+            <h3>Tetris</h3>
+            <p>Stack the blocks</p>
+            <span class="badge">PLAYABLE</span>
+        </div>
+        <div class="game-card available" onclick="window.location.href='snake.html'">
+            <div class="game-icon">
+                <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                    <path d="M14 32C14 32 16 20 24 16C32 12 36 20 36 20" stroke="#ffd700" stroke-width="2" fill="none"/>
+                    <path d="M36 20C36 20 38 18 38 14C38 12 36 10 34 12" stroke="#ffd700" stroke-width="2" fill="none"/>
+                    <circle cx="30" cy="14" r="1.5" fill="#ffd700"/>
+                    <circle cx="34" cy="13" r="1.5" fill="#ffd700"/>
+                    <path d="M14 32L10 38H38L34 32" stroke="#ffd700" stroke-width="2" fill="none"/>
+                    <line x1="24" y1="32" x2="24" y2="38" stroke="#ffd700" stroke-width="2"/>
+                    <line x1="18" y1="32" x2="16" y2="38" stroke="#ffd700" stroke-width="2"/>
+                    <line x1="30" y1="32" x2="32" y2="38" stroke="#ffd700" stroke-width="2"/>
+                </svg>
+            </div>
+            <h3>Snake</h3>
+            <p>Classic snake game</p>
+            <span class="badge">PLAYABLE</span>
+        </div>
+        <div class="game-card available" onclick="window.location.href='memory.html'">
+            <div class="game-icon">
+                <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                    <rect x="6" y="6" width="14" height="14" rx="2" stroke="#ffd700" stroke-width="2" fill="none"/>
+                    <rect x="28" y="6" width="14" height="14" rx="2" stroke="#ffd700" stroke-width="2" fill="none"/>
+                    <rect x="6" y="28" width="14" height="14" rx="2" stroke="#ffd700" stroke-width="2" fill="none"/>
+                    <rect x="28" y="28" width="14" height="14" rx="2" stroke="#ffd700" stroke-width="2" fill="none"/>
+                    <circle cx="13" cy="13" r="2" fill="#ffd700"/>
+                    <circle cx="35" cy="35" r="2" fill="#ffd700"/>
+                </svg>
+            </div>
+            <h3>Memory</h3>
+            <p>Match the pairs</p>
+            <span class="badge">PLAYABLE</span>
+        </div>
+        <div class="game-card available" onclick="window.location.href='pong.html'">
+            <div class="game-icon">
+                <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+                    <rect x="4" y="10" width="6" height="28" rx="2" fill="#ffd700"/>
+                    <rect x="38" y="10" width="6" height="28" rx="2" fill="#ffd700" opacity="0.6"/>
+                    <circle cx="24" cy="24" r="4" fill="#ffd700"/>
+                    <line x1="24" y1="4" x2="24" y2="44" stroke="rgba(255, 215, 0, 0.3)" stroke-width="1.5" stroke-dasharray="3 3"/>
+                </svg>
+            </div>
+            <h3>Pong</h3>
+            <p>Classic pong game</p>
+            <span class="badge">PLAYABLE</span>
+        </div>
+    </div>
+</body>
+</html>

+ 23 - 0
src/web/Games/init.agi

@@ -0,0 +1,23 @@
+/*
+	Games Module Register Script
+	A mini game collection for ArozOS
+*/
+
+//Setup the module information
+var moduleLaunchInfo = {
+    Name: "Games",
+	Desc: "A collection of mini games",
+	Group: "Games",
+	IconPath: "img/module_icon.png",
+	Version: "0.1.0",
+	StartDir: "index.html",
+	SupportFW: true,
+	LaunchFWDir: "index.html",
+	SupportEmb: false,
+	InitFWSize: [800, 600],
+	SupportedExt: []
+}
+
+//Register the module
+console.log("Registering Games module");
+registerModule(JSON.stringify(moduleLaunchInfo));

+ 431 - 0
src/web/Games/memory.html

@@ -0,0 +1,431 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Memory - ArozOS</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+
+        body {
+            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+            background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0f0f0f 100%);
+            color: #e0e0e0;
+            min-height: 100vh;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            user-select: none;
+        }
+
+        .top-bar {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            width: 100%;
+            max-width: 560px;
+            padding: 16px 0;
+        }
+
+        #backBtn {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 18px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            transition: background 0.2s;
+            display: flex;
+            align-items: center;
+            gap: 6px;
+        }
+
+        #backBtn:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+
+        #backBtn svg {
+            width: 16px;
+            height: 16px;
+        }
+
+        #resetBtn {
+            background: none;
+            border: 1px solid rgba(255, 215, 0, 0.3);
+            color: #ffd700;
+            width: 40px;
+            height: 40px;
+            border-radius: 50%;
+            cursor: pointer;
+            transition: transform 0.15s;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+
+        #resetBtn:hover {
+            transform: scale(1.1);
+            border-color: rgba(255, 215, 0, 0.6);
+        }
+
+        #resetBtn svg {
+            width: 20px;
+            height: 20px;
+        }
+
+        .game-info {
+            display: flex;
+            gap: 24px;
+            font-size: 1rem;
+            font-family: 'Courier New', monospace;
+        }
+
+        .game-info span {
+            background: rgba(0, 0, 0, 0.5);
+            padding: 4px 12px;
+            border-radius: 4px;
+            min-width: 60px;
+            text-align: center;
+            border: 1px solid rgba(255, 215, 0, 0.2);
+        }
+
+        .difficulty-bar {
+            display: flex;
+            gap: 8px;
+            margin-bottom: 16px;
+        }
+
+        .diff-btn {
+            background: rgba(255, 255, 255, 0.05);
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            color: #aaa;
+            padding: 6px 16px;
+            border-radius: 4px;
+            cursor: pointer;
+            font-size: 0.85rem;
+            transition: all 0.2s;
+        }
+
+        .diff-btn:hover, .diff-btn.active {
+            background: rgba(255, 215, 0, 0.2);
+            border-color: rgba(255, 215, 0, 0.5);
+            color: #ffd700;
+        }
+
+        #board {
+            display: grid;
+            gap: 8px;
+            padding: 16px;
+            background: rgba(0, 0, 0, 0.3);
+            border: 2px solid rgba(255, 215, 0, 0.2);
+            border-radius: 8px;
+        }
+
+        .card {
+            width: 70px;
+            height: 90px;
+            perspective: 600px;
+            cursor: pointer;
+        }
+
+        .card-inner {
+            width: 100%;
+            height: 100%;
+            position: relative;
+            transform-style: preserve-3d;
+            transition: transform 0.4s;
+        }
+
+        .card.flipped .card-inner {
+            transform: rotateY(180deg);
+        }
+
+        .card.matched .card-inner {
+            transform: rotateY(180deg);
+        }
+
+        .card-face {
+            position: absolute;
+            width: 100%;
+            height: 100%;
+            backface-visibility: hidden;
+            border-radius: 8px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+
+        .card-front {
+            background: linear-gradient(135deg, #2a2a2a, #1a1a1a);
+            border: 2px solid rgba(255, 215, 0, 0.3);
+        }
+
+        .card-front svg {
+            width: 36px;
+            height: 36px;
+        }
+
+        .card-back {
+            background: rgba(255, 215, 0, 0.1);
+            border: 2px solid rgba(255, 215, 0, 0.5);
+            transform: rotateY(180deg);
+            font-size: 2rem;
+        }
+
+        .card.matched .card-back {
+            background: rgba(76, 175, 80, 0.15);
+            border-color: rgba(76, 175, 80, 0.5);
+        }
+
+        .overlay {
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            background: rgba(0, 0, 0, 0.75);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            z-index: 100;
+        }
+
+        .overlay.hidden {
+            display: none;
+        }
+
+        .modal {
+            background: #141414;
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            border-radius: 12px;
+            padding: 32px;
+            text-align: center;
+            max-width: 300px;
+        }
+
+        .modal h2 {
+            margin-bottom: 12px;
+            font-size: 1.5rem;
+            color: #4caf50;
+        }
+
+        .modal p {
+            margin-bottom: 20px;
+            color: #888888;
+        }
+
+        .modal button {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 24px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            margin: 0 4px;
+            transition: background 0.2s;
+        }
+
+        .modal button:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+    </style>
+</head>
+<body>
+    <div class="top-bar">
+        <button id="backBtn" onclick="goBack()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M15 18L9 12L15 6" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+            Back
+        </button>
+        <button id="resetBtn" onclick="initGame()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
+                <path d="M3 12C3 7.03 7.03 3 12 3C15.5 3 18.58 5 20 8" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M21 4V9H16" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                <path d="M21 12C21 16.97 16.97 21 12 21C8.5 21 5.42 19 4 16" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M3 20V15H8" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+        </button>
+        <div class="game-info">
+            <span id="moves">Moves: 0</span>
+            <span id="pairs">Pairs: 0</span>
+        </div>
+    </div>
+
+    <div class="difficulty-bar">
+        <button class="diff-btn active" onclick="setDifficulty(0)">4x3</button>
+        <button class="diff-btn" onclick="setDifficulty(1)">4x4</button>
+        <button class="diff-btn" onclick="setDifficulty(2)">6x4</button>
+    </div>
+
+    <div id="board"></div>
+
+    <div class="overlay hidden" id="overlay">
+        <div class="modal" id="modal">
+            <h2>You Win!</h2>
+            <p id="modalMsg"></p>
+            <button onclick="initGame()">Play Again</button>
+            <button onclick="goBack(); hideOverlay();">Back to Games</button>
+        </div>
+    </div>
+
+    <script>
+        const CARD_ICONS = [
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 2L15 8L21 9L17 14L18 20L12 17L6 20L7 14L3 9L9 8Z" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="9" stroke="#ffd700" stroke-width="1.5" fill="none"/><path d="M12 7V12L15 15" stroke="#ffd700" stroke-width="1.5" stroke-linecap="round"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C8 3 4 7 4 12C4 17 8 21 12 21C16 21 20 17 20 12C20 7 16 3 12 3Z" stroke="#ffd700" stroke-width="1.5" fill="none"/><path d="M9 12C9 9.5 10.5 7.5 12 7.5" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 2L14 10L22 10L16 15L18 22L12 18L6 22L8 15L2 10L10 10Z" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 2L15 8L21 9L17 14L18 20L12 17L6 20L7 14L3 9L9 8Z" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="9" stroke="#ffd700" stroke-width="1.5" fill="none"/><path d="M12 7V12L15 15" stroke="#ffd700" stroke-width="1.5" stroke-linecap="round"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C8 3 4 7 4 12C4 17 8 21 12 21C16 21 20 17 20 12C20 7 16 3 12 3Z" stroke="#ffd700" stroke-width="1.5" fill="none"/><path d="M9 12C9 9.5 10.5 7.5 12 7.5" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 2L14 10L22 10L16 15L18 22L12 18L6 22L8 15L2 10L10 10Z" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 2L15 8L21 9L17 14L18 20L12 17L6 20L7 14L3 9L9 8Z" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="9" stroke="#ffd700" stroke-width="1.5" fill="none"/><path d="M12 7V12L15 15" stroke="#ffd700" stroke-width="1.5" stroke-linecap="round"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 3C8 3 4 7 4 12C4 17 8 21 12 21C16 21 20 17 20 12C20 7 16 3 12 3Z" stroke="#ffd700" stroke-width="1.5" fill="none"/><path d="M9 12C9 9.5 10.5 7.5 12 7.5" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>',
+            '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 2L14 10L22 10L16 15L18 22L12 18L6 22L8 15L2 10L10 10Z" stroke="#ffd700" stroke-width="1.5" fill="none"/></svg>'
+        ];
+
+        const DIFFICULTIES = [
+            { cols: 4, rows: 3, pairs: 6 },
+            { cols: 4, rows: 4, pairs: 8 },
+            { cols: 6, rows: 4, pairs: 12 }
+        ];
+
+        let currentDiff = 0;
+        let cards = [];
+        let flippedCards = [];
+        let matchedPairs = 0;
+        let moves = 0;
+        let locked = false;
+
+        function setDifficulty(idx) {
+            currentDiff = idx;
+            document.querySelectorAll('.diff-btn').forEach((b, i) => {
+                b.classList.toggle('active', i === idx);
+            });
+            initGame();
+        }
+
+        function initGame() {
+            const diff = DIFFICULTIES[currentDiff];
+            const totalPairs = diff.pairs;
+
+            const selectedIcons = [];
+            const allIndices = Array.from({ length: CARD_ICONS.length }, (_, i) => i);
+            while (selectedIcons.length < totalPairs) {
+                const idx = allIndices[Math.floor(Math.random() * allIndices.length)];
+                selectedIcons.push(CARD_ICONS[idx]);
+                allIndices.splice(allIndices.indexOf(idx), 1);
+            }
+
+            const cardValues = [...selectedIcons, ...selectedIcons];
+            for (let i = cardValues.length - 1; i > 0; i--) {
+                const j = Math.floor(Math.random() * (i + 1));
+                [cardValues[i], cardValues[j]] = [cardValues[j], cardValues[i]];
+            }
+
+            cards = cardValues;
+            flippedCards = [];
+            matchedPairs = 0;
+            moves = 0;
+            locked = false;
+
+            document.getElementById('moves').textContent = 'Moves: 0';
+            document.getElementById('pairs').textContent = 'Pairs: 0';
+
+            renderBoard(diff);
+            hideOverlay();
+        }
+
+        function renderBoard(diff) {
+            const board = document.getElementById('board');
+            board.style.gridTemplateColumns = `repeat(${diff.cols}, 70px)`;
+            board.innerHTML = '';
+
+            for (let i = 0; i < cards.length; i++) {
+                const card = document.createElement('div');
+                card.className = 'card';
+                card.dataset.index = i;
+
+                card.innerHTML = `
+                    <div class="card-inner">
+                        <div class="card-face card-front">
+                            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                                <path d="M12 3V21M3 12H21M6 6L18 18M18 6L6 18" stroke="#ffd700" stroke-width="1.5" stroke-linecap="round"/>
+                            </svg>
+                        </div>
+                        <div class="card-face card-back">
+                            ${cards[i]}
+                        </div>
+                    </div>
+                `;
+
+                card.addEventListener('click', () => flipCard(card));
+                board.appendChild(card);
+            }
+        }
+
+        function flipCard(card) {
+            if (locked || card.classList.contains('flipped') || card.classList.contains('matched')) return;
+
+            card.classList.add('flipped');
+            flippedCards.push(card);
+
+            if (flippedCards.length === 2) {
+                moves++;
+                document.getElementById('moves').textContent = 'Moves: ' + moves;
+                checkMatch();
+            }
+        }
+
+        function checkMatch() {
+            locked = true;
+            const [card1, card2] = flippedCards;
+
+            if (cards[card1.dataset.index] === cards[card2.dataset.index]) {
+                card1.classList.add('matched');
+                card2.classList.add('matched');
+                matchedPairs++;
+                document.getElementById('pairs').textContent = 'Pairs: ' + matchedPairs;
+                flippedCards = [];
+                locked = false;
+
+                if (matchedPairs === DIFFICULTIES[currentDiff].pairs) {
+                    setTimeout(() => showWin(), 500);
+                }
+            } else {
+                setTimeout(() => {
+                    card1.classList.remove('flipped');
+                    card2.classList.remove('flipped');
+                    flippedCards = [];
+                    locked = false;
+                }, 800);
+            }
+        }
+
+        function showWin() {
+            const overlay = document.getElementById('overlay');
+            const msg = document.getElementById('modalMsg');
+
+            msg.textContent = 'Completed in ' + moves + ' moves!';
+            overlay.classList.remove('hidden');
+        }
+
+        function hideOverlay() {
+            document.getElementById('overlay').classList.add('hidden');
+        }
+
+        function goBack() {
+            window.location.href = 'index.html';
+        }
+
+        initGame();
+    </script>
+</body>
+</html>

+ 557 - 0
src/web/Games/minesweeper.html

@@ -0,0 +1,557 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Minesweeper - ArozOS</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+
+        body {
+            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+            background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0f0f0f 100%);
+            color: #e0e0e0;
+            min-height: 100vh;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            user-select: none;
+        }
+
+        .top-bar {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            width: 100%;
+            max-width: 520px;
+            padding: 16px 0;
+        }
+
+        #backBtn {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 18px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            transition: background 0.2s;
+            display: flex;
+            align-items: center;
+            gap: 6px;
+        }
+
+        #backBtn:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+
+        #backBtn svg {
+            width: 16px;
+            height: 16px;
+        }
+
+        .game-info {
+            display: flex;
+            gap: 24px;
+            font-size: 1rem;
+            font-family: 'Courier New', monospace;
+        }
+
+        .game-info span {
+            background: rgba(0, 0, 0, 0.5);
+            padding: 4px 12px;
+            border-radius: 4px;
+            min-width: 60px;
+            text-align: center;
+            border: 1px solid rgba(255, 215, 0, 0.2);
+        }
+
+        #resetBtn {
+            background: none;
+            border: 1px solid rgba(255, 215, 0, 0.3);
+            color: #ffd700;
+            width: 40px;
+            height: 40px;
+            border-radius: 50%;
+            cursor: pointer;
+            transition: transform 0.15s;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+
+        #resetBtn:hover {
+            transform: scale(1.1);
+            border-color: rgba(255, 215, 0, 0.6);
+        }
+
+        #resetBtn svg {
+            width: 20px;
+            height: 20px;
+        }
+
+        .difficulty-bar {
+            display: flex;
+            gap: 8px;
+            margin-bottom: 16px;
+        }
+
+        .diff-btn {
+            background: rgba(255, 255, 255, 0.05);
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            color: #aaa;
+            padding: 6px 16px;
+            border-radius: 4px;
+            cursor: pointer;
+            font-size: 0.85rem;
+            transition: all 0.2s;
+        }
+
+        .diff-btn:hover, .diff-btn.active {
+            background: rgba(255, 215, 0, 0.2);
+            border-color: rgba(255, 215, 0, 0.5);
+            color: #ffd700;
+        }
+
+        #board {
+            display: grid;
+            gap: 1px;
+            background: rgba(0, 0, 0, 0.4);
+            border: 2px solid rgba(255, 215, 0, 0.2);
+            border-radius: 4px;
+            padding: 2px;
+        }
+
+        .cell {
+            width: 32px;
+            height: 32px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: 0.9rem;
+            font-weight: bold;
+            cursor: pointer;
+            border-radius: 2px;
+            transition: background 0.1s;
+        }
+
+        .cell.hidden {
+            background: linear-gradient(135deg, #2a2a2a, #1a1a1a);
+            border: 1px solid rgba(255, 215, 0, 0.15);
+        }
+
+        .cell.hidden:hover {
+            background: linear-gradient(135deg, #333333, #2a2a2a);
+            border-color: rgba(255, 215, 0, 0.3);
+        }
+
+        .cell.revealed {
+            background: rgba(255, 255, 255, 0.03);
+        }
+
+        .cell.flagged {
+            background: linear-gradient(135deg, #2a2a2a, #1a1a1a);
+        }
+
+        .cell.mine-exploded {
+            background: rgba(255, 100, 50, 0.5);
+        }
+
+        .cell.mine-shown {
+            background: rgba(255, 215, 0, 0.1);
+        }
+
+        .n1 { color: #5b9bd5; }
+        .n2 { color: #4caf50; }
+        .n3 { color: #ffd700; }
+        .n4 { color: #c77dff; }
+        .n5 { color: #ff5722; }
+        .n6 { color: #00bcd4; }
+        .n7 { color: #ffd700; }
+        .n8 { color: #888; }
+
+        .overlay {
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            background: rgba(0, 0, 0, 0.7);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            z-index: 100;
+        }
+
+        .overlay.hidden {
+            display: none;
+        }
+
+        .modal {
+            background: #141414;
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            border-radius: 12px;
+            padding: 32px;
+            text-align: center;
+            max-width: 300px;
+        }
+
+        .modal h2 {
+            margin-bottom: 12px;
+            font-size: 1.5rem;
+        }
+
+        .modal.win h2 {
+            color: #4caf50;
+        }
+
+        .modal.lose h2 {
+            color: #ff6432;
+        }
+
+        .modal p {
+            margin-bottom: 20px;
+            color: #888888;
+        }
+
+        .modal button {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 24px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            margin: 0 4px;
+            transition: background 0.2s;
+        }
+
+        .modal button:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+
+        .cell svg {
+            width: 20px;
+            height: 20px;
+        }
+    </style>
+</head>
+<body>
+    <div class="top-bar">
+        <button id="backBtn" onclick="goBack()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M15 18L9 12L15 6" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+            Back
+        </button>
+        <button id="resetBtn" onclick="initGame()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M3 12C3 7.03 7.03 3 12 3C15.5 3 18.58 5 20 8" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M21 4V9H16" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                <path d="M21 12C21 16.97 16.97 21 12 21C8.5 21 5.42 19 4 16" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M3 20V15H8" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+        </button>
+        <div class="game-info">
+            <span id="mineCount">Mines: 0</span>
+            <span id="timer">Time: 0s</span>
+        </div>
+    </div>
+
+    <div class="difficulty-bar">
+        <button class="diff-btn active" onclick="setDifficulty(0)">Beginner</button>
+        <button class="diff-btn" onclick="setDifficulty(1)">Intermediate</button>
+        <button class="diff-btn" onclick="setDifficulty(2)">Expert</button>
+    </div>
+
+    <div id="board"></div>
+
+    <div class="overlay hidden" id="overlay">
+        <div class="modal" id="modal">
+            <h2 id="modalTitle"></h2>
+            <p id="modalMsg"></p>
+            <button onclick="initGame()">Play Again</button>
+            <button onclick="goBack(); hideOverlay();">Back to Games</button>
+        </div>
+    </div>
+
+    <script>
+        const DIFFICULTIES = [
+            { rows: 9, cols: 9, mines: 10 },
+            { rows: 16, cols: 16, mines: 40 },
+            { rows: 16, cols: 30, mines: 99 }
+        ];
+
+        const FLAG_SVG = '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5 22V4" stroke="#ffd700" stroke-width="2"/><path d="M5 4L20 4L15 11L20 11L5 11" fill="#ffd700" stroke="#ffd700" stroke-width="1.5"/></svg>';
+        const BOMB_SVG = '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="13" r="7" fill="#ff4444" stroke="#ff6432" stroke-width="1.5"/><path d="M12 6V3" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/><circle cx="12" cy="2" r="1.5" fill="#ffd700"/><path d="M10 3L11 2" stroke="#ffd700" stroke-width="1.5" stroke-linecap="round"/><path d="M14 3L13 2" stroke="#ffd700" stroke-width="1.5" stroke-linecap="round"/></svg>';
+        const MISS_SVG = '<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6 6L18 18M18 6L6 18" stroke="#ff4444" stroke-width="2" stroke-linecap="round"/></svg>';
+
+        const FLAG_EMOJI = '\u{1F6A7}';
+        const BOMB_EMOJI = '\u{1F4A3}';
+        const CROSS_EMOJI = '\u274C';
+
+        let currentDiff = 0;
+        let board = [];
+        let rows, cols, totalMines;
+        let revealed = [];
+        let flagged = [];
+        let gameOver = false;
+        let firstClick = true;
+        let timerInterval = null;
+        let seconds = 0;
+        let flagCount = 0;
+
+        function setDifficulty(idx) {
+            currentDiff = idx;
+            document.querySelectorAll('.diff-btn').forEach((b, i) => {
+                b.classList.toggle('active', i === idx);
+            });
+            initGame();
+        }
+
+        function initGame() {
+            const diff = DIFFICULTIES[currentDiff];
+            rows = diff.rows;
+            cols = diff.cols;
+            totalMines = diff.mines;
+
+            board = [];
+            revealed = [];
+            flagged = [];
+            gameOver = false;
+            firstClick = true;
+            flagCount = 0;
+            seconds = 0;
+
+            if (timerInterval) clearInterval(timerInterval);
+            timerInterval = null;
+
+            for (let r = 0; r < rows; r++) {
+                board[r] = [];
+                revealed[r] = [];
+                flagged[r] = [];
+                for (let c = 0; c < cols; c++) {
+                    board[r][c] = 0;
+                    revealed[r][c] = false;
+                    flagged[r][c] = false;
+                }
+            }
+
+            updateUI();
+            renderBoard();
+            hideOverlay();
+        }
+
+        function placeMines(safeR, safeC) {
+            let placed = 0;
+            while (placed < totalMines) {
+                const r = Math.floor(Math.random() * rows);
+                const c = Math.floor(Math.random() * cols);
+                if (board[r][c] === -1) continue;
+                if (Math.abs(r - safeR) <= 1 && Math.abs(c - safeC) <= 1) continue;
+                board[r][c] = -1;
+                placed++;
+            }
+
+            for (let r = 0; r < rows; r++) {
+                for (let c = 0; c < cols; c++) {
+                    if (board[r][c] === -1) continue;
+                    let count = 0;
+                    for (let dr = -1; dr <= 1; dr++) {
+                        for (let dc = -1; dc <= 1; dc++) {
+                            const nr = r + dr, nc = c + dc;
+                            if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && board[nr][nc] === -1) {
+                                count++;
+                            }
+                        }
+                    }
+                    board[r][c] = count;
+                }
+            }
+        }
+
+        function renderBoard() {
+            const boardEl = document.getElementById('board');
+            boardEl.style.gridTemplateColumns = `repeat(${cols}, 32px)`;
+            boardEl.innerHTML = '';
+
+            for (let r = 0; r < rows; r++) {
+                for (let c = 0; c < cols; c++) {
+                    const cell = document.createElement('div');
+                    cell.className = 'cell hidden';
+                    cell.dataset.r = r;
+                    cell.dataset.c = c;
+
+                    cell.addEventListener('click', () => handleClick(r, c));
+                    cell.addEventListener('contextmenu', (e) => {
+                        e.preventDefault();
+                        handleRightClick(r, c);
+                    });
+
+                    boardEl.appendChild(cell);
+                }
+            }
+        }
+
+        function getCell(r, c) {
+            return document.querySelector(`.cell[data-r="${r}"][data-c="${c}"]`);
+        }
+
+        function handleClick(r, c) {
+            if (gameOver || flagged[r][c] || revealed[r][c]) return;
+
+            if (firstClick) {
+                firstClick = false;
+                placeMines(r, c);
+                startTimer();
+            }
+
+            if (board[r][c] === -1) {
+                loseGame(r, c);
+                return;
+            }
+
+            revealCell(r, c);
+            checkWin();
+        }
+
+        function revealCell(r, c) {
+            if (r < 0 || r >= rows || c < 0 || c >= cols) return;
+            if (revealed[r][c] || flagged[r][c]) return;
+
+            revealed[r][c] = true;
+            const cell = getCell(r, c);
+            cell.classList.remove('hidden');
+            cell.classList.add('revealed');
+
+            if (board[r][c] > 0) {
+                cell.textContent = board[r][c];
+                cell.classList.add('n' + board[r][c]);
+            } else if (board[r][c] === 0) {
+                for (let dr = -1; dr <= 1; dr++) {
+                    for (let dc = -1; dc <= 1; dc++) {
+                        if (dr === 0 && dc === 0) continue;
+                        revealCell(r + dr, c + dc);
+                    }
+                }
+            }
+        }
+
+        function handleRightClick(r, c) {
+            if (gameOver || revealed[r][c]) return;
+
+            const cell = getCell(r, c);
+            if (flagged[r][c]) {
+                flagged[r][c] = false;
+                flagCount--;
+                cell.classList.remove('flagged');
+                cell.innerHTML = '';
+            } else {
+                flagged[r][c] = true;
+                flagCount++;
+                cell.classList.add('flagged');
+                cell.innerHTML = FLAG_SVG;
+            }
+
+            document.getElementById('mineCount').textContent = 'Mines: ' + (totalMines - flagCount);
+        }
+
+        function loseGame(explodedR, explodedC) {
+            gameOver = true;
+            if (timerInterval) clearInterval(timerInterval);
+
+            const cell = getCell(explodedR, explodedC);
+            cell.classList.remove('hidden');
+            cell.classList.add('mine-exploded');
+            cell.innerHTML = BOMB_SVG;
+
+            for (let r = 0; r < rows; r++) {
+                for (let c = 0; c < cols; c++) {
+                    if (board[r][c] === -1 && !(r === explodedR && c === explodedC)) {
+                        const mc = getCell(r, c);
+                        mc.classList.remove('hidden');
+                        mc.classList.add('mine-shown');
+                        if (!flagged[r][c]) {
+                            mc.innerHTML = BOMB_SVG;
+                        }
+                    }
+                    if (flagged[r][c] && board[r][c] !== -1) {
+                        const mc = getCell(r, c);
+                        mc.innerHTML = MISS_SVG;
+                    }
+                }
+            }
+
+            setTimeout(() => showModal(false), 500);
+        }
+
+        function checkWin() {
+            let unrevealedSafe = 0;
+            for (let r = 0; r < rows; r++) {
+                for (let c = 0; c < cols; c++) {
+                    if (board[r][c] !== -1 && !revealed[r][c]) {
+                        unrevealedSafe++;
+                    }
+                }
+            }
+
+            if (unrevealedSafe === 0) {
+                gameOver = true;
+                if (timerInterval) clearInterval(timerInterval);
+
+                for (let r = 0; r < rows; r++) {
+                    for (let c = 0; c < cols; c++) {
+                        if (board[r][c] === -1) {
+                            flagged[r][c] = true;
+                            const mc = getCell(r, c);
+                            mc.innerHTML = FLAG_SVG;
+                            mc.classList.add('flagged');
+                        }
+                    }
+                }
+                document.getElementById('mineCount').textContent = 'Mines: 0';
+                setTimeout(() => showModal(true), 300);
+            }
+        }
+
+        function startTimer() {
+            timerInterval = setInterval(() => {
+                seconds++;
+                document.getElementById('timer').textContent = 'Time: ' + seconds + 's';
+            }, 1000);
+        }
+
+        function updateUI() {
+            document.getElementById('mineCount').textContent = 'Mines: ' + totalMines;
+            document.getElementById('timer').textContent = 'Time: 0s';
+        }
+
+        function showModal(isWin) {
+            const overlay = document.getElementById('overlay');
+            const modal = document.getElementById('modal');
+            const title = document.getElementById('modalTitle');
+            const msg = document.getElementById('modalMsg');
+
+            modal.className = 'modal ' + (isWin ? 'win' : 'lose');
+            title.textContent = isWin ? 'You Win!' : 'Game Over';
+            msg.textContent = isWin ? 'Congratulations! Time: ' + seconds + 's' : 'Better luck next time!';
+
+            overlay.classList.remove('hidden');
+        }
+
+        function hideOverlay() {
+            document.getElementById('overlay').classList.add('hidden');
+        }
+
+        function goBack() {
+            window.location.href = 'index.html';
+        }
+
+        initGame();
+    </script>
+</body>
+</html>

+ 454 - 0
src/web/Games/pong.html

@@ -0,0 +1,454 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Pong - ArozOS</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+
+        body {
+            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+            background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0f0f0f 100%);
+            color: #e0e0e0;
+            min-height: 100vh;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            user-select: none;
+        }
+
+        .top-bar {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            width: 100%;
+            max-width: 560px;
+            padding: 16px 0;
+        }
+
+        #backBtn {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 18px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            transition: background 0.2s;
+            display: flex;
+            align-items: center;
+            gap: 6px;
+        }
+
+        #backBtn:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+
+        #backBtn svg {
+            width: 16px;
+            height: 16px;
+        }
+
+        #resetBtn {
+            background: none;
+            border: 1px solid rgba(255, 215, 0, 0.3);
+            color: #ffd700;
+            width: 40px;
+            height: 40px;
+            border-radius: 50%;
+            cursor: pointer;
+            transition: transform 0.15s;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+
+        #resetBtn:hover {
+            transform: scale(1.1);
+            border-color: rgba(255, 215, 0, 0.6);
+        }
+
+        #resetBtn svg {
+            width: 20px;
+            height: 20px;
+        }
+
+        .game-layout {
+            display: flex;
+            gap: 24px;
+            align-items: flex-start;
+        }
+
+        #gameCanvas {
+            border: 2px solid rgba(255, 215, 0, 0.3);
+            border-radius: 4px;
+            background: rgba(0, 0, 0, 0.5);
+        }
+
+        .side-panel {
+            display: flex;
+            flex-direction: column;
+            gap: 16px;
+        }
+
+        .panel-box {
+            background: rgba(255, 255, 255, 0.03);
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            border-radius: 8px;
+            padding: 16px;
+            min-width: 140px;
+        }
+
+        .panel-box h3 {
+            font-size: 0.85rem;
+            color: #ffd700;
+            margin-bottom: 8px;
+            text-transform: uppercase;
+            letter-spacing: 1px;
+        }
+
+        .stat {
+            font-size: 1.2rem;
+            font-family: 'Courier New', monospace;
+            color: #ffd700;
+            text-align: center;
+            margin-bottom: 4px;
+        }
+
+        .controls {
+            font-size: 0.8rem;
+            color: #888888;
+            line-height: 1.8;
+        }
+
+        .controls .key {
+            display: inline-block;
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.3);
+            color: #ffd700;
+            padding: 1px 6px;
+            border-radius: 3px;
+            font-family: 'Courier New', monospace;
+            font-size: 0.75rem;
+            min-width: 20px;
+            text-align: center;
+        }
+
+        .overlay {
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            background: rgba(0, 0, 0, 0.75);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            z-index: 100;
+        }
+
+        .overlay.hidden {
+            display: none;
+        }
+
+        .modal {
+            background: #141414;
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            border-radius: 12px;
+            padding: 32px;
+            text-align: center;
+            max-width: 300px;
+        }
+
+        .modal h2 {
+            margin-bottom: 12px;
+            font-size: 1.5rem;
+        }
+
+        .modal.win h2 {
+            color: #4caf50;
+        }
+
+        .modal.lose h2 {
+            color: #ff6432;
+        }
+
+        .modal p {
+            margin-bottom: 20px;
+            color: #888888;
+        }
+
+        .modal button {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 24px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            margin: 0 4px;
+            transition: background 0.2s;
+        }
+
+        .modal button:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+    </style>
+</head>
+<body>
+    <div class="top-bar">
+        <button id="backBtn" onclick="goBack()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M15 18L9 12L15 6" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+            Back
+        </button>
+        <button id="resetBtn" onclick="initGame()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
+                <path d="M3 12C3 7.03 7.03 3 12 3C15.5 3 18.58 5 20 8" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M21 4V9H16" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                <path d="M21 12C21 16.97 16.97 21 12 21C8.5 21 5.42 19 4 16" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M3 20V15H8" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+        </button>
+        <div class="game-info">
+            <span id="score">0</span>
+        </div>
+    </div>
+
+    <div class="game-layout">
+        <canvas id="gameCanvas" width="480" height="360"></canvas>
+        <div class="side-panel">
+            <div class="panel-box">
+                <h3>Score</h3>
+                <div class="stat" id="scoreDisplay">0</div>
+                <h3 style="margin-top:8px;">High Score</h3>
+                <div class="stat" id="highScore">0</div>
+            </div>
+            <div class="panel-box">
+                <h3>Controls</h3>
+                <div class="controls">
+                    <div><span class="key">↑</span> <span class="key">↓</span> Move paddle</div>
+                    <div>Mouse: Move paddle</div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="overlay hidden" id="overlay">
+        <div class="modal" id="modal">
+            <h2 id="modalTitle"></h2>
+            <p id="modalMsg"></p>
+            <button onclick="initGame()">Play Again</button>
+            <button onclick="goBack(); hideOverlay();">Back to Games</button>
+        </div>
+    </div>
+
+    <script>
+        const CANVAS_WIDTH = 480;
+        const CANVAS_HEIGHT = 360;
+        const PADDLE_WIDTH = 12;
+        const PADDLE_HEIGHT = 60;
+        const BALL_SIZE = 8;
+        const WIN_SCORE = 5;
+        const PADDLE_SPEED = 6;
+        const INITIAL_BALL_SPEED = 3;
+
+        const canvas = document.getElementById('gameCanvas');
+        const ctx = canvas.getContext('2d');
+
+        let playerY = CANVAS_HEIGHT / 2 - PADDLE_HEIGHT / 2;
+        let aiY = CANVAS_HEIGHT / 2 - PADDLE_HEIGHT / 2;
+        let ballX = CANVAS_WIDTH / 2;
+        let ballY = CANVAS_HEIGHT / 2;
+        let ballDX = INITIAL_BALL_SPEED;
+        let ballDY = INITIAL_BALL_SPEED * (Math.random() > 0.5 ? 1 : -1);
+        let score = 0;
+        let highScore = parseInt(localStorage.getItem('pongHighScore') || '0');
+        let gameOver = false;
+        let gameStarted = false;
+        let animationId = null;
+
+        document.getElementById('highScore').textContent = highScore;
+
+        function initGame() {
+            playerY = CANVAS_HEIGHT / 2 - PADDLE_HEIGHT / 2;
+            aiY = CANVAS_HEIGHT / 2 - PADDLE_HEIGHT / 2;
+            resetBall();
+            score = 0;
+            gameOver = false;
+            gameStarted = false;
+
+            document.getElementById('scoreDisplay').textContent = '0';
+            document.getElementById('overlay').classList.add('hidden');
+
+            if (animationId) cancelAnimationFrame(animationId);
+            animationId = requestAnimationFrame(gameLoop);
+        }
+
+        function resetBall() {
+            ballX = CANVAS_WIDTH / 2;
+            ballY = CANVAS_HEIGHT / 2;
+            ballDX = INITIAL_BALL_SPEED * (Math.random() > 0.5 ? 1 : -1);
+            ballDY = INITIAL_BALL_SPEED * (Math.random() > 0.5 ? 1 : -1);
+        }
+
+        function gameLoop() {
+            if (gameOver) return;
+
+            update();
+            draw();
+
+            animationId = requestAnimationFrame(gameLoop);
+        }
+
+        function update() {
+            if (!gameStarted) return;
+
+            ballX += ballDX;
+            ballY += ballDY;
+
+            if (ballY <= 0 || ballY >= CANVAS_HEIGHT - BALL_SIZE) {
+                ballDY = -ballDY;
+            }
+
+            if (ballX <= PADDLE_WIDTH + 10 && ballY >= playerY && ballY <= playerY + PADDLE_HEIGHT) {
+                ballDX = Math.abs(ballDX);
+                const hitPos = (ballY - playerY) / PADDLE_HEIGHT;
+                ballDY = INITIAL_BALL_SPEED * (0.5 + hitPos) * (Math.random() > 0.5 ? 1 : -1);
+                ballDX += 0.5;
+            }
+
+            if (ballX >= CANVAS_WIDTH - PADDLE_WIDTH - BALL_SIZE - 10 && ballY >= aiY && ballY <= aiY + PADDLE_HEIGHT) {
+                ballDX = -Math.abs(ballDX);
+                const hitPos = (ballY - aiY) / PADDLE_HEIGHT;
+                ballDY = INITIAL_BALL_SPEED * (0.5 + hitPos) * (Math.random() > 0.5 ? 1 : -1);
+            }
+
+            if (ballX < 0) {
+                endGame(false);
+                return;
+            }
+
+            if (ballX > CANVAS_WIDTH) {
+                score++;
+                document.getElementById('scoreDisplay').textContent = score;
+                if (score >= WIN_SCORE) {
+                    endGame(true);
+                    return;
+                }
+                resetBall();
+            }
+
+            const aiTarget = ballY - PADDLE_HEIGHT / 2;
+            const aiDiff = aiTarget - aiY;
+            aiY += Math.sign(aiDiff) * Math.min(Math.abs(aiDiff), PADDLE_SPEED * 0.7);
+        }
+
+        function draw() {
+            ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
+
+            ctx.strokeStyle = 'rgba(255, 215, 0, 0.3)';
+            ctx.setLineDash([5, 5]);
+            ctx.beginPath();
+            ctx.moveTo(CANVAS_WIDTH / 2, 0);
+            ctx.lineTo(CANVAS_WIDTH / 2, CANVAS_HEIGHT);
+            ctx.stroke();
+            ctx.setLineDash([]);
+
+            ctx.fillStyle = '#ffd700';
+            ctx.fillRect(10, playerY, PADDLE_WIDTH, PADDLE_HEIGHT);
+
+            ctx.fillStyle = 'rgba(255, 215, 0, 0.6)';
+            ctx.fillRect(CANVAS_WIDTH - 10 - PADDLE_WIDTH, aiY, PADDLE_WIDTH, PADDLE_HEIGHT);
+
+            ctx.fillStyle = '#ffd700';
+            ctx.fillRect(ballX, ballY, BALL_SIZE, BALL_SIZE);
+
+            if (!gameStarted) {
+                ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
+                ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
+                ctx.fillStyle = '#ffd700';
+                ctx.font = 'bold 18px Segoe UI';
+                ctx.textAlign = 'center';
+                ctx.fillText('Press any key or click to start', CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2);
+            }
+        }
+
+        function endGame(isWin) {
+            gameOver = true;
+
+            if (score > highScore) {
+                highScore = score;
+                localStorage.setItem('pongHighScore', highScore.toString());
+                document.getElementById('highScore').textContent = highScore;
+            }
+
+            const overlay = document.getElementById('overlay');
+            const modal = document.getElementById('modal');
+            const title = document.getElementById('modalTitle');
+            const msg = document.getElementById('modalMsg');
+
+            modal.className = 'modal ' + (isWin ? 'win' : 'lose');
+            title.textContent = isWin ? 'You Win!' : 'Game Over';
+            msg.textContent = 'Score: ' + score + ' | High Score: ' + highScore;
+
+            overlay.classList.remove('hidden');
+        }
+
+        function hideOverlay() {
+            document.getElementById('overlay').classList.add('hidden');
+        }
+
+        function goBack() {
+            window.location.href = 'index.html';
+        }
+
+        function startGame() {
+            if (gameStarted) return;
+            gameStarted = true;
+        }
+
+        function handleKey(e) {
+            if (['ArrowUp', 'ArrowDown'].indexOf(e.key) !== -1) {
+                e.preventDefault();
+            }
+
+            if (gameOver) return;
+
+            startGame();
+
+            switch (e.key) {
+                case 'ArrowUp':
+                    playerY = Math.max(0, playerY - 20);
+                    break;
+                case 'ArrowDown':
+                    playerY = Math.min(CANVAS_HEIGHT - PADDLE_HEIGHT, playerY + 20);
+                    break;
+            }
+        }
+
+        canvas.addEventListener('mousemove', (e) => {
+            if (gameOver) return;
+            startGame();
+
+            const rect = canvas.getBoundingClientRect();
+            const mouseY = e.clientY - rect.top;
+            playerY = Math.max(0, Math.min(CANVAS_HEIGHT - PADDLE_HEIGHT, mouseY - PADDLE_HEIGHT / 2));
+        });
+
+        canvas.addEventListener('click', () => {
+            if (gameOver) return;
+            startGame();
+        });
+
+        document.addEventListener('keydown', handleKey);
+        initGame();
+    </script>
+</body>
+</html>

+ 496 - 0
src/web/Games/snake.html

@@ -0,0 +1,496 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Snake - ArozOS</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+
+        body {
+            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+            background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0f0f0f 100%);
+            color: #e0e0e0;
+            min-height: 100vh;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            user-select: none;
+        }
+
+        .top-bar {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            width: 100%;
+            max-width: 560px;
+            padding: 16px 0;
+        }
+
+        #backBtn {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 18px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            transition: background 0.2s;
+            display: flex;
+            align-items: center;
+            gap: 6px;
+        }
+
+        #backBtn:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+
+        #backBtn svg {
+            width: 16px;
+            height: 16px;
+        }
+
+        #resetBtn {
+            background: none;
+            border: 1px solid rgba(255, 215, 0, 0.3);
+            color: #ffd700;
+            width: 40px;
+            height: 40px;
+            border-radius: 50%;
+            cursor: pointer;
+            transition: transform 0.15s;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+
+        #resetBtn:hover {
+            transform: scale(1.1);
+            border-color: rgba(255, 215, 0, 0.6);
+        }
+
+        #resetBtn svg {
+            width: 20px;
+            height: 20px;
+        }
+
+        .game-layout {
+            display: flex;
+            gap: 24px;
+            align-items: flex-start;
+        }
+
+        #gameCanvas {
+            border: 2px solid rgba(255, 215, 0, 0.3);
+            border-radius: 4px;
+            background: rgba(0, 0, 0, 0.5);
+        }
+
+        .side-panel {
+            display: flex;
+            flex-direction: column;
+            gap: 16px;
+        }
+
+        .panel-box {
+            background: rgba(255, 255, 255, 0.03);
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            border-radius: 8px;
+            padding: 16px;
+            min-width: 140px;
+        }
+
+        .panel-box h3 {
+            font-size: 0.85rem;
+            color: #ffd700;
+            margin-bottom: 8px;
+            text-transform: uppercase;
+            letter-spacing: 1px;
+        }
+
+        .stat {
+            font-size: 1.2rem;
+            font-family: 'Courier New', monospace;
+            color: #ffd700;
+            text-align: center;
+            margin-bottom: 4px;
+        }
+
+        .controls {
+            font-size: 0.8rem;
+            color: #888888;
+            line-height: 1.8;
+        }
+
+        .controls .key {
+            display: inline-block;
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.3);
+            color: #ffd700;
+            padding: 1px 6px;
+            border-radius: 3px;
+            font-family: 'Courier New', monospace;
+            font-size: 0.75rem;
+            min-width: 20px;
+            text-align: center;
+        }
+
+        .overlay {
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            background: rgba(0, 0, 0, 0.75);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            z-index: 100;
+        }
+
+        .overlay.hidden {
+            display: none;
+        }
+
+        .modal {
+            background: #141414;
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            border-radius: 12px;
+            padding: 32px;
+            text-align: center;
+            max-width: 300px;
+        }
+
+        .modal h2 {
+            margin-bottom: 12px;
+            font-size: 1.5rem;
+        }
+
+        .modal.lose h2 {
+            color: #ff6432;
+        }
+
+        .modal p {
+            margin-bottom: 20px;
+            color: #888888;
+        }
+
+        .modal button {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 24px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            margin: 0 4px;
+            transition: background 0.2s;
+        }
+
+        .modal button:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+    </style>
+</head>
+<body>
+    <div class="top-bar">
+        <button id="backBtn" onclick="goBack()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M15 18L9 12L15 6" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+            Back
+        </button>
+        <button id="resetBtn" onclick="initGame()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
+                <path d="M3 12C3 7.03 7.03 3 12 3C15.5 3 18.58 5 20 8" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M21 4V9H16" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                <path d="M21 12C21 16.97 16.97 21 12 21C8.5 21 5.42 19 4 16" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M3 20V15H8" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+        </button>
+    </div>
+
+    <div class="game-layout">
+        <canvas id="gameCanvas" width="400" height="400"></canvas>
+        <div class="side-panel">
+            <div class="panel-box">
+                <h3>Score</h3>
+                <div class="stat" id="score">0</div>
+                <h3 style="margin-top:8px;">High Score</h3>
+                <div class="stat" id="highScore">0</div>
+            </div>
+            <div class="panel-box">
+                <h3>Controls</h3>
+                <div class="controls">
+                    <div><span class="key">↑</span> <span class="key">↓</span> <span class="key">←</span> <span class="key">→</span> Move</div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="overlay hidden" id="overlay">
+        <div class="modal" id="modal">
+            <h2 id="modalTitle">Game Over</h2>
+            <p id="modalMsg"></p>
+            <button onclick="initGame()">Play Again</button>
+            <button onclick="goBack(); hideOverlay();">Back to Games</button>
+        </div>
+    </div>
+
+    <script>
+        const CANVAS_SIZE = 400;
+        const GRID_COUNT = 20;
+        const CELL_SIZE = CANVAS_SIZE / GRID_COUNT;
+        const INITIAL_SPEED = 150;
+        const SPEED_INCREMENT = 3;
+        const MIN_SPEED = 50;
+
+        const canvas = document.getElementById('gameCanvas');
+        const ctx = canvas.getContext('2d');
+
+        let snake = [];
+        let food = null;
+        let direction = { x: 1, y: 0 };
+        let nextDirection = { x: 1, y: 0 };
+        let score = 0;
+        let highScore = parseInt(localStorage.getItem('snakeHighScore') || '0');
+        let gameSpeed = INITIAL_SPEED;
+        let gameOver = false;
+        let gameStarted = false;
+        let lastUpdate = 0;
+        let animationId = null;
+
+        document.getElementById('highScore').textContent = highScore;
+
+        function initGame() {
+            snake = [
+                { x: 5, y: 10 },
+                { x: 4, y: 10 },
+                { x: 3, y: 10 }
+            ];
+            direction = { x: 1, y: 0 };
+            nextDirection = { x: 1, y: 0 };
+            score = 0;
+            gameSpeed = INITIAL_SPEED;
+            gameOver = false;
+            gameStarted = false;
+
+            document.getElementById('score').textContent = '0';
+            document.getElementById('overlay').classList.add('hidden');
+
+            placeFood();
+
+            if (animationId) cancelAnimationFrame(animationId);
+            animationId = requestAnimationFrame(gameLoop);
+        }
+
+        function placeFood() {
+            let valid = false;
+            while (!valid) {
+                food = {
+                    x: Math.floor(Math.random() * GRID_COUNT),
+                    y: Math.floor(Math.random() * GRID_COUNT)
+                };
+                valid = true;
+                for (let segment of snake) {
+                    if (segment.x === food.x && segment.y === food.y) {
+                        valid = false;
+                        break;
+                    }
+                }
+            }
+        }
+
+        function gameLoop(timestamp) {
+            if (gameOver) return;
+
+            if (timestamp - lastUpdate > gameSpeed) {
+                update();
+                lastUpdate = timestamp;
+            }
+
+            draw();
+            animationId = requestAnimationFrame(gameLoop);
+        }
+
+        function update() {
+            direction = nextDirection;
+
+            const head = {
+                x: snake[0].x + direction.x,
+                y: snake[0].y + direction.y
+            };
+
+            if (head.x < 0 || head.x >= GRID_COUNT || head.y < 0 || head.y >= GRID_COUNT) {
+                endGame();
+                return;
+            }
+
+            for (let segment of snake) {
+                if (segment.x === head.x && segment.y === head.y) {
+                    endGame();
+                    return;
+                }
+            }
+
+            snake.unshift(head);
+
+            if (head.x === food.x && head.y === food.y) {
+                score += 10;
+                document.getElementById('score').textContent = score;
+                gameSpeed = Math.max(MIN_SPEED, INITIAL_SPEED - Math.floor(score / 50) * SPEED_INCREMENT);
+                placeFood();
+            } else {
+                snake.pop();
+            }
+        }
+
+        function draw() {
+            ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);
+
+            for (let r = 0; r < GRID_COUNT; r++) {
+                for (let c = 0; c < GRID_COUNT; c++) {
+                    ctx.fillStyle = (r + c) % 2 === 0 ? 'rgba(255, 255, 255, 0.02)' : 'rgba(255, 255, 255, 0.04)';
+                    ctx.fillRect(c * CELL_SIZE, r * CELL_SIZE, CELL_SIZE, CELL_SIZE);
+                }
+            }
+
+            if (food) {
+                ctx.fillStyle = '#ff4444';
+                ctx.beginPath();
+                ctx.arc(
+                    food.x * CELL_SIZE + CELL_SIZE / 2,
+                    food.y * CELL_SIZE + CELL_SIZE / 2,
+                    CELL_SIZE / 2.5,
+                    0,
+                    Math.PI * 2
+                );
+                ctx.fill();
+                ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
+                ctx.beginPath();
+                ctx.arc(
+                    food.x * CELL_SIZE + CELL_SIZE / 2 - 2,
+                    food.y * CELL_SIZE + CELL_SIZE / 2 - 2,
+                    CELL_SIZE / 6,
+                    0,
+                    Math.PI * 2
+                );
+                ctx.fill();
+            }
+
+            for (let i = 0; i < snake.length; i++) {
+                const segment = snake[i];
+                const alpha = 1 - (i / snake.length) * 0.5;
+
+                if (i === 0) {
+                    ctx.fillStyle = '#ffd700';
+                    ctx.fillRect(
+                        segment.x * CELL_SIZE + 1,
+                        segment.y * CELL_SIZE + 1,
+                        CELL_SIZE - 2,
+                        CELL_SIZE - 2
+                    );
+
+                    ctx.fillStyle = '#0a0a0a';
+                    const eyeSize = CELL_SIZE / 6;
+                    const eyeOffset = CELL_SIZE / 4;
+
+                    if (direction.x === 1) {
+                        ctx.fillRect(segment.x * CELL_SIZE + CELL_SIZE - eyeOffset - eyeSize, segment.y * CELL_SIZE + eyeOffset, eyeSize, eyeSize);
+                        ctx.fillRect(segment.x * CELL_SIZE + CELL_SIZE - eyeOffset - eyeSize, segment.y * CELL_SIZE + CELL_SIZE - eyeOffset - eyeSize, eyeSize, eyeSize);
+                    } else if (direction.x === -1) {
+                        ctx.fillRect(segment.x * CELL_SIZE + eyeOffset, segment.y * CELL_SIZE + eyeOffset, eyeSize, eyeSize);
+                        ctx.fillRect(segment.x * CELL_SIZE + eyeOffset, segment.y * CELL_SIZE + CELL_SIZE - eyeOffset - eyeSize, eyeSize, eyeSize);
+                    } else if (direction.y === -1) {
+                        ctx.fillRect(segment.x * CELL_SIZE + eyeOffset, segment.y * CELL_SIZE + eyeOffset, eyeSize, eyeSize);
+                        ctx.fillRect(segment.x * CELL_SIZE + CELL_SIZE - eyeOffset - eyeSize, segment.y * CELL_SIZE + eyeOffset, eyeSize, eyeSize);
+                    } else {
+                        ctx.fillRect(segment.x * CELL_SIZE + eyeOffset, segment.y * CELL_SIZE + CELL_SIZE - eyeOffset - eyeSize, eyeSize, eyeSize);
+                        ctx.fillRect(segment.x * CELL_SIZE + CELL_SIZE - eyeOffset - eyeSize, segment.y * CELL_SIZE + CELL_SIZE - eyeOffset - eyeSize, eyeSize, eyeSize);
+                    }
+                } else {
+                    ctx.fillStyle = `rgba(255, 215, 0, ${alpha})`;
+                    ctx.fillRect(
+                        segment.x * CELL_SIZE + 1,
+                        segment.y * CELL_SIZE + 1,
+                        CELL_SIZE - 2,
+                        CELL_SIZE - 2
+                    );
+                }
+            }
+
+            if (!gameStarted) {
+                ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
+                ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);
+                ctx.fillStyle = '#ffd700';
+                ctx.font = 'bold 20px Segoe UI';
+                ctx.textAlign = 'center';
+                ctx.fillText('Press any arrow key to start', CANVAS_SIZE / 2, CANVAS_SIZE / 2);
+            }
+        }
+
+        function endGame() {
+            gameOver = true;
+
+            if (score > highScore) {
+                highScore = score;
+                localStorage.setItem('snakeHighScore', highScore.toString());
+                document.getElementById('highScore').textContent = highScore;
+            }
+
+            const overlay = document.getElementById('overlay');
+            const modal = document.getElementById('modal');
+            const title = document.getElementById('modalTitle');
+            const msg = document.getElementById('modalMsg');
+
+            modal.className = 'modal lose';
+            title.textContent = 'Game Over';
+            msg.textContent = 'Score: ' + score + (score >= highScore && score > 0 ? ' (New High Score!)' : '');
+
+            overlay.classList.remove('hidden');
+        }
+
+        function hideOverlay() {
+            document.getElementById('overlay').classList.add('hidden');
+        }
+
+        function goBack() {
+            window.location.href = 'index.html';
+        }
+
+        function handleKey(e) {
+            if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].indexOf(e.key) !== -1) {
+                e.preventDefault();
+            }
+
+            if (gameOver) return;
+
+            switch (e.key) {
+                case 'ArrowUp':
+                    if (direction.y !== 1) nextDirection = { x: 0, y: -1 };
+                    gameStarted = true;
+                    break;
+                case 'ArrowDown':
+                    if (direction.y !== -1) nextDirection = { x: 0, y: 1 };
+                    gameStarted = true;
+                    break;
+                case 'ArrowLeft':
+                    if (direction.x !== 1) nextDirection = { x: -1, y: 0 };
+                    gameStarted = true;
+                    break;
+                case 'ArrowRight':
+                    if (direction.x !== -1) nextDirection = { x: 1, y: 0 };
+                    gameStarted = true;
+                    break;
+            }
+        }
+
+        document.addEventListener('keydown', handleKey);
+        initGame();
+    </script>
+</body>
+</html>

+ 662 - 0
src/web/Games/tetris.html

@@ -0,0 +1,662 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Tetris - ArozOS</title>
+    <style>
+        * {
+            margin: 0;
+            padding: 0;
+            box-sizing: border-box;
+        }
+
+        body {
+            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+            background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 50%, #0f0f0f 100%);
+            color: #e0e0e0;
+            min-height: 100vh;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            user-select: none;
+        }
+
+        .top-bar {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+            width: 100%;
+            max-width: 560px;
+            padding: 16px 0;
+        }
+
+        #backBtn {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 18px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            transition: background 0.2s;
+            display: flex;
+            align-items: center;
+            gap: 6px;
+        }
+
+        #backBtn:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+
+        #backBtn svg {
+            width: 16px;
+            height: 16px;
+        }
+
+        .game-layout {
+            display: flex;
+            gap: 24px;
+            align-items: flex-start;
+        }
+
+        #gameCanvas {
+            border: 2px solid rgba(255, 215, 0, 0.3);
+            border-radius: 4px;
+            background: rgba(0, 0, 0, 0.5);
+        }
+
+        .side-panel {
+            display: flex;
+            flex-direction: column;
+            gap: 16px;
+        }
+
+        .panel-box {
+            background: rgba(255, 255, 255, 0.03);
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            border-radius: 8px;
+            padding: 16px;
+            min-width: 140px;
+        }
+
+        .panel-box h3 {
+            font-size: 0.85rem;
+            color: #ffd700;
+            margin-bottom: 8px;
+            text-transform: uppercase;
+            letter-spacing: 1px;
+        }
+
+        #nextCanvas {
+            display: block;
+            margin: 0 auto;
+            border-radius: 4px;
+            background: rgba(0, 0, 0, 0.3);
+        }
+
+        .stat {
+            font-size: 1.2rem;
+            font-family: 'Courier New', monospace;
+            color: #ffd700;
+            text-align: center;
+            margin-bottom: 4px;
+        }
+
+        .controls {
+            font-size: 0.8rem;
+            color: #888888;
+            line-height: 1.8;
+        }
+
+        .controls .key {
+            display: inline-block;
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.3);
+            color: #ffd700;
+            padding: 1px 6px;
+            border-radius: 3px;
+            font-family: 'Courier New', monospace;
+            font-size: 0.75rem;
+            min-width: 20px;
+            text-align: center;
+        }
+
+        .overlay {
+            position: fixed;
+            top: 0;
+            left: 0;
+            width: 100%;
+            height: 100%;
+            background: rgba(0, 0, 0, 0.75);
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            z-index: 100;
+        }
+
+        .overlay.hidden {
+            display: none;
+        }
+
+        .modal {
+            background: #141414;
+            border: 1px solid rgba(255, 215, 0, 0.2);
+            border-radius: 12px;
+            padding: 32px;
+            text-align: center;
+            max-width: 300px;
+        }
+
+        .modal h2 {
+            margin-bottom: 12px;
+            font-size: 1.5rem;
+        }
+
+        .modal.win h2 {
+            color: #4caf50;
+        }
+
+        .modal.lose h2 {
+            color: #ff6432;
+        }
+
+        .modal p {
+            margin-bottom: 20px;
+            color: #888888;
+        }
+
+        .modal button {
+            background: rgba(255, 215, 0, 0.15);
+            border: 1px solid rgba(255, 215, 0, 0.4);
+            color: #ffd700;
+            padding: 8px 24px;
+            border-radius: 6px;
+            cursor: pointer;
+            font-size: 0.9rem;
+            margin: 0 4px;
+            transition: background 0.2s;
+        }
+
+        .modal button:hover {
+            background: rgba(255, 215, 0, 0.3);
+        }
+    </style>
+</head>
+<body>
+    <div class="top-bar">
+        <button id="backBtn" onclick="goBack()">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M15 18L9 12L15 6" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+            Back
+        </button>
+        <button id="resetBtn" onclick="initGame()" style="background:none;border:1px solid rgba(255,215,0,0.3);color:#ffd700;width:40px;height:40px;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;">
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
+                <path d="M3 12C3 7.03 7.03 3 12 3C15.5 3 18.58 5 20 8" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M21 4V9H16" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                <path d="M21 12C21 16.97 16.97 21 12 21C8.5 21 5.42 19 4 16" stroke="#ffd700" stroke-width="2" stroke-linecap="round"/>
+                <path d="M3 20V15H8" stroke="#ffd700" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+        </button>
+    </div>
+
+    <div class="game-layout">
+        <canvas id="gameCanvas" width="300" height="600"></canvas>
+        <div class="side-panel">
+            <div class="panel-box">
+                <h3>Next</h3>
+                <canvas id="nextCanvas" width="100" height="100"></canvas>
+            </div>
+            <div class="panel-box">
+                <h3>Score</h3>
+                <div class="stat" id="score">0</div>
+                <h3 style="margin-top:8px;">Lines</h3>
+                <div class="stat" id="lines">0</div>
+                <h3 style="margin-top:8px;">Level</h3>
+                <div class="stat" id="level">1</div>
+            </div>
+            <div class="panel-box">
+                <h3>Controls</h3>
+                <div class="controls">
+                    <div><span class="key">←</span> <span class="key">→</span> Move</div>
+                    <div><span class="key">↑</span> Rotate</div>
+                    <div><span class="key">↓</span> Soft drop</div>
+                    <div><span class="key">Space</span> Hard drop</div>
+                    <div><span class="key">P</span> Pause</div>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <div class="overlay hidden" id="overlay">
+        <div class="modal" id="modal">
+            <h2 id="modalTitle"></h2>
+            <p id="modalMsg"></p>
+            <button onclick="initGame()">Play Again</button>
+            <button onclick="goBack(); hideOverlay();">Back to Games</button>
+        </div>
+    </div>
+
+    <script>
+        const COLS = 10;
+        const ROWS = 20;
+        const BLOCK_SIZE = 30;
+        const COLORS = [
+            null,
+            '#ffd700',
+            '#ffcc00',
+            '#ffb300',
+            '#ff9800',
+            '#ff5722',
+            '#ffc107',
+            '#ffeb3b'
+        ];
+
+        const SHAPES = [
+            null,
+            [[1, 1, 1, 1]],
+            [[1, 1], [1, 1]],
+            [[0, 1, 0], [1, 1, 1]],
+            [[1, 0, 0], [1, 1, 1]],
+            [[0, 0, 1], [1, 1, 1]],
+            [[1, 1, 0], [0, 1, 1]],
+            [[0, 1, 1], [1, 1, 0]]
+        ];
+
+        const POINTS = [0, 100, 300, 500, 800];
+
+        const canvas = document.getElementById('gameCanvas');
+        const ctx = canvas.getContext('2d');
+        const nextCanvas = document.getElementById('nextCanvas');
+        const nextCtx = nextCanvas.getContext('2d');
+
+        let board = [];
+        let currentPiece = null;
+        let nextPiece = null;
+        let score = 0;
+        let lines = 0;
+        let level = 1;
+        let gameOver = false;
+        let paused = false;
+        let dropInterval = 1000;
+        let lastDrop = 0;
+        let animationId = null;
+
+        function createBoard() {
+            board = [];
+            for (let r = 0; r < ROWS; r++) {
+                board[r] = [];
+                for (let c = 0; c < COLS; c++) {
+                    board[r][c] = 0;
+                }
+            }
+        }
+
+        function randomPiece() {
+            const id = Math.floor(Math.random() * 7) + 1;
+            const shape = SHAPES[id].map(row => [...row]);
+            return {
+                id: id,
+                shape: shape,
+                x: Math.floor(COLS / 2) - Math.floor(shape[0].length / 2),
+                y: 0
+            };
+        }
+
+        function rotatePiece(piece) {
+            const rows = piece.shape.length;
+            const cols = piece.shape[0].length;
+            const rotated = [];
+            for (let c = 0; c < cols; c++) {
+                rotated[c] = [];
+                for (let r = rows - 1; r >= 0; r--) {
+                    rotated[c].push(piece.shape[r][c]);
+                }
+            }
+            return rotated;
+        }
+
+        function isValid(shape, px, py) {
+            for (let r = 0; r < shape.length; r++) {
+                for (let c = 0; c < shape[r].length; c++) {
+                    if (shape[r][c]) {
+                        const nx = px + c;
+                        const ny = py + r;
+                        if (nx < 0 || nx >= COLS || ny >= ROWS) return false;
+                        if (ny >= 0 && board[ny][nx]) return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        function lockPiece() {
+            for (let r = 0; r < currentPiece.shape.length; r++) {
+                for (let c = 0; c < currentPiece.shape[r].length; c++) {
+                    if (currentPiece.shape[r][c]) {
+                        const py = currentPiece.y + r;
+                        const px = currentPiece.x + c;
+                        if (py < 0) {
+                            endGame(false);
+                            return;
+                        }
+                        board[py][px] = currentPiece.id;
+                    }
+                }
+            }
+            clearLines();
+            spawnPiece();
+        }
+
+        function clearLines() {
+            let cleared = 0;
+            for (let r = ROWS - 1; r >= 0; r--) {
+                if (board[r].every(cell => cell !== 0)) {
+                    board.splice(r, 1);
+                    const newRow = [];
+                    for (let c = 0; c < COLS; c++) newRow.push(0);
+                    board.unshift(newRow);
+                    cleared++;
+                    r++;
+                }
+            }
+            if (cleared > 0) {
+                lines += cleared;
+                score += POINTS[cleared] * level;
+                level = Math.floor(lines / 10) + 1;
+                dropInterval = Math.max(100, 1000 - (level - 1) * 80);
+                updateStats();
+            }
+        }
+
+        function spawnPiece() {
+            currentPiece = nextPiece || randomPiece();
+            nextPiece = randomPiece();
+            if (!isValid(currentPiece.shape, currentPiece.x, currentPiece.y)) {
+                endGame(false);
+            }
+        }
+
+        function getDropY() {
+            let dy = currentPiece.y;
+            while (isValid(currentPiece.shape, currentPiece.x, dy + 1)) {
+                dy++;
+            }
+            return dy;
+        }
+
+        function drawBlock(context, x, y, colorId, size) {
+            const color = COLORS[colorId];
+            context.fillStyle = color;
+            context.fillRect(x * size, y * size, size, size);
+            context.fillStyle = 'rgba(255, 255, 255, 0.15)';
+            context.fillRect(x * size, y * size, size, 2);
+            context.fillRect(x * size, y * size, 2, size);
+            context.fillStyle = 'rgba(0, 0, 0, 0.2)';
+            context.fillRect(x * size + size - 2, y * size, 2, size);
+            context.fillRect(x * size, y * size + size - 2, size, 2);
+            context.strokeStyle = 'rgba(0, 0, 0, 0.3)';
+            context.strokeRect(x * size, y * size, size, size);
+        }
+
+        function drawGhost() {
+            const ghostY = getDropY();
+            if (ghostY !== currentPiece.y) {
+                ctx.globalAlpha = 0.2;
+                for (let r = 0; r < currentPiece.shape.length; r++) {
+                    for (let c = 0; c < currentPiece.shape[r].length; c++) {
+                        if (currentPiece.shape[r][c]) {
+                            const color = COLORS[currentPiece.id];
+                            ctx.fillStyle = color;
+                            ctx.fillRect(
+                                (currentPiece.x + c) * BLOCK_SIZE,
+                                (ghostY + r) * BLOCK_SIZE,
+                                BLOCK_SIZE, BLOCK_SIZE
+                            );
+                            ctx.strokeStyle = 'rgba(255, 215, 0, 0.3)';
+                            ctx.strokeRect(
+                                (currentPiece.x + c) * BLOCK_SIZE,
+                                (ghostY + r) * BLOCK_SIZE,
+                                BLOCK_SIZE, BLOCK_SIZE
+                            );
+                        }
+                    }
+                }
+                ctx.globalAlpha = 1;
+            }
+        }
+
+        function draw() {
+            ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+            for (let r = 0; r < ROWS; r++) {
+                for (let c = 0; c < COLS; c++) {
+                    if (board[r][c]) {
+                        drawBlock(ctx, c, r, board[r][c], BLOCK_SIZE);
+                    }
+                }
+            }
+
+            if (currentPiece) {
+                drawGhost();
+                for (let r = 0; r < currentPiece.shape.length; r++) {
+                    for (let c = 0; c < currentPiece.shape[r].length; c++) {
+                        if (currentPiece.shape[r][c]) {
+                            drawBlock(ctx, currentPiece.x + c, currentPiece.y + r, currentPiece.id, BLOCK_SIZE);
+                        }
+                    }
+                }
+            }
+
+            drawNext();
+
+            if (paused) {
+                ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
+                ctx.fillRect(0, 0, canvas.width, canvas.height);
+                ctx.fillStyle = '#ffd700';
+                ctx.font = 'bold 24px Segoe UI';
+                ctx.textAlign = 'center';
+                ctx.fillText('PAUSED', canvas.width / 2, canvas.height / 2);
+                ctx.font = '14px Segoe UI';
+                ctx.fillStyle = '#888888';
+                ctx.fillText('Press P to resume', canvas.width / 2, canvas.height / 2 + 30);
+            }
+        }
+
+        function drawNext() {
+            nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height);
+            if (!nextPiece) return;
+
+            const shape = nextPiece.shape;
+            const size = 22;
+            const offsetX = (nextCanvas.width - shape[0].length * size) / 2;
+            const offsetY = (nextCanvas.height - shape.length * size) / 2;
+
+            for (let r = 0; r < shape.length; r++) {
+                for (let c = 0; c < shape[r].length; c++) {
+                    if (shape[r][c]) {
+                        const x = offsetX + c * size;
+                        const y = offsetY + r * size;
+                        nextCtx.fillStyle = COLORS[nextPiece.id];
+                        nextCtx.fillRect(x, y, size, size);
+                        nextCtx.fillStyle = 'rgba(255, 255, 255, 0.15)';
+                        nextCtx.fillRect(x, y, size, 2);
+                        nextCtx.fillRect(x, y, 2, size);
+                        nextCtx.fillStyle = 'rgba(0, 0, 0, 0.2)';
+                        nextCtx.fillRect(x + size - 2, y, 2, size);
+                        nextCtx.fillRect(x, y + size - 2, size, 2);
+                        nextCtx.strokeStyle = 'rgba(0, 0, 0, 0.3)';
+                        nextCtx.strokeRect(x, y, size, size);
+                    }
+                }
+            }
+        }
+
+        function updateStats() {
+            document.getElementById('score').textContent = score;
+            document.getElementById('lines').textContent = lines;
+            document.getElementById('level').textContent = level;
+        }
+
+        function gameLoop(timestamp) {
+            if (gameOver) return;
+            if (paused) {
+                animationId = requestAnimationFrame(gameLoop);
+                return;
+            }
+
+            if (timestamp - lastDrop > dropInterval) {
+                moveDown();
+                lastDrop = timestamp;
+            }
+
+            draw();
+            animationId = requestAnimationFrame(gameLoop);
+        }
+
+        function moveDown() {
+            if (isValid(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {
+                currentPiece.y++;
+            } else {
+                lockPiece();
+            }
+        }
+
+        function moveLeft() {
+            if (isValid(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) {
+                currentPiece.x--;
+            }
+        }
+
+        function moveRight() {
+            if (isValid(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) {
+                currentPiece.x++;
+            }
+        }
+
+        function rotate() {
+            const rotated = rotatePiece(currentPiece);
+            if (isValid(rotated, currentPiece.x, currentPiece.y)) {
+                currentPiece.shape = rotated;
+            } else if (isValid(rotated, currentPiece.x + 1, currentPiece.y)) {
+                currentPiece.x++;
+                currentPiece.shape = rotated;
+            } else if (isValid(rotated, currentPiece.x - 1, currentPiece.y)) {
+                currentPiece.x--;
+                currentPiece.shape = rotated;
+            }
+        }
+
+        function hardDrop() {
+            const dy = getDropY();
+            score += (dy - currentPiece.y) * 2;
+            currentPiece.y = dy;
+            updateStats();
+            lockPiece();
+        }
+
+        function softDrop() {
+            if (isValid(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {
+                currentPiece.y++;
+                score += 1;
+                updateStats();
+            }
+        }
+
+        function handleKey(e) {
+            if (gameOver) return;
+
+            if (e.key === 'p' || e.key === 'P') {
+                paused = !paused;
+                return;
+            }
+
+            if (paused) return;
+
+            switch (e.key) {
+                case 'ArrowLeft':
+                    e.preventDefault();
+                    moveLeft();
+                    break;
+                case 'ArrowRight':
+                    e.preventDefault();
+                    moveRight();
+                    break;
+                case 'ArrowDown':
+                    e.preventDefault();
+                    softDrop();
+                    break;
+                case 'ArrowUp':
+                    e.preventDefault();
+                    rotate();
+                    break;
+                case ' ':
+                    e.preventDefault();
+                    hardDrop();
+                    break;
+            }
+        }
+
+        function endGame(isWin) {
+            gameOver = true;
+            cancelAnimationFrame(animationId);
+
+            const overlay = document.getElementById('overlay');
+            const modal = document.getElementById('modal');
+            const title = document.getElementById('modalTitle');
+            const msg = document.getElementById('modalMsg');
+
+            modal.className = 'modal lose';
+            title.textContent = 'Game Over';
+            msg.textContent = 'Score: ' + score + ' | Lines: ' + lines;
+
+            overlay.classList.remove('hidden');
+        }
+
+        function showModal(isWin) {
+            const overlay = document.getElementById('overlay');
+            const modal = document.getElementById('modal');
+            const title = document.getElementById('modalTitle');
+            const msg = document.getElementById('modalMsg');
+
+            modal.className = 'modal ' + (isWin ? 'win' : 'lose');
+            title.textContent = isWin ? 'You Win!' : 'Game Over';
+            msg.textContent = isWin ? 'Congratulations! Score: ' + score : 'Better luck next time!';
+
+            overlay.classList.remove('hidden');
+        }
+
+        function hideOverlay() {
+            document.getElementById('overlay').classList.add('hidden');
+        }
+
+        function goBack() {
+            window.location.href = 'index.html';
+        }
+
+        function initGame() {
+            createBoard();
+            score = 0;
+            lines = 0;
+            level = 1;
+            dropInterval = 1000;
+            gameOver = false;
+            paused = false;
+            lastDrop = 0;
+
+            if (animationId) cancelAnimationFrame(animationId);
+
+            updateStats();
+            spawnPiece();
+
+            document.getElementById('overlay').classList.add('hidden');
+
+            animationId = requestAnimationFrame(gameLoop);
+        }
+
+        document.addEventListener('keydown', handleKey);
+        initGame();
+    </script>
+</body>
+</html>