Modo código (estilo Roll20)
Construye tu sistema escribiendo HTML, CSS y sheet-workers como en Roll20: transpilador, sandbox aislado, botones de tirada y vuelta al código.
El modo código te deja construir un sistema escribiendo, con las mismas palabras que usabas en el creador de fichas de Roll20: attr_, @{}, repeating_, rolltemplate y sheet-workers. Tu código no se "ejecuta tal cual": se compila al motor de Roliando, así que obtienes campos, diseño, tiradas y automatización de verdad, integrados con el resto de la app (combate, tokens, chat, permisos).
Para quién es:
- Vienes de Roll20 y quieres traerte tu ficha sin volver a montarla a mano.
- Prefieres escribir a arrastrar widgets.
- Quieres tocar el CSS o automatizar cálculos con JavaScript.
No necesitas usarlo para todo: puedes transpilar tu HTML una vez y seguir en el creador visual, o al revés (generar el código desde un sistema que ya tenías).
Cómo abrirlo
- Entra a Taller → tu sistema → Editar (en la piel clásica el Taller se llama Creaciones).
- En la cabecera pulsa Código.
Verás cinco pestañas: HTML, CSS, Sheet Workers, Roll Template y Glosario, con una vista previa viva al lado.
El CSS y la plantilla de tirada son los mismos que la pestaña Estilo del creador: edites donde edites, es el mismo contenido.
Antes de nada: cómo es de seguro
Tu sistema lo ven otras personas en su navegador, así que hay tres reglas que no se saltan:
| Pieza | Qué pasa de verdad |
|---|---|
| HTML | Nunca se muestra en crudo. Se transpila a campos + diseño (widgets). Es una entrada de datos, no una plantilla que se inyecta. |
| CSS | Se filtra y se acota a tu ficha (nunca afecta al resto de la app). Solo admite imágenes y tipografías subidas por ti. |
| Sheet Workers | Corren en un sandbox aislado (QuickJS): sin acceso al navegador, sin red, sin datos de otras personas. |
Esto también significa que hay cosas de Roll20 que no se pueden replicar tal cual (un <div> con maquetación libre, por ejemplo): tu markup se traduce a los widgets de Roliando. Lo que ganas a cambio es que la ficha funciona en móvil, en el VTT y con el motor de reglas.
Pestaña HTML
Aquí pegas o escribes el markup. Tiene tres botones:
- Transpilar a campos + diseño — convierte el HTML en un sistema real.
- Separar hoja completa — si pegaste el archivo entero de Roll20 (con
<style>y<script type="text/worker">dentro), reparte cada parte a su pestaña. - Generar desde el sistema — la operación inversa: escribe el HTML a partir de los campos y el diseño que ya tienes.
Qué reconoce el transpilador
| Escribes (Roll20) | Obtienes (Roliando) | |
|---|---|---|
<input type="number" name="attr_fuerza" value="10"> | Campo número fuerza con valor por defecto 10 | |
<input type="text" name="attr_nombre"> | Campo texto | |
<textarea name="attr_notas"> | Campo texto (multilínea) | |
<input type="checkbox" name="attr_escudo"> | Campo sí/no | |
<select name="attr_clase"> + <option> | Campo selección con sus opciones | |
Grupo de <input type="radio" name="attr_x"> | Campo selección (las opciones son los value) | |
attr_hp y attr_hp_max (o `name="hp\ | max"`) | Un solo campo recurso (actual/máximo) |
<span name="attr_mod"> | Campo número de solo mostrar | |
<fieldset class="repeating_ataques"> | Widget filas dinámicas con sus columnas | |
<button type="roll" value="/roll 1d20+@{fuerza}"> | Botón de tirada + su campo rollable | |
<h1>…<h4>, <legend> | Separador de sección |
La etiqueta de cada campo se saca, por este orden: del <label> que lo envuelve, del atributo title/placeholder, del texto anterior, y si no, de la propia clave.
Ejemplo mínimo
<h3>Atributos</h3>
<label>Fuerza <input type="number" name="attr_fuerza" value="10"></label>
<label>Destreza <input type="number" name="attr_destreza" value="10"></label>
<span name="attr_mod_fuerza"></span>
<input type="number" name="attr_pv" value="20">
<input type="number" name="attr_pv_max" value="20">
<label>Clase</label>
<select name="attr_clase" title="Clase">
<option value="guerrero">Guerrero</option>
<option value="mago">Mago</option>
</select>
<button type="roll" name="roll_iniciativa" value="/roll 1d20+@{destreza}">Iniciativa</button>Al pulsar Transpilar verás un resumen (cuántos campos, recursos, listas, tiradas) y los avisos de lo que se aproximó. Después eliges:
- Reemplazar campos y diseño — deja el sistema tal cual dice el HTML. Pide confirmación porque borra lo que hubiera.
- Añadir lo nuevo — conserva tus campos y solo suma los que faltaban.
Tras aplicar, afina en las pestañas Campos y Diseño como en cualquier sistema.
Traer tu ficha de Roll20 entera
- Abre tu ficha en Roll20 y copia el HTML completo (si tienes un solo archivo con estilos y workers dentro, mejor).
- Pégalo en la pestaña HTML.
- Pulsa Separar hoja completa: el
<style>se va a CSS y cada<script type="text/worker">a Sheet Workers. Cualquier otro<script>se descarta (nunca se ejecuta) y se te avisa de cuántos. - Pulsa Transpilar a campos + diseño y aplica.
Con eso tienes campos, diseño, estilo y automatización de tu ficha original.
Para traer personajes (no la ficha, sino las fichas rellenadas de tus jugadores) existe el importador aparte, en la pantalla de fichas.
Pestaña CSS
Escribe CSS normal. Por debajo, cada selector se acota a tu ficha.
.charsheet(la raíz en Roll20) equivale a la raíz de la ficha aquí: puedes usarla igual.- Tus clases
.sheet-loquesease conservan. html,bodyy:rootse traducen también a la raíz de la ficha.
Además tienes ganchos estables para pintar las piezas de Roliando:
| Selector | Qué es |
|---|---|
.sys-sheet | Toda la ficha |
.sys-tab | La rejilla de una pestaña |
.sys-widget | Cualquier tarjeta de widget |
.sys-widget-stat_block | Tarjetas de característica (y así con cada tipo) |
.sys-sheet.sys-roll-card | La tarjeta de resultado de una tirada (compuesto, sin espacio) |
.sys-roll-message[data-kind="critico"] | El mensaje según resultado: critico, exito, fallo, pifia |
.charsheet { background: #101018; }
.sheet-stats input { text-align: center; }
.sys-widget-stat_block { border-color: #b8860b; }
.sys-roll-message[data-kind="critico"] { font-weight: 700; }Qué se filtra: se descartan propiedades no visuales, @import, url() externos, expression, javascript: y selectores raros. position: fixed pasa a absolute para que nada tape la app. Verás la lista exacta de lo descartado bajo el editor.
Imágenes y tipografías: por seguridad solo se admiten las que subas tú. Súbelas desde la pestaña Estilo del creador y púlsalas para insertarlas (una fuente entra ya como @font-face lista para usar).
Pestaña Sheet Workers
Automatización con JavaScript, igual que en Roll20:
on("change:fuerza", function() {
getAttrs(["fuerza"], function(v) {
setAttrs({ mod_fuerza: Math.floor((Number(v.fuerza) - 10) / 2) });
});
});Pulsa Probar con datos de ejemplo para ejecutarlo ahí mismo: verás qué campos cambiarían, lo que imprimas con console.log y cualquier error.
Qué tienes disponible
| Función | Qué hace |
|---|---|
on("change:clave", fn) | Reacciona al cambio de un campo. Acepta varios separados por espacios. |
on("sheet:opened", fn) | Se dispara al recalcular la ficha. |
getAttrs(["a","b"], fn) | Lee campos. El callback recibe un objeto con sus valores. |
setAttrs({ a: 1 }) | Escribe campos. |
getSectionIDs(sec, fn) | Devuelve lista vacía (las filas dinámicas aún no se recorren). |
console.log(...) | Sale en el panel de la prueba. |
Math, JSON, String, Number… | Los objetos estándar de JavaScript. |
Qué NO existe dentro (a propósito)
fetch, XMLHttpRequest, setTimeout, document, window, process, require, WebAssembly. No hay red, ni DOM, ni forma de ver datos de otras personas. Si tu worker los usa, dará error dentro del sandbox y el resto seguirá funcionando.
Límites
- Tiempo: si un worker se cuelga (un
while(true)), se corta solo. No congela la ficha. - Memoria: 16 MB por ejecución.
- Cascada: si un
setAttrsdispara otroon("change:…"), se encadena hasta 8 vueltas. - Valores:
setAttrssolo guarda números, textos y sí/no. Objetos y arrays se ignoran.
Cuándo se ejecutan en la partida
En la ficha real se recalculan solos cuando algo cambia y al abrirla. Solo recalcula y guarda quien puede editar (el dueño o el máster); el resto ve los valores ya guardados.
Consejo: escribe workers idempotentes (que con los mismos datos de entrada den siempre el mismo resultado). Un worker que hace
setAttrs({ x: x + 1 })se recalcularía en bucle; hay un tope que lo corta, pero el resultado no tendrá sentido.
Pestaña Roll Template
Es tu <rolltemplate>: cómo se ve la tarjeta cuando alguien tira. Markdown con valores del resultado.
**{{etiqueta}}** — sacó **{{total}}**
{{#if critico}}¡CRÍTICO!{{else}}{{#if pifia}}pifia{{/if}}{{/if}}| Valor | Qué trae |
|---|---|
{{total}} | El resultado final |
{{etiqueta}} | Nombre de la tirada |
{{resultado}} | Éxito / Fallo / Crítico / Pifia |
{{critico}}, {{pifia}}, {{exito}}, {{fallo}} | 1 o 0, para usar con {{#if}} |
{{objetivo}} | El umbral, si lo había |
{{#each dados}}{{this}} {{/each}} | Los dados uno a uno |
También puedes usar cualquier campo de la ficha. Y la vistes con CSS mediante .sys-roll-message.
Referencias: @{} y compañía
Puedes escribir referencias como en Roll20 y funcionan igual:
| Roll20 | Equivale a | Dónde vale | ||
|---|---|---|---|---|
@{fuerza} | {{fuerza}} | Textos vivos, plantilla de tirada, fórmulas de botones | ||
| `@{selected\ | hp} / @{target\ | ca}` | {{hp}} / {{ca}} | Igual |
| `@{hp\ | max}` | {{hp_max}} | Igual |
Las dos sintaxis conviven: usa la que te salga.
Botones de tirada, en detalle
Un <button type="roll" value="/roll 1d20+@{fuerza}+2">Ataque</button> se convierte en:
- Un campo rollable propio del botón (llamado
roll_ataque), con el dado (1d20) y el bono (fuerza + 2) ya puestos. - Un botón en el diseño que lo lanza.
Es una tirada simple: da el total, sin éxito/fallo (la dificultad la pone el máster, como /roll). Si quieres umbral, crítico o modos de tirada, ajusta el campo en Campos o las reglas globales en Reglas de tirada.
El botón no toca tus características: crea su propio campo, así dos botones que usan la misma característica no se pisan.
Glosario rápido
| En Roll20 | En Roliando |
|---|---|
attr_fuerza | Campo fuerza |
attr_hp + attr_hp_max | Campo recurso (actual/máx) |
@{fuerza} | {{fuerza}} |
repeating_ataques | Widget de filas dinámicas |
<rolltemplate> | Plantilla de tirada |
| sheet-worker | Automatización (sandbox) |
.charsheet | .sys-sheet (raíz de la ficha) |
Lo tienes también dentro del editor, en la pestaña Glosario.
Volver del sistema al código
Generar desde el sistema escribe el HTML a partir de los campos y el diseño actuales. Sirve para abrir en modo código un sistema que montaste con el creador visual, tocarlo como texto y transpilarlo de vuelta.
El viaje de ida y vuelta conserva clave, tipo, etiqueta, opciones de los desplegables, los recursos con su máximo y la clave de los botones de tirada.
Límites conocidos
Cosas que hoy no se traducen (te avisa el propio transpilador cuando las detecta):
%{habilidad}(tiradas por nombre de Roll20).- Las pestañas de Roll20 (esos
<input type="radio" class="sheet-tab">): todo cae en una sola pestaña. Reorganízalo luego en Diseño. - Un campo derivado de Roliando sale como
<span>al generar código: Roll20 no tiene derivados (allí eso lo hacen los workers), así que al volver se importa como número. - Dentro de las filas dinámicas, las fórmulas por fila y los botones de tirada se colocan pero no se cablean solos.
- Maquetación libre (
<div>con clases y posiciones): tu markup se traduce a widgets, no se copia píxel a píxel.
Problemas frecuentes
"No se reconoció ningún campo" Tu HTML no tiene name="attr_…". Es lo único que el transpilador considera un campo.
"El worker no cambia nada" Comprueba que el nombre del evento coincide con la clave del campo (no con su etiqueta): on("change:fuerza") funciona si el campo es fuerza. Pulsa Probar para verlo.
"Mi CSS no se aplica" Mira los avisos bajo el editor: puede que la propiedad no esté permitida o que el url() apunte fuera. Sube la imagen desde Estilo y vuelve a insertarla.
"He transpilado y he perdido campos" Usaste Reemplazar. Usa Añadir lo nuevo para conservar lo que ya tenías.
"La tirada no da éxito ni fallo" Es lo esperado: un /roll de Roll20 es una tirada simple. Configura el umbral en el campo o en las reglas de tirada del sistema.
Tamaños máximos
HTML 30.000 caracteres · Sheet Workers 30.000 · CSS 20.000 · Plantilla de tirada 2.000.