Arquitectura de la misión
No hay scripts. Hay lógica: cómo están organizados los nodos y las variables en Romergo
Cuando se habla de lógica en el editor de juegos, generalmente se llega rápidamente a los scripts. En algún lugar el autor escribe JavaScript, en otro Python, y en otro estudia su propio lenguaje de motor. Esto da una libertad casi ilimitada, pero junto con ella trae errores de sintaxis, bucles colgados, plugins incompatibles y código que seis meses después da miedo abrir incluso al propio autor.
En Romergo tomé otro camino. No hay scripts arbitrarios dentro de la misión. No se puede insertar una función, hacer una solicitud de red o acceder directamente al reproductor. En cambio, la historia se construye a partir de un conjunto limitado pero suficientemente expresivo: nodos lógicos, variables, condiciones y efectos.
Esto no significa que en Romergo solo se puedan hacer bifurcaciones simples. Se puede recordar las decisiones del jugador, contar puntos, mostrar y ocultar opciones, elegir diferentes rutas en los capítulos siguientes, crear eventos aleatorios y generar interfaces interactivas. Simplemente, en lugar de la orden "ejecuta este código", el autor describe "en tal estado debería ocurrir esto".
El gráfico ya es un programa
La lógica más básica Romergo está directamente en el mapa del capítulo. Las escenas se conectan mediante transiciones, y los nodos especiales deciden hacia dónde continuará la experiencia.
Si se simplifica mucho, una pequeña misión se ve así:
Inicio
↓
Conversación con el guardia
↓
¿Tienes pase?
├─ sí → Archivo cerrado
└─ no → Camino alternativo
Esta ya es una lógica ejecutable. Player entra en el nodo de inicio, muestra la escena, lee el estado de la historia y elige la transición adecuada. El autor ve la misma ruta como un mapa comprensible, y no como un conjunto de if, goto e identificadores de servicio.

*Fragmento del Flow real en Builder: la escena Final Accusation transmite la decisión a Switch, luego varios If / Else verifican el estado y ramifican la historia hacia diferentes finales. El panel abierto de Logic en la parte inferior muestra todo el conjunto disponible: Dead End, Checkpoint, If / Else, Switch, Random y Teleport.*
Actualmente, en el panel de lógica hay seis nodos principales:
- **Fin del juego** detiene la ruta actual. Esto puede ser una derrota, un mal final o simplemente un resultado cerrado intencionalmente.
- **Punto de control** guarda el estado en este punto y comienza una nueva historia de retorno. El jugador podrá regresar al punto de control, pero no retroceder más allá de él.
- **Si / Sino** comprueba una regla. La salida verdadera sigue la condición que coincide, la falsa permanece como ruta alternativa.
- **Interruptor** es adecuado cuando hay más de dos opciones. Sus ramas se comprueban de arriba hacia abajo: se activa la primera condición que coincide, y la rama sin condición se convierte en la opción por defecto.
- **Aleatorio** selecciona una de las salidas conectadas. La aleatoriedad guarda la semilla y el paso en el estado de progreso, por lo que la partida guardada se puede restaurar sin lanzar caóticamente al jugador a otra ruta.
- **Teletransportar** no decide nada por sí mismo. Ayuda a romper una larga conexión visual y a conectar cuidadosamente partes distantes de un gran mapa.
Inicio y Fin enmarcan el capítulo, las escenas normales muestran el contenido, y los nodos lógicos los convierten en una ruta. Ya en este nivel se puede crear una historia lineal, una bifurcación, varios finales, un evento aleatorio y un punto de retorno seguro, sin una sola línea de script.
Una variable es la memoria de la historia
Un solo grafo no es suficiente si la historia debe recordar lo que ocurrió antes. Para esto, en la misión hay variables de tres tipos simples:
booleanalmacena un hecho: si se ha encontrado la llave, si el héroe ha mentido, si la alarma está encendida;numberalmacena un número: confianza, salud, cantidad de pruebas o puntos de reputación;stringalmacena un valor elegido: el nombre de la ruta, la facción o el código de la decisión.
Cada variable tiene una clave, una etiqueta comprensible para el autor y un valor inicial. A una variable numérica se le pueden describir adicionalmente un mínimo y un máximo, y una variable de servicio se puede ocultar del panel de estado del jugador o mostrar solo al cumplirse una condición.
Lo principal aquí es que las variables pertenecen a la totalidad de la partida del quest, y no a una sola escena. Si en el primer capítulo el jugador obtuvo un pase, en el cuarto capítulo se puede comprobar la misma bandera. Al pasar por la meta hacia el siguiente capítulo, el estado no se reinicia. Se conserva junto con las opciones elegidas, los efectos aplicados, el punto de control y el paso actual de aleatoriedad.
Se obtiene un sencillo ciclo del autor:
la elección del jugador registra un valor
↓
la variable almacena el estado
↓
la condición lo lee más tarde
↓
el gráfico, la escena o la interfaz reacciona
Por ejemplo, en la primera escena la elección «Mostrar la foto encontrada» puede establecer portrait_revealed = true. Más tarde, el nodo **Si / Sino** verificará esta bandera y abrirá una nueva escena de conversación. Aún más tarde, la interfaz del terminal mostrará una entrada adicional solo a los jugadores que revelaron la foto.
Una variable conecta tres partes diferentes de la misión. Para esto no es necesario pasar manualmente el valor entre escenas o capítulos: todas leen un mismo estado general de progreso.

*La variable route en una tarjeta tiene asignada una clave estable, un nombre comprensible, un tipo de valor y la visibilidad del estado. Las conexiones con elecciones y ramas se encuentran más abajo en la misma página.*
Las elecciones escriben, las ramas leen
En una escena normal, la forma más comprensible de cambiar el estado es agregar un efecto a la opción de elección. En el editor visual, esto se ve como una asignación:
«Confiar en Mary» → ally = "mary"
«Irse solo» → ally = "none"
Después de esto, Switch puede dirigir al jugador a la escena deseada según el valor de ally. La página de variables muestra por separado qué elecciones registran la variable y qué ramas la leen. Es un pequeño detalle, pero en una gran aventura reemplaza la búsqueda agotadora a través de decenas de escenas.

*Las ramas Switch se verifican de arriba hacia abajo. En este ejemplo, la ruta Laboratory se activa en route = lab, y Habitat en route = habitat.*
Las condiciones admiten comparaciones habituales:
- igual y diferente;
- mayor, mayor o igual;
- menor, menor o igual;
- el valor existe o aún no se ha creado.
En el caso simple, el autor elige la variable, el operador y el valor directamente en la configuración de If / Else o Switch. Para una lógica más compuesta, el runtime general entiende grupos **todas las condiciones**, **cualquier condición** y negación.
Esta regla se puede describir estructuralmente:
{
"op": "all",
"conditions": [
{ "op": "gte", "key": "evidence", "value": 3 },
{ "op": "eq", "key": "alarm_active", "value": false }
]
}
Se parece a un pequeño script, pero fundamentalmente no lo es. Aquí no se puede llamar a una función ni cambiar algo de forma aleatoria. Romergo conoce de antemano todas las operaciones permitidas, verifica la estructura y la ejecuta de la misma manera en la vista previa Builder y en el Player publicado.
Efectos: pequeños comandos sin lenguaje de programación
La condición lee el estado, y el efecto lo cambia. Runtime Romergo admite varias operaciones atómicas:
setescribe un valor específico;incydecincrementan o decrementan un número;togglecambia un indicador lógico;clampmantiene un número dentro de un límite dado.
En el inspector normal de selección, el escenario principal es deliberadamente simple: seleccionar una variable y registrar un nuevo valor a través de set. En la lógica avanzada de las escenas de la interfaz, las condiciones y los efectos se pueden establecer como estructuras verificables. Por ejemplo, la transición entre estados del terminal puede al mismo tiempo recordar una decisión, agregar una evidencia y activar la alarma:

*El efecto está vinculado directamente a la opción de respuesta: tres opciones escriben en route los valores lab, habitat y server. El campo de la variable y el nuevo valor siguen siendo separados incluso en el inspector estrecho.*
[
{ "op": "set", "key": "terminal_decision", "value": "cut-power" },
{ "op": "inc", "key": "evidence", "amount": 1 },
{ "op": "toggle", "key": "alarm_active" }
]
Este enfoque tiene una limitación importante: no es una calculadora de fórmulas arbitrarias. No se puede escribir evidence * trust / 2, ejecutar un ciclo o crear su propia función. El comportamiento complejo se construye a partir de varios pasos explícitos, y la expansión de la lógica se realiza a través de nuevas operaciones verificables runtime, y no mediante la ejecución de código desconocido.
Para el autor, esto es un poco menos ilimitado, pero la historia sigue siendo predecible. Los mismos efectos se pueden verificar antes de la publicación, guardar, sincronizar entre jugadores y reproducir después de cargar el progreso.
Por qué dentro del nodo lógico todavía no hay otro Flow
A pesar de toda la predictibilidad, el enfoque actual tiene una desventaja honesta: para una persona sin experiencia en desarrollo, la forma «variable — operador — valor» ya puede parecer programación. Y cuando aparecen grupos de condiciones y varios efectos, la estructura declarativa sigue siendo segura para Player, pero no necesariamente se vuelve simple para el autor.
Parece natural llegar algún día a nodos visuales y dentro de la propia lógica. En lugar de una lista de condiciones, se podrían conectar los bloques **Y**, **O**, **NO**, comparar variables y cambiar valores. En papel, esto parece más amigable que el texto o JSON.
Pero luego me imagino un escenario real: el autor abre un nodo lógico en el mapa del capítulo y dentro de él descubre otro Flow con sus propios nodos y conexiones. Resulta un gráfico dentro de un gráfico. Hay que entender dónde te encuentras ahora, cómo regresar al nivel de la historia y en cuál de los dos Flow buscar el error. Para un principiante, tal anidamiento puede parecer más aterrador que la forma actual.
Por lo tanto, por ahora se utiliza un compromiso. La ruta de la historia permanece visual, y las condiciones y efectos dentro de los nodos se muestran en campos explícitos compactos. Esto funciona, pero no considero que la interfaz esté completamente resuelta. Quizás más adelante aparezca una combinación más clara de plantillas listas, configuración paso a paso y bloques visuales, una que realmente reduzca la complejidad, y no simplemente la transfiera a otro editor.
La lógica vive no solo en el mapa
Las escenas de la interfaz utilizan el mismo estado. Un widget, mensaje, opción de respuesta, tarea, notificación o flujo de medios puede aparecer solo si coincide showWhen. El valor de la métrica se puede vincular a una variable, y la transición entre estados del widget se puede iniciar después de un retraso, según una condición o después de la acción del jugador.
Por ejemplo, la pantalla de la computadora de a bordo puede comportarse así:
1. Al principio, solo se ve el terminal bloqueado.
2. Después de la elección del jugador, el efecto establece terminal_unlocked = true.
3. La condición desbloquea el esquema de la nave y nuevos botones.
4. Hacer clic en el botón cambia el estado del widget y aumenta evidence.
5. Cuando evidence >= 3, aparece una notificación oculta y se desbloquea una nueva rama de la misión.
El mapa del capítulo, las elecciones normales y la interfaz interactiva no crean tres sistemas separados. Ellos leen y modifican un solo objeto de estado. Por lo tanto, una pista encontrada en el diálogo puede desbloquear un elemento de la interfaz, y una acción dentro de la interfaz puede cambiar la escena siguiente.
Es aquí donde la lógica declarativa comienza a sentirse como verdadera programación. Solo que en lugar de archivos, funciones y un bus de eventos, el autor trabaja con entidades comprensibles de la historia: hechos, elecciones, condiciones y transiciones.
Por qué intencionalmente no agrego JavaScript arbitrario
La posibilidad de insertar un script parece el camino más corto hacia cualquier nueva mecánica. Pero tan pronto como la misión publicada obtiene el derecho de ejecutar código arbitrario, todo el modelo de producto cambia.
Es necesario decidir qué API del navegador están disponibles para este código, cómo limitar la red y el almacenamiento, qué hacer con los bucles infinitos, cómo trasladar la misión fuera de línea, cómo sincronizarla en un juego cooperativo y cómo garantizar que un proyecto antiguo continúe funcionando después de actualizar Player.
Una regla declarativa es mucho más aburrida que una función arbitraria, y por eso es más confiable. Se puede validar antes de ejecutarla. Se puede entender qué variables lee y escribe. Se puede guardar de manera segura el progreso en medio de la cadena. Se puede ejecutar la misión de la misma manera en el navegador, en una compilación autónoma y en el Player integrado.
El vocabulario limitado aquí no obstaculiza la lógica, sino que establece sus límites. Si aparece una operación realmente útil, es mejor añadirla al runtime general y dar a todos los autores un comportamiento uniforme y comprobado, que obligar a cada proyecto a inventar su propio motor.
De postre: su propio HTML y CSS
Al mismo tiempo, Romergo aún deja espacio para código real allí donde es más seguro: en la presentación de una escena normal.
En el proyecto se puede crear un tema de apariencia propio en HTML y CSS y usarlo en diferentes capítulos. HTML establece la ubicación de las áreas preparadas: la ventana de réplica, el retrato, el nombre del personaje, el texto, la pregunta y los botones de selección. CSS permite cambiar significativamente estas áreas: marcos, fondo, forma de las tarjetas, márgenes, tipografía y la reacción al tamaño de la pantalla.
Los temas listos **Standard**, **Minimalism**, **Brutalism**, **Romance** y **Neon** muestran un rango confirmado sin maquetación manual. Al crear un tema personalizado, Romergo copia la plantilla seleccionada: después de esto, su HTML y CSS se pueden editar y verificar inmediatamente en la vista previa real Player.

*Aquí no hay concept art: a la izquierda se muestra el CSS real del tema incorporado Brutalism, a la derecha, el resultado del mismo código en la vista previa del teléfono. El interruptor Desktop / Mobile permite comprobar de inmediato las reglas adaptativas, y el tema personalizado comienza a funcionar desde una copia de la plantilla seleccionada.*
Pero el borde permanece igual. En el HTML personalizado no hay <script>, manejadores de eventos, formularios, iframes ni recursos externos. CSS no puede cargar un url() o @import externo. Las áreas obligatorias de la escena deben permanecer en su lugar; si la plantilla las ha perdido, Player vuelve al formato estándar seguro.
Es decir, HTML y CSS son responsables de **cómo se ve la historia**, mientras que los nodos, variables, condiciones y efectos son responsables de **cómo funciona**.
Me gusta precisamente esa separación. El autor puede hacer que una misión no se parezca visualmente a las demás, pero su realización sigue siendo parte del runtime general verificable. La capa externa se puede recolorear y reconstruir radicalmente, sin convertir cada tema en un programa separado.
Código sin código no significa ausencia de lógica
Romergo no tiene como objetivo reemplazar el lenguaje de programación por imágenes. El gráfico no es adecuado para matemáticas complejas, y el conjunto de efectos atómicos no se convertirá en un motor de automatización universal.
Sin embargo, para una historia interactiva, a menudo se necesitan otras cosas: recordar un hecho, cambiar un contador, abrir una opción, elegir una ruta, mostrar el estado de la interfaz, guardar un punto de retorno y transmitir todas estas decisiones al siguiente capítulo.
Para esto, los nodos y variables no resultan ser una versión simplificada de los scripts, sino un lenguaje más directo de la propia historia. El autor no describe comandos para la computadora, sino las relaciones de causa y efecto del mundo: el jugador tomó una decisión, el estado cambió, la historia reaccionó.
Y si quieres un poco de código real, HTML y CSS todavía te esperan de postre.