1// The boot module: the only page JavaScript the seam contributes.2//3// It does three things and nothing else:4//5// REGISTERS the three custom elements. Until this runs, `<atlas-viewport>`6// is an unknown tag that renders nothing and breaks nothing — which is what7// makes the seam deletable rather than merely small.8//9// OPENS the diagnostics seams a headless driver reads (docs/render-seam.md §8).10//11// HOOKS the one after-swap rescan issue #5 §4.3 allows. A morph swap can12// replace the scene node whole; the seam has to be told to look again. That13// is the entire glue budget: one listener, no `hx-on` anywhere, and no14// other behaviour on the page belongs to this lane.15//16// Note what is NOT here: no interaction handlers, no route knowledge, no17// session writes. Everything a reader does that is discrete goes to the18// server as an ordinary request, and comes back as a new scene.1920import { logger } from "./log.ts";21import { AtlasViewport } from "./viewport.ts";22import { AtlasChart } from "./chart/element.ts";23import { AtlasGlobe } from "./globe/element.ts";24import { expose } from "./diagnostics.ts";25import { wireMinting } from "./mint.ts";2627const log = logger("boot");2829/** Register the elements. Safe to call twice; the second call does nothing. */30export function register(): void {31 if (customElements.get("atlas-viewport")) return;32 customElements.define("atlas-chart", AtlasChart);33 customElements.define("atlas-globe", AtlasGlobe);34 customElements.define("atlas-viewport", AtlasViewport);35}3637/** Every viewport on the page. There is one, but nothing here assumes it. */38function viewports(): AtlasViewport[] {39 return [...document.querySelectorAll("atlas-viewport")]40 .filter((element): element is AtlasViewport => element instanceof AtlasViewport);41}4243/**44 * Start the seam.45 *46 * The after-swap hook listens for htmx's own settle event and for a plain47 * custom event, so a page that swaps by some other means — a test, a future48 * framework, a hand-written fetch — has one documented way to say "look49 * again" without this module knowing anything about htmx.50 */51export function boot(): void {52 register();53 const rescan = () => {54 for (const viewport of viewports()) viewport.rescan();55 wireMinting();56 };57 // Both spellings of the same two events. htmx 4 separates the words with58 // colons -- `htmx:after:swap` -- where htmx 2 camel-cased them, and a seam59 // listening only for the old names is a seam that is never told a swap60 // happened: the scene node is replaced whole, the watcher's observer goes61 // with it, and everything this lane draws quietly stops answering the page.62 // `atlas:rescan` is the plain custom event a page that swaps by some other63 // means can raise without this module knowing anything about htmx.64 const swapped = [65 "htmx:after:swap", "htmx:after:settle",66 "htmx:afterSwap", "htmx:afterSettle",67 "atlas:rescan",68 ];69 for (const name of swapped) document.body.addEventListener(name, rescan);70 for (const viewport of viewports()) expose(viewport);71 wireMinting();72 log.info("the seam is up", { op: "render", viewports: viewports().length });73}7475if (typeof document !== "undefined") {76 if (document.readyState === "loading") {77 document.addEventListener("DOMContentLoaded", boot, { once: true });78 } else {79 boot();80 }81}