@liquidcars/atlas-layout
v0.1.21
Published
Declarative layout compiler for LiquidCars Atlas models
Maintainers
Readme
@liquidcars/atlas-layout
Compilador inicial para modelos declarativos de LiquidCars Atlas. Convierte entidades anidadas con layouts row, grid, masonry y volume en el modelo plano que consume @liquidcars/atlas.
import { compileAtlasModel } from "@liquidcars/atlas-layout";
const resolved = compileAtlasModel(authorModel);
atlas.model = resolved;
console.table(resolved.diagnostics);Las librerías de geometrías pueden aportar sus proporciones canónicas sin acoplar el compilador al renderer:
const resolved = compileAtlasModel(authorModel, {
geometryCatalog: getGeometryCatalog()
});Cada entrada del catálogo puede declarar id, aliases y canonicalSize.
Una geometría externa desconocida conserva el tamaño de fallback de una caja,
de modo que la compilación sigue siendo recuperable si falta un pack.
Los grids bidimensionales aceptan plane: "xz" | "xy" | "yz". El plano
predeterminado sigue siendo xz; xy resulta útil para galerías concebidas
para una vista frontal.
Los layouts row aceptan packing: "preserve" | "compact". El modo
compact recompone las bandas creadas por constraints de alineación sobre el
eje principal y elimina los huecos que dejan las posiciones iniciales.
layout.groups permite declarar composiciones invisibles de hermanos inmediatos.
Cada grupo tiene id, members y un layout interno. Las constraints del
nivel padre pueden referenciar el id del grupo; tras calcular posiciones, el
compilador elimina el grupo y emite únicamente las entidades reales.
Cuando el layout interno de un grupo es auto, el optimizador también compara
órdenes alternativos de sus miembros con la métrica global del modelo. Los
grupos pequeños prueban todas sus permutaciones; los grupos mayores exploran un
vecindario determinista y acotado. De este modo las relaciones externas pueden
reordenar una composición virtual para reducir cruces sin mutar el documento
fuente. El orden declarado se conserva como desempate.
Un layout row puede distribuir el espacio asignado por un tamaño explícito
o una constraint de igualdad mediante justify: "start" | "center" | "end" |
"space-between" | "space-around" | "space-evenly". padding define los límites
interiores y gap actúa como separación mínima. Los grupos virtuales se
recalculan después de recibir su tamaño definitivo.
Las entidades con children deben declarar type: container. Las hojas pueden
omitir type y se normalizan como items. type: shell se acepta únicamente
como alias de compatibilidad. Un contenedor puede no tener geometría o usar una
primitiva geo.*; las geometrías personalizadas de los packs, como infra.cloud,
sólo se permiten en entidades hoja.
Un contenedor puede declarar open: true para comenzar expandido. El estado
cerrado es el valor predeterminado, por lo que open: false se normaliza
omitiendo la propiedad. Declarar open en una hoja o usar un valor que no sea
booleano produce un diagnóstico fatal.
La presentación puede conservar una vista inicial sin introducir datos de cámara en el algoritmo de layout:
render:
camera:
position: [12.4, 7.2, 18.6]
target: [0, 1.5, 0]
zoom: 1.35Filtered projections
compileAtlasProjection(source, visibleIds, options) compiles a temporary model
containing only the requested entities and their required ancestors. Relations,
constraints and virtual layout groups are pruned consistently. The source object is
never mutated, making the helper suitable for selection-driven render.focus reflow.
Las coordenadas son coordenadas del modelo. zoom es un multiplicador de
encuadre independiente del tamaño del viewport y se conserva al compilar YAML
o Markdown.
Para compilar una fuente YAML durante el build:
import { compileAtlasFileToJson } from "@liquidcars/atlas-layout/build";
await compileAtlasFileToJson(
"layers-model.atlas.yaml",
"public/layers-model.resolved.json"
);En Vite (y también en Astro mediante vite.plugins) se pueden importar las fuentes directamente:
// vite.config.js
import atlasLayout from "@liquidcars/atlas-layout/vite";
export default {
plugins: [atlasLayout()]
};// src/main.js
import "@liquidcars/atlas";
import atlasModel from "../layers-model.atlas.yaml";
document.querySelector("liquidcars-atlas").model = atlasModel;El plugin transforma .atlas.yaml, .atlas.yml, .atlas.md y .atlas.markdown en módulos ESM durante el build y reenvía sus warnings al diagnóstico del bundler. Un diagnóstico fatal detiene el build.
También se puede compilar texto YAML directamente:
import { compileAtlasYaml } from "@liquidcars/atlas-layout/yaml";
const resolved = compileAtlasYaml(yamlText);La API principal recibe un objeto JavaScript ya parseado. Se aceptan entidades anidadas mediante children o entidades planas con referencias parent; internamente ambas formas se normalizan al contrato plano. Las entradas de texto se manejan mediante los subpaths /yaml y /build durante el build.
El entrypoint principal exporta ATLAS_LAYOUT_VERSION como un módulo JavaScript
compatible con navegadores. Un test lo mantiene sincronizado con el manifest
del paquete, sin requerir importaciones JSON en tiempo de ejecución. Las
aplicaciones anfitrionas pueden compararlo con la versión declarada en sus
propias dependencias.
En Markdown se acepta front matter YAML, un bloque completo ```atlas o bloques separados ```atlas-model, ```atlas-layout, ```atlas-render y ```atlas-relations. Por ejemplo:
```atlas
version: 1
entities:
- id: source
geometry: sphere
layout:
algorithm: row
```Las etiquetas de los elementos se colocan debajo por defecto. El modelo puede
cambiar esa política de forma heredable mediante style.label.anchor; una
entidad concreta puede sobrescribirla con la misma propiedad. Los títulos de
los contenedores conservan su colocación automática salvo que el contenedor
declare un anclaje explícito:
style:
label:
anchor: bottom
entities:
- id: source
geometry: sphere
- id: exceptional
geometry: box
style:
label:
anchor: topLas relaciones admiten el modo visual canónico directed, bidirectional o broken:
relations:
- id: source-to-rules
from: source
to: rules
label: feeds
text: Sends normalized source data to the rules engine.
url: https://example.com/relations/source-to-rules
mode: bidirectional
- from: rules
to: output
mode: brokenlabel es el título corto visible junto a la conexión, text permite documentar su significado y url enlaza documentación externa desde el panel de información. mode es la forma recomendada y el compilador siempre la emite normalizada. Para facilitar la migración se aceptan también visual, render, type, direction, bidirectional: true y broken: true, además de los alias two-way, both e interrupted. La forma abreviada puede incluir el modo como cuarto valor: [from, to, label, mode]. Un modo desconocido conserva la relación como directed y añade el diagnóstico UNKNOWN_RELATION_MODE.
Las relaciones pueden organizarse en capas temáticas declarando relationGroups
en la raíz y un único group en cada relación. render.visibleRelationGroups
filtra esas capas sin cambiar relationMode. El compilador genera un id estable
y único cuando la relación no lo trae, y el renderer puede agrupar visualmente las
relaciones paralelas entre los mismos extremos en un solo portador.
Las relaciones también pueden declararse en relations dentro de cualquier entidad
type: container. El compilador aplana las relaciones raíz y anidadas en un único
array de runtime. La exportación visual usa una forma canónica: cada relación se
guarda en el contenedor común más profundo de sus dos extremos; si no existe un
contenedor común, se guarda en relations en la raíz. Así, compilar, editar y
volver a exportar no depende de dónde se declaró originalmente la conexión.
En un documento Markdown dividido, el bloque de relaciones contiene una lista YAML:
```atlas-relations
- from: source
to: rules
mode: bidirectional
```Un mismo documento puede contener varios modelos nombrados. El nombre se añade
al identificador del bloque, separado por espacio o por ::
```atlas overview
entities:
- id: source
geometry: sphere
```
```atlas process
entities:
- id: rules
geometry: prism
```Los bloques divididos usan el mismo nombre (atlas-model overview,
atlas-relations overview, etc.). Para estos documentos se utiliza la API
compileAtlasMarkdownDocument, que devuelve { models, defaultModel }:
import { compileAtlasMarkdownDocument } from "@liquidcars/atlas-layout/yaml";
const document = compileAtlasMarkdownDocument(markdown);
document.models.overview; // modelo normalizado listo para Atlas
document.models.process; // segundo modelo normalizadoparseAtlasMarkdown y compileAtlasMarkdown mantienen el contrato anterior
para un único modelo y emiten un error explícito si reciben varios. El plugin
de Vite conserva ese comportamiento para un solo modelo; con varios bloques
exporta el documento nombrado completo. También se puede declarar un conjunto
de modelos en front matter mediante models: y seleccionar el predeterminado
con defaultModel:.
El parser Markdown/YAML sólo se ejecuta en build time. El bundle del componente visual no incorpora este parser.
El resultado mantiene palette, theme, entities y relations, con p y s resueltos para todas las entidades. diagnostics contiene warnings, errores recuperables y errores fatales; los contenedores fijos que no pueden contener su contenido conservan layoutError: "overflow" para que el renderer pueda señalarlos visualmente.
El espacio de una celda y el tamaño de la geometría son conceptos distintos. Cuando el layout asigna una celda rectangular a una geometría sin size explícito, la figura se centra y se escala uniformemente para caber en el menor volumen compatible; no se estira por separado en x, y y z. Por eso una esfera conserva s[0] === s[1] === s[2], aunque su celda sea rectangular. Un size explícito sigue teniendo prioridad y permite al autor solicitar una proporción concreta.
row, grid/masonry y volume producen posiciones deterministas. variant: masonry desplaza las filas alternas media celda sin exigir una sección stagger; stagger.offset queda disponible como override explícito. Para conservar legibilidad frontal se recomienda plane: xy, y para una composición lateral, plane: yz. Las constraints de tamaño y alineación, el empaquetado compacto, los grupos virtuales y la distribución justify forman parte del contrato estable de autoría.
auto delega en el optimizador global la elección de algoritmo, dirección y
plano para ese propietario de layout. El compilador prueba alternativas de
graph, row, grid y volume mediante una búsqueda determinista y puntúa el modelo
completo, no cada contenedor de forma aislada. La búsqueda resuelve primero los
contenidos anidados y después sus propietarios, de modo que la composición global
se decide con tamaños y afinidades estables. graph también aporta variantes
espaciales internas con varios carriles de profundidad; auto puede elegirlas
sin que el autor tenga que fijar un nuevo algoritmo. Las intersecciones físicas
3D y los solapamientos son condiciones estrictas. Entre las soluciones válidas,
la función perceptiva equilibra los atravesamientos y cruces proyectados con la
legibilidad frontal, la alineación ortogonal, la longitud media de las relaciones,
la compacidad volumétrica, la coherencia de orientación y las proporciones
excesivamente alargadas. Los carriles de profundidad automáticos emplean un paso
compacto; un layout graph explícito conserva el paso completo. Un direction, plane,
gap o padding declarado junto a auto queda bloqueado y limita las
alternativas. Si no se declara gap, se utiliza 3.
layout:
algorithm: auto
# direction: z # opcional: bloquea el eje, pero no el algoritmo resueltoLa cámara inicial de render.camera es la vista principal de la puntuación. Se
combina con una vista frontal canónica —que mide cuántos frentes quedan ocultos—
y varias perspectivas oblicuas para evitar una solución que solo resulte legible
desde un ángulo. Un host como
Atlas Studio también puede pasar la vista interactiva con
compileAtlasModel(source, { autoLayoutCamera: camera }). Cada propietario
automático produce un diagnóstico informativo AUTO_LAYOUT_RESOLVED con la
configuración elegida y las métricas globales, incluidas la oclusión frontal,
las peores métricas proyectadas y las intersecciones espaciales. analyzeAtlasLayout(model,
{ camera }) permite puntuar un modelo ya compilado con la misma función
objetivo.
graph implementa un layout por capas sensible a las relaciones. Proyecta las
relaciones de descendientes sobre los hijos inmediatos del contenedor, asigna
capas según la dirección del flujo y utiliza barridos de baricentro para reducir
cruces y longitud de conexiones. Los empates conservan el orden de autoría para
que el resultado sea determinista. Las relaciones con layout: false no
participan. Los ciclos se rompen de forma estable y producen el diagnóstico
GRAPH_CYCLE_STABILIZED. Cuando varios contenedores usan graph, una pasada
jerárquica adicional utiliza las relaciones que cruzan sus límites para alinear
carriles entre contenedores. De este modo, dos elementos relacionados pueden
quedar en la misma vertical u horizontal aunque no sean hermanos directos.
El gap predeterminado de graph es 3; puede reducirse de forma explícita
para modelos compactos. Las relaciones siguen determinando las capas sobre
direction. Elegir automáticamente entre composiciones alternativas en x,
y o z pertenece a una fase de optimización asistida, no al compilador
determinista.
layout:
algorithm: graph
direction: y
plane: xy
gap: 3El enrutado avanzado de tubos alrededor de geometrías permanece como una fase posterior e independiente de la colocación de nodos.
