# GEMINI.md — Reglas del Servidor VIBE Coding

## Arquitectura del Proyecto

Este proyecto es un **juego multijugador en tiempo real** que se ejecuta en el navegador web.
Los estudiantes SOLO escriben código **frontend** (HTML, CSS, JavaScript).
El servidor ya está configurado y funcionando en `code-fiesta.xyz`.

## Reglas Importantes

### 1. Solo Frontend
- Crear ÚNICAMENTE: `index.html`, archivos `.js`, archivos `.css`, e imágenes
- **NO crear** `server.js`, `app.js`, ni ningún archivo de servidor
- **NO usar** `npm install`, `require()`, ni módulos de Node.js
- Todo el código debe funcionar directamente en el navegador

### 2. Estructura de Archivos
```
mi-juego/
├── index.html      (página principal - OBLIGATORIO)
├── style.css       (estilos - opcional)
├── game.js         (lógica del juego - opcional)
└── img/            (imágenes - opcional)
    ├── player.png
    └── enemy.png
```

### 3. Servidor de Juegos - WebSocket API

El servidor multijugador está en: `wss://code-fiesta.xyz/ws`

#### Conectar al servidor:
```javascript
const ws = new WebSocket('wss://code-fiesta.xyz/ws');

ws.onopen = () => {
    console.log('Conectado al servidor');
};

ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    // Manejar mensajes según msg.type
};
```

#### Crear una sala:
```javascript
ws.send(JSON.stringify({
    type: 'CREATE_ROOM',
    nickname: 'MiNombre'
}));
// Respuesta: { type: 'ROOM_CREATED', roomCode: 'ABC123', playerId: '...', players: [...] }
```

#### Unirse a una sala:
```javascript
ws.send(JSON.stringify({
    type: 'JOIN_ROOM',
    roomCode: 'ABC123',
    nickname: 'MiNombre'
}));
// Respuesta: { type: 'ROOM_JOINED', roomCode: '...', playerId: '...', players: [...] }
```

#### Enviar datos a todos en la sala (RELAY):
```javascript
// Enviar a todos los demás jugadores
ws.send(JSON.stringify({
    type: 'RELAY',
    data: {
        action: 'MOVE',
        x: 100,
        y: 200
    }
}));

// Enviar a todos INCLUYÉNDOME a mí mismo
ws.send(JSON.stringify({
    type: 'RELAY',
    data: { action: 'MOVE', x: 100, y: 200 },
    includeSelf: true
}));
```

#### Enviar datos a un jugador específico:
```javascript
ws.send(JSON.stringify({
    type: 'RELAY_TO',
    targetId: 'id_del_jugador',
    data: { action: 'ATTACK', damage: 10 }
}));
```

#### Guardar datos compartidos (estado de la sala):
```javascript
// Guardar
ws.send(JSON.stringify({
    type: 'SET_STATE',
    key: 'puntuaciones',
    value: { jugador1: 10, jugador2: 5 }
}));

// Obtener
ws.send(JSON.stringify({
    type: 'GET_STATE',
    key: 'puntuaciones'
}));
// Respuesta: { type: 'STATE', key: 'puntuaciones', value: { jugador1: 10, jugador2: 5 } }
```

#### Salir de la sala:
```javascript
ws.send(JSON.stringify({ type: 'LEAVE_ROOM' }));
```

### 4. Tipos de Mensajes que Recibe el Cliente

```javascript
ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);

    switch (msg.type) {
        case 'ROOM_CREATED':
            // msg.roomCode, msg.playerId, msg.players
            break;

        case 'ROOM_JOINED':
            // msg.roomCode, msg.playerId, msg.players
            break;

        case 'PLAYER_JOINED':
            // msg.playerId, msg.nickname, msg.players
            break;

        case 'PLAYER_LEFT':
            // msg.playerId, msg.nickname, msg.players
            break;

        case 'RELAY':
            // msg.from.id, msg.from.nickname, msg.data
            break;

        case 'STATE_UPDATED':
            // msg.key, msg.value, msg.updatedBy.id, msg.updatedBy.nickname
            break;

        case 'STATE':
            // msg.key, msg.value
            break;

        case 'ERROR':
            // msg.message
            break;

        case 'LEFT_ROOM':
            // Confirmación de que saliste de la sala
            break;
    }
};
```

### 5. Límites del Servidor
- Máximo **30 jugadores** por sala
- Máximo **20 archivos** por upload
- Máximo **5 MB** por archivo
- Código de sala: 6 caracteres (letras y números)
- Nickname: máximo 20 caracteres

### 6. Subir el Juego al Servidor
1. Abrir `https://code-fiesta.xyz` en el navegador
2. Escribir el nombre del equipo (en inglés, sin espacios)
3. Seleccionar TODOS los archivos del juego
4. Hacer clic en "Upload"
5. El juego estará disponible en: `https://code-fiesta.xyz/students/NOMBRE_EQUIPO/`

### 7. Ejemplo Completo: Juego Mínimo Multijugador

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mi Juego Multijugador</title>
    <style>
        body { font-family: sans-serif; text-align: center; padding: 20px; }
        canvas { border: 2px solid #333; display: block; margin: 20px auto; }
        input, button { font-size: 1.2rem; padding: 10px; margin: 5px; }
    </style>
</head>
<body>
    <div id="lobby">
        <h1>Mi Juego</h1>
        <input type="text" id="nickname" placeholder="Tu nombre">
        <br>
        <button onclick="createRoom()">Crear Sala</button>
        <br>
        <input type="text" id="roomCode" placeholder="Código de sala">
        <button onclick="joinRoom()">Unirse</button>
        <p id="status"></p>
    </div>

    <div id="game" style="display:none;">
        <h2>Sala: <span id="roomDisplay"></span></h2>
        <p>Jugadores: <span id="playerList"></span></p>
        <canvas id="canvas" width="600" height="400"></canvas>
    </div>

    <script>
        const ws = new WebSocket('wss://code-fiesta.xyz/ws');
        let myId = null;
        let players = {};

        ws.onopen = () => {
            document.getElementById('status').textContent = 'Conectado al servidor';
        };

        ws.onmessage = (event) => {
            const msg = JSON.parse(event.data);

            if (msg.type === 'ROOM_CREATED' || msg.type === 'ROOM_JOINED') {
                myId = msg.playerId;
                document.getElementById('lobby').style.display = 'none';
                document.getElementById('game').style.display = 'block';
                document.getElementById('roomDisplay').textContent = msg.roomCode;
                updatePlayerList(msg.players);
            }

            if (msg.type === 'PLAYER_JOINED' || msg.type === 'PLAYER_LEFT') {
                updatePlayerList(msg.players);
            }

            if (msg.type === 'RELAY') {
                // Aquí manejar los datos del juego
                // msg.from.id, msg.from.nickname, msg.data
            }

            if (msg.type === 'ERROR') {
                document.getElementById('status').textContent = 'Error: ' + msg.message;
            }
        };

        function createRoom() {
            const nickname = document.getElementById('nickname').value || 'Jugador';
            ws.send(JSON.stringify({ type: 'CREATE_ROOM', nickname }));
        }

        function joinRoom() {
            const nickname = document.getElementById('nickname').value || 'Jugador';
            const roomCode = document.getElementById('roomCode').value;
            ws.send(JSON.stringify({ type: 'JOIN_ROOM', roomCode, nickname }));
        }

        function updatePlayerList(playerArray) {
            document.getElementById('playerList').textContent =
                playerArray.map(p => p.nickname).join(', ');
        }

        // === Tu lógica de juego va aquí ===

    </script>
</body>
</html>
```

## Consejos para Gemini CLI

Cuando pidas a Gemini que cree un juego, incluye esto en tu prompt:
- "Create a multiplayer browser game using ONLY frontend code (HTML, CSS, JavaScript)"
- "Use WebSocket connection to wss://code-fiesta.xyz/ws for multiplayer"
- "Follow the API described in GEMINI.md"
- "Do NOT create any server-side code"
- "The game must work as a single index.html file or a few static files"