Apps de mesa

Escribe una pequeña página —un puzzle, una consola, una votación— y preséntala a tus jugadores: las cuatro plantillas, cómo hablar con la mesa, por qué la respuesta no puede ir en el código, los recursos y lo que dentro de la caja no existe.

Una app de mesa es una pequeña página que escribes tú —HTML, CSS y JavaScript— y que enseñas a tus jugadores como una ventana flotante más. Un puzzle que tocan todos a la vez, una consola de nave, un mapa de estrellas que reacciona, una votación, una cuenta atrás.

No hace falta saber programar para usarla: hay cuatro plantillas que funcionan tal cual y a las que solo hay que cambiarles dos cosas.


Dónde está

Modo Inmersión → Mostrar a la mesa → pestaña App.

Ahí tienes las plantillas, tus apps guardadas y el botón Ampliar, que abre el editor a pantalla completa con resaltado, avisos en línea, autocompletado y la subida de recursos. Para escribir de verdad, usa el grande.


El camino corto

  1. Pulsa Cerradura de runas. Se rellena todo, incluida la respuesta.
  2. Pulsa Probar: la ves tal y como la verán ellos.
  3. Pulsa Presentar a la mesa.

Ya está. Aparece como ventana flotante para todos los miembros de la campaña, se mueve, se redimensiona, se minimiza y se retira con la papelera (que la quita para todos).


Cómo funciona por debajo, en una frase

Tu código se ejecuta en el navegador de cada jugador, dentro de una caja aislada. Esa caja es lo que hace que esto pueda existir sin ser un peligro: tu app no puede ver la sesión de nadie, ni sus datos, ni mandar nada fuera.

A cambio, hay cosas que fuera funcionan y aquí no. No son caprichos; cada una tapa un agujero concreto. Están todas en la pestaña Ayuda del editor, y el linter te avisa mientras escribes.

No existeQué pasaEn su lugar
localStorage, sessionStorageLanzan un errorUna variable; y roliando.guardar() para lo que deba durar
alert, confirm, promptBloqueadosPinta el mensaje en la página
fetch, XMLHttpRequestNo hay redroliando.enviar() para hablar con la mesa
window.openBloqueado
import, requireNo hay módulosPega lo que necesites

El sonido sí funciona, pero no arranca hasta que alguien toca la ventana. Crea o reanuda tu AudioContext dentro de un clic, o llama a roliando.sonar() desde uno.


Hablar con la mesa

Dentro de tu app tienes un objeto roliando. Es todo lo que puedes pedirle a Roliando, y no hay nada más:

roliando.yo                    // { nombre, esMaster } — quién está mirando
roliando.assets                // { nombre: url } de lo que hayas subido
roliando.estado                // lo que guardaste la última vez (o null)

roliando.enviar(datos)                        // mándalo a los demás, ahora
roliando.alRecibir(function (datos, quien) {}) // escucha lo que mandan ellos
roliando.guardar(datos)                       // que sobreviva a recargar

await roliando.comprobar(intento)   // → { ok, intentos, agotado }
`roliando.alAbrir(fn)` — el máster la ha abierto a mano desde «En la mesa»: enseña lo que
enseñarías al acertar. Llega una vez, y también al abrir la app si ya estaba abierta.

roliando.resuelto('ha abierto la cerradura.')  // al chat de la campaña
roliando.sonar('gong')                         // por el volumen de cada uno

roliando.alProgreso(function (lista) {})  // quién va por dónde (solo si diriges)

Que todos vean lo mismo

enviar y alRecibir son las dos mitades de lo mismo. Una app que solo manda es una app donde cada uno ve lo suyo:

// Al girar una runa: que los demás la vean girar
roliando.enviar({ giros: giros });

// Y al revés
roliando.alRecibir(function (datos) {
  if (datos.giros) { giros = datos.giros; pintar(); }
});

enviar es rápido y efímero: para lo que se toca en vivo. Lo que debe seguir ahí después de un F5 va en guardar, que persiste de verdad y va más espaciado. Lo normal es llamar a los dos.

Las dos caras de una app

El mismo código recibe roliando.yo.esMaster. Los jugadores ven la cerradura; tú ves el tablero:

if (roliando.yo.esMaster) {
  roliando.alProgreso(function (lista) {
    // [{ nombre: 'Cerbrick', intentos: 3, resuelto: false }, ...]
    pintarTablero(lista);
  });
}

La respuesta de un puzzle

Esto es lo más importante de toda la guía. Tu código viaja al navegador de tus jugadores para ejecutarse allí, así que cualquier cosa escrita dentro se puede leer. Una solución en el código es una solución publicada.

Por eso hay un campo La respuesta, abajo a la derecha en el editor grande. Lo que pongas ahí se queda en el servidor y no viaja a nadie. Tu app solo puede preguntar:

roliando.comprobar(giros).then(function (r) {
  if (r.ok) { /* abierta */ }
  else if (r.agotado) { /* se acabaron los intentos */ }
  else { /* falló: r.intentos dice cuántas veces lleva */ }
});

La respuesta puede ser una lista (["ᛁ","ᚦ","ᚠ","ᛚ"]), un número, un objeto o una palabra suelta: se compara con lo que tu app manda a comprobar.

El tope de intentos

Con la respuesta a salvo, lo único que puede hacer alguien que quiera saltárselo es probar combinaciones. Cuatro runas con seis símbolos son 1.296, que un bucle prueba en un suspiro.

El campo intentos pone un tope por persona. Vacío = sin tope, que para un acertijo de ambiente está bien. Y esa misma cuenta es la que alimenta tu tablero.


Imágenes y sonidos

Pestaña Recursos del editor grande. Lo que subas ahí son las únicas direcciones que tu app puede cargar: cualquier otra se bloquea, y lo hace en silencio (no falla, simplemente no aparece). El linter te avisa si escribes una dirección de fuera.

En el código los pides por su nombre:

<img id="mapa">
document.getElementById('mapa').src = roliando.assets.mapa_estelar;
roliando.sonar('gong');

sonar es mejor que un <audio> a pelo: suena fuera de la app, por el volumen de efectos que cada jugador ya tiene puesto, así que respeta su slider y no se pelea con la llamada de voz.


Guardar y reutilizar

Guardar deja la app en tu biblioteca con su respuesta y su tope. Aparece en Mis apps y vuelve al editor de un clic. Es lo que convierte «me monté un puzzle» en «tengo mis puzzles».


Las cuatro plantillas

Qué esQué tocar
Cerradura de runasCuatro runas que giran; la combinación la comprueba el servidorLos cuatro índices de la respuesta
Votación de la mesaUna pregunta, unas opciones, recuento en vivoLa pregunta y las opciones, primera línea del JS
Cuenta atrásEl reloj corre para todos; lo lleva el másterSEGUNDOS
Pizarra compartidaUn lienzo donde dibujan todos a la vezNada

La cuenta atrás la lleva uno solo y los demás la siguen, y es a propósito: con dos relojes corriendo a la vez las cuentas compartidas se descuadran.


Límites

  • Tres apps a la vez por mesa. Cada una es una página web con su JavaScript corriendo en el navegador de todos; a partir de ahí estorba más de lo que aporta.
  • 60.000 caracteres entre HTML, CSS y JS.
  • Cuenta con una o dos décimas de segundo de ida y vuelta. Para puzzles, diales, palancas y revelados es invisible. Para nada que dependa de reflejos, no da.
  • El sonido suena en todos, pero cada navegador arranca cuando le llega el mensaje. Para ambiente y golpes de tensión sobra; para algo sincronizado al milisegundo, no.
  • En modo emisión la app se ve, pero ahí es una foto: nadie la toca.
  • En la sala de espera todavía no se pueden presentar.

Si algo no va

«No se ve nada». Mira el contador de errores arriba: un fallo de sintaxis deja la app muda —se pinta el HTML y no pasa nada más—, que desde fuera parece que no funciona sin más pista.

«La imagen no carga». ¿La subiste en Recursos? Si es una dirección de fuera, se bloquea sin avisar.

«Dice que no aunque acierto». ¿Está puesta La respuesta? Sin ella, comprobar dice que no a todo.

«Cada uno ve una cosa». Te falta roliando.alRecibir: estás mandando pero no escuchando.

«No suena». El navegador no deja sonar hasta que alguien toca la ventana. Arranca el audio desde un clic.

Todas las guías de Roliando