Diseñador de Mapa (Blueprint Designer)#
El Diseñador de Mapa es un editor de mapa a vista de pájaro: un lienzo paneable/zoomeable donde cada sala es una caja y cada conector es una puerta entre dos salas. Es una vista a nivel de grafo del mapa del juego, deliberadamente superficial. Nunca toca lo que hay dentro de una sala (eso es territorio del Editor de Salas: hotspots, áreas caminables, regiones). Todo su trabajo es autorar qué salas existen y cómo se conectan, y después materializar ese grafo en archivos de sala reales cuando se lo pidas.
Llegas a él desde el Hub (con el dev server corriendo). La barra de herramientas tiene tres herramientas: Seleccionar, Sala (soltar una caja), Conectar (dibujar un enlace, con botones de dirección ida/vuelta/bidi y un switch de tipo de conector pared/libre). También tiene Deshacer/Rehacer, Auto-distribuir, Ajustar, un toggle de Sprites (los fondos de las salas dentro de las cajas), un selector de Escala del diagrama (1:16 / 1:8 / 2:8 / 4:8), y las dos acciones de guardado: Guardar Diseño y Ejecutar Andamiaje.
La fuente de verdad se queda en las salas#
projects/<id>/blueprint.json es solo layout: posiciones de caja, pistas de ruteo de
conectores, y (para salas que todavía no existen) una descripción de "stub" pendiente. Nunca
se vuelve la fuente de verdad del contenido de una sala: los hotspots, áreas caminables y
regiones reales siempre viven en projects/<id>/rooms/<slug>.js, exactamente donde los
escribe el Editor de Salas. Abrir el Diseñador de Mapa lee cada archivo de sala, deriva una
caja por sala y un conector por cada región de warp existente, y lo fusiona con las últimas
posiciones guardadas: una sala sin posición guardada cae en una cuadrícula automática. Esto hace
que el editor sea seguro de abandonar a mitad de un diseño: en el peor caso pierdes algún
acomodo de cajas, nunca contenido de sala.
Una puerta también puede estar autorada sin región warp: como reacción de un hotspot, en una
cadena onEnter, o como warp dentro de un vigía o una cinemática. Ésas son salidas reales, y el
diagrama las cuenta en la línea de estado y las lista por sala en el panel de propiedades (cada
una diciendo dónde vive), pero no las dibuja como conectores. Un conector aquí está respaldado
por una región (Ejecutar Andamiaje hace upsert y borrado de regiones por id estable), así que una
línea dibujada sin región atrás ofrecería un "quitar conexión" que no podría funcionar. Para
editar ésas, ve al Editor de Salas; o dibuja un conector aquí y andamíalo
para tener una zona warp de verdad al lado.
Stubs: cajas a escala real#
Una caja para una sala que todavía no existe es un stub. Los stubs se dibujan como un
modelo a escala literal de las dimensiones reales en píxeles de la sala, a una proporción fija
1:8 (ajustable desde el selector de Escala de la barra, que solo cambia el zoom del
diagrama, no la sala): una sala de 1920×1080 se dibuja como una caja de 240×135. Arrastrar
el handle de resize de un stub edita directamente su realW/realH real, controlado por dos
interruptores scrollX/scrollY (apagados por defecto: un stub arranca siendo exactamente
una pantalla, y activas cada eje antes de que pueda crecer en una sala con scroll). La altura
por defecto de un stub sale del área jugable del proyecto (roomViewport.h cuando el juego
reserva una franja de GUI, o la altura completa de la resolución para un juego sin GUI /
pantalla completa), con un override guiVisible por stub para proyectos mixtos (p. ej. salas
de cinemática a pantalla completa en un juego que por lo demás tiene GUI).
Una vez que un stub se materializa (ver Ejecutar Andamiaje más abajo), su caja se bloquea:
el .js de la sala pasa a ser la fuente de verdad de sus dimensiones, así que redimensionar
la caja es puramente cosmético y ya no escribe nada. Sus dos casillas de scroll pasan a
sólo-lectura por la misma razón, y reportan lo que dice el archivo de la sala: X está
prendido salvo que la sala lo apague, Y está apagado salvo que la sala lo prenda, igual que
lo lee el motor.
Cuando una sala es más grande que la ventana que su cámara puede alcanzar, el panel lo dice en rojo: esta sala mide 1024px de alto y 276px no se ven nunca. El diagrama es donde eso salta a la vista (la caja es visiblemente más alta que la pantalla que tiene al lado) y Ejecutar Andamiaje puede arreglarlo (más abajo).
Tipos de conector: pared vs libre#
Un conector entre dos salas es de uno de estos tipos:
- pared (el default): se ancla al lado de la caja por el que lo arrastres (el más
cercano de arriba/abajo/izquierda/derecha), en el punto de esa pared donde soltaste. Esto es
una puerta real: genera un par dominó de regiones (una región de warp pegada a la
pared en la sala de origen, y una región de entrada justo adentro de la sala destino),
cableadas con un token
WARPTOROOM:<sala>|<entrada>y el facing correspondiente. - libre: sin pared, sin dominó. Sueltas el ancla en cualquier punto dentro de la caja y el par de puertas se coloca ahí, al estilo disparador de piso. Esta es la forma que realmente tienen los warps de piso de SCUMM (un disparador "camina fuera de este borde" que cubre toda la sala, sin una pared que abrazar), y también es cómo modelarías un pseudo-cuarto tipo "afuera" al que cualquier sala pueda warpear sin una pared compartida literal.
La dirección es independiente del tipo: ida (A→B de una vía), vuelta (B→A de una vía), o bidi (ambas direcciones, generando ambos dominós). Cuando el editor deriva conectores de warps existentes al cargar, clasifica cada uno automáticamente: un warp cuyo polígono abraza una pared (dentro de aproximadamente 12% de un borde) se lee como pared en esa posición; algo más central se lee como libre en su punto real. Esto reemplazó una adivinanza anterior de "pared más cercana" que anclaba mal los warps de piso ubicados a medio camino en salas muy anchas.
Ruteo ortogonal#
Los conectores rutean en ángulos rectos en vez de una línea diagonal: cada extremo sale perpendicular a su ancla (la normal de la pared para pared, el eje dominante hacia la otra sala para libre), y después los dos extremos se unen con a lo sumo dos dobleces (un jog en el medio si ambas salidas corren sobre el mismo eje, un solo codo si son mixtas). La ruta se recalcula en vivo mientras arrastras cualquiera de las dos cajas, y también puedes agarrar el handle del punto medio de un conector y arrastrarlo para doblar la ruta a través de un waypoint manual; las anclas de pared mantienen su salida de pared fija sin importar qué, pero un ancla libre se reapunta hacia donde arrastraste. Esquivar obstáculos (rutear alrededor de otras cajas) no está implementado: las rutas pueden cruzar cajas ajenas; solo se minimiza la cantidad de esquinas.
Sprites de sala#
Cada caja puede mostrar el PNG de fondo de su sala, semitransparente, con el nombre y el id dibujados sobre una placa para que se lean encima de cualquier arte. El botón 🖼 Sprites de la barra (o la tecla V) los muestra u oculta; es una preferencia de quien mira, guardada en el navegador, no parte del diseño, así que cambiarla nunca marca el diagrama como sin guardar. Arranca encendido. Como una caja es su sala a escala real, la imagen entra exacta (sin recortes ni franjas): el mapa se vuelve una maqueta a escala del juego. Las cajas se dibujan desde una miniatura chica en caché, así que un mapa de cincuenta salas se arrastra igual de fluido que uno de cinco.
El panel de propiedades gana un campo FONDO para la sala seleccionada, con 🖼 Elegir…
y ✕. Elegir… abre un selector que lista los PNG que ya están en assets/rooms/ y ofrece
Importar del disco…; un archivo importado se guarda como assets/rooms/<idDeSala>.png y
el campo se llena con esa ruta. Dos reglas lo mantienen honesto:
- Un stub adopta el tamaño de la imagen. Importa un PNG de 2560×1080 en un stub de una pantalla y el stub pasa a medir 2560×1080, con el scroll X encendido por ti (el mismo gesto de "sincronizar dimensiones" que ofrece el Editor de Salas). Una sala existente conserva su tamaño: si la imagen mide distinto, la línea de estado lo dice y te manda al Editor de Salas, y el diálogo de Ejecutar Andamiaje lo repite en una línea de aviso que nombra cada fondo en cola que no coincide con su sala, con los dos tamaños, para que lo tengas enfrente justo cuando confirmas.
- El archivo de la sala lo escribe sólo Ejecutar Andamiaje. En un stub el fondo viaja
dentro del stub, como todo lo demás suyo. En una sala existente la ruta nueva queda en
cola. El campo muestra la etiqueta
pendiente, el diálogo de confirmación la lista en su propia línea ("1 fondo(s) asignado(s): …") y la cola sobrevive una recarga igual que un conector sin andamiar. ✕ quita la referencia de la misma forma; el PNG nunca se borra. - Importar copia el archivo al instante. Importar del disco… escribe el PNG en el
proyecto en el momento en que lo eliges, antes de cualquier confirmación, y aunque después
canceles el andamiaje; la línea de estado lo dice. Si ya había un archivo con ese nombre,
queda respaldado (los últimos cinco), así que equivocarte de archivo te cuesta una vuelta a
assets/rooms/, no el arte.
Guardar Diseño vs Ejecutar Andamiaje#
Esta es la separación clave (load-bearing) del editor:
- Guardar Diseño escribe solo
blueprint.json: posiciones de caja, pistas de eje de scroll, descripciones de stub, tipo/modo/anclas de conector. Nunca toca un archivo.jsde sala. Puedes diseñar libremente, guardar todo el tiempo, y nada en disco fuera del archivo de layout cambia. - Ejecutar Andamiaje es la acción explícita, con confirmación de por medio, que realmente
materializa el diseño: escribe un
.jsreal por cada stub, y genera las regiones dominó (o de punto libre) para cada conector que todavía no esté respaldado por un warp. Primero abre un modal de resumen, nombrando exactamente qué salas se van a crear y cuántas salas existentes se van a tocar, antes de escribir nada.
El contrato que hace esto seguro de correr repetidamente: las salas existentes solo reciben agregados, nunca se reescriben. Conectar un stub nuevo a una sala que ya existe agrega la región de entrada/warp de esa sala (un upsert por id estable) sin tocar nada más de lo ya autorado ahí: sus hotspots, áreas caminables, otras regiones sobreviven intactas. Las dos casillas opt-in de más abajo son las únicas excepciones, y cada una lo dice en su propia etiqueta: cambian un campo en las salas que nombran, y arrancan desmarcadas. Andamiar un diseño dos veces es idempotente: los stubs ya materializados y los conectores ya generados se saltan, así que volver a correrlo solo agarra lo nuevo desde la última pasada.
Borrar una sala#
Al seleccionar una caja, el panel muestra un botón para quitarla (también sirven las teclas
Supr o Retroceso). En un stub que nunca se andamió es ✕ Quitar caja, que sólo saca la
caja y sus conectores del diagrama, y Deshacer la devuelve. En una sala que ya existe es
🗑 Eliminar sala…, y ésa sí toca archivos: tras una confirmación que nombra cada sala
conectada, el archivo de la sala se mueve a una copia .bak y las regiones de puerta que
apuntaban a ella se quitan de sus vecinas. Deshacer no la recupera; ↺ Restaurar sala, en la
barra, devuelve la última sala eliminada, una sola vez. Sus conexiones hay que volver a dibujarlas.
Borrar una sala y Ejecutar Andamiaje también guardan el diagrama al terminar. Si ese guardado falla, el editor queda marcado como sin guardar y la barra de estado dice por qué, así que Guardar Diseño lo reintenta. Restaurar recarga el diagrama entero desde el disco, así que, si tienes cambios sin guardar, pregunta antes de descartarlos (y con ellos el historial de deshacer).
Opt-in de walkable prototipo#
El diálogo de confirmación de Ejecutar Andamiaje tiene un checkbox desmarcado por defecto: generar áreas caminables prototipo. Cuando está activo, cualquier sala tocada por esa pasada de andamiaje que no tenga área caminable existente recibe un rectángulo simple alineado a los ejes: una franja de piso por defecto en la zona inferior-media, agrandada para también cubrir la caja delimitadora de cada región de puerta (warp y entrada) que la pasada acaba de agregar, así la sala queda caminable de punta a punta (puedes spawnear en la entrada y alcanzar cada salida) sin dibujar un polígono a mano primero. Es un punto de partida pensado para refinarse en el Editor de Salas, no un área caminable final. El chequeo es por sala y no destructivo: una sala que ya tiene un piso (aunque sea un solo triángulo) se deja completamente intacta y el helper no devuelve nada para ella, así que volver a correr el andamiaje con el checkbox activo nunca sobreescribe geometría caminable autorada a mano.
Puertas que caerían fuera del piso#
Una región de puerta es un trigger que el jugador tiene que pisar, así que una puerta sin piso caminable debajo es inerte: parece autorada y no hace nada. El andamiaje ancla una puerta pared a la pared que arrastraste, y una pared es justo donde normalmente no hay piso.
Así que el diálogo de confirmación las nombra en ámbar antes de que confirmes: 4 puerta(s) van a caer fuera del área caminable de su sala, así que no se van a poder pisar, con la sala, el id de la región y las coordenadas. Sólo avisa: nunca toca el piso. Hacerle crecer el área caminable dibujada a mano para que se coma una puerta es precisamente la reescritura que el contrato de sólo-agregar prohíbe, así que mover la puerta (o extender el piso) es una decisión del Editor de Salas. Las salas sin piso quedan fuera del aviso: ya las cubre el checkbox de walkable prototipo de arriba, que crece su rectángulo sobre los bounding boxes de las puertas a propósito.
El chequeo es un ensayo del proceso real, no una predicción: le pregunta al mismo código de colocación de puertas dónde van a caer, y al mismo test de punto-en-polígono que usa el juego corriendo si hay piso debajo, así que lo que el diálogo avisa es lo que efectivamente se escribe. Una puerta cuenta como alcanzable si cualquier esquina o su centro toca el piso, porque un solapamiento parcial sigue siendo una puerta que se puede pisar.
Opt-in de scroll de cámara#
El diagrama sabe algo que ninguna otra herramienta está tan bien parada para notar: si una sala es más grande que la ventana que su cámara puede alcanzar. El scroll vertical está apagado salvo que la sala lo prenda, así que una sala más alta que el área jugable esconde su extremo lejano para siempre, y esa banda es, casi siempre, donde se pintó el piso.
La segunda casilla desmarcada-por-default de Ejecutar Andamiaje ofrece el arreglo, nombrando
cada sala afectada y cuánto esconde: prender el scroll vertical de cámara en 2 sala(s)… QA Room
1 (276px). Marcarla escribe scrollY en esos archivos de sala (el único campo que lee la
cámara del runtime) y el resumen lo reporta en su propia línea. Después de eso, el Validar del
Editor de Salas se queda callado sobre esas salas, porque el diagrama y el validador juzgan el
alcance con el mismo modelo compartido.
Es una oferta, nunca automático, y sólo para el eje vertical. Las dos restricciones son a
propósito: un fondo alto encuadrado deliberadamente con el origin del viewport de la sala es una
técnica válida, así que prender el scroll por decreto rompería una elección legítima; y el
scroll horizontal ya viene prendido, así que una sala ancha con scrollX explícitamente apagado
es alguien diciendo que la quiere encuadrada.
Flujo de trabajo#
- Abre el Diseñador de Mapa: las salas existentes aparecen automáticamente como cajas bloqueadas a escala real; los warps existentes aparecen como conectores.
- Usa la herramienta Sala para soltar cajas de stub nuevas (selector de sala existente o un stub nuevo, nombrado al soltar) y redimensiónalas para fijar sus dimensiones reales (controlado por scrollX/scrollY).
- Usa la herramienta Conectar para enlazar cajas: elige una dirección (ida/vuelta/bidi) y un tipo (pared/libre), y arrastra de una caja a otra.
- Auto-distribuye para desapilar un layout enredado (force-directed: separa cajas superpuestas, atrae las salas conectadas), y después Ajusta para encuadrar todo.
- Guarda Diseño tantas veces como quieras: siempre es seguro, solo cajas.
- Cuando estés listo para convertir stubs y conectores pendientes en contenido real, Ejecuta Andamiaje, revisa el resumen de confirmación (y activa las áreas caminables prototipo si sirve), y confirma.
- Abre las salas recién andamiadas en el Editor de Salas para agregar hotspots y refinar o reemplazar el piso prototipo, o asigna el fondo de cada sala aquí mismo primero (Elegir… en el panel) y deja que Ejecutar Andamiaje lo escriba junto con lo demás.
Nada de esto es real hasta Ejecutar Andamiaje. Soltar stubs, dibujar conectores, incluso hacer clic en Guardar Diseño: nada de eso escribe un archivo de sala. El diagrama es una propuesta que vive enteramente en
blueprint.jsonhasta que le pides explícitamente al editor que la materialice, y aún entonces solo agrega a lo que ya existe. Si una sesión termina a mitad de un diseño sin Guardar, lo peor que puede pasar es perder posiciones de caja sin guardar. En el momento en que algo se ve mal después de Andamiar, los archivos de sala mismos son el lugar para revisar, ya que son lo único que realmente se escribió.