Editor de Salas#
Una sala es la unidad de ubicación del juego: una imagen de fondo más cada tipo de
contenido autorado que se apila encima. Es la única herramienta donde prácticamente todos
los demás subsistemas del motor se cruzan — los hotspots reusan la misma UI de reacciones
que el Editor de Reacciones, el archivo de reglas de una sala es lo que el Editor de
Cinemáticas y el Editor de Puzzles escriben, sus regiones son el destino de los pasos
NPCENTER/NPCEXIT de una cinemática, y su fondo alimenta al Orquestador de Escenas y a
cada personaje colocado dentro. Es la herramienta más grande de toda la suite, precisamente
por esto.
Llegas a él desde el Hub (con el dev server corriendo). La barra de herramientas tiene
un desplegable Sala, + Nuevo, Guardar (escribe el módulo de la sala), un
Exportar oculto (vía de escape de código fuente generado, mantenida para depuración),
Validar (resumen + wireframe + advertencias de conexión), Deshacer/Rehacer,
Escalar Todo, Seleccionar Todo, una herramienta 🏞️ BG (mover/redimensionar el
fondo — G), y un preview 🎚️ Sandbox (ambos cubiertos más abajo). Bajo la barra hay una
franja de miniaturas de salas para saltar de una a otra sin volver al desplegable; viene en
tres tamaños y se puede plegar, y tu elección queda recordada.
Tres docks flotantes viven sobre el propio canvas en vez de comerse filas de la barra: las herramientas (arriba al centro por defecto), los chips de visibilidad (abajo al centro) y los controles de zoom (in / out / fit / %, arriba a la derecha). Cada uno arranca con un asa ✥ — clic para despegarlo, arrastrarlo donde quieras, clic de nuevo para devolverlo a su sitio — y un tirador ◢ en la esquina inferior derecha fija su ancho. La posición y el ancho se recuerdan por dock, así que la distribución que armes es la que encuentras la próxima sesión.
El dock de herramientas cambia qué edita un clic en el canvas: Seleccionar,
Caminable, Hotspot, Walk-B (walk-behind), Regiones, Escala Z,
Personaje, Efectos, Luz Z, Capas, y Surface FX — cada una con su propio
atajo de teclado (W, H, B, R, Z, C, E, L, P, F). Junto a ellas, ✎
Tweak es una acción y no un modo: abre un retoque de píxeles puntual sobre lo que esté en
contexto — el sprite del hotspot seleccionado, o el fondo de la sala. El panel de Capas lleva
el mismo botón para el PNG de la capa seleccionada. Los chips de
visibilidad ocultan cualquier categoría de capa para una vista más limpia sin abandonar la
herramienta activa. El panel lateral muestra propiedades de lo que esté seleccionado; el
canvas es la sala misma, paneada/zoomeada con una transformación contain-fit.
Editar un polígono#
Casi todo lo que autoras en una sala es un polígono — áreas caminables, hotspots, walk-behinds, regiones, zonas de luz, áreas de efecto y la máscara de recorte de una capa funcionan todas igual. Haces clic para ir colocando vértices de a uno y después vuelves a hacer clic sobre el primero para cerrar la forma. Una vez cerrada puedes remodelarla sin volver a dibujarla:
- Arrastra un vértice para moverlo.
- Haz clic en una arista para insertar un vértice ahí y empezar a arrastrarlo al toque.
- Arrastra desde adentro de la forma para mover el polígono entero.
El cursor te dice cuál de esas cosas va a hacer el clic antes de que te comprometas — una manito señaladora sobre un vértice, un cursor de copia sobre una arista, una mano abierta dentro de la forma, y una cruz en todo lo demás (donde el clic coloca un punto nuevo). Es el mismo vocabulario en todas las herramientas de polígono, así que la forma que estés editando nunca te cambia los gestos.
Anatomía de una sala#
Un descriptor de sala es un módulo JS plano: un id, un string description sin envoltura
(ver la nota de i18n más abajo), un background, y arreglos paralelos para cada subsistema
— hotspots[], walkableAreas[], regions[], lightZones[], layers[],
reflections[] + un único bloque lighting, partyAnchors[], más un archivo rules
(compartido con los Editores de Cinemáticas y Puzzles) que guarda cinemáticas/watchers/
globalWatchers asociados a esta sala.
Hotspots#
Un hotspot es { id, name, poly, walkTo:{x,y}, defaultVerb, reactions:{...} } — un
polígono clicable más el punto al que camina el personaje del jugador antes de que dispare
la reacción. Al dibujar el hotspot ese punto se deriva solo — centro del borde inferior de
la forma, un paso por delante de ella (te paras frente a la puerta, no dentro del marco),
clampeado al cuarto y al área caminable para que lo que se escribe sea un lugar donde un
personaje realmente podría pararse. Ese paso se mide contra tu elenco, no en píxeles fijos:
es una fracción del alto en pantalla del personaje en ese punto, así que se lee igual con
el juego a 320×200 que a 1920×1080, y se acorta solo en un hotspot al fondo del cuarto,
donde el escalado por profundidad achica al personaje. El botón 📍 Colocar lo pisa a mano y deja el punto
exactamente donde haces clic; Validate avisa cuando un walk-to queda fuera del cuarto o
fuera del piso caminable (en el juego el personaje se engancha al punto de piso más cercano
igual, así que llega — pero no al punto que elegiste). Más allá de la forma, un hotspot
lleva comportamiento de sprite
(interruptores visible/habilitado, opacidad, un modo dynamic opcional que lo dibuja
ordenado por profundidad contra los personajes vía z/sortY en vez de como arte de fondo
plano) y tres tarjetas de comportamiento opcionales:
- Animación — conecta el hotspot a una animación de categoría objeto (secuencia
idle/frames) en vez de un sprite estático. Ese «en vez de» es literal, y tiene una
consecuencia que conviene saber antes de salir a depurarla: en cuanto el hotspot está
animado, lo que se dibuja es el frame del clip, así que una reacción
SETFRAMEsobre ese hotspot no cambia nada visible. Para mover un hotspot animado a un frame concreto vaSETANIMFRAME:<n>— el editor te avisa si agarras el token equivocado. - Audio en loop —
hs.audio = { id, on }para un loop ambiental persistente (radio, fuente, maquinaria); habilitarlo autocablea la reacciónusea un tokenTOGGLEHOTSPOTAUDIOsin argumentos que se autotarguetea al hotspot (a prueba de renombrado — nunca hardcodea el id del hotspot), y se retira limpiamente si ya habías autorado una reacciónusea mano. - Abrible —
hs.openable = { open, closedFrame, openFrame }para una puerta/contenedor con dos cuadros; habilitarlo autocablea las reaccionesopen/closeaSETHOTSPOTOPEN:open/SETHOTSPOTOPEN:closed, mismo autotargeteo, misma regla de no pisar reacciones autoradas a mano.
El tamaño de un hotspot con sprite vive en un solo lugar: Tamaño del sprite, dos cajas en píxeles de sala unidas por un 🔗, el mismo corchete que ya lleva el ancho/alto del cuarto. Vinculadas, cualquiera de las dos escala el arte de forma uniforme. Desvinculadas, el Alto lo estira o lo aplana solo (×0.05 a ×3 de su proporción natural), que es lo que quieres cuando una cosa tiene que leerse más chaparra y no más chica; y entonces editar el Ancho deja ese alto donde lo pusiste en vez de arrastrarlo. El alto necesita la proporción del propio sprite para hacer su cuenta, así que él y el 🔗 se quedan apagados hasta que una imagen termine de decodificar — un 1:1 inventado querría decir otra cosa en silencio apenas llegara el arte de verdad.
Abajo de las cajas hay dos botones. ⊡ Ajuste rect es el reset del tamaño: devuelve los dos
ejes a los píxeles naturales de la imagen — un píxel de imagen, un píxel de sala — y rehace el
polígono como ese rectángulo. ⬡ Trazar contorno en cambio recorre el canal alfa y devuelve
una silueta de 24 vértices. Los dos miden la imagen que el juego realmente dibuja: en un
hotspot que carga a la vez un icono estático y una animación, ese es el cuadro de la
animación y no el icono, porque la animación es lo que el runtime renderiza (una animación
pausada igual muestra su cuadro actual — playing controla el avance, no la visibilidad).
Un hotspot con sprite además se puede posar: más allá del tamaño y la rotación, la Deformación del sprite lo inclina en cualquiera de los dos ejes (±80°). Es una transformación viva, no un horneado — el PNG en disco no se toca, así que puedes dejar un cartel apoyado en diagonal y deshacerlo arrastrando el fader de vuelta. Reiniciar deformación devuelve las inclinaciones y el pin de esquinas a neutro y deja el tamaño en paz a propósito: deshacer una pose nunca debería redimensionar una cosa, y para eso está ⊡ Ajuste rect. Un valor que quedó en neutro directamente no se escribe al archivo del cuarto. Los tiradores de esquina del canvas siguen la forma deformada, y el cursor también: el test de click muestrea el sprite donde realmente se dibuja.
El polígono sigue siendo el límite generoso. Aplanar un sprite no achica el área clickeable — un click adentro del polígono pero afuera del sprite sigue contando, porque esa es la zona que dibujaste tú. Si quieres que el área de click siga al sprite aplanado, vuelve a correr ⬡ Trazar contorno después; traza la silueta deformada.
La deformación y el horneado de ✎ Retocar coinciden. Los mismos ángulos de inclinación dan la misma pose los pongas acá o los hornees en los píxeles con Retocar, así que puedes prototipar en vivo y hornear más tarde sin que el objeto se corra.
◳ Pinchar esquinas es el último control y el que funciona distinto. Inclinar y estirar son una matriz que el motor aplica en vivo, por cuadro, gratis; un pin de 4 esquinas es perspectiva — un cartel visto de costado, una pantalla inclinada contra la pared — y ninguna matriz en vivo la puede expresar. Por eso el botón enciende cuatro tiradores en el lienzo en lugar de agregar un fader: arrástralos, con ⇧ para una grilla de 5%, y el sprite se inclina en profundidad. Como es perspectiva, el motor hornea el resultado en píxeles y cachea el horneado, así que sigue sin costar nada por cuadro; lo que sí cuesta es que el pin está limitado a un ancho de sprite de recorrido por esquina, que es lo que mantiene acotado el bitmap horneado. El pin se guarda relativo a la caja del propio sprite, así que cambiar el Ancho más tarde reescala la inclinación con el arte en vez de romperla. Los tiradores están apagados por defecto porque uno de ellos cae exactamente donde cae el de redimensionar — encender el modo es cómo le dices al editor a cuál de los dos te referías. Reiniciar deformación borra el pin junto con las dos inclinaciones. ⊡ Ajuste rect en cambio lo conserva: un pin es la forma de la cosa, así que la caja ajustada se traza a través de él en vez de aplanarlo.
Un hotspot con sprite también lleva una sección Sprite FX en el panel — efectos
visuales por-hotspot renderizados por el mismo applier en juego, preview del editor y
sandbox (WYSIWYG por construcción): Sombra (toggle de 3 estados: apagada, básica
drop-shadow con X/Y/blur/color, o silueta — el contorno del propio sprite aplanado sobre
el piso exactamente como las sombras de personajes, rotable los 360° completos), Brillo
(bloom exterior desde el alfa del sprite), Difuminado, y Contorno (anillo trazado
desde la silueta del sprite). La sombra de silueta hereda el lighting del room por
defecto — mismo ángulo/largo/suavidad que las sombras de personajes, para que todas las
sombras del cuarto coincidan — con un toggle Heredar luz del room que materializa valores
explícitos por-hotspot cuando quieres dirigir un objeto aparte. Todos los knobs siguen la
convención "0 = apagado" y un hotspot sin tocar serializa byte-idéntico (hs.fx
simplemente ausente). Los hotspots sin sprite ignoran la sección — no hay nada que sombrear.
Un hotspot con sprite ofrece además 🎬 Enviar a animación, que copia el PNG a la carpeta
de fotogramas de la animación — nunca se referencia el sprite del hotspot, así que
normalizar o retocar un fotograma más tarde no puede volver atrás y mutar el arte del
hotspot. El selector lista las animaciones de objeto que ya tiene el cuarto para añadirle un
fotograma, más + Animación nueva, que crea una desde este sprite (ID precargado como
<hotspotId>_default — o _default_2, _3… si ese nombre ya está tomado, porque los IDs de
animación son globales al proyecto y dos cuartos pueden tener el mismo ID de hotspot;
renombrable después en el editor de Animaciones) y se la asigna al hotspot. Asignar avisa antes: un hotspot animado deja de dibujar su sprite estático en el
juego, porque manda la animación.
Separar un objeto del arte de fondo#
Un objeto pintado en tu fondo puede convertirse en el sprite de un hotspot sin salir del editor. Delinéalo con el polígono del hotspot y aprieta ⧉ Copiar para levantar esa región al sprite propio del hotspot — el fondo queda intacto — o ✂ Cortar para levantarla y perforar esa región en la imagen de fondo. En los dos casos el sprite nuevo queda fijado para dibujarse exactamente donde estaba, píxel a píxel, así que nada parece moverse en el momento en que lo aprietas. Lo que ganaste es que el objeto ahora se puede mover, ocultar, animar o sombrear, en vez de ser pintura.
Cortar es el que reescribe un archivo, así que pregunta antes, y la primera vez que cortas en
un cuarto guarda una copia prístina del fondo original en alternates/. El hueco que deja
queda tapado por el sprite nuevo hasta que muevas u ocultes el hotspot. El cuarto se guarda
solo justo después de un corte, para que el sprite y el hueco aterricen juntos — una recarga
no puede dejarte con uno y sin el otro.
El deshacer también devuelve el fondo.
Ctrl+Zdespués de un corte restaura la imagen de fondo y desconecta el sprite en un solo paso;Ctrl+Shift+Zvuelve a aplicar los dos. La copia de respaldo está para ir más atrás de lo que llega tu historial, no para el arrepentimiento del momento.
El orden de pintado es el orden de la lista. Los sprites de los hotspots se dibujan en
el orden en que aparecen en la lista de hotspots — el último pinta encima — y los botones
▲▼ de cada fila mueven un hotspot dentro de ese orden (▲ más atrás, ▼ más adelante).
Es lo que necesitas cuando abrir un contenedor revela algo adentro: autoras el cajón y la
llave como siempre, haces SHOWHOTSPOT de la llave al abrir el cajón, y bajas la llave en
la lista para que pinte sobre el sprite del cajón abierto. Ojo que este es un eje distinto
del modo dynamic de arriba — z/sortY ordenan un hotspot contra los personajes por
profundidad, mientras que el orden de la lista ordena el arte estático de un hotspot contra
otros hotspots.
El punto de color oculta y muestra el hotspot. Cada fila de la lista arranca con un punto del color de la capa de hotspots, y se atenúa cuando ese hotspot está oculto. Haz clic — o enfócalo y aprieta Enter — para alternarlo entre visible y oculto sin salir de la lista; es un atajo del botón VISIBLE / OCULTO del panel y hace exactamente lo mismo, deshacer incluido. Útil mientras estás vistiendo una sala y quieres sacar un objeto de en medio un rato.
🔒 Bloquea el hotspot que ya terminaste de colocar. Apilar hotspots trae un problema de
selección: el de arriba se come todos los clics, y llegar al de atrás obliga a barajar el
orden con ▲▼ y devolverlo después. El botón 🔒 de cada fila lo resuelve por el otro lado
— un hotspot bloqueado se vuelve transparente al canvas, así que el clic pasa de largo y
llega al que está debajo. Tampoco se puede arrastrar, deformar, escalar, rotar ni borrar
mientras esté bloqueado, y sus manijas de transformación dejan de dibujarse. La fila de la
lista lo sigue seleccionando igual (si no, no habría forma de desbloquearlo), y el candado es
sólo de autoría: se guarda como locked: true en la sala y el juego nunca lo lee.
Un objeto que el elenco rodea: ¿walk-behind o hotspot con profundidad? Las dos herramientas resuelven el mismo problema visual desde lados distintos, y cuál te toca depende de dónde vive el arte. Si el objeto está pintado en el fondo del cuarto —una columna, un mostrador—, es un walk-behind: calcas el polígono encima y pones la línea base donde el objeto apoya en el piso. Si el objeto tiene su propio sprite, y sobre todo si son varios (motos estacionadas a distintas distancias, barriles sueltos), es un hotspot con profundidad: enciende Profundidad (delante/detrás) en su panel y cada objeto trae su propia perilla, en vez de un polígono calcado sobre el arte por cada uno. Con Escala por profundidad encendida además se achican con la zona de escala del cuarto, que es justo lo que quieres cuando están a distintas distancias.
La línea de cruce es Y de orden (sortY), y en 0 = automático es el pie del sprite:
el objeto tapa al personaje mientras este camine por detrás de ese pie, y queda detrás en
cuanto lo pase. Súbela o bájala a mano sólo cuando el arte miente sobre dónde apoya (una moto
con la sombra pintada muy abajo, un objeto en perspectiva). Sesgo Z es el desempate para
cuando dos cosas comparten la misma Y.
El click sigue al pintado: cuando dos hotspots se superponen, el que ves arriba es el que recibe el click. Los píxeles transparentes del sprite igual dejan pasar al que está debajo, así que un hotspot con un objeto opaco chiquito sobre un lienzo transparente grande no bloquea a sus vecinos.
Las reacciones se abren en un modal dedicado ("Editar reacciones") que reusa
tools/_reactions-ui.js's buildVerbRow — exactamente las mismas filas por verbo que
renderiza el Editor de Reacciones, con pickers tipados/mensaje/cadena para cada verbo (la
grilla de 9 verbos SCUMM), nunca un campo de texto libre. Esto reemplazó un input
.react-text de texto libre anterior que podía serializar [object Object] para
reacciones compuestas; edita hs.reactions en memoria y lo confirma a través del propio
guardado del editor de salas, sin un round-trip aparte.
Las interacciones con objetos — "usar esta llave en este hotspot" — tienen su propio
botón justo debajo, y su propio modal. Son las claves compuestas planas <verb>_<itemId>
que el runtime resuelve directamente, y sostienen buena parte de los puzzles de inventario
de un juego, así que son una entrada de primera clase y no una sección plegada adentro del
modal de reacciones. Eliges el item, armas su cadena de efectos, listo, sin cambiar al
Editor de Reacciones. Cada fila trae la insignia ⚡ regla de
puzzle a la par del editor dedicado: dice crear o editar según exista ya una regla
guardada para esa clave, y abre el modal de reglas apilado encima del que estás usando.
Los dos botones se reparten hs.reactions y cada uno cuenta sólo su mitad, así que el
número de cada botón coincide con lo que vas a ver adentro. Editar uno nunca toca las
claves del otro.
La conducta de un hotspot tiene dos casas, y los dos botones cuentan las dos. Las
reacciones de arriba viven en el archivo de la sala; una regla de puzzle vive en cambio
en el archivo rules de la sala, y en runtime la regla guardada se consulta primero. O
sea que un hotspot puede estar completamente cableado —abrir un teclado, quedarse con una
moneda— con todas las reacciones del archivo de sala en blanco, que es exactamente cómo se
ve un hotspot autoreado enteramente con el badge ⚡. Por eso las dos cuentas son la unión: un
verbo cuenta si tiene reacción o regla. Un compuesto que existe sólo como regla igual
tiene su fila, con la celda en (no reactions) y el badge en estado editar — la regla
tiene la conducta, y la fila se reconstruye del archivo de reglas cada vez en lugar de
escribirse de vuelta como una clave vacía.
Cada fila responde por su propia clave y por ninguna otra. La fila del use pelado habla
de <hotspot>.use; <hotspot>.use_moneda es una fila del modal de interacciones con objetos,
con su propio badge. Así que un hotspot cuya única regla es un compuesto muestra el verbo
pelado en estado crear —ese verbo de verdad todavía no tiene regla— y al tocar el badge
arranca una regla nueva bajo la clave pelada, no abre la del compuesto.
Una reacción autorada en el verbo walk nunca puede dispararse, y Validate lo dice.
Caminar hacia un hotspot solo lo aproxima — _walkAndAct/_walkToNpc en shell/main.js
descartan la acción pendiente sin condición apenas el verbo es walk, venga el click de la
barra clásica o del verb-coin, y ponerle walk al Verbo por defecto del hotspot tampoco
lo rescata. Como ese contenido de verdad nunca puede correr, Validate lo marca en rojo,
chequeando las dos casas que mira el resolver — el hotspot.reactions.walk plano de la sala
y una regla condicionada <hotspotId>.walk que el modal ⚡ todavía puede sembrar — y nombra
las dos salidas que sí funcionan: mover la cadena a otro verbo, o al paso-por-encima de una
región, que es la superficie que significa "cuando el jugador llega acá".
Áreas caminables#
walkableAreas son polígonos (una sala puede tener más de uno, p. ej. parches de piso
desconectados) que definen por dónde puede caminar un personaje; core/walkable.js hace
el point-in-polygon + pathfinding real en runtime. Tres modos de dibujo construyen un
polígono: Polígono (clic para colocar vértices uno a uno), Libre (mantener
presionado y arrastrar, muestreando puntos a lo largo del trazo — solo para caminable), y
Pincel (un cepillo que rellena una máscara de bitmap; al soltar la traza vía
marching-squares y la simplifica con Douglas-Peucker a una tolerancia ajustable en vivo).
El modo Pincel es genérico para cualquier herramienta que sostenga un polígono (caminable,
walk-behind, región, hotspot, efectos), no solo áreas caminables, y ofrece un modo semilla
Reemplazar (la máscara arranca vacía) o Mezcla (la máscara se siembra desde la
forma actual, para retoques).
El puntero del Pincel tiene tres posiciones: el Pincel pone área, la Goma la saca, y
la Varita selecciona por color un pedazo del fondo. Alt invierte pincel y goma mientras
lo mantengas apretado, y cada uno lleva su propio grosor — así conviven un pincel ancho para
tirar la forma de un saque y una goma fina para afinarla, sin volver al slider cada vez.
Lo que la goma le hace a la forma que corta no es un mal menor. Un trazo que parte un área en dos te deja dos áreas: la original conserva su id, sus ajustes y cualquier regla que la apunte, y el segundo pedazo pasa a ser hermana. Un toque en el medio deja un agujero — un área hermana marcada como no caminable, que es como siempre se modeló acá una columna en medio del piso. Las dos cosas salen del mismo trazo, y volver a pintar encima reescribe ese mismo conjunto en vez de apilar duplicados. Las otras herramientas de polígono no tienen forma de expresar un agujero, así que ahí sigue ganando el pedazo más grande — pero ahora lo avisan, en vez de descartarlo en silencio.
En modo Polígono, una goma de vértices barre varios de una pasada, para adelgazar un borde que volvió más denso de lo que querías; el clic derecho sobre un vértice suelto sigue borrando ese solo. Ninguna de las dos baja un polígono de tres vértices.
Un área caminable también puede llevar agujeros — un hueco no caminable recortado del piso, para poder rodear la pata de una mesa o una columna sin necesitar un segundo polígono desconectado. Al convertir un área en agujero, cada vértice que arrastres se mantiene dentro del piso al que pertenece: si intentas llevarlo más allá del borde del piso, se ajusta al ras contra ese borde en su lugar, así puedes morder justo hasta el límite sin llegar nunca a asomar el agujero fuera de la forma caminable. Mover el agujero completo funciona igual — se desliza sobre el piso sin dejar que ninguna parte se salga.
Un agujero es además la forma más limpia de bloquear una puerta cerrada: pones uno sobre el umbral y lo apagas cuando la puerta se abre, en vez de dibujar un segundo parche caminable que tenga que traslaparse con el primero. Un solo piso significa una sola autoridad de escala y ninguna costura de traslape que se te pueda ir mal. Un área caminable chica aparte sigue valiendo la pena para áreas realmente grandes que desbloqueas más tarde — nada más dale un traslape generoso con el piso al que se une.
Un linter puro (core/walkable_lint.js) corre al cargar y al guardar, y muestra geometría
malformada — auto-intersecciones, polígonos casi degenerados, áreas "agujero"
desconectadas, y un agujero que termina asomando fuera de su piso (por haber remodelado el
piso después de colocar el agujero, o en una sala autorada antes de que existiera esta
restricción) — como advertencias no bloqueantes en un panel flotante; solo reporta,
nunca repara el polígono automáticamente.
El chequeo de auto-cruce no busca sólo la "X" evidente: también marca el contorno que se toca a sí mismo, que es la forma que en la práctica sale de dibujar pegando a vértice. Si arrastras un punto justo encima de otro, o encima de una arista que ya trazaste, o vuelves sobre un tramo que acabas de dibujar, el área queda estrangulada a cero ancho en ese punto — las dos líneas nunca se cruzan, así que un chequeo de cruces no lo ve, pero un personaje que tenga que pasar por ahí atraviesa una compuerta de 0px y el click queda muerto. La solución es siempre la misma: vuelve a trazar el contorno como un lazo simple, o corre el vértice un par de píxeles. Repetir el primer punto al final para "cerrar" el área no es un defecto — los contornos se cierran solos y ese punto de más se ignora.
El linter mide "cerca" igual que el juego corriendo — unas cuantas veces el alto en
pantalla del personaje, leído de characters.json a través del mismo
core/charScale.js que usa el motor — así que una advertencia y el síntoma que
sentirías jugando son el mismo evento. Además chequea el invariante que de verdad
importa: a toda área transitable se tiene que poder llegar caminando desde donde
arranca el jugador. El piso que pintaste pero al que nadie llega se marca aunque no
esté ni cerca del resto, que es algo que un chequeo de "estas dos casi se tocan" nunca
puede ver. Un hueco que sella un área a propósito —el patrón de puerta cerrada de más
arriba— no se marca: el chequeo ignora los obstáculos declarados, así que sólo cuenta
el piso que no conecta por su propia geometría.
El panel tiene tres estados, no dos: analizando, N advertencias y no se pudo
analizar. La distinción importa porque cero advertencias ya es un veredicto — significa
que la sala se revisó y está impecable, y el panel se esconde. Así que una pasada que falla
lo dice en su propio chip rojo (pasa el mouse por encima para ver el motivo de fondo) en vez
de devolver una lista vacía que se leería como certificado de limpieza, tanto en el panel
como en la nota del guardado. La geometría que el linter no puede leer — un vértice con
x/y ausente o no numérico, que las herramientas del editor no pueden producir pero un
archivo de sala editado a mano o importado sí — se saltea en vez de tumbar la pasada
entera, y se reporta como su propia advertencia nombrando el área o el hueco, así siempre
sabes qué es lo que el informe no cubre.
Regiones#
Las regiones son áreas poligonales (no puntos) con un type autoritativo:
generic, entrance, o warp — un reg.type explícito gana, y las salas antiguas
sin uno se clasifican por heurística (un onWalkOver que dispara WARPTOROOM: se lee
como warp; un id que contiene "entrance" se lee como entrance; todo lo demás es
generic), así los archivos de sala más viejos siguen clasificando correctamente sin
migración. Una región puede llevar una reacción onWalkOver, autorada con el mismo widget
compartido de construcción de efectos usado en otros lados. Las regiones entrance son
lo que el paso NPCENTER del Editor de Cinemáticas y el selector de warp entre salas listan
como puntos de llegada válidos — la columna derecha del selector de salas filtra a
zoneType(r) === 'entrance' cuando estás cableando un warp entre salas o el punto de
entrada de un NPC.
Detector de reglas huérfanas#
Las reacciones de una sala se cablean por el id de su dueño (<id>.<verbo>) pero viven en el
archivo de reglas, así que renombrar un id puede dejarlas apuntando a algo que ya no existe —
simplemente dejan de disparar, en silencio, sin nada en las insignias que lo muestre (una
insignia solo pregunta "¿hay una regla para este id?", nunca "¿el id de alguna regla sigue
existiendo?").
Renombrar un hotspot ahora ofrece llevarse sus reglas. Guarda la sala después de renombrar e Ignitor te dice cuántas claves siguen apuntando al id viejo y pregunta antes de moverlas — nunca reescribe el archivo de otro editor a tus espaldas, y decir que no simplemente las deja huérfanas, que es para lo que está la tira de abajo. Cualquier comentario que hayas escrito arriba de esas reglas viaja con ellas. Si renombras en varios pasos antes de guardar, se lee igual como un solo movimiento, del id original al último. Renombrar una región todavía no hace esto, así que esa dirección sigue cayendo en la tira.
El panel de la sala saca a la luz lo que quede: una tira roja lista cada clave de regla huérfana, con
un botón que abre las claves exactas en un diálogo para que sepas qué arreglar y dónde. Chequea
claves con forma de hotspot o región (<id>.<verbo>) contra cada id todavía vivo en la sala;
las claves de reacciones de personaje comparten el mismo archivo de reglas pero se dejan afuera
a propósito, porque las filas de un personaje nunca se vuelven obsoletas de esta forma. La tira
no dibuja nada cuando la sala está limpia.
Reacciones de entrada de la sala#
La sala misma también lleva reacciones: room.onEnter, los eventos que disparan cuando el
jugador llega — en la primera visita, en cada visita, o en una cantidad de visitas
específica — que es también lo que edita el modo Sala del Editor de Reacciones.
La tool Select abre la misma superficie de autoría sin cambiar de editor: un tercer
hermano de los modales de reacciones de hotspot y región, al que se llega con un botón que
muestra el conteo de eventos en vivo. Cada fila es un disparador (el campo de número solo se
muestra para visitCount) más el mismo editor de cadena de efectos compartido que usa
cualquier otra reacción. El dato es la forma idéntica que lee shell/room_enter.js, así que
una sala autorada desde cualquiera de los dos editores abre igual en el otro, y un evento que
queda en cero tokens se descarta al guardar, igual que una reacción de hotspot vacía. A
diferencia de hotspots y regiones, este botón no lleva la insignia ⚡ regla de puzzle —
nada en el motor lee hoy una regla guardada desde la entrada de sala, así que la lógica
condicional de entrada sigue viviendo en los Room Watchers del Editor de Puzzles.
Zonas de luz#
room.lightZones es un arreglo de polígonos { id, poly, brightness, tint?, feather?,
enabled?, brightnessZone? }, desacoplado del área caminable — una sala puede teñir un
parche de sol u oscurecer un rincón sin importar por dónde puedan pararse realmente los
personajes. El resolveLightAt() de core/light.js elige la zona bajo los pies de un
personaje en cada cuadro; cuando ninguna zona cubre los pies, cae al brightness/tint del
legacy walkableArea que el shell ya pasaba, así que las salas sin ninguna zona de luz
renderizan exactamente igual que antes (cero migración). brightness corre de -100 a 100
(negativo oscurece), tint es un override hex (si no, el shell por defecto usa
blanco/negro según el signo), y feather es un ancho de caída en px en el borde de la
zona (0 = borde duro).
El enabled de una zona se autora acá, pero también se puede cambiar en pleno juego: los
tokens LIGHTZONE_ON / LIGHTZONE_OFF encienden o apagan una zona por id — de esta sala o
de otra —, así que una lámpara que el jugador apaga realmente deja de iluminar el piso. El
cambio se recuerda por sala y sobrevive tanto a volver a entrar como a un guardado, y la
condición isLightZoneOn lo lee de vuelta. Es el gemelo visual de WALKABLE_ON /
REGION_ON y no mueve nada: una zona apagada sigue siendo una zona por la que se camina.
Surface FX de sala#
Una única herramienta Surface FX cubre dos cosas relacionadas pero independientes,
ambas manejadas por una sola configuración de luz (room.lighting = { mode, angle, len,
soft, alpha, offsetX, offsetY }, modo none/blob/silhouette/both — ausente o none
significa que el shell no dibuja nada, el contrato de cero delta):
- Sombras de personaje — blob o silueta, proyectadas desde esa única luz de sala. La proyecta cada personaje de la sala, NPCs incluidos: es una propiedad de la luz de la sala, no de quién es jugable. La sombra se ancla al píxel opaco más bajo del sprite, así que el padding transparente horneado en un PNG no puede despegarla de los pies; los sliders Offset X / Offset Y son la vía de escape para el arte que igual no coincide, o para una sombra corrida a propósito. Mueven la sombra en píxeles sin cambiarle la forma — una Y negativa mete su borde de contacto bajo el sprite, que es como se tapa una costura que todavía se nota; 0 significa que la sombra arranca justo en los pies.
- Reflejos (
room.reflections[]), cuatro tipos: puddle (un parche de piso poligonal con squash + amplitud/velocidad de wobble que refleja a los personajes; Qué se refleja elige el modelo: solo quien lo pisa, todos con el reflejo siguiendo al personaje al alejarse, o una Línea de agua para un estanque visto desde su orilla), wall-mirror (un rect o un polígono libre de recorte con parallax + un slider de tinte de vidrio, para espejos reales), bg-region (un rect fuente copiado a un rect/poly destino, para reflejos de eco de fondo baratos — marca Reflejar también a los personajes y quien camina encima se refleja en vivo, como los muebles), y water (una zona que ondula el fondo que ya está debajo, sin reflejar nada). Cada zona también tienealphay un modoblend. Wall-mirror, bg-region y water pueden alternar entre un rect plano y un polígono de recorte libre — que es lo que vas a querer para el agua, porque un estanque rara vez es un rectángulo. Un personaje al que un walk-behind está tapando deja de reflejarse — en cualquier lado, en toda zona que refleje al elenco. Sale gratis y no hay nada que marcar: si la pared que borra al actor está entre él y la cámara, su reflejo delataría que hay alguien parado ahí. La prueba es la misma que ya usaba el espejo —los pies del personaje dentro del polígono de un walk-behind que repinta, por encima de su baseline—, así que un walk-behindnormalolight, que no tapa a nadie, no cambia nada.
Water es el tipo al que ir cuando quieres que un estanque, un charco quieto o un río lento se muevan sin reflejar nada: redibuja el arte que ya está ahí, ondulando, en su sitio. Dibujas una zona sobre el agua de tu fondo, pones amplitud y velocidad de la onda, y eso es todo — no hay rectángulo de origen que apuntar a ningún lado, porque una zona de agua se muestrea a sí misma. (Apuntar un bg-region a su propio destino es justo el error que este tipo vuelve imposible: bg-region voltea lo que muestrea, así que apuntarlo al estanque pinta el estanque al revés encima del estanque.)
Un wall-mirror tiene dos ajustes de profundidad independientes, y es fácil confundir uno con el otro. Uno decide a quién refleja; el otro decide dónde se pinta el espejo.
A quién refleja: "No reflejar por encima de Y". Por defecto un wall-mirror refleja a todos los personajes de la sala, estén donde estén. Cuando el espejo en realidad es una ventana — una abertura por la que el jugador puede caminar tanto por delante como por detrás — activa esta casilla y la zona pasa a tener su propio plano de reflejo: un personaje con los pies por encima de la línea cuenta como que está detrás del vidrio y no proyecta reflejo (ni deriva de parallax). La línea toma por defecto el borde inferior del rect del espejo, que es donde el vidrio suele tocar el piso; fíjala a mano cuando el arte no coincide, por ejemplo un espejo colgado alto en la pared cuyo contacto con el piso queda bastante más abajo que su propio rect. Los pies justo sobre la línea cuentan como adelante, igual que resuelven ese mismo empate las líneas base de los walk-behinds. La opción viene apagada, así que los espejos existentes no cambian.
Dónde se pinta: "Profundidad Y (orden de dibujo)". Es la línea en la que el espejo entra al
orden de profundidad de los personajes. Los pies por debajo pasan por delante del reflejo;
los pies por encima quedan detrás, y el vidrio los tapa. Déjala en 0 y decide el motor: un
espejo cuyo cristal repinta un walk-behind de oclusión se levanta justo por encima de la línea
base de ese walk-behind, para que el reflejo caiga sobre la pared repintada en vez de que el
repintado lo borre; cualquier otro espejo se dibuja temprano, detrás de todos.
Esa elección automática es una suposición, y lee mal algunas salas. Asocia un espejo con un walk-behind por cajas que se solapan, así que un porche — donde el walk-behind es la baranda y los postes que están delante del personaje, no la pared donde viven las ventanas — les da a las ventanas una profundidad por debajo de la franja pisable, y el reflejo termina pintado encima de la cara del personaje sin que nada más lo mueva. Poner la línea de profundidad por encima de la franja es el arreglo, y no hay forma de llegar ahí con el ajuste anterior: ese sólo decide quién se refleja.
Por debajo del walk-behind que repinta el cristal, gana el repintado. Si pones la línea de profundidad debajo de esa base, el arte de la pared tapa el reflejo donde lo cruce. En un porche eso es exactamente lo correcto — los postes sí están delante de la ventana. En un espejo colgado de una pared repintada es el bug que el automático existe para evitar, y por eso el automático sigue siendo el valor por defecto.
Cuando pones una línea de profundidad, el lienzo la dibuja punteada cruzando el espejo, para que la compares de un vistazo contra la franja pisable. Es una referencia, no un tirador: la profundidad automática depende de qué walk-behind reclama el cristal, y eso vive en el motor, así que el editor dibuja sólo la línea que autoraste tú.
Hacia dónde mira el reflejo. Dos casillas más, una por eje, y contestan preguntas distintas. «Voltear L↔R (espejo real)» da vuelta el reflejo de izquierda a derecha; destíldala para un espejo de la pared del fondo, donde el reflejo tiene que conservar la orientación del personaje en vez de invertirse nariz con nariz. «Voltear ↑↔↓ (frente/espalda)» es la que buscas cuando el cristal mira al jugador: quien camina alejándose de la pantalla está parado de frente a ese cristal, así que el espejo tiene que mostrarle la cara, y quien te da la cara tiene que reflejar su espalda. Déjala destildada y tienes una ventana: estás mirando a través del vidrio a alguien del otro lado, así que lo que corresponde ver es su orientación real.
La segunda no es el mismo tipo de interruptor que la primera, aunque estén juntas. Izquierda y derecha son el mismo dibujo dado vuelta, así que ese volteo sale gratis. Frente y espalda son cuadros de animación distintos, así que ésta va a buscar el otro lado — lo que significa que el personaje necesita arte de las dos direcciones. Si falta cualquiera de los dos lados, el reflejo se queda callado como estaba en vez de meter una pose de perfil, así que prenderla puede verse como que no pasó nada: eso lo está diciendo el arte del personaje, no la casilla. Las dos vienen apagadas para los espejos que ya tenías.
Encender y apagar una superficie durante el juego#
Cada zona de reflejo lleva una condición de Visibilidad reactiva, y también las sombras de personaje de la sala y la fuente de luz de cada hotspot. Déjala en — siempre — y la superficie se dibuja como siempre. Ponle una condición y solo se dibuja mientras esa condición se cumple: el espejo que deja de reflejar cuando se raja, el charco que se seca después de la lluvia, las sombras que desaparecen cuando se corta la luz, el resplandor de la lámpara que sigue a su interruptor.
Es el mismo constructor de condiciones que usan las reglas de puzzle, las reacciones de
hotspot, las capas de sala y los efectos de sala:
un flag, una comparación, o all / any / not anidados tan profundo como haga falta. El
interruptor habitual es un flag: condiciona el espejo a espejo_roto y después
SETFLAG:espejo_roto desde cualquier regla, reacción, opción de diálogo o paso de escena.
Como el estado vive en el flag, sobrevive al guardado y a volver a entrar a la sala
gratis, y un mismo flag puede manejar varias superficies a la vez.
La condición se evalúa en cada cuadro, así que la superficie vuelve en el momento en que la condición se cumple de nuevo — no hay nada que re-disparar al entrar a la sala.
Apagar las sombras significa que no hay sombra. Condicionar las sombras de personaje a que no se dibujen no vuelve a la elipse de contacto por defecto del motor: ese respaldo solo aplica a salas que no tienen bloque
lightingen absoluto. Apagado es apagado.En el editor siempre se dibuja. El canvas te muestra la superficie digan lo que digan tus flags — tienes que ver lo que estás autorando. La condición es una compuerta de runtime, no un interruptor de vista previa del editor.
Nada de esto pasa por el manifiesto de tokens de efecto — el surface FX y la iluminación son estado de render continuo atado a que la sala esté abierta, no tokens de un solo disparo. La condición de visibilidad de arriba es declarativa por la misma razón: se relee en cada cuadro en vez de voltearse con un token.
Colocar personajes#
La herramienta Personaje deja un personaje en el punto clickeado y lo previsualiza
exactamente como el juego lo va a dibujar parado ahí. El tamaño es la escala de actor de
runtime (base × profundidad × sizePct × el sizeBias del área) aplicada a los píxeles
naturales del propio sprite — no a un supuesto fijo de 512 de alto, que no describía a ningún
personaje embarcado y podía errarle desde un 1% hasta 3× según el arte. La pose es la que el
runtime resuelve en reposo: el facing y el anim por defecto de la colocación
alimentan la misma cascada de core/animations.js que corre el motor
(anim → idle → walk → sprite estático), incluida la regla de espejo que toma un clip que
mira a la izquierda para dibujar uno que mira a la derecha. Así que el sprite que arrastras a
su lugar, su caja de selección, su sombra y su ancla de pies son todos el frame que va a ver
el jugador.
Anclas de fiesta (party anchors)#
room.partyAnchors[] son marcadores de slot numerados genéricos ({x, y}, sin personaje
hardcodeado) — dónde queda estacionada una fiesta comprometida (más de un personaje
simultáneamente controlado/visible) al parquear en esta sala. La herramienta Personaje
tiene un sub-modo place (coloca un personaje real) y un sub-modo partyslot
(coloca uno de estos marcadores de ancla en su lugar); en runtime, un botón de slot de
fiesta de GUI resuelve el ancla N a cualquier personaje que ocupe el slot de fiesta N. Un
arreglo partyAnchors vacío se descarta antes de guardar, así las salas sin slots
estacionados quedan byte-idénticas a como estaban antes de que existiera la funcionalidad.
Fondo y capas de parallax#
El fondo se importa a través de un modal dedicado (elegir una imagen, fijar/bloquear
ancho×alto, elegir la ruta de guardado bajo assets/rooms/, y opcionalmente marcar ajustar el
viewport de la sala a este BG) con una vista previa en vivo; también hay un slot de fondo
alternativo A/B para comparar arte candidato sin tocar room.background hasta que promuevas uno
explícitamente al guardar.
La herramienta 🏞️ BG (G) reposiciona y redimensiona la imagen de fondo en sí:
arrastras para moverla, tiras de una esquina para escalar (con aspect-lock por defecto, Alt
para escala libre). Todo el transform es transitorio — nunca toca los datos de la sala
hasta que le das Aplicar, que hornea el resultado en el PNG a sus dimensiones nativas de
píxel (respetando render.pixelArt para el smoothing). Mientras hay un transform sin hornear
pendiente, el Guardar de la sala te avisa primero, y los slots alternativos A/B quedan
bloqueados; cambiar de sala descarta el transform pendiente. Es la forma de reacomodar o
reescalar un fondo ligeramente desalineado en el sitio, sin dar la vuelta por un editor de
imágenes.
Encima del fondo,
room.layers[] agrega capas de profundidad parallax ({ id, src, parallax, z, band?, repeatX,
mask? }), validadas en vivo por el core/roomLayers.js puro; el editor se autoconduce con
un reloj de vista previa para mostrar el scroll/ciclo de cuadros como lo haría el shell, ya
que el editor en sí no tiene cámara para panear.
El Plano de una capa decide de qué lado del PNG del fondo cae, y el Orden Z la ordena contra las otras capas de ese mismo lado. En Según el orden Z, el plano sale del número como siempre: z menor a 0 pinta sobre el arte de la sala pero detrás de tus personajes, z mayor a 0 pinta delante de ellos. Ese par se mide contra el elenco, no contra el fondo — que es la razón por la que ningún z, por negativo que sea, ponía nunca una capa debajo del arte del fondo.
Pasa el Plano a Detrás del fondo del cuarto cuando quieras justamente eso: un cielo, un horizonte, una ventana iluminada vista desde adentro. La capa se dibuja antes del fondo, así que sólo se ve por los píxeles transparentes del PNG — o sea que necesita un hueco por dónde asomarse. Si el fondo es completamente opaco la capa está bien autorada y es invisible, así que la franja de validación te lo dice sin vueltas y te manda a ✂ recorte o a ✎ Tweak a abrir el hueco. Una capa que nunca elige plano se queda exactamente donde estaba.
La lista de capas se lee en orden de pintado, agrupada por plano y de arriba hacia abajo —
o sea que lo que lees hacia abajo es lo que se dibuja de atrás hacia adelante. Los botones
▲▼ de cada fila mueven la capa por ese orden intercambiando su Z con la del vecino, y
sólo la mueven dentro de su propio plano: pasar de un plano a otro es cambiar el Plano o el
signo de z, así que en el borde de un grupo el botón queda apagado. En el plano de fondo el
badge muestra el puesto de la capa dentro de ese plano (⤓fondo 2/3) en vez de un z pelado,
porque un z de -1000 ahí no dice nada sobre dónde cae la capa respecto de tu elenco.
Si una capa no puede entrar a cuadro nunca, te lo dice. Es la única falla que el canvas no
te puede mostrar: el editor dibuja las capas planas en su offset porque no tiene cámara,
mientras que el juego las dibuja en offset − cámara × parallax, y las dos imágenes coinciden
sólo con la cámara en cero. Una capa puede estar bien autorada, animar bien en la vista previa
y aun así no aparecer nunca en el juego porque la cámara no llega hasta ahí. La franja de
validación nombra la banda que la capa recorre durante todo el paneo, la banda que ocupa el
cuadro y — la parte accionable — el rango de offsets que sí funcionaría: uno para "asoma en
algún momento" y otro para "se ve durante todo el paneo". Las capas que repiten quedan exentas,
porque el tiling cubre la banda igual.
✎ Retocar vive al lado del campo de imagen de la capa y abre ese PNG en el editor de píxeles — el mismo retoque puntual que reciben el sprite de un hotspot y el fondo de la sala. Qué abre depende de cómo la capa saque su arte: una capa estática o con scroll es un solo archivo y abre derecho; una hoja de sprites también es un solo archivo, pero estás editando todos los cuadros de una, y el título del modal lo dice. Una capa armada con una secuencia de PNG no tiene un solo archivo, así que pregunta antes: te dice cuántos cuadros son y que sólo se toca el primero, un cambio que verías en la vista previa parada y no en la animación. Las secuencias se editan mejor en el editor de animaciones. El botón está apagado mientras la capa no tenga imagen.
Viewport de la sala#
El viewport de una sala es la ventana que muestra la cámara. Por defecto una sala usa el viewport global del proyecto (la resolución compartida y el setup de letterbox); un override por-sala deja que una sala lleve el suyo propio, guardado con la sala. La sección VIEWPORT DE SALA es donde lo fijas — activa el override, y luego arrastra los bordes de la guía naranja para dimensionar la ventana (la esquina ✥ la mueve). Una opción Centrado (letterbox) descarta el origen y deja que la ventana se auto-centre en runtime dentro del viewport del proyecto, pensada para salas que caben dentro de la ventana. La guía se puede bloquear desde la barra de visibilidad para no moverla sin querer.
Origen X / Y es el punto de la sala al que mira la esquina superior izquierda de la ventana:
el origen de la cámara. Es lo que permite enfocar una banda del medio de un fondo grande sin
recortar el PNG: arrastra la esquina ✥ sobre el arte hasta que la guía quede sobre la parte que
quieres, y el juego arranca su cámara ahí. En una sala que scrollea (los flags de Camera Scroll
X/Y), el origen es donde empieza el paneo en vez de un encuadre fijo. Todo lo que queda fuera de
la guía se sombrea fuerte, porque es fondo que el jugador nunca va a ver; el origen también
aparece en la etiqueta de la guía como @ x,y. Las coordenadas autorales — hotspots, áreas
caminables, regiones — siguen en espacio de sala y no se mueven.
⊞ Ajustar al BG dimensiona el viewport al fondo de la sala en un clic — útil cuando el arte de una sala no es la resolución del proyecto. El modal de Import BG ofrece lo mismo como checkbox, y viene marcado por defecto justo cuando las dimensiones del arte importado no coinciden con el viewport efectivo actual, así un desajuste se corrige solo al importar; la sección Viewport marca ese mismo desajuste con un resaltado ámbar cuando la ventana efectiva no coincide con la sala.
Validar chequea alcance contra esa ventana. El sombreado te muestra dónde está la zona muerta; el validador te dice cuándo te cuesta algo. Una sala más alta (o más ancha) que su ventana con el Camera Scroll de ese eje apagado no puede mostrar nunca el extremo lejano — una sala de 1024px de alto en una ventana de 748px esconde sus últimos 276px para siempre, y ahí es justo donde suele pintarse el piso. Validar reporta la banda con las dos salidas (prender el scroll de ese eje, o hacer la sala del tamaño de la ventana), y escala a hallazgo rojo cuando un área caminable, un hotspot o un personaje colocado queda entero dentro de la zona muerta: contenido que el jugador no ve ni puede alcanzar. El solapamiento parcial se deja pasar — un piso que sigue más allá del borde inferior es una elección de autor normal — y una banda de unos pocos píxeles se trata como redondeo del fondo, así que el chequeo se queda callado en salas apenas más altas que su ventana.
Sonido ambiente#
Una sala puede llevar un ambiente en bucle — lluvia contra la ventana, el zumbido de una
heladera, grillos de noche. Eliges el archivo de assets/audio/ambience/ y las opciones de
abajo deciden cómo suena:
- Offset (s) — dónde arranca la reproducción la primera vez, en segundos dentro del archivo.
- Inicio de bucle (s) — a dónde vuelve al repetir, para que una intro que sólo se escucha una vez quede fuera del bucle.
- Bucle — destildado lo vuelve un one-shot en vez de una cama sonora.
Los dos campos son posiciones dentro del archivo, así que el panel muestra la Duración del archivo elegido encima de ellos, y avisa cuando un offset o un inicio de bucle cae después del final — un valor pasado del final reproduce silencio, que de otro modo no se distingue de una ruta rota.
Descripción de la sala#
room.description todavía se autora como un string sin envoltura, no como un lid — la
migración de content-i18n a strings monolingües (core/strings.js) todavía no llegó a los
nombres/descripciones de sala en este editor. Se usa como el nombre de display de la sala
en selectores y en el validador cuando está definido, cayendo al id crudo si no.
Previsualizar la sala como el juego#
El botón 🎚️ Sandbox compone la sala actual exactamente como la dibujaría el juego final:
la sala clipeada 1:1 en el viewport real de sala (cámara en el origen), con la GUI principal
real del proyecto pintada encima por el mismo computeLayout() / drawGui() que corre el
motor en runtime — usando los registries booteados de proyecto / strings / personajes / GUIs, no
un mock-up. Es el único lugar del editor que muestra el fondo, los personajes, los hotspots y el
HUD compuestos juntos a la resolución real del proyecto, en vez de la vista de overlay plano del
editor. Alterna GUI / Personajes / Hotspots / Áreas / Efectos / Walk-behinds / Capas / Luz con
repintado inmediato, y arrastra un personaje colocado para chequear el encuadre — el drag es local al
sandbox, así que nunca mueve nada en la sala real. El sandbox se resiembra cada vez que cambias de
sala.
Efectos dibuja los efectos de sala con el mismo despacho que corre el frame: la capa atrás bajo los personajes, la de adelante encima, y un efecto en modo profundidad en su propio lugar del orden por Y — así que este es el lugar donde pruebas una línea de profundidad contra tu elenco, con un personaje pasando por delante del efecto y otro por detrás en la misma imagen. La Vista previa del editor de salas anima un efecto solo; el sandbox es donde lo ves contra la gente que tiene que caminarle alrededor.
Hotspots pinta el arte de los hotspots, y respeta la profundidad: uno con Profundidad
(delante/detrás) encendida entra al mismo orden por Y que los personajes, en su pie (o en su
sortY si lo fijaste), mientras que los demás se quedan en la capa fija de siempre, detrás de
todo el elenco. Es el lugar para probar las motos estacionadas antes de tocar el juego.
Walk-behinds repinta el fondo a través del polígono de cada walk-behind en su propio lugar de ese mismo orden, así que un personaje parado por encima de una baseline queda realmente tapado por la columna o el mostrador en vez de caminarles por encima. Los tres modos se comportan como en el juego: occlude repinta, light tira su tinte sobre quien esté detrás, y normal sólo ordena. Arrastra un personaje cruzando una baseline y ves el frame exacto en el que pasa a estar detrás.
Capas dibuja las capas de parallax de la sala en sus tres bandas — una capa con z menor a 0 va detrás de tus personajes, una con z mayor a 0 pinta encima, y una en el plano Detrás del fondo del cuarto va debajo del arte de la sala — y las dos primeras son justo lo que el preview de la herramienta de capas no puede mostrarte, porque ahí no hay elenco al que ponerse delante. Luz suma las zonas de luz de la sala, el wash difuminado del piso, en su lugar bajo los personajes. Una capa con condición de visibilidad se dibuja acá pase lo que pase con tus flags, igual que en la vista de edición: el preview es para ver la capa, no para simular la partida.
Ojo que las dos respetan los interruptores de la propia sala — una sala con las capas apagadas en runtime, o una zona de luz sin difuminado, tampoco dibujan nada acá, porque es lo que hace el juego con ellas.
Flujo de trabajo#
- Elige una Sala del desplegable, o + Nuevo. El tamaño que te ofrece es una pantalla del área jugable de este proyecto — el viewport de sala cuando el juego reserva una franja de GUI, la resolución completa cuando no — así que una sala que aceptes tal cual se ve entera y el Validate no dice nada de ella. (Antes proponía un fijo 1512 × 1008, que a la resolución default de 1280×1024 era más ancho que la pantalla y con 260 px dentro de la banda que la cámara no alcanza: un default que disparaba el validador del propio editor.) El diseñador de blueprint dimensiona sus stubs con la misma respuesta.
- Importa un fondo si la sala todavía no tiene uno.
- Cambia de herramienta para autorar cada capa: dibuja el área Caminable (Polígono, Libre, o Pincel), coloca Hotspots y abre su modal de reacciones, agrega Regiones (tipando entradas para que cinemáticas/warps puedan targetearlas), ajusta zonas de Luz Z, define la única luz de Surface FX de la sala más cualquier reflejo, coloca Personajes y slots de ancla de fiesta, y apila Capas parallax.
- Presta atención al panel del linter caminable mientras dibujas — marca auto-intersecciones e islas desconectadas sin bloquearte.
- Valida antes de dar la sala por terminada — renderiza un resumen wireframe, chequea
conexiones entre salas (entradas/warps) y marca lo que quedó autorado fuera de la
ventana visible (ver más abajo). Su lista Conecta con encuentra las salidas de una
sala donde sea que estén autoradas — una región warp, la reacción de un hotspot, el
onEnterde la sala, un watcher o una cutscene del archivo de reglas — y nombra la superficie de la que cuelga cada una, así "esta sala no lleva a ningún otro lado" sólo aparece cuando de verdad es así. - Guarda. Deshacer/rehacer cubre la sesión (pila en memoria de 10 pasos); no persiste entre recargas.
La máscara de bitmap del pincel de Pintar nunca se serializa y deshacer no la restaura. Solo el polígono trazado-y-simplificado es parte de los datos de la sala; la máscara en sí es un objeto scratch transitorio
{ canvas, mctx, idx, w, h }. Deshacer/ rehacer restaura el polígono correctamente, pero limpia la superposición de pintura y reconstruye una máscara nueva desde el polígono en el que quedaste — así que un trazo de pincel a medio hacer no tiene un paso de "deshacer el trazo". Termina y suelta un trazo de pincel (dejando que trace hacia el polígono) antes de disparar deshacer, o la visualización de pintura en progreso simplemente desaparece sin tocar la forma efectivamente guardada.