Salto de escenas y cambio de entradas mediante UI
Haz clic en un botón → salta a una apertura prediseñada distinta. Escribe en un cuadro de texto → cambia lo que dice una entrada a la IA. Esta receta te muestra ambas técnicas.
Parte 1: Cambiar entre aperturas con un botón
Lo que vas a construir
Un mundo con varias escenas de apertura prediseñadas. El jugador ve la apertura "principal" primero, con botones clicables. Cuando hace clic en uno, el primer mensaje del chat instantáneamente cambia a otra apertura prediseñada — sin generación de IA, solo el texto que escribiste.
Cómo funciona
En Yumina, puedes crear varios saludos en la pestaña First Message del editor. Cuando un jugador inicia una nueva sesión, todos los saludos se empaquetan como swipes (izquierda/derecha para alternar) en el primer mensaje. Los jugadores ya pueden hacer swipe manualmente — pero lo que queremos es: permitir que el jugador salte a un saludo específico con un solo clic.
Para eso sirve la API switchGreeting(index) — permite que componentes personalizados salten directamente al N-ésimo saludo por código.
El jugador hace clic en "Entrar a la Cueva Oscura"
→ el código llama api.switchGreeting(1)
→ El primer mensaje cambia al saludo n.º 2 (el índice empieza en 0, por lo que 1 = el segundo)
→ El jugador ve instantáneamente tu apertura prediseñada de la cueva oscuraPaso a paso
Paso 1: Crea varios saludos en la pestaña First Message
Abre el editor y haz clic en la pestaña First Message en la barra lateral izquierda.
Esta pestaña es específicamente para gestionar aperturas. Puedes crear varios saludos — cada uno se convierte en un swipe.
Crea el primer saludo (apertura principal — presenta la elección de ruta):
Haz clic en "Create First Message". Escribe la apertura principal en el cuadro de texto. Esto es lo que el jugador ve primero al abrir la sesión — describe la escena y guíalo hacia una elección:
*Te despiertas en un bosque misterioso. La niebla matinal se arremolina entre árboles ancestrales.*
Dos caminos se separan ante ti:
**A la izquierda** — un sendero estrecho hacia la oscuridad. Aire frío y ecos lejanos.
**A la derecha** — un sendero salpicado de sol con flores silvestres y canto de pájaros.
¿Por cuál camino irás?¿Por qué solo describir la escena en lugar de pedirle a la IA que responda? Porque el saludo es texto fijo que escribiste previamente, no generado por IA. Tienes control preciso sobre cada palabra que el jugador ve.
Crea el segundo saludo (apertura de la cueva oscura):
Haz clic en "Add Greeting" en la parte inferior. Verás aparecer pestañas numeradas 1 y 2. Haz clic en 2 para cambiar al cuadro de edición del segundo saludo. Escribe la apertura de la ruta de la cueva oscura:
*Pisas el sendero de la izquierda. El dosel se espesa por encima, devorando la luz. En cuestión de minutos, el camino se estrecha hasta convertirse en una grieta en una pared de roca — la entrada a una cueva.*
*Sale un aire frío que trae el olor a piedra húmeda y algo metálico. Una luz tenue azul-verdosa parpadea en lo profundo — hongos bioluminiscentes adheridos a las paredes.*
*Tomas aliento y entras. Detrás de ti, el último resquicio de luz diurna se reduce a una línea pálida, luego se desvanece.*
Estás solo en la oscuridad.Este texto solo se muestra después de que el jugador haga clic en "Entrar a la Cueva Oscura". Antes de eso, el jugador ve el primer saludo (la apertura principal).
Crea el tercer saludo (apertura del prado soleado):
Haz clic en "Add Greeting" de nuevo. Cambia a la pestaña 3 y escribe la apertura de la ruta del prado soleado:
*Eliges el sendero de la derecha. Los árboles se ralean y la cálida luz del sol inunda el dosel. En cuestión de minutos, el bosque se abre a una vasta pradera que se extiende hasta el horizonte.*
*Flores silvestres de todos los colores se mecen suavemente con la brisa. Un arroyo brilla en la distancia. En algún lugar cercano, un pájaro canta una melodía que nunca habías oído.*
*Sientes cómo la tensión en tus hombros se desvanece. Sea cual sea este lugar, se siente seguro.*
Bienvenido a la Pradera Siempreflor.El orden de los saludos es el índice
El orden de las pestañas numeradas en la parte inferior es el parámetro index para switchGreeting(). Pestaña 1 = índice 0 (mostrado por defecto), pestaña 2 = índice 1, pestaña 3 = índice 2. Usarás este índice al escribir el código del botón más adelante.
Ahora tienes 3 saludos. Tras guardar el mundo, una nueva sesión mostrará por defecto el primero (la apertura principal). A continuación crearemos botones para que el jugador pueda hacer clic y pasar al segundo o tercero.
Paso 2: Crea una variable de seguimiento de ruta
Necesitamos una variable que registre "qué ruta eligió el jugador". Esta variable tiene dos usos:
- Hacer que los botones desaparezcan tras la elección (el código TSX comprueba esta variable — si no es
"none", no muestra los botones) - Permitir que la conversación posterior conozca la ruta actual (las reglas de comportamiento pueden cambiar entradas del lorebook según esta variable)
Editor → barra lateral izquierda → pestaña Variables → haz clic en "Add Variable"
| Campo | Qué rellenar | Por qué |
|---|---|---|
| Nombre visible | Ruta actual | Para tu propia referencia |
| ID | current_route | El código lee/escribe la variable usando este ID |
| Tipo | String | Porque el valor es texto ("none", "dark", "light") |
| Valor por defecto | none | Significa "aún no elegido". El código del botón comprueba este valor |
| Categoría | Tag | Solo una etiqueta de categoría, facilita encontrarla en la lista de variables |
| Reglas de comportamiento | No modifiques esta variable. Está controlada por la elección de la UI del jugador. | Le dice a la IA que no modifique esta variable — solo el botón puede hacerlo |
El campo Reglas de comportamiento es una instrucción para la IA. Si no lo escribes, la IA puede decidir por su cuenta cambiar el valor de esta variable en su respuesta (por ejemplo, la IA piensa "el jugador entró en la cueva" y pone
current_routea"dark"por sí misma). Una vez que escribes la regla, la IA no la tocará.
Paso 3: (Opcional) Crea entradas de lore y reglas de comportamiento
Si quieres que las respuestas posteriores de la IA hagan referencia a un worldbuilding distinto tras elegir la ruta, haz este paso. Si solo quieres cambiar el texto de la apertura sin cambios posteriores del mundo, puedes omitirlo.
Crea dos entradas de lore (deshabilitadas por defecto):
Editor → pestaña Entries → crea una nueva entrada
Entrada de lore de la cueva oscura:
| Campo | Qué rellenar | Por qué |
|---|---|---|
| Nombre | Lore de la cueva oscura | Para tu propia referencia |
| Sección | System Presets | Las entradas en la sección de presets se envían a la IA cada vez |
| Habilitada | No (desactivado) | Deshabilitada por defecto — tras elegir la ruta oscura, una regla de comportamiento la habilitará |
Contenido:
[Ambientación del mundo: Cueva de Fauces de Sombra]
El jugador está explorando la Cueva de Fauces de Sombra. Detalles clave:
- Antiguas ruinas enanas, abandonadas durante siglos
- Hongos bioluminiscentes proporcionan una débil luz azul-verde
- Criaturas extrañas acechan en los túneles más profundos
- La temperatura baja cuanto más se adentra uno
Mantén una atmósfera tensa de horror-supervivencia. Describe sonidos que reverberan, sombras parpadeantes, agua goteando y el peso opresivo de la piedra sobre la cabeza.Entrada de lore del prado soleado: Crea otra entrada, también deshabilitada por defecto, con contenido que describa el escenario y la atmósfera del prado.
¿Por qué deshabilitada por defecto? Porque antes de que el jugador elija una ruta, ninguno de los dos worldbuilding debería influir en la IA. Solo después de que el jugador elija, la regla de comportamiento habilita la entrada correspondiente y deshabilita la otra.
Crea dos reglas de comportamiento:
Editor → pestaña Behaviors → Add Behavior
Comportamiento 1: "Elegir ruta oscura"
| Campo | Qué rellenar | Por qué |
|---|---|---|
| Nombre | Elegir ruta oscura | Para tu propia referencia |
| Disparador | Selecciona "Action" → Action ID choose-dark | Se dispara cuando el código TSX llama executeAction("choose-dark") |
Luego, en "Execute Actions", añade en orden:
| Tipo de acción | Configuración | Efecto |
|---|---|---|
| Modificar variable | current_route set a dark | Registra que el jugador eligió la ruta oscura |
| Habilitar entrada | Dark Cave Lore | Activa el escenario de la cueva oscura |
| Deshabilitar entrada | Sunlit Meadow Lore | Desactiva el escenario del prado (evita que ambos estén activos) |
Comportamiento 2: "Elegir ruta luminosa" — créalo de la misma manera. El action ID es choose-light, y las acciones se invierten (habilitar el lore del prado, deshabilitar el lore de la cueva).
¿Por qué no usar simplemente
setVariableen el código TSX? PorquesetVariablesolo puede cambiar variables — no puede activar/desactivar entradas. Las acciones "Enable Entry" / "Disable Entry" del comportamiento son las que habilitan/deshabilitan entradas en tiempo de ejecución. Así que cuando se hace clic en un botón, hacemos tres cosas a la vez:setVariable(cambiar la variable) +executeAction(disparar el comportamiento para alternar entradas) +switchGreeting(cambiar la apertura).
Paso 4: Añade botones de selección de ruta en el Root Component
Este es el paso clave que hace que aparezcan botones en la interfaz del chat.
Editor → sección Custom UI → abre index.tsx → pega el siguiente código (reemplazando el predeterminado):
export default function MyWorld() {
const api = useYumina();
const hasChosen = api.variables.current_route !== "none";
return (
<Chat renderBubble={(msg) => (
<div>
{/* Renderiza el texto del mensaje normalmente */}
<div
style={{ color: "#e2e8f0", lineHeight: 1.7 }}
dangerouslySetInnerHTML={{ __html: msg.contentHtml }}
/>
{/* Botones de selección de ruta */}
{/* msg.messageIndex === 0 significa mostrar solo en el primer mensaje */}
{/* !hasChosen significa ocultarlos una vez hecha una elección */}
{msg.messageIndex === 0 && !hasChosen && (
<div style={{
display: "flex",
gap: "12px",
marginTop: "16px",
}}>
<button
onClick={() => {
api.setVariable("current_route", "dark"); // Record the choice, making the buttons disappear
api.executeAction("choose-dark"); // Fire the behavior rule to toggle lore entries
api.switchGreeting?.(1); // Switch to the 2nd greeting
}}
style={{
flex: 1,
padding: "16px",
background: "linear-gradient(135deg, #1e1b4b, #312e81)",
border: "1px solid #4338ca",
borderRadius: "12px",
color: "#c7d2fe",
fontSize: "15px",
fontWeight: "bold",
cursor: "pointer",
}}
>
Enter the Dark Cave
</button>
<button
onClick={() => {
api.setVariable("current_route", "light");
api.executeAction("choose-light");
api.switchGreeting?.(2); // Switch to the 3rd greeting
}}
style={{
flex: 1,
padding: "16px",
background: "linear-gradient(135deg, #365314, #4d7c0f)",
border: "1px solid #65a30d",
borderRadius: "12px",
color: "#ecfccb",
fontSize: "15px",
fontWeight: "bold",
cursor: "pointer",
}}
>
Walk to the Sunlit Meadow
</button>
</div>
)}
</div>
)} />
);
}Explicación línea por línea:
<Chat renderBubble={...} />— usa la interfaz de chat predeterminada de la plataforma (cuadro de entrada, cambio de swipes, puntos de guardado vienen integrados), solo tomas el control de cómo se renderizan las burbujasconst api = useYumina()— obtiene la API de Yumina, permitiéndote leer variables, escribir variables, disparar acciones, cambiar saludosapi.variables.current_route— lee el valor actual de la variable de rutahasChosen— si no es"none", el jugador ya ha elegidomsg.contentHtml— el HTML prerrenderizado que renderBubble recibe (el Markdown ya está procesado)msg.messageIndex === 0— solo muestra botones en el primer mensaje (no en cada mensaje)!hasChosen— los botones desaparecen tras hacer una elecciónapi.setVariable("current_route", "dark")— pone la variable a"dark", por lo quehasChosenpasa atruey los botones desaparecenapi.executeAction("choose-dark")— dispara la regla de comportamiento que creamos en el Paso 3api.switchGreeting?.(1)— cambia el primer mensaje al índice 1 (el segundo saludo).?.es encadenamiento opcional — si la API no está disponible, no lanzará error
¿No quieres escribir código tú mismo? Usa Studio AI
Editor arriba → haz clic en "Enter Studio" → panel AI Assistant → describe en lenguaje natural lo que quieres y la IA generará el código por ti.
Paso 5: Guarda y prueba
- Haz clic en "Save" en la parte superior del editor
- Haz clic en "Start Game" o vuelve a la página de inicio y comienza una nueva sesión
- Verás la apertura principal con dos botones debajo
- Haz clic en "Entrar a la Cueva Oscura" — el primer mensaje se convierte instantáneamente en tu apertura prediseñada de la cueva y los botones desaparecen
- Envía algunos mensajes a la IA — si hiciste el Paso 3, las respuestas de la IA estarán influidas por el lore de la cueva
- ¿Quieres probar la otra ruta? Vuelve al inicio y comienza una nueva sesión, esta vez haciendo clic en el otro botón
Solución de problemas:
| Síntoma | Causa probable | Solución |
|---|---|---|
| No veo los botones | El código del Root Component no se guardó o tiene un error de sintaxis | Comprueba el estado de compilación en la parte inferior de la sección Custom UI — debería mostrar un "OK" verde |
| El clic del botón no hace nada | switchGreeting aún no se desplegó en el servidor | Asegúrate de estar usando la última versión |
| El botón hace clic pero la apertura no cambia | No hay suficientes saludos | Confirma que hay 3 saludos en la pestaña First Message |
| El botón hace clic pero no desaparece | La variable no se está fijando correctamente | Revisa el editor — ¿el valor predeterminado de la variable es none, y el código del Root Component comprueba correctamente current_route? |
| El lore no cambia | Regla de comportamiento mal configurada | Verifica que el action ID del comportamiento coincida con el código (choose-dark / choose-light) |
Parte 2: La entrada del jugador modifica el contenido de una entrada
Lo que vas a construir
Añade un cuadro de entrada de texto en la interfaz del chat. El jugador escribe algo en él (por ejemplo, una regla personalizada, el nombre de un personaje o una instrucción de la historia). Tras hacer clic en "Aplicar", el texto se inyecta en una entrada del lorebook — cambiando lo que la IA ve a continuación.
Cómo funciona
Las entradas de Yumina soportan sintaxis de macros. Puedes escribir {{variableId}} en el contenido de una entrada — es un marcador de posición. Cada vez que el motor construye el prompt para enviar a la IA, sustituye automáticamente el marcador de posición por el valor actual de la variable.
Por ejemplo:
- Escribes en una entrada:
Special rule: {{custom_rule}} - La variable
custom_ruletiene el valor"All magic is allowed" - El prompt que recibe la IA tiene esa línea reescrita como:
Special rule: All magic is allowed
Punto clave: la sustitución no es en vivo. Ocurre cada vez que se construye el prompt — es decir, cuando el jugador envía su siguiente mensaje y la IA está a punto de responder.
Cronología completa:
1. El contenido de la entrada dice: "Special rule: {{custom_rule}}"
2. El valor actual de la variable custom_rule = "All magic is allowed"
3. El jugador envía un mensaje → el motor construye el prompt → sustituye {{custom_rule}} por el valor de la variable
→ La IA recibe "Special rule: All magic is allowed" → la IA responde acorde
4. El jugador escribe "Magic is forbidden" en el cuadro de entrada, hace clic en "Aplicar"
5. El código llama a setVariable("custom_rule", "Magic is forbidden")
→ el valor de la variable se actualiza inmediatamente
6. ¡Pero la IA aún no lo sabe! El prompt no se ha reconstruido.
7. El jugador envía otro mensaje → el motor reconstruye el prompt → esta vez usa el nuevo valor
→ La IA recibe "Special rule: Magic is forbidden" → la IA empieza a obedecer la nueva reglaResumen en una línea: cambiar la variable es instantáneo, pero la IA ve el cambio en el siguiente mensaje.
Paso a paso
Paso 1: Crea una variable de tipo string
Esta variable contiene lo que el jugador escribe.
Editor → pestaña Variables → "Add Variable"
| Campo | Qué rellenar | Por qué |
|---|---|---|
| Nombre visible | Regla personalizada | Para tu propia referencia |
| ID | custom_rule | El macro {{custom_rule}} en las entradas busca este ID |
| Tipo | String | Porque el contenido es texto arbitrario que el jugador escribe |
| Valor por defecto | (déjalo vacío, o establece uno predeterminado como All magic is allowed) | Vacío = nueva sesión sin regla; no vacío = una regla inicial |
| Reglas de comportamiento | No modifiques esta variable. La establece el jugador a través de la UI. | Le dice a la IA que no modifique esta variable por sí misma |
Paso 2: Usa el macro en una entrada
Ahora crea una entrada que use {{custom_rule}} como marcador de posición. El motor lo sustituirá automáticamente al construir el prompt.
Editor → pestaña Entries → crea una nueva entrada
| Campo | Qué rellenar | Por qué |
|---|---|---|
| Nombre | Reglas del mundo | Para tu propia referencia |
| Sección | System Presets | Las entradas en la sección de presets se envían a la IA cada vez |
Contenido:
[Reglas del mundo]
La siguiente regla está en vigor en este mundo y debe respetarse en todo momento:
{{custom_rule}}¿Qué pasa? Cada vez que el motor construye el prompt, escanea todo el contenido de las entradas en busca de
{{...}}. Si lo que está entre llaves coincide con un ID de variable, el valor actual de esa variable lo sustituye. Así{{custom_rule}}se sustituye con el valor de la variablecustom_rule.Si la variable está vacía, la línea queda vacía — la IA ve "The following rule is in effect..." sin nada después. Si el valor es "Magic is forbidden", la IA ve "The following rule is in effect... Magic is forbidden".
Paso 3: Añade un cuadro de entrada en el Root Component
Queremos un cuadro de entrada en la interfaz del chat donde el jugador pueda escribir una nueva regla. Esta entrada se escribe dentro del renderBubble del Root Component y solo se muestra debajo del último mensaje (para evitar que aparezca una entrada bajo cada mensaje).
En tu index.tsx, añade lo siguiente. Si ya tienes el código de la Parte 1, simplemente añade esto dentro del JSX que devuelve renderBubble, debajo del texto del mensaje:
// Cerca del inicio de MyWorld() (fuera de <Chat>), añade esto
const api = useYumina(); // Si ya lo tienes, no lo dupliques
const msgs = api.messages || [];
const [ruleInput, setRuleInput] = React.useState("");
const currentRule = String(api.variables.custom_rule || "");
// Dentro de renderBubble, añade una comprobación
const isLastMsg = msg.messageIndex === msgs.length - 1; // si este es el último mensaje
// En el JSX que devuelve renderBubble, debajo del texto del mensaje
{isLastMsg && (
<div style={{
marginTop: "12px",
padding: "12px",
background: "rgba(30,41,59,0.5)",
borderRadius: "8px",
border: "1px solid #334155",
}}>
<div style={{ fontSize: "12px", color: "#94a3b8", marginBottom: "6px" }}>
World Rule: {currentRule || "(not set)"}
</div>
<div style={{ display: "flex", gap: "8px" }}>
<input
type="text"
value={ruleInput}
onChange={(e) => setRuleInput(e.target.value)}
placeholder="Type a new rule..."
style={{
flex: 1, padding: "6px 10px", background: "#1e293b",
border: "1px solid #475569", borderRadius: "6px",
color: "#e2e8f0", fontSize: "13px", outline: "none",
}}
onKeyDown={(e) => {
if (e.key === "Enter" && ruleInput.trim()) {
api.setVariable("custom_rule", ruleInput.trim());
setRuleInput("");
}
}}
/>
<button
onClick={() => {
if (ruleInput.trim()) {
api.setVariable("custom_rule", ruleInput.trim());
setRuleInput("");
}
}}
style={{
padding: "6px 14px", background: "#4338ca", borderRadius: "6px",
color: "#e0e7ff", fontSize: "13px", fontWeight: "600",
cursor: "pointer", border: "none",
}}
>
Apply
</button>
</div>
</div>
)}Explicación línea por línea:
isLastMsg— solo muestra la entrada en el último mensaje, de lo contrario cada mensaje tendría unacurrentRule— lee el valor actual de la variable, mostrado encima de la entrada para que el jugador vea la regla actualruleInput— estado de React que sigue lo que se está escribiendoonKeyDown— presionar Enter también envía, no solo hacer clic en el botónapi.setVariable("custom_rule", ...)— escribe el texto del jugador en la variable. En la siguiente respuesta de la IA,{{custom_rule}}en la entrada se sustituye con este textosetRuleInput("")— limpia la entrada tras enviar
¿Por qué ponerlo dentro de renderBubble?
El Root Component de Yumina es un archivo TSX — por defecto devolver <Chat /> te da la UI de chat integrada de la plataforma. Para insertar elementos interactivos (botones, entradas) en el chat, hay dos caminos: 1) ponerlos dentro de <Chat renderBubble={...} />, como aquí, para que se rendericen junto a las burbujas de mensaje; 2) poner <Chat /> y tu componente flotante en un layout flex compartido (para barras laterales). Si quieres una UI a pantalla completa totalmente fuera del chat (por ejemplo, una novela visual pura), omite <Chat /> por completo — escribe tu propio layout, usa <MessageList /> + <MessageInput /> directamente si es necesario.
Paso 4: Guarda y prueba
- Guarda el mundo, inicia una nueva sesión
- Debajo del último mensaje, verás "World Rule: (not set)" y un cuadro de entrada
- Escribe "Magic is forbidden" y haz clic en "Apply" (o presiona Enter)
- El texto encima de la entrada cambia a "World Rule: Magic is forbidden" — la variable se ha actualizado
- Ahora envía un mensaje (por ejemplo, "I try to cast a fireball") — aquí es cuando el motor construye el prompt, sustituyendo
{{custom_rule}}con "Magic is forbidden" - La respuesta de la IA debería reflejar esta regla (por ejemplo, "You raise your hand to cast, but your mana feels locked away by some unseen force")
- Cambia la regla de nuevo (por ejemplo, a "Only fire magic is allowed") y envía otro mensaje — la IA se adapta
Combinando ambos patrones
Puedes combinar el cambio de saludos y la modificación de entradas. Un ejemplo concreto:
Creación de personaje + apertura de historia:
- El saludo principal (índice 0) no es la historia — es un formulario de creación de personaje con entradas para nombre, clase y trasfondo
- El jugador lo rellena →
setVariableescribe sus entradas en variables → las entradas con macros{{player_name}},{{player_class}},{{player_backstory}}recogen los valores - El jugador hace clic en "Iniciar aventura" →
switchGreeting(1)salta a la apertura real de la historia - Desde la primera respuesta de la IA en adelante, la IA ya conoce el nombre, clase y trasfondo del personaje del jugador
Referencia rápida
| Qué quieres | Cómo hacerlo |
|---|---|
| Saltar a una apertura prediseñada | switchGreeting(index) — el índice coincide con el orden de saludos en la pestaña First Message (base 0) |
| Permitir que la entrada del jugador cambie el comportamiento de la IA | Variable de tipo string + {{variableId}} en la entrada + llamar a setVariable() desde la UI |
| Mostrar botones solo en el primer mensaje | Dentro de <Chat renderBubble>, comprueba msg.messageIndex === 0 |
| Ocultar botones tras elegir | Registra la elección en una variable, comprueba hasChosen en TSX |
| Cambiar lore tras la elección de ruta | Crea un comportamiento con acciones "Enable Entry" / "Disable Entry" |
| Reproducir un sonido al cambiar | Añade acciones "Play Music" o "Play Sound Effect" en el comportamiento |
| Mostrar una notificación al cambiar | Añade la acción "Show Notification" en el comportamiento |
Pruébalo tú mismo — mundo demo importable
Descarga este archivo JSON e impórtalo para probar la experiencia completa:
Cómo importar:
- Ve a Yumina → My Worlds → Create New World
- En el editor, haz clic en "More Actions" → "Import Package"
- Selecciona el archivo
.jsondescargado - El mundo se crea con todos los saludos, variables, comportamientos y Root Component preconfigurados
- Inicia una nueva sesión y pruébalo
Qué incluye:
- 3 saludos (apertura principal + cueva oscura + prado soleado)
- 2 variables (
current_routepara el seguimiento de ruta,custom_rulepara la regla editable por el jugador) - 2 comportamientos de acción (alternar entradas de lore cuando se elige una ruta)
- Un Root Component (
<Chat renderBubble>con los botones de selección de ruta + editor de reglas) - Una entrada de lore usando el macro
{{custom_rule}}
Esta es la Receta #1
Vienen más recetas — sistemas de combate, interfaces de tienda, seguimiento de misiones y más. Cada receta combina variables, entradas, comportamientos y UI para construir algo mayor que la suma de sus partes.
