npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@liquidcars/atlas

v0.1.51

Published

Reusable 3D conceptual atlas Web Component for LiquidCars-style models

Readme

@liquidcars/atlas

Componente web reutilizable para explorar modelos conceptuales en 3D. El componente lee una isla de datos con palette, entities y relations, resuelve coordenadas relativas mediante parent y permite explorar geometrías, contenedores, relaciones animadas y selección contextual.

Prueba local

Desde la carpeta del paquete:

python3 -m http.server 4173

Después abre http://localhost:4173/ (o http://localhost:4173/demo/). La demo usa el mismo modelo LiquidCars que la página actual, pero carga el componente como módulo ESM independiente. Es importante servirlo por HTTP, no abrir el HTML directamente con file://.

Uso directo en una página

<script type="module" src="./dist/liquidcars-atlas.js"></script>

<liquidcars-atlas height="720" relation-mode="selected" relation-marker="cone" shell-labels="on" toolbar="on">
  <script type="application/json">
  {
    "palette": {
      "channels": "#58b6ec",
      "offers": "#48c8b0"
    },
    "entities": [
      {
        "id": "offers",
        "name": "OFFERS",
        "sub": "Stock y servicios",
        "p": [0, -3, 0],
        "s": [11, 3.4, 5],
        "c": "#48c8b0",
        "type": "container",
        "text": "..."
      }
    ],
    "relations": [
      {
        "from": "dealer",
        "to": "base-offer",
        "label": "mantiene",
        "text": "Mantiene sincronizada la oferta base del concesionario."
      }
    ]
  }
  </script>
</liquidcars-atlas>

También se puede cargar el modelo desde JavaScript:

const atlas = document.querySelector('liquidcars-atlas');
atlas.model = model;
atlas.select('distribution-agreement'); // selecciona sin mover la cámara
atlas.focusSelection();                 // centra y amplía la selección explícitamente
atlas.setSelectionNavigation('preserve'); // 'preserve' | 'center' | 'fit'
atlas.selectRelation(0); // también acepta el id de una relación
atlas.getRelationBundle(); // conexiones A↔B que comparten el tubo de la selección
atlas.setRelationMode('all'); // 'all' | 'selected' | 'callers' | 'called' | 'none'
atlas.setRelationMarker('cone'); // 'cone' por defecto; 'ring' conserva el indicador clásico
atlas.setVisibleRelationGroups(['electric', 'water']); // null vuelve a mostrar todos
atlas.setToolbarVisible(true); // también se puede usar toolbar="on" | "off"
atlas.setPanelVisible(true);   // también se puede usar panel="on" | "off"
atlas.setItemFacing('camera'); // valor por defecto; usa 'model' para conservar la orientación original
atlas.zoomIn();
atlas.zoomOut();
atlas.panBy(-1.5, 0); // desplazamiento horizontal/vertical en el plano de cámara
atlas.panTo(0, 0, 0); // centra la cámara en un punto del mundo
atlas.fit();
atlas.frontView();
const initialView = atlas.getCameraView();
atlas.setCameraView(initialView, { animate: false });
atlas.restoreInitialCamera({ animate: false });
atlas.setShellLabels(true);
atlas.setContainerOpen('distribution-agreements', true);
atlas.toggleContainer('distribution-agreements');
console.log(atlas.isContainerOpen('distribution-agreements'));
console.log(atlas.getOpenContainerIds());
atlas.restoreInitialContainerState();
atlas.openAllContainers();
atlas.closeAllContainers();
atlas.setTheme({
  background: { color: '#07121e', glow: '#20394b' },
  lighting: { ambient: 1.8, directional: 3.0 },
  ui: { breadcrumbs: true, panel: true, toolbar: true, hint: false }
});
atlas.setPalette({ channels: '#58b6ec', offers: '#48c8b0', connection: '#f4edba' });
atlas.setSelectionMode('event'); // el clic emite lc-select sin navegar internamente

// El componente se puede modificar sin volver a crearlo.
atlas.addEntity({ id: 'service', name: 'Service', geometry: 'cone', p: [4, 0, 0], s: [2, 2, 2] });
atlas.updateEntity('service', { text: 'Servicio actualizado', c: '#ed8f98' });
atlas.addRelation({ from: 'service', to: 'offers', label: 'publica', text: 'Publica ofertas validadas.', mode: 'bidirectional' });
atlas.updateRelation(0, { mode: 'broken' });
atlas.removeRelation(0);
atlas.removeEntity('service');

atlas.addEventListener('lc-select', event => {
  if (event.detail.kind === 'entity') {
    console.log('Entidad seleccionada:', event.detail.id, event.detail.entity);
  } else if (event.detail.kind === 'relation') {
    console.log('Relación seleccionada:', event.detail.index, event.detail.relation);
  }
});
atlas.addEventListener('lc-model-change', event => {
  console.log('Modelo actualizado:', event.detail.kind);
});

El mismo bloque theme puede formar parte del JSON del modelo. Los estilos principales también están expuestos como variables CSS (--lc-bg, --lc-bg-glow, --lc-panel-bg, --lc-toolbar-bg, --lc-crumb-bg, etc.), por lo que una aplicación puede adaptar la apariencia sin modificar el bundle. Las propiedades atlas.theme y atlas.styles son alias prácticos de esta configuración.

Eventos disponibles: lc-ready, lc-error, lc-warning, lc-select, lc-model-change, lc-relation-mode, lc-relation-marker-change, lc-relation-groups-change, lc-item-facing-change, lc-focus-change, lc-print-ready, lc-print-error, lc-print-restored y lc-disconnect. lc-select usa un detalle discriminado: las entidades incluyen { kind: 'entity', id, entity, source } y las relaciones { kind: 'relation', id, index, relation, source }. Los campos históricos id y entity se conservan para las selecciones de entidad. Al volver a la vista general, kind, id, entity y relation son null. Los eventos de selección y cambios de modelo son bubbles y composed, por lo que funcionan también al integrar el componente en otras capas de Web Components.

El comportamiento del clic se puede elegir con selection-mode="internal" (por defecto) o selection-mode="event". En el segundo caso el componente emite lc-select con source: "pointer", pero deja la decisión a la página anfitriona. La API equivalente es setSelectionMode() (también disponible como setClickBehavior()).

La selección interna conserva la cámara por defecto. Un doble clic, el botón Enfocar selección del panel o focusSelection() centran y amplían el elemento seleccionado. El comportamiento automático puede cambiarse con el atributo selection-navigation="preserve|center|fit", mediante setSelectionNavigation() o declarativamente en el modelo:

render:
  relationMarker: cone # ring conserva el indicador circular clásico
  navigation:
    onSelect: preserve
  itemFacing: model # opt-out; camera es el valor por defecto

Impresión

Atlas prepara automáticamente una representación WYSIWYG al entrar en el modo de impresión del navegador. La captura conserva el ángulo, el zoom, el foco y los objetos visibles, pero omite la toolbar, el panel de información y las indicaciones de interacción. Al terminar se restaura el canvas WebGL. Los conos animados indican el sentido incluso en una captura estática. Un modelo puede recuperar los aros clásicos con render.relationMarker: ring.

La misma funcionalidad puede controlarse explícitamente:

const atlas = document.querySelector("liquidcars-atlas");
const transparent = atlas.captureFrame(); // canvas 2D con alfa
const themed = atlas.captureFrame({ background: "theme" }); // añade el fondo visual del componente
const white = atlas.captureFrame({ background: "#ffffff" }); // fondo sólido opcional
const presentation = atlas.captureFrame({ background: "transparent", scale: 2 }); // salida HD
const copied = await atlas.copyFrame({ background: "theme", scale: 2 }); // portapapeles PNG
const portable = await atlas.copyFrame({ background: "transparent", scale: 2, fallback: "download" });
atlas.prepareForPrint();
atlas.restoreAfterPrint();

captureFrame() usa WebGLRenderingContext.readPixels() para funcionar también en navegadores que no permiten copiar directamente un canvas WebGL sin preserveDrawingBuffer. El framebuffer permanece transparente: el fondo de tema se compone en el canvas 2D únicamente cuando se solicita y no recibe luces ni sombras de la escena. scale vuelve a renderizar temporalmente entre 1× y 4×, respetando el límite de framebuffer del navegador, y restaura inmediatamente el canvas interactivo. Los colores WebGL semitransparentes se convierten de alfa premultiplicado a alfa directo para conservar el tono de los contenedores abiertos cuando el PNG se coloca sobre un fondo claro. Para evitar que un bloque se divida entre páginas, el componente aplica break-inside: avoid durante la impresión.

La toolbar incorpora las variantes PNG con fondo y transparente. Ambas usan copyFrame() a resolución 2×; si el portapapeles de imágenes no está disponible, la acción descarga atlas-view.png. La API emite lc-image-export con el método empleado (clipboard o download) y lc-image-export-error si tampoco puede generar el archivo.

Contrato de datos

  • palette: mapa de nombres de color a valores CSS/hex.
  • theme (opcional): configuración de background, lighting, panel, toolbar, breadcrumbs, hint y ui. ui permite mostrar u ocultar panel, toolbar, breadcrumbs y hint.
  • render.camera (opcional): vista inicial con position, target y zoom. Las coordenadas pertenecen al espacio del modelo; zoom conserva el encuadre relativo entre tamaños de visor.
  • render.initialMode: 2d o 3d. render.views."2d".theme admite auto (hereda el fondo del documento), light o dark; render.views."2d".grid activa o desactiva los puntos (por defecto, true). render.views."2d".background permite un color CSS concreto. render.ui.toolbar acepta true, false o una lista como [mode, zoom, fit] para mostrar solo esos controles.
  • render.focus (opcional): filtrado visual por selección. mode acepta all o connected, effect acepta dim o hide, y layout distingue posiciones estables (preserve) de una proyección recompilada (reflow).
  • render.relationMarker (opcional): forma de los indicadores animados de relación. Admite cone (por defecto, conserva el sentido en capturas estáticas) o ring.
  • style.label.anchor (opcional): posición predeterminada de las etiquetas de los elementos (auto, top, bottom, left o right). Si se omite, los elementos usan bottom; una entidad puede sobrescribirlo con su propio style.label.anchor. Los títulos de contenedores mantienen su colocación automática salvo override explícito.
  • entities: objetos con id, name, p, s, c, type, text, url y opcionalmente parent, geometry, radius, segments, frontLabel, anchor y ports. Un contenedor puede declarar open: true para comenzar abierto; el valor predeterminado es cerrado y se omite al serializar. Las URL HTTP(S) se abren en una pestaña nueva desde el panel de información.
  • p es la posición local respecto a parent; una entidad sin parent usa coordenadas de escena.
  • s son dimensiones absolutas locales [x, y, z].
  • relations acepta objetos {from, to, label, text, url} o la forma corta [from, to, label]. label es el título corto de la conexión, text su descripción y url su documentación externa en el panel de información.
  • relationGroups declara capas temáticas {id, label, color, description} y cada relación puede referenciar una con group. render.visibleRelationGroups las filtra sin alterar el modo de relaciones. Las conexiones paralelas visibles comparten automáticamente un portador translúcido, pero cada conductor conserva selección, dirección, marcador e inspector propios. El campo visual opcional mode admite directed (por defecto), bidirectional y broken. En modo bidireccional los indicadores animados circulan en ambos sentidos por el mismo tubo; en modo broken los dos tramos se sustituyen por un único tubo rojo con tres indicadores que vibran localmente. distribuidos a lo largo del recorrido.

Geometrías incluidas en esta primera versión: box, cylinder, sphere, cone, frustum-cone, frustum-pyramid, frustum-triangle, prism, pyramid-square, pyramid-triangle, octahedron, dodecahedron e icosahedron. Las variantes frustum-* son sólidos truncados con dos caras finitas paralelas; las dimensiones s se aplican sobre su caja final normalizada.

Las etiquetas se rasterizan con relleno claro y un contorno oscuro proporcional para mantener el contraste sobre geometrías tanto claras como oscuras.

Geometry packs

Las geometrías pueden distribuirse en paquetes independientes. El componente expone registerGeometryPack(), unregisterGeometryPack(), getGeometryCatalog() y getGeometryPackCatalog(); los mismos métodos están disponibles como estáticos en LiquidCarsAtlas. Los identificadores usan un namespace (infra.server, emoji-fluent.robot, architecture.hexagonal.port, etc.) y las primitivas integradas también se publican como geo.box, geo.sphere, etc. Los nombres históricos sin namespace siguen siendo compatibles. Los namespaces pueden contener segmentos separados por puntos, de modo que packs especializados como architecture.hexagonal convivan con architecture.

getGeometryCatalog() conserva el catálogo operativo de geometrías. getGeometryPackCatalog() describe las librerías registradas, incluyendo autoría, licencia, procedencia y recursos, sin duplicar estos datos en cada geometría.

El módulo exporta también ATLAS_VERSION, y la clase registrada expone la misma versión mediante customElements.get("liquidcars-atlas").version. Esta segunda forma identifica la implementación que el navegador utiliza realmente si accidentalmente se cargan varias versiones del core.

import { registerGeometryPack } from "@liquidcars/atlas";

const robotImage = new URL("./assets/robot.svg", import.meta.url).href;

registerGeometryPack({
  namespace: "example",
  name: "Example visual assets",
  version: "0.1.0",
  authors: [{ name: "Example Studio", url: "https://example.com" }],
  license: { spdx: "MIT", url: "https://opensource.org/license/mit" },
  sources: [{
    id: "example-artwork",
    name: "Example artwork",
    authors: ["Example Studio"],
    license: "MIT"
  }],
  resources: [{
    id: "robot",
    kind: "image",
    mimeType: "image/svg+xml",
    path: "./assets/robot.svg",
    url: robotImage,
    source: "example-artwork"
  }],
  palette: { backplate: "#193142", image: "#ffffff" },
  geometries: [{
    id: "robot",
    canonicalSize: [2.4, 2.4, .5],
    resource: "robot",
    create({ resources }) {
      return { parts: [
        { shape: "box", size: [.92, .92, .12], color: "backplate", radius: .16 },
        { shape: "plane", size: [.84, .84, 1], position: [0, 0, .07],
          color: "image", image: resources.robot.url, imageFit: "contain",
          transparent: true, edges: false }
      ] };
    }
  }]
});

El modelo configura cada instancia sin conocer la implementación del paquete:

{
  "geometry": "example.robot",
  "geometryPalette": { "backplate": "#284b63" }
}

Cada definición puede declarar parámetros tipados, una paleta local, proporciones canónicas y anchors. Los recursos declarados por el pack se entregan a create({ resources }) indexados por id; pueden estar empaquetados mediante new URL("./assets/...", import.meta.url), ser data URIs o apuntar a un recurso remoto. sources permite atribuir una colección de terceros una sola vez y cada recurso puede sobrescribir authors o license.

Las piezas declarativas admiten primitivas, posición, rotación, escala, materiales e imágenes por URL/data URI; los SVG también pueden proporcionarse inline. Para planos con imagen, imageFit admite cover, contain y stretch. Desde 0.1.40, shape: "svg-extrude" convierte rutas SVG en una malla con profundidad real, por lo que una marca puede formar parte del volumen sin convertirse en texto ni en una textura plana:

{
  shape: "svg-extrude",
  svg: resources.postgresql.content,
  size: [.24, .24, .05],
  position: [.2, -.04, .44],
  color: "#4169e1",
  emissive: "#4169e1",
  emissiveIntensity: .4,
  bevel: .04,
  curveSegments: 6,
  edges: false
}

emissive y emissiveIntensity permiten conservar colores vivos bajo la iluminación 3D sin eliminar el relieve ni las sombras. El helper exportado createSvgExtrudeGeometry(svg, options) admite rutas con líneas, curvas cuadráticas y cúbicas, arcos elípticos y subtrazados. El renderer mantiene Three.js encapsulado para evitar que los packs dependan de su versión interna. Las relaciones parten por defecto de la superficie orientada hacia el otro extremo. anchor: center conserva el comportamiento centrado cuando sea necesario, y fromAnchor y toAnchor permiten elegir puertos explícitos declarados por una geometría.

Si un namespace no está registrado, Atlas conserva el modelo renderizable con una caja roja de fallback y emite lc-warning con el código GEOMETRY_NOT_REGISTERED. Si la factoría del pack falla se usa el código GEOMETRY_BUILD_FAILED.

La paleta puede cambiarse después de cargar el modelo mediante atlas.setPalette({ nombre: color }) o asignando atlas.palette = { ... }. El cambio actualiza las piezas, aristas y relaciones sin reconstruir el modelo.

Las acciones de navegación y exploración también están disponibles para la página anfitriona: zoomIn(), zoomOut(), panBy(), panTo(), fit(), frontView(), getCameraView(), setCameraView(), restoreInitialCamera(), setRelationMarker(), setItemFacing(), toggleItemFacing(), setShellLabels(), toggleShellLabels(), setPanelVisible(), setFocusFilter(), clearFocusFilter(), getFocusedIds(), isContainerOpen(), getOpenContainerIds(), setContainerOpen(), setOpenContainers(), toggleContainer(), restoreInitialContainerState(), openAllContainers() y closeAllContainers(). El usuario puede desplazar la vista con el botón derecho, con Shift + arrastre o mediante dos dedos en una pantalla táctil. Así se puede construir una barra de controles propia sin depender de la toolbar interna.

Cada cambio del estado vivo emite lc-container-state-change. Su detalle contiene openContainers, changedContainers, changedContainer, open y source, de modo que el host puede consultar o persistir una interacción sin acceder a detalles internos del componente.

Una vista inicial portable puede declararse dentro del modelo:

entities:
  - id: distribution-agreements
    type: container
    open: true
    children: []
render:
  focus:
    mode: connected
    effect: dim
    layout: preserve
    opacity: 0.12
  camera:
    position: [12.4, 7.2, 18.6]
    target: [0, 1.5, 0]
    zoom: 1.35

La API equivalente es setFocusFilter({ mode, effect, layout, opacity }). getFocusedIds() devuelve la selección, sus vecinos directos y los contenedores ancestros necesarios. El evento lc-focus-change permite que un host conectado a @liquidcars/atlas-layout recompile una proyección cuando layout es reflow.

position y target fijan la dirección observada. Cuando existe zoom, éste prevalece para calcular la distancia final y mantener el encuadre; si se omite, Atlas lo deriva de la distancia declarada.

La escena también se puede editar en caliente. updateModel(patch) reemplaza las secciones indicadas; addEntity, updateEntity y removeEntity gestionan entidades, mientras addRelation, updateRelation y removeRelation gestionan relaciones. Cada operación reconstruye la geometría necesaria, conserva la cámara y la selección cuando sigue siendo válida, y emite lc-model-change con el tipo de operación y el modelo resultante.

getRenderStats() devuelve una instantánea de entidades, relaciones, objetos animados, draw calls y contadores de geometrías, texturas y programas del renderer. Resulta útil para comprobar que una secuencia repetida de mutaciones vuelve a una línea base estable. Al reconstruir o desconectar el componente se liberan geometrías, materiales, texturas, cargas de imagen pendientes y el contexto WebGL.

Distribución

El archivo dist/liquidcars-atlas.js es un módulo ESM autocontenido: Three.js se incluye dentro del bundle, por lo que el consumidor no necesita instalar otra dependencia para probarlo. El bundle no contiene ningún modelo de negocio ni datos de LiquidCars Atlas; los modelos se suministran aparte mediante model, src o un <script type="application/json">. Para una distribución privada se puede servir ese archivo desde un CDN propio o desde el mismo sitio. Para publicar en npm, después de revisar el API estable:

npm publish --access public

Una vez publicado, los consumidores podrán instalarlo con npm install @liquidcars/atlas o cargar el bundle desde un CDN compatible con npm.

Para probar el paquete sin publicarlo, basta con instalar el tarball generado:

npm install ./liquidcars-atlas-0.1.40.tgz

Estado

0.1.40 añade SVG extruido nativo para que los geometry packs puedan construir marcas volumétricas a partir de recursos vectoriales sin recurrir a campos de texto. 0.1.39 incorpora metadatos normalizados de autoría, licencia, procedencia y recursos para los geometry packs, añade getGeometryPackCatalog() y entrega los recursos declarados a create({ resources }). Se mantiene intacto getGeometryCatalog() para conservar la compatibilidad. 0.1.28 rasteriza explícitamente los SVG sobre un canvas antes de subirlos a WebGL y emite diagnósticos cuando falla la carga o la conversión. 0.1.27 añade carga automática de imágenes SVG remotas, SVG mediante data URI y SVG inline, manteniendo las mismas opciones de cara y ajuste que las imágenes raster. 0.1.26 mantiene el centro como anclaje implícito de toda relación y utiliza los puertos de geometrías externas únicamente cuando el modelo los solicita. También evita recorrer los materiales de geometrías compuestas en cada frame, refuerza la liberación de recursos y expone getRenderStats(). 0.1.24 incorporó geometry packs independientes, namespaces, parámetros personalizados, paletas locales, anchors e imágenes declarativas. La versión 0.1.23 añadió desplazamiento lateral de cámara mediante ratón, teclado modificador y gestos táctiles, además de la API pública panBy() y panTo(). Se conserva la selección contextual de relaciones introducida en 0.1.22: el usuario puede seleccionar un tubo directamente. Cuando varias conexiones comparten extremos, los clics sucesivos recorren sus conductores y el panel enumera el tubo virtual completo para permitir una selección precisa. La API pública añade selectRelation(), getRelationBundle(), selectedRelation y selection, y la selección se conserva durante las mutaciones del modelo siempre que el elemento siga existiendo. Se mantienen las correcciones de geometría, toolbar, etiquetas, paleta externa, edición en caliente y los modos directed, bidirectional y broken introducidos en las versiones anteriores.

Hyperlinked Atlas documents

Entities and relations can keep their external url and also declare an atlasRef such as atlas:actors/dealer.atlas.md#inventory. A leading slash (atlas:/overview.atlas.md) starts at the root of the host's document collection; otherwise the path resolves beside the current document. The optional fragment selects an entity in the destination. Paths cannot escape the collection root.

The information panel accepts content: { format: "markdown", value: "…" } or content: { format: "html", value: "…" }. It also accepts a source instead of an inline value when a content resolver is configured. HTML is restricted to text formatting and safe atlas: or HTTP(S) links. Existing text remains the fallback when content is absent.

The host supplies documents and optional external content:

atlas.setDocumentResolver(async ({ uri, from }) => ({
  uri,
  model: await loadAndCompileDocument(uri, from)
}));
atlas.setContentResolver(async ({ source, from, format }) =>
  loadContent(source, from, format));
await atlas.load(initialModel);
atlas.setDocumentUri("atlas:/overview.atlas.md");

The component exposes openAtlas(reference), goHome(), goBack(), goForward(), goToVisit(index) and getDocumentHistory(). Navigation and failures emit lc-navigation and lc-navigation-error. Home, Back and Forward appear in a top navigation bar; holding Back or Forward opens a visit list. Hosts with their own top bar can set navigation-controls="external" and connect those controls to the public history methods, as Atlas Studio does. Selecting a linked entity or relation shows a floating link button beside it. The information panel remains focused on descriptive content and external documentation. Studio's Markdown and visual views can open a local folder; they treat that folder as the root of atlas:/. Where supported, Studio requests read and write directory access. It discovers document names, reads files only as they are opened or referenced, and caches their text in the current tab. Save writes the active Markdown document back to its original file, including edits from the visual editor; switching editors preserves the document and visit history. Nothing is sent to a server. Browsers without the directory picker use a file-input fallback, whose native dialog may call the selection “Upload”; Studio still reads the files locally on demand. In that fallback, Save opens a picker or downloads a copy because the selected files cannot be written in place. See examples/hyperlinks for two linked documents and an external Markdown information file.

Named models and cloud destinations

The optional model selector identifies a technical model key within the destination document. Titles may change without changing the reference:

| Destination | Reference | | --- | --- | | Current document | atlas:?model=process | | Local collection | atlas:actors/dealer.atlas.md?model=inventory | | Current cloud publication | atlas://cloud/DOCUMENT_ID@published?model=process | | Fixed cloud revision | atlas://cloud/DOCUMENT_ID@r3?model=process | | Authorized cloud Draft | atlas://cloud/DOCUMENT_ID@draft?model=process |

Append #entityId to select an entity. URI-encode model keys and fragments. Omitting model uses the destination document's defaultModel. A cloud origin cannot resolve local document or content paths; a local origin may open cloud documents through its host resolver.

The exported atlasReferenceTarget(reference, from) parses the document kind, version and model selector. The resolver may return context alongside uri and model; the runtime carries that context in history and navigation events. Return a canonical revision URI when resolving @published to pin the visit. Cloud history visits invoke the resolver again so the host can recheck access. The runtime does not grant authorization or contact a cloud deployment itself.

Use setNavigationGuard(async () => { ... }) to finish pending saves before navigation. Resolution errors, missing models and missing entity fragments leave the origin active. History retains 2D/3D mode, camera, diagram zoom and scroll, selection, open containers and filters. Hosts that rebuild the component can use restoreNavigationState(state, { restorePresentation: true }) to restore its presentation as well as its history.