Guía de UI personalizada
La UI personalizada es cómo los creadores le dan a sus Mundos un aspecto distintivo. Battle Royale tiene una interfaz táctica completa con barras de salud, un feed de muertes y un mapa dinámico. El Mundo romántico Sakura Season usa un diseño de novela visual con retratos de personajes y fondos de escena. El éxito sorpresa Still ejecuta un juego de puzzle completo dentro de su UI.
Ninguno de estos creadores escribió el código ellos mismos. Describieron lo que querían y Studio AI lo construyó.
Esta guía enseña el arte de hacer que tu Mundo se vea increíble. Para lo básico y la configuración, consulta Para empezar: Visuales y audio.
Tres formas en que un Mundo puede verse
Cada Mundo en Yumina cae en uno de tres estilos visuales. La decisión que tomes aquí da forma a todo lo demás.
Chat por defecto (no necesita UI personalizada)
Los mensajes aparecen como burbujas de texto. Hay un cuadro de entrada en la parte inferior. Todo se desplaza naturalmente. Esto es con lo que comienza cada nuevo Mundo, y para muchos Mundos es todo lo que necesitas.
Mejor para: roleplay de slice-of-life, aventuras simples, chats de personajes, cualquier Mundo donde la escritura ES la experiencia.
Si la escritura de la IA es lo que hace especial a tu Mundo, el chat por defecto mantiene a los jugadores enfocados en ella. No añadas UI personalizada solo porque puedes.
Burbujas de mensaje personalizadas
La personalización más popular en la plataforma. Mantienes la experiencia completa de chat (desplazamiento, streaming, swipes, cuadro de entrada) pero cambias cómo se ve cada mensaje.
Lo que esto desbloquea:
- Fondos y fuentes temáticas que coinciden con el estado de ánimo de tu Mundo
- Retratos de personajes junto al diálogo
- Una barra de estadísticas (HP, oro, afinidad) visible en cada mensaje
- Estilo de juego de horror con tonos oscuros y fuentes inquietantes
- Hablantes codificados por color en escenas multipersonaje
No estás reemplazando el chat. Lo estás decorando.
Modo de aplicación completa
La opción más poderosa. Controlas cada píxel. El chat se convierte en solo un Componente en tu diseño más grande, o puedes saltártelo por completo y construir algo completamente diferente.
Lo que esto desbloquea:
- Motores de novela visual con fondos de escena y sprites de personajes
- Navegación de mapa donde hacer clic en una ubicación envía un mensaje
- Pantallas de batalla por turnos
- Simuladores de teléfono donde diferentes "apps" desencadenan diferentes comportamientos de IA
- Paneles interactivos, pantallas de inventario, diarios de misión
Battle Royale usa el modo de aplicación completa para su vista táctica general. Still lo usa para su interfaz de puzzle. Estos Mundos no se parecen en absoluto a aplicaciones de chat.
La decisión: empieza con el chat por defecto. Si tu Mundo necesita atmósfera visual, añade burbujas personalizadas. Si tu Mundo necesita paneles interactivos, diseños tipo juego o una experiencia que no sea de chat, ve al modo de aplicación completa.
Studio AI es tu constructor
No necesitas escribir código. Necesitas saber lo que quieres y describirlo claramente.
Cómo funciona
Abre el editor, haz clic en Enter Studio y habla con el asistente de IA. Describe el aspecto que quieres en lenguaje natural. Studio AI genera el código y ves una vista previa en vivo en el panel Canvas.
Buenos prompts
Cuanto más específica sea tu descripción, mejor será el resultado. Aquí está el patrón: describe el diseño, el estado de ánimo y qué Variables mostrar.
Vago (la IA tiene que adivinarlo todo):
"Hazlo verse genial"
Bueno (diseño y estado de ánimo claros):
"Quiero una interfaz oscura con tema de horror. Barra de salud roja en la parte superior, mensajes estilizados como texto de máquina de escribir antigua en papel amarillento, efecto de niebla oscura alrededor de los bordes."
Genial (diseño + estado de ánimo + Variables específicas + comportamiento):
"Construye un diseño de novela visual. Imagen de fondo a pantalla completa desde la Variable
scene_bg. Retrato del personaje a la izquierda desdecharacter_sprite. Cuadro de diálogo semitransparente en la parte inferior con el nombre del personaje desdespeaker_nameen rosa. Cuando la afinidad esté por encima de 75, añade un sutil efecto de partículas de corazón."
El proceso iterativo
Nadie lo logra perfecto en el primer intento. Los mejores Mundos se construyen mediante refinamiento:
- Describe la imagen general — "Quiero un diseño de novela visual con fondos de escena y retratos de personajes"
- Revisa la vista previa del Canvas — ¿el diseño se siente bien? ¿El espaciado es bueno?
- Refina los detalles — "Haz el cuadro de diálogo más transparente. Mueve el retrato del personaje al lado derecho. Usa una fuente serif para el diálogo."
- Añade pulido — "Añade una animación de fundido cuando la escena cambie. Haz que el medidor de afinidad brille cuando aumente."
Cada ronda toma segundos. Cinco rondas de iteración superan a una hora intentando describir todo de antemano.
Qué decirle a Studio AI sobre tus Variables
Studio AI puede leer las definiciones de Variables de tu Mundo, pero ayuda explicar qué importa:
"Mis Variables: health (0-100, mostrar como barra roja), gold (number, mostrar como texto con un icono de moneda), location (string como 'forest' o 'cave', mostrar en la esquina superior derecha), is_night (boolean, cuando es true oscurece el fondo)"
Lo que es posible: la API puente
Tu UI personalizada puede hacer mucho más que mostrar Variables. Esto es lo que el puente te da, explicado en términos de lo que puedes CONSTRUIR, no qué funciones llamar.
Leer el estado del juego
Tu UI puede leer cualquier Variable, el historial completo de mensajes, quién es el jugador actual, qué Modelo está seleccionado, si la IA está generando actualmente y más. Así es como funcionan las barras de estadísticas, inventarios y rastreadores de misiones: leen Variables y las muestran visualmente.
Controlar el chat
Tu UI puede enviar mensajes como jugador, editar o eliminar mensajes existentes, pedirle a la IA que regenere, detener la generación a mitad del stream o reiniciar la conversación. Así es como funcionan los botones interactivos: un botón "Beber la poción" envía ese texto como mensaje del jugador, activando a la IA para que responda.
Reproducir audio
Tu UI puede reproducir música de fondo, efectos de sonido, fundirse entre pistas y controlar el volumen. Combinado con Variables, puedes tener música que cambie según la ubicación o el estado de ánimo automáticamente.
Side completions — múltiples "voces" de IA en un Mundo
Esta es una de las capacidades más poderosas en toda la plataforma. Tu UI puede llamar a ai.complete() para ejecutar una conversación de IA separada que nunca toca el chat principal. La IA responde solo a tu UI: el jugador no lo ve como un mensaje de chat, y no afecta el historial ni el estado de la conversación principal.
Piensa en lo que esto desbloquea:
- Conversaciones telefónicas de NPC: un personaje tiene su propia ventana de chat dentro de tu UI. El jugador le envía mensajes de texto, la IA responde con la voz de ese personaje, y la historia principal continúa por separado. Cada personaje secundario puede tener su propio prompt de sistema y personalidad.
- Descripciones de elementos generadas por IA: el jugador pasa el cursor sobre un elemento en su inventario, y la IA escribe una descripción única sobre la marcha basada en el contexto actual de la historia.
- Sistemas de pistas: un botón "pensar" que analiza la situación del jugador y ofrece un empujón sin que la IA principal rompa el personaje.
- Paneles de monólogo interno: un panel lateral que muestra lo que piensa un NPC, generado por un prompt de IA diferente al que impulsa el diálogo.
- Paneles de traducción o resumen: resúmenes o traducciones en tiempo real impulsados por IA de la conversación que ocurre junto al chat principal.
Puedes pasar includeLorebook: "matched" para que la IA secundaria vea el mismo lore del Mundo y perfiles de personajes que el chat principal, manteniendo las conversaciones secundarias en el canon en lugar de desviarse. O omítelo para tareas que no necesitan contexto del Mundo (traducciones, clasificaciones, utilidad pura).
Las llamadas secundarias comparten el mismo límite de tasa y facturación de créditos que el chat principal. Consulta la Referencia API para la firma completa del método, los límites y las opciones de includeLorebook.
Inyección de contexto invisible
Tu UI puede enviar un mensaje que la IA principal vea en su siguiente turno pero que el jugador nunca vea en el chat. Llama a injectContext() y el motor desliza un mensaje único de sistema (o usuario) en el siguiente prompt, luego lo descarta automáticamente.
Así es como haces que la IA reaccione a cosas que suceden fuera de la conversación principal:
- Eventos fuera de escena: "El NPC susurró para sí mismo después de que te fuiste: 'No puedo dejar que encuentren la carta.'" La IA teje esto en su próxima respuesta naturalmente.
- Cambios ambientales: "Ha empezado a llover. La entrada de la cueva ahora está parcialmente inundada." El jugador no ve esta instrucción, pero la IA describe la lluvia.
- Consecuencias impulsadas por UI: cuando el jugador hace clic en un botón en tu UI personalizada (como robar de una tienda), inyecta contexto diciéndole a la IA lo que ocurrió para que pueda reaccionar.
- Mensajes telefónicos y notificaciones: "Acabas de recibir un texto enigmático: 'Esta noche, 9pm, lugar habitual.'" La IA incorpora esto en la narrativa sin que el jugador vea un mensaje del sistema.
A diferencia de ai.complete(), que ejecuta una llamada de IA separada, injectContext() se alimenta en la próxima respuesta de la IA principal. Los dos se complementan: usa ai.complete() cuando quieras una voz de IA separada, usa injectContext() cuando quieras que la IA principal sepa de algo que el jugador no dijo.
Consulta la Referencia API para la firma del método.
Guardar y cargar
Almacenamiento persistente que sobrevive a las Sesiones. Puntuaciones más altas, logros desbloqueados, preferencias del jugador, ajustes personalizados: cualquier cosa que quieras recordar entre Sesiones de juego.
Navegar y notificar
Alternar modo inmersivo, mostrar notificaciones toast, copiar texto al portapapeles, cambiar entre variantes de saludo. Tu UI tiene los mismos controles que tiene la interfaz incorporada de la plataforma.
Dónde encontrar la API completa
La referencia completa método por método con firmas de tipo y ejemplos está en dos lugares:
- Referencia API — el recorrido guiado con ejemplos elaborados
- Especificación del mundo: UI personalizada — la especificación legible por máquina, diseñada para consumo por IA
Dale la especificación del Mundo a Studio AI, Claude o Cursor cuando construyas UI compleja. Manejarán los detalles técnicos.
Las tres rutas de personalización
Ruta 1: Pregúntale a Studio AI (recomendado para la mayoría de los creadores)
Esta es la ruta que toman la mayoría de los Mundos exitosos. Describes lo que quieres, Studio AI escribe el código, refinas mediante conversación.
Fortalezas: no se necesita conocimiento de código. Iteración rápida. Studio AI conoce toda la API y maneja casos extremos (streaming, estados vacíos, diseño móvil) automáticamente.
Cuándo usar: empieza siempre aquí. Cambia a otra ruta solo si te encuentras con algo que Studio AI no puede hacer.
Ruta 2: Usa una IA externa (Claude, Cursor, ChatGPT)
Si prefieres una herramienta de IA diferente, o si estás construyendo algo complejo que se beneficia de una conversación más larga, puedes usar cualquier IA que escriba código. La clave es darle el contexto técnico de Yumina.
Dile a la IA externa:
- Tu código es TSX (React), ejecutándose en un iframe sandbox
- Todo está disponible como globales: React, useYumina, Icons, Chat, MessageList, MessageInput, Tailwind CSS
- El archivo de entrada es
index.tsxconexport default function MyWorld() { ... } - El estado del juego viene de
useYumina(): Variables, mensajes, estado de streaming, todo - Usa
varyfunction()en lugar deconst/let/funciones flecha - Sin sintaxis TypeScript (sin genéricos, sin aserciones
as, sin interfaces)
Cuándo usar: UIs complejas multi-archivo, cuando quieres más control sobre la conversación, o cuando ya estás trabajando en un editor de código impulsado por IA.
Ruta 3: Codifica a mano (para desarrolladores experimentados)
Abre el editor, ve a Custom UI y escribe TSX directamente. La vista previa en vivo se actualiza mientras escribes.
Cuándo usar: eres un desarrollador que piensa en React, o quieres control preciso sobre cada detalle.
Reglas básicas para el código de UI personalizada
Estas se aplican sin importar qué ruta tomes. Si estás usando Studio AI, las maneja automáticamente: esta sección es para entender lo que está ocurriendo bajo el capó, o para depurar cuando algo va mal.
Las seis reglas
1. Formato del archivo de entrada
index.tsx debe exportar un componente función por defecto. Esta es la raíz de tu UI:
export default function MyWorld() {
return <Chat />;
}2. Globales: no los importes
Estos ya están disponibles en todas partes, sin necesidad de importar: React, useYumina, Icons, Chat, MessageList, MessageInput, useAssetFont, y todas las clases CSS de Tailwind.
Escribir import React from "react" no romperá nada (se elimina silenciosamente), pero es innecesario.
3. Tus propios archivos SÍ pueden importarse
Los root components multi-archivo usan sintaxis de módulo ES:
import StatBar from "./stat-bar"
import DialogueBox from "./dialogue-box"4. Usa React.useState(), no useState()
React está en alcance como módulo, pero los hooks individuales no están desestructurados. Siempre prefija con React.:
var [count, setCount] = React.useState(0)5. Usa var y function(), no const/let/funciones flecha
El sandbox ocasionalmente tiene problemas de alcance con const/let y funciones flecha. var y function() son más robustos:
// Prefiere esto
var api = useYumina()
var items = api.variables.inventory || []
// En lugar de esto
const api = useYumina()
const items = api.variables.inventory ?? []6. Sin sintaxis TypeScript
Sin genéricos (<T>), sin interfaces, sin aserciones de tipo as, sin satisfies. El sandbox compila TSX pero no TypeScript completo.
Patrones comunes
Estos son los bloques de construcción que combinan los Mundos top. Cada descripción te dice lo que hace el patrón y cuándo usarlo. Los ejemplos de código son colapsables: están ahí como referencia, pero Studio AI los genera por ti.
Burbujas de mensaje personalizadas
El patrón más común. Mantén la experiencia completa de chat, solo cambia cómo se ven los mensajes. Usa <Chat renderBubble={...} /> para tomar control del renderizado de burbujas mientras la plataforma maneja todo lo demás (desplazamiento, streaming, swipes, entrada).
Cuándo usar: quieres mensajes temáticos (horror oscuro, romance elegante, terminal de ciencia ficción) sin reconstruir todo el chat.
Ejemplo de código: burbujas temáticas con estadísticas
export default function MyWorld() {
var api = useYumina()
return (
<Chat renderBubble={function(msg) {
if (msg.role === "user") {
return (
<div className="ml-auto max-w-[80%] rounded-xl bg-blue-500/20 px-4 py-3 text-blue-100">
{msg.rawContent}
</div>
)
}
return (
<div className="mr-auto max-w-[85%] rounded-xl border border-zinc-700 bg-zinc-900 p-4">
<div dangerouslySetInnerHTML={{ __html: msg.contentHtml }} />
<div className="mt-3 flex gap-4 text-xs text-zinc-400">
<span>HP {api.variables.health}/100</span>
<span>Gold {api.variables.gold}</span>
</div>
</div>
)
}} />
)
}Visualizaciones de estadísticas y HUDs
Un panel fijo que muestra salud, oro, afinidad, ubicación o cualquier otra Variable. Generalmente colocado encima del chat (usando la prop children de <Chat>) o al lado (diseño flex).
Cuándo usar: tu Mundo rastrea estadísticas que los jugadores necesitan ver en todo momento: RPGs, juegos de supervivencia, sims de citas con medidores de afinidad.
Ejemplo de código: barra HUD superior
export default function MyWorld() {
var api = useYumina()
return (
<Chat>
<div className="shrink-0 px-4 py-2 bg-black/60 backdrop-blur flex gap-4 text-xs text-zinc-300">
<div className="flex items-center gap-1">
<Icons.Heart className="w-3 h-3 text-red-400" />
<span>{api.variables.health || 100}/100</span>
</div>
<div className="flex items-center gap-1">
<Icons.Coins className="w-3 h-3 text-amber-400" />
<span>{api.variables.gold || 0}</span>
</div>
<div className="ml-auto text-zinc-500">
{api.variables.location || "Unknown"}
</div>
</div>
</Chat>
)
}Diseño de novela visual
Fondo de escena a pantalla completa, sprite de personaje, cuadro de diálogo semitransparente en la parte inferior. La opción más cinematográfica. Generalmente lee datos de escena y personaje desde Variables que la IA actualiza mediante Directivas.
Cuándo usar: romance, drama, historias de slice-of-life donde la atmósfera visual importa más que una interfaz de chat tradicional.
Ejemplo de código: shell VN con fondos de escena
export default function MyWorld() {
var api = useYumina()
var bg = api.variables.scene_bg
var sprite = api.variables.character_sprite
var speaker = api.variables.speaker_name
var lastMsg = (api.messages || []).slice(-1)[0]
return (
<div
className="relative w-full h-full bg-cover bg-center"
style={{
backgroundImage: bg
? "url(" + bg + ")"
: "linear-gradient(135deg, #1e293b, #0f172a)"
}}
>
{sprite && (
<img
src={sprite}
className="absolute bottom-0 left-1/2 -translate-x-1/2 max-h-[80%] pointer-events-none"
/>
)}
<div className="absolute inset-x-4 bottom-4">
<div className="rounded-xl border border-white/10 bg-black/70 p-4 backdrop-blur-sm">
{speaker && (
<div className="mb-1 text-sm font-bold text-pink-300">{speaker}</div>
)}
<div className="leading-relaxed text-zinc-100">
{lastMsg ? lastMsg.content : ""}
</div>
</div>
<div className="mt-2">
<MessageInput />
</div>
</div>
</div>
)
}Panel de juego en barra lateral
Chat a la izquierda, un panel fijo a la derecha mostrando información del personaje, estadísticas, inventario o un mapa. Lo mejor de ambos mundos: los jugadores obtienen la experiencia completa de chat Y la información persistente del juego.
Cuándo usar: RPGs, juegos de aventura, cualquier Mundo donde los jugadores necesiten referenciar estadísticas o inventario mientras chatean.
Ejemplo de código: chat + barra lateral
export default function MyWorld() {
var api = useYumina()
return (
<div className="flex h-full">
<div className="flex-1 min-w-0">
<Chat />
</div>
<aside className="w-72 shrink-0 border-l border-border bg-card p-4 overflow-y-auto">
<div className="text-sm font-bold mb-3">{api.variables.player_name || "Adventurer"}</div>
<div className="space-y-2 text-xs">
<div className="flex justify-between">
<span className="text-muted-foreground">HP</span>
<span>{api.variables.health || 100}/{api.variables.max_health || 100}</span>
</div>
<div className="h-1.5 rounded-full bg-zinc-800 overflow-hidden">
<div
className="h-full bg-red-500 transition-all duration-300"
style={{ width: ((api.variables.health || 100) / (api.variables.max_health || 100) * 100) + "%" }}
/>
</div>
</div>
<div className="mt-4 text-xs text-muted-foreground">
<div className="font-medium mb-2">Inventory</div>
<div className="grid grid-cols-3 gap-1">
{(api.variables.inventory || []).map(function(item, i) {
return (
<div key={i} className="aspect-square rounded border border-border bg-muted flex items-center justify-center text-[10px]">
{item.name || "?"}
</div>
)
})}
</div>
</div>
</aside>
</div>
)
}Botones y opciones interactivas
Botones que envían mensajes o establecen Variables al hacer clic. La forma más simple de interactividad más allá de escribir. Especialmente poderoso para el saludo inicial: conviértelo en una pantalla de creación de personaje, un selector de dificultad o un abridor de historia ramificada.
Cuándo usar: cualquier Mundo donde quieras que el jugador elija entre opciones en lugar de (o además de) escribir.
Ejemplo de código: saludo como creación de personaje
export default function MyWorld() {
var api = useYumina()
return (
<Chat renderBubble={function(msg) {
if (msg.messageIndex === 0 && msg.role === "assistant") {
return (
<div className="space-y-4">
<div dangerouslySetInnerHTML={{ __html: msg.contentHtml }} />
<div className="flex gap-3">
<button
onClick={function() {
api.setVariable("class", "Warrior")
api.sendMessage("I choose Warrior")
}}
className="px-4 py-3 rounded-lg border border-zinc-600 hover:bg-zinc-800 transition"
>
Warrior
</button>
<button
onClick={function() {
api.setVariable("class", "Mage")
api.sendMessage("I choose Mage")
}}
className="px-4 py-3 rounded-lg border border-zinc-600 hover:bg-zinc-800 transition"
>
Mage
</button>
</div>
</div>
)
}
return <div dangerouslySetInnerHTML={{ __html: msg.contentHtml }} />
}} />
)
}Errores comunes
Añadir UI personalizada cuando no la necesitas. El chat por defecto es limpio, rápido y mantenido por la plataforma. Si la fortaleza de tu Mundo es la calidad de escritura, el chat por defecto mantiene a los jugadores enfocados en ella. No añadas complejidad de UI por el simple hecho de hacerlo.
Olvidar el streaming. Cuando la IA está generando, msg.isStreaming es true y el contenido está incompleto. Tu burbuja debe manejar el texto parcial con elegancia: no analices el contenido asumiendo que está completo.
No probar en móvil. Muchos jugadores usan teléfonos. Si tu barra lateral tiene 320px de ancho, no cabrá en una pantalla móvil. Usa clases responsive de Tailwind (hidden md:block para ocultar paneles en pantallas pequeñas) o prueba tu diseño en anchos estrechos.
Bloquear la entrada. Si vas al modo de aplicación completa y olvidas incluir <MessageInput /> (o tu propia entrada que llama a api.sendMessage()), los jugadores no pueden hablar con la IA. Siempre asegúrate de que haya una forma de enviar mensajes.
Usar const y funciones flecha. El sandbox a veces tiene problemas de alcance con estas. Usa var y function() en su lugar. Studio AI hace esto automáticamente, pero si estás codificando a mano o pegando desde una IA externa, mira esto.
Importar globales. Escribir import React from "react" o import { useState } from "react" puede causar errores. React, useYumina, Icons, Chat, MessageList, MessageInput: estos son todos globales. No los importes.
Consulta también
- Referencia API — la referencia completa método por método para
useYumina(),ai.complete(),injectContext()y todos los demás métodos del puente - Diseñando el estado del juego — las Variables que tu UI lee y muestra
- Diseño de audio — reproduciendo audio desde tu UI personalizada mediante la API puente
- Directivas y Macros de IA — cómo la IA actualiza el estado que tu UI renderiza
Especificación legible por máquina → Especificación del mundo: UI personalizada
