Skip to content

Mapa y navegación de escenas

Construye una interfaz de mapa clicable — el jugador hace clic en una ubicación → la escena cambia, las entradas de lore se intercambian, la BGM hace crossfade, y la IA describe la atmósfera de la nueva zona. Esta receta te muestra cómo conectarlo todo con variables, comportamientos, entradas de lore y el Root Component.


Lo que vas a construir

Un sistema visual de navegación por mapa integrado en el chat:

  • UI de mapa — un panel de mapa con cuadrícula debajo del último mensaje, con cada ubicación como un botón con icono emoji
  • Resaltado de ubicación actual — el botón de la ubicación actual del jugador usa un color diferente para que sea instantáneamente reconocible
  • Cambio de escena — haz clic en una ubicación → el comportamiento se dispara → las entradas de lore se intercambian (antigua ubicación deshabilitada, nueva habilitada) → la IA describe la llegada a la nueva zona
  • Crossfade de BGM — cada ubicación tiene su propia música de fondo; el cambio usa crossfade (fundido cruzado) para una transición suave en lugar de un corte abrupto
  • Cuatro ubicaciones — Pueblo, Bosque, Cueva, Mercado, cada una con descripciones de atmósfera y BGM únicas

Cómo funciona

El núcleo de todo el sistema es: botón dispara comportamiento → comportamiento actualiza variable + alterna entradas + crossfade música + solicita respuesta de IA → IA describe la nueva escena.

El jugador hace clic en el botón "Forest" del mapa
  → El código llama a api.executeAction("go-forest")
  → El comportamiento se dispara:
    1. current_location set a "forest"
    2. Deshabilitar entrada "Village Atmosphere", habilitar entrada "Forest Atmosphere"
    3. Crossfade a la BGM del bosque
    4. Solicitar respuesta de IA con contexto: "El jugador viaja del pueblo al bosque"
  → La IA recibe la nueva entrada de lore + contexto → describe la escena del bosque
  → El Root Component detecta que current_location cambió → el botón "Forest" se resalta en el mapa

¿Qué es crossfade? Crossfade es una técnica de transición de audio — la pista antigua se desvanece gradualmente mientras la nueva pista aumenta gradualmente, con ambas reproduciéndose simultáneamente durante una breve superposición. El efecto es como una transición de escena de película: la música nunca se corta y se reinicia abruptamente, sino que fluye suavemente de una pieza a la siguiente. En Yumina, la acción "Play Music" de los comportamientos soporta una operación crossfade — simplemente especificas el nuevo ID de pista y la duración del fundido.


Paso a paso

Paso 1: Crea una variable

Necesitamos 1 variable para seguir la ubicación actual del jugador.

Editor → barra lateral → pestaña Variables → haz clic en "Add Variable"

CampoValorPor qué
Nombre visibleUbicación actualPara tu propia referencia
IDcurrent_locationLos comportamientos y el Root Component leen/escriben usando este ID
TipoStringPorque los valores son texto ("village", "forest", "cave", "market")
Valor por defectovillageLas nuevas sesiones empiezan en el Pueblo
CategoríaCustomCategoría dedicada para el sistema de mapa
Reglas de comportamientoNo modifiques esta variable. Está controlada por la UI de mapa del jugador. El valor actual representa la ubicación del jugador.Le dice a la IA que no cambie la ubicación por su cuenta — solo los clics del mapa del jugador pueden

Paso 2: Crea cuatro entradas de lore para ubicaciones

Cada ubicación necesita una entrada de lore que describa su atmósfera. Solo "Village" está habilitada por defecto; las otras tres están deshabilitadas.

Editor → pestaña Lore → crea entradas una por una

Entrada 1: Atmósfera del Pueblo

CampoValorPor qué
NombreAtmósfera del PuebloPara tu propia referencia
SecciónSystem PresetsLas entradas de la sección de presets se envían a la IA cada vez
Habilitada (activado)El juego empieza en el Pueblo, así que está habilitado por defecto

Contenido:

[Ubicación actual: Aldea]
El jugador está en la Aldea. Al describir la escena, transmite la siguiente atmósfera:
- Una pequeña aldea apacible con caminos de adoquines que serpentean entre casas de madera
- Volutas de humo se alzan desde los tejados; el aire lleva el aroma de pan recién hecho y guiso
- Los aldeanos charlan junto al pozo; el repique rítmico del martillo resuena desde la herrería
- Campos dorados de trigo se extienden a lo lejos, ondeando suavemente con la brisa
- El ambiente general es cálido, tranquilo y lleno de vida cotidiana

Entrada 2: Atmósfera del Bosque

CampoValorPor qué
NombreAtmósfera del BosquePara tu propia referencia
SecciónSystem PresetsSección de presets
HabilitadaNo (desactivado)Será habilitada por un comportamiento cuando el jugador viaje aquí

Contenido:

[Ubicación actual: Bosque]
El jugador está en el Bosque. Al describir la escena, transmite la siguiente atmósfera:
- Árboles ancianos imponentes bloquean la mayor parte de la luz solar; solo una luz moteada se filtra hasta el musgo de abajo
- El aire es húmedo y fresco, una mezcla de tierra, resina de árbol y aromas de flores silvestres
- El canto de los pájaros viene de todas direcciones, puntuado por el chasquido agudo y ocasional de una rama que se quiebra
- Los arbustos a lo largo del sendero pueden ocultar conejos, ciervos o algo más peligroso
- Cuanto más te adentras, más densos son los árboles y más tenue la luz
- El ambiente general es misterioso, primigenio y lleno de lo desconocido

Entrada 3: Atmósfera de la Cueva

CampoValorPor qué
NombreAtmósfera de la CuevaPara tu propia referencia
SecciónSystem PresetsSección de presets
HabilitadaNo (desactivado)Será habilitada por un comportamiento

Contenido:

[Ubicación actual: Cueva]
El jugador está en la Cueva. Al describir la escena, transmite la siguiente atmósfera:
- Hongos bioluminiscentes se aferran a las paredes de roca, derramando un débil resplandor azul-verde
- El agua gotea desde las estalactitas, y cada gota resuena por la caverna
- El aire es frío y húmedo, con un aroma metálico de minerales y arroyos subterráneos
- El suelo bajo los pies es resbaladizo y desigual; los túneles más adentro están negros como la pez
- A veces, un gruñido grave inidentificable o el crujido de una roca moviéndose retumba desde las profundidades — puede que no sea seguro aquí abajo
- El ambiente general es oscuro, opresivo y cargado de peligros ocultos

Entrada 4: Atmósfera del Mercado

CampoValorPor qué
NombreAtmósfera del MercadoPara tu propia referencia
SecciónSystem PresetsSección de presets
HabilitadaNo (desactivado)Será habilitada por un comportamiento

Contenido:

[Ubicación actual: Mercado]
El jugador está en el Mercado. Al describir la escena, transmite la siguiente atmósfera:
- Tiendas y puestos coloridos se alinean en filas, repletos de toda clase de mercancías
- Los mercaderes pregonan sus productos; los sonidos del regateo suben y bajan por todos lados
- El aire es una mezcla de especias, carne asándose, cuero y flores
- El escaparate de una tienda de objetos mágicos parpadea con una luz extraña; un alquimista mezcla pociones en una esquina
- La multitud bulle — viajeros de toda raza y profesión convergen aquí
- El ambiente general es animado, bullicioso y lleno de energía comercial

¿Por qué solo "Village" está habilitada por defecto? Porque el juego empieza en el Pueblo. Si las cuatro entradas estuvieran habilitadas a la vez, la IA recibiría descripciones de atmósfera para el Pueblo, Bosque, Cueva y Mercado simultáneamente y no sabría qué escena describir. Habilitar solo una a la vez mantiene a la IA enfocada en la ubicación actual.


Paso 3: (Opcional) Sube BGM para las ubicaciones

Si quieres que cada ubicación tenga su propia música de fondo, primero necesitas subir archivos de audio.

Editor → pestaña Audio → añadir pistas

ID de pistaNombreTipoBucleFade InFade Out
bgm_villageVillageBGM2s2s
bgm_forestForestBGM2s2s
bgm_caveCaveBGM2s2s
bgm_marketMarketBGM2s2s

¿No tienes archivos de audio? Omite este paso. El núcleo de la navegación por mapa es el cambio de entradas de lore — la BGM es la guinda del pastel. Siempre puedes añadirla después.

En la playlist de BGM, establece autoPlay a true y por defecto a bgm_village. Cuando el jugador cambie de ubicación, los comportamientos usarán la acción crossfade para una transición suave entre pistas.

Cómo funciona el crossfade

Un simple "detener pista antigua → reproducir nueva pista" deja un hueco discordante — la música se corta, luego una pieza diferente comienza repentinamente. El crossfade funciona de forma distinta: las pistas antigua y nueva se superponen durante una ventana de tiempo. Digamos que estableces una duración de fundido de 3 segundos:

  • Segundo 0: Pista antigua al 100% de volumen, nueva pista empieza a reproducirse al 0%
  • Segundo 1.5: Pista antigua al 50%, nueva pista al 50%
  • Segundo 3: Pista antigua al 0% (se detiene), nueva pista al 100%

El efecto es como dos colores en una paleta mezclándose lentamente y luego separándose — la transición es sedosamente suave, y el jugador apenas nota que la pista cambió; la atmósfera simplemente cambia naturalmente.


Paso 4: Crea comportamientos

Cada ubicación necesita un comportamiento — cuando el jugador hace clic en un botón del mapa, el comportamiento correspondiente se dispara y maneja todo para el cambio de ubicación.

Editor → pestaña Behaviors → añade comportamientos uno por uno

Comportamiento 1: Ir al Pueblo

WHEN (disparador):

CampoValorPor qué
Trigger TypeActionSe dispara cuando el código del Root Component llama a executeAction("go-village")
Action IDgo-villageCorresponde al evento de clic del botón del mapa

DO (acciones):

#Tipo de acciónConfiguraciónPropósito
1Modificar variablecurrent_location set a villageActualiza la ubicación actual
2Deshabilitar entrada de loreForest AtmosphereApaga otras entradas de ubicación
3Deshabilitar entrada de loreCave AtmosphereApaga otras entradas de ubicación
4Deshabilitar entrada de loreMarket AtmosphereApaga otras entradas de ubicación
5Habilitar entrada de loreVillage AtmosphereEnciende la entrada de la ubicación objetivo
6Reproducir músicabgm_village, operación: crossfade, duración de fundido 3sCrossfade a la BGM del Pueblo
7Solicitar respuesta de IAContexto: El jugador ha regresado a la Aldea. Describe la escena que ve el jugador al llegar.Hace que la IA genere una descripción de llegada

¿Por qué deshabilitar las otras tres primero y luego habilitar la objetivo? Porque el jugador podría venir de cualquier ubicación. Si va al Pueblo desde el Bosque, la entrada del Bosque debe apagarse; si viene de la Cueva, la entrada de la Cueva debe apagarse. El enfoque más simple es siempre apagar todas las otras ubicaciones, luego encender la objetivo — esto produce el resultado correcto sin importar de dónde venga el jugador.

Comportamiento 2: Ir al Bosque

WHEN:

CampoValor
Trigger TypeAction
Action IDgo-forest

DO:

#Tipo de acciónConfiguraciónPropósito
1Modificar variablecurrent_location set a forestActualiza la ubicación actual
2Deshabilitar entrada de loreVillage AtmosphereApaga otras ubicaciones
3Deshabilitar entrada de loreCave AtmosphereApaga otras ubicaciones
4Deshabilitar entrada de loreMarket AtmosphereApaga otras ubicaciones
5Habilitar entrada de loreForest AtmosphereEnciende la ubicación objetivo
6Reproducir músicabgm_forest, operación: crossfade, duración de fundido 3sCrossfade BGM
7Solicitar respuesta de IAContexto: El jugador ha entrado en el Bosque. Describe la escena que ve el jugador al adentrarse en el bosque.La IA describe la escena de llegada

Comportamiento 3: Ir a la Cueva

WHEN:

CampoValor
Trigger TypeAction
Action IDgo-cave

DO:

#Tipo de acciónConfiguraciónPropósito
1Modificar variablecurrent_location set a caveActualiza la ubicación actual
2Deshabilitar entrada de loreVillage AtmosphereApaga otras ubicaciones
3Deshabilitar entrada de loreForest AtmosphereApaga otras ubicaciones
4Deshabilitar entrada de loreMarket AtmosphereApaga otras ubicaciones
5Habilitar entrada de loreCave AtmosphereEnciende la ubicación objetivo
6Reproducir músicabgm_cave, operación: crossfade, duración de fundido 3sCrossfade BGM
7Solicitar respuesta de IAContexto: El jugador ha entrado en la Cueva. Describe la escena que ve el jugador al entrar.La IA describe la escena de llegada

Comportamiento 4: Ir al Mercado

WHEN:

CampoValor
Trigger TypeAction
Action IDgo-market

DO:

#Tipo de acciónConfiguraciónPropósito
1Modificar variablecurrent_location set a marketActualiza la ubicación actual
2Deshabilitar entrada de loreVillage AtmosphereApaga otras ubicaciones
3Deshabilitar entrada de loreForest AtmosphereApaga otras ubicaciones
4Deshabilitar entrada de loreCave AtmosphereApaga otras ubicaciones
5Habilitar entrada de loreMarket AtmosphereEnciende la ubicación objetivo
6Reproducir músicabgm_market, operación: crossfade, duración de fundido 3sCrossfade BGM
7Solicitar respuesta de IAContexto: El jugador ha llegado al Mercado. Describe la escena que ve el jugador al entrar.La IA describe la escena de llegada

Los cuatro comportamientos siguen exactamente la misma estructura — solo la ubicación objetivo difiere. Cada comportamiento hace tres cosas: (1) actualiza la variable → (2) intercambia entradas + crossfade música → (3) hace que la IA describa la nueva escena. El patrón es uniforme, así que añadir una nueva ubicación más tarde es solo cuestión de copiar un comportamiento y ajustar los parámetros.

¿Por qué "Request AI Reply" en lugar de "Tell AI"?

"Tell AI" solo inyecta texto oculto en el contexto — la IA no responderá inmediatamente. Espera hasta que el jugador envíe el siguiente mensaje. "Request AI Reply" dispara una respuesta de IA de inmediato, con tu texto como contexto de fondo para esa respuesta. Para la navegación por mapa, queremos que el jugador vea a la IA describir la nueva escena en el instante en que hace clic en un botón, sin tener que enviar otro mensaje primero. Por eso "Request AI Reply" es la mejor opción aquí.


Paso 5: Añade el panel de mapa al Root Component

Este es el paso que hace que la UI del mapa aparezca en la interfaz del chat. Usamos botones de div estilizados con iconos emoji para crear un "mapa" simple — no se necesitan recursos de imagen.

Editor → sección Custom UI → abre index.tsx → pega lo siguiente (reemplaza el predeterminado return <Chat />):

tsx
export default function MyWorld() {
  const api = useYumina();

  // ---- Lee la variable ----
  const currentLocation = String(api.variables.current_location || "village");

  // ---- Configuraciones de ubicaciones ----
  const locations = [
    { id: "village", label: "Village", icon: "🏘️", action: "go-village",
      color: "#92400e", bg: "#fef3c7", border: "#f59e0b",
      activeBg: "#f59e0b", activeColor: "#ffffff" },
    { id: "forest",  label: "Forest", icon: "🌲", action: "go-forest",
      color: "#166534", bg: "#dcfce7", border: "#22c55e",
      activeBg: "#22c55e", activeColor: "#ffffff" },
    { id: "cave",    label: "Cave", icon: "🕳️", action: "go-cave",
      color: "#3b0764", bg: "#f3e8ff", border: "#a855f7",
      activeBg: "#a855f7", activeColor: "#ffffff" },
    { id: "market",  label: "Market", icon: "🏪", action: "go-market",
      color: "#9a3412", bg: "#ffedd5", border: "#f97316",
      activeBg: "#f97316", activeColor: "#ffffff" },
  ];

  // ---- Lista de mensajes, usada para encontrar el último ----
  const msgs = api.messages || [];

  return (
    <Chat renderBubble={(msg) => {
      const isLastMsg = msg.messageIndex === msgs.length - 1;
      return (
    <div>
      {/* Renderiza el texto del mensaje normalmente (la plataforma ya produjo HTML — solo usa contentHtml) */}
      <div
        style={{ color: "#e2e8f0", lineHeight: 1.7 }}
        dangerouslySetInnerHTML={{ __html: msg.contentHtml }}
      />

      {/* Panel del mapa — solo en el último mensaje */}
      {isLastMsg && (
        <div style={{
          marginTop: "16px",
          padding: "16px",
          background: "rgba(15,23,42,0.6)",
          borderRadius: "12px",
          border: "1px solid #334155",
        }}>
          {/* Título */}
          <div style={{
            fontSize: "13px",
            color: "#94a3b8",
            marginBottom: "12px",
            fontWeight: "600",
            letterSpacing: "0.05em",
          }}>
            WORLD MAP
          </div>

          {/* Diseño de cuadrícula 2x2 */}
          <div style={{
            display: "grid",
            gridTemplateColumns: "1fr 1fr",
            gap: "10px",
          }}>
            {locations.map((loc) => {
              const isActive = currentLocation === loc.id;
              return (
                <button
                  key={loc.id}
                  onClick={() => {
                    if (!isActive) {
                      api.executeAction(loc.action);
                    }
                  }}
                  style={{
                    padding: "14px 10px",
                    background: isActive
                      ? loc.activeBg
                      : loc.bg,
                    border: `2px solid ${isActive ? loc.activeBg : loc.border}`,
                    borderRadius: "10px",
                    color: isActive ? loc.activeColor : loc.color,
                    fontSize: "14px",
                    fontWeight: "700",
                    cursor: isActive ? "default" : "pointer",
                    opacity: isActive ? 1 : 0.85,
                    display: "flex",
                    flexDirection: "column",
                    alignItems: "center",
                    gap: "6px",
                    transition: "all 0.2s ease",
                  }}
                >
                  <span style={{ fontSize: "28px" }}>{loc.icon}</span>
                  <span>{loc.label}</span>
                  {isActive && (
                    <span style={{
                      fontSize: "11px",
                      opacity: 0.9,
                      fontWeight: "500",
                    }}>
                      You are here
                    </span>
                  )}
                </button>
              );
            })}
          </div>
        </div>
      )}
    </div>
      );
    }} />
  );
}

Desglose línea por línea:

  • api.variables.current_location — lee el valor de la variable de ubicación actual
  • locations — un array de configuración que define el ID, etiqueta en inglés, icono emoji, action ID del comportamiento y colores para los estados normal y resaltado de cada ubicación. Para añadir una nueva ubicación, simplemente añade una entrada al array
  • isLastMsg — el mapa solo se muestra en el último mensaje, no en cada uno
  • isActive — comprueba si este botón coincide con la ubicación actual. Si es así, el botón usa el color resaltado y muestra "You are here"
  • !isActive se comprueba antes de llamar a executeAction — evita que el jugador haga clic repetidamente en la ubicación actual. Ya estás en el Pueblo; hacer clic en Pueblo de nuevo no hace nada
  • gridTemplateColumns: "1fr 1fr" — un layout de cuadrícula de dos columnas de igual ancho, cuatro botones dispuestos en una cuadrícula 2x2
  • transition: "all 0.2s ease" — animación sutil al hacer hover

¿Quieres un layout diferente?

Cambia gridTemplateColumns a "1fr 1fr 1fr" para tres columnas, o "1fr" para una pila vertical de una sola columna. gap controla el espaciado entre botones. El layout está completamente controlado por CSS Grid — ajústalo como quieras.


Paso 6: Guarda y prueba

  1. Haz clic en Save en la parte superior del editor
  2. Haz clic en Start Game o vuelve a la página de inicio e inicia una nueva sesión
  3. Verás un panel de mapa debajo del mensaje de la IA con cuatro botones de ubicación. El botón "Village" está resaltado, mostrando "You are here"
  4. Haz clic en Forest — la IA responde inmediatamente con un pasaje describiendo la escena del bosque, y el botón "Forest" se resalta en el mapa
  5. Si configuraste BGM, deberías escuchar la música hacer crossfade de la pista del pueblo a la del bosque
  6. Haz clic en Cave — la escena cambia de nuevo, la IA describe la cueva, la BGM hace crossfade
  7. Intenta hacer clic en la ubicación actualmente resaltada — no pasa nada (ya estás allí)
  8. Chatea normalmente con la IA, luego cambia de ubicación — todo funciona; el mapa permanece en la parte inferior del último mensaje

Si algo sale mal:

SíntomaCausa probableSolución
No puedo ver el panel del mapaEl código del Root Component no se guardó o tiene un error de sintaxisComprueba el estado de compilación en la parte inferior del panel Custom UI — debería mostrar "OK" verde
Hacer clic en un botón no hace nadaEl action ID del comportamiento no coincideConfirma que los action IDs de los comportamientos (go-village, etc.) coincidan exactamente con el campo action del array locations en el código
La IA no responde con una nueva escenaAl comportamiento le falta la acción "Request AI Reply"Comprueba que la última acción de cada comportamiento sea "Request AI Reply"
El resaltado del mapa no cambiaLa variable no se está actualizandoComprueba que la primera acción de cada comportamiento sea "Modify Variable" apuntando a current_location
La BGM no cambiaID de pista no coincide o audio no subidoConfirma que los IDs de pista en el comportamiento coincidan con los IDs de pista en la pestaña Audio
La transición de BGM suena discordanteNo se está usando crossfadeConfirma que la operación de la acción "Play Music" esté establecida en crossfade con una duración de fundido de al menos 2-3 segundos
Las cuatro entradas están habilitadas a la vezEl comportamiento olvidó deshabilitar las otras entradasCada comportamiento debe deshabilitar las otras tres entradas de ubicación antes de habilitar la entrada de la ubicación objetivo

Ideas de expansión

Añadir más ubicaciones

¿Quieres añadir una quinta ubicación (digamos, "Puerto")? Cuatro cosas que hacer:

  1. Pestaña Lore → crea una entrada "Harbor Atmosphere" (deshabilitada por defecto)
  2. Pestaña Audio → crea una pista bgm_harbor (opcional)
  3. Pestaña Behaviors → crea un comportamiento "Go to Harbor" con action ID go-harbor, mismo patrón de acción que los otros cuatro. Vuelve también a cada uno de los cuatro comportamientos existentes y añade una acción "Disable Lore Entry: Harbor Atmosphere"
  4. Root Component → añade una entrada al array locations:
tsx
{ id: "harbor", label: "Harbor", icon: "⚓", action: "go-harbor",
  color: "#1e40af", bg: "#dbeafe", border: "#3b82f6",
  activeBg: "#3b82f6", activeColor: "#ffffff" },

El layout de cuadrícula se adapta automáticamente — 5 botones se organizarán como 2 en la primera fila, 2 en la segunda, 1 en la tercera.

Restringir rutas de viaje

Si no quieres que el jugador salte libremente entre dos ubicaciones cualesquiera (por ejemplo, "debes pasar por el Bosque para llegar a la Cueva"), añade lógica de ruta al Root Component:

tsx
// Define las rutas alcanzables
const routes = {
  village: ["forest", "market"],       // Desde Village se puede ir a Forest y Market
  forest:  ["village", "cave"],        // Desde Forest se puede ir a Village y Cave
  cave:    ["forest"],                 // Desde Cave solo se puede volver a Forest
  market:  ["village"],                // Desde Market solo se puede volver a Village
};

const reachable = routes[currentLocation] || [];

// Añade comprobaciones al onClick y al style del botón
const canGo = reachable.includes(loc.id);
// ...
onClick={() => {
  if (!isActive && canGo) {
    api.executeAction(loc.action);
  }
}}
style={{
  // ...
  opacity: isActive ? 1 : canGo ? 0.85 : 0.3,
  cursor: isActive ? "default" : canGo ? "pointer" : "not-allowed",
}}

Las ubicaciones inalcanzables aparecen desvanecidas y no clicables — el jugador puede ver de un vistazo que "no puedo ir allí ahora mismo".


Referencia rápida

Qué quieresCómo hacerlo
Seguir la ubicación actual del jugadorVariable de tipo string current_location con IDs de ubicación como valores
Cambiar de escena al hacer clic en un botónDisparador del comportamiento establecido en "Action", action ID coincide con executeAction() en el Root Component
Intercambiar atmósfera de ubicaciónAcciones del comportamiento: "Disable Lore Entry" para apagar la ubicación antigua, "Enable Lore Entry" para encender la nueva
Transición suave de BGMAcción del comportamiento "Play Music" con operación establecida en crossfade, duración de fundido 2-3 segundos
La IA describe la nueva escena inmediatamente al hacer clicAcción del comportamiento "Request AI Reply" con contexto de llegada
Resaltar la ubicación actualCompara current_location con el ID del botón dentro del Root Component; el botón coincidente obtiene estilo resaltado
Evitar volver a hacer clic en la ubicación actualComprobación if (!isActive) antes de llamar a executeAction
Mostrar el mapa solo en el último mensajeComprueba msg.messageIndex === msgs.length - 1 dentro de <Chat renderBubble>

Pruébalo tú mismo — mundo demo importable

Descarga este JSON e impórtalo como un nuevo mundo para ver todo en acción:

recipe-12-demo.json

Cómo importar:

  1. Ve a Yumina → My WorldsCreate New World
  2. En el editor, haz clic en More ActionsImport Package
  3. Selecciona el archivo .json descargado
  4. Se crea un nuevo mundo con todas las variables, entradas, comportamientos y el Root Component preconfigurados
  5. Inicia una nueva sesión y pruébalo

Qué incluye:

  • 1 variable (current_location siguiendo la ubicación actual)
  • 4 entradas de lore (atmósfera de Pueblo / Bosque / Cueva / Mercado — solo Pueblo habilitada por defecto)
  • 4 comportamientos (Ir a Pueblo / Ir a Bosque / Ir a Cueva / Ir a Mercado — cada uno intercambia entradas + crossfade música + solicita descripción de IA)
  • Un Root Component (panel de mapa con cuadrícula 2x2 con resaltado de ubicación actual)
  • 4 pistas de BGM (tendrás que subir tus propios archivos de audio para reemplazar las URLs de marcador de posición)

Esta es la Receta #12

Esta receta muestra el combo clásico de comportamientos + Root Component — los botones disparan comportamientos, y cada comportamiento simultáneamente actualiza una variable, intercambia entradas de lore, hace crossfade de BGM, y solicita una respuesta de IA. El mismo patrón funciona para navegación por pisos, exploración de habitaciones, portales del mundo, o cualquier otra cosa que implique "moverse entre múltiples escenas".