3 KiB
Architecture — the embeddability design (generated pages + manifest)
The simple recipes are in ../how-to.md. This is the design that makes every map embeddable by default: the build generates a self-contained page per map.
What bun run tree generates
After the per-bundle vite builds, internal/generate-tree.mjs writes the served tree:
public/doxa-maps/
├── index.html ← staging root (semantic tree of every map)
├── manifest.json ← machine-readable catalog + ready-made embed snippets
└── <bundle>/
├── <bundle>.js ← the bundle IIFE (the island)
├── index.html ← per-bundle staging/showcase page
├── <profile>/index.html ← ★ standalone page per profile — link it or iframe it
└── <instance>/index.html ← ★ same, per parameterized instance (e.g. prayer/)
The ★ pages are the embeddable-by-default surface: every .vue profile (and every
instance in a *.instances.json) automatically gets a directly linkable, iframe-able URL —
no per-map work.
Anatomy of a generated profile page
Each <profile>/index.html is a bare full-page map — no chrome, so the URL is the map
("Share shares THE MAP"). It loads: the Mapbox GL peer (once, same realm), the bundle IIFE via
a relative ../<bundle>.js, and mounts the element with that profile's config. The token
resolves by the ladder (prop → ?tk= → baked → window.MAP_TOKEN_URL → tokenUrl →
same-origin /api/maps/token), fetched at page load — tokens are treated as data, never eval'd.
All URLs stay relative unless embedBaseUrl is set, so the whole tree can be dropped under
any web-root or subpath and keeps working (check:drop gates this).
The manifest — embed snippets as data
manifest.json (doxa-maps-manifest@1) lists every bundle → profiles, each with element,
scriptUrl, iframeUrl, and a ready-made embed object:
embed.iframe— a paste-ready<iframe src=".../<profile>/index.html" …>snippetembed.script— the<script src>+<element profile-config='…'>pair
Hosts, staging pages, and the share button all read this one catalog — snippets are generated once, never hand-written.
Two embed modes, one rule about iframes
| Mode | What | When |
|---|---|---|
| script + element | host page loads the IIFE, drops the tag | full integration: host styles/sizes it, passes config |
| iframe / direct link | point at the generated <profile>/index.html |
zero-effort embeds, CMSs that only allow iframes, shared links |
Both are supported on built pages. The one "never iframe" rule applies only to the dev
staging script (internal/staging.js), which mounts elements directly because a dev-server
iframe crosses realms (instanceof breaks). Built pages have no such problem — the generated
staging (staging-forge.js) itself uses an iframe stage.