Capítulo core de la guía Neblla — el contrato base del SDK. Imprescindible: el resto de capítulos asumen lo que hay aquí.

Neblla — core

Qué es

Neblla es un SDK multijugador que se carga con una etiqueta <script>. Da salas, mensajería en tiempo real, identidad, persistencia, amigos, pagos e IA — sin servidor propio, sin npm, sin build. El mismo código vale desde el prototipo hasta producción: la lógica de servidor corre en un peer, en WASM o en infraestructura de Neblla sin reescritura (ver servidor.txt). El SDK también funciona desde Node.js sin HTML.

Direcciones

El SDK se sirve desde neblla.com/connect/app/:appId. Esa URL no cambia nunca, se aloje donde se aloje la app.

Conexión

Antes de cualquier código hay que crear la app (en developers.neblla.com o vía MCP); eso devuelve un APP_ID. App mínima:


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Mi App</title>
  <script src="https://neblla.com/connect/app/APP_ID"></script>
</head>
<body>
  <script>
    window.onNeblla = (neblla) => {
      console.log("hola");
    };
  </script>
</body>
</html>

Cuando la página carga, onNeblla se ejecuta con el SDK ya conectado. El script tag NO necesita type="module".

Estructura canónica — 6 ficheros

Si la app vive alojada en Neblla, el link público apunta a index.html. La plantilla canónica son seis archivos; solo index.html es obligatorio, el resto existen si la app los necesita.

Front-end (corre en el navegador):

Server-side (lógica aislada, sin DOM, carpeta server/):

Contrato de la estructura:

Modelo cliente / presentador / servidor

Presentador y servidor son roles distintos. En modo peer pueden coincidir en el mismo dispositivo por casualidad; en infraestructura no, porque el servidor no es un dispositivo.

Contrato events-only

CLIENT y SERVER nunca se llaman directamente. Solo se comunican por eventos:

| Emisor (método) | Receptor (evento) | Semántica | |--------------------------------------|--------------------------|-----------| | sendMessage(data) desde cliente | 'message' en todos | Broadcast entre pares. Te llega a ti mismo con fromMe: true. | | sendMessage(data) desde server | 'messageFromServer' | Voz autoritaria del juego, llega a todos los clientes. | | tellServer(data) (cliente) | 'messageToServer' | Privado al server. Llega a room.js/gathering.js/lobby.js según fase. No se difunde. | | tellPresenter(data) (cliente) | 'messageToPresenter' | Privado al cliente con isPresenter === true. No se difunde. | | setState(state) (server) | 'state' en todos | Estado autoritario. Actualiza neblla.state en todos, incluidos peers de respaldo. |

Los mensajes son JSON abierto y efímeros: usa el server para reenviar estado a los nuevos. Registro de listeners: neblla.on(event, cb) / neblla.off(event, cb) ('*' escucha todos).

Ciclo de vida de una sala

1. lobby — todo usuario conectado aterriza en la sala especial lobby. Para matchmaking, elegir nombre, ver salas — no para jugar. Los eventos llevan un booleano isLobby. 2. gathering — bookRoom({ config? }) reserva una sala con id único (lo elige el servidor, nunca el cliente). Nace en estado gathering, visible desde el lobby vía neblla.gathering. Los jugadores entran con joinRoom(roomId). 3. running — alguien (normalmente el presentador) llama a startRoom(). El SDK elige al server y arranca server/room.js. A partir de ahí funciona tellServer / messageFromServer / setState.

leaveRoom() vuelve al lobby. Un usuario solo puede estar en una sala a la vez. Mismo nombre de sala = mismo grupo. Detalle completo en salas.txt.

Cinco patrones de app

Decide el patrón ANTES de codificar — los esqueletos son distintos. Cuatro preguntas: ¿es multi-usuario? ¿hay autoridad (un server que valida)? ¿esa autoridad muestra UI distinta? y si es multi sin autoridad, ¿salas separadas o un único espacio común?

| Patrón | Autoridad | UI doble | Multi | Salas | Ejemplos | |------------------|----------------|----------|-------|-------|----------| | Turn-based | Sí (server) | No | Sí | Sí | Ajedrez, UNO, conecta 4, hundir la flota | | Host-controllers | Sí (server) | Sí | Sí | Sí | Kahoot, Jeopardy, Pictionary, Hombres lobo | | Collab realtime | No | No | Sí | Sí | Pizarra compartida, canvas, watch party | | Lobby-only | No | No | Sí | No | Mural global, pixel-canvas, cursores en vivo | | Solo + save | — | — | No | No | Hábitos, sudoku, diario |

Se pueden mezclar o inventar patrones propios.

Patrón mínimo de app funcional

Lógica autoritaria — el cliente pide, room.js valida y emite:


// client.js — pedir acción:
neblla.tellServer({ action: 'play-card', card: 5 });

// room.js — validar y emitir estado:
let gameState = neblla.state || initialState();

neblla.on('messageToServer', event => {
  gameState = applyAction(gameState, event.user.id, event.data);
  neblla.setState(gameState);
});

// client.js — reaccionar:
neblla.on('state', state => render(state));

Multiplexar mensajes con un campo type:


neblla.sendMessage({ type: 'state-update', state });

neblla.on('message', event => {
  switch (event.data.type) {
    case 'chat': handleChat(event); break;
    case 'state-update': handleState(event); break;
  }
});

Reglas clave