| .. | ||
| src | ||
| index.html | ||
| index.js | ||
| README.md | ||
| template-map-a.vue | ||
| template-map-b.vue | ||
template-bundle — copy this to start a new map
Your starting point. Copy this folder, then build your map inside the copy — don't start from
blank. It's a tiny working bundle (two trivial profiles that render a colored box, no Mapbox, no
data) plus a src/ sandbox laid out for your real code.
Two zones — know which one a file is in
| Zone | What | Edit it? |
|---|---|---|
library/ (imported as @map/…) |
shared, reusable building blocks — map, legends, toolbars, composables, color + API registries | No — reuse only. A change here can break every other map. |
app-profiles/<your-map>/src/ |
your private sandbox — screens, colors, API wiring, components, utils | Yes — build anything. Nothing here leaks to another map. |
Rule of thumb: local by default. Code only moves into library/ once a second map genuinely
needs it — an expert move, not a first move. To see everything library/ offers, read
../../docs/reference.md (that's the menu you pick from).
Build a new map — the steps
- Copy this folder →
app-profiles/<your-map>/, then change exactly four things:- the folder name (= bundle name = output file
<your-map>.js), - the tag in
index.js(customElements.define('<your-map>', …)), - the tag +
profilestrings inindex.html(the staging page must mount your tag), - the
.vuefilenames — renametemplate-map-a.vueto your screen's name and deletetemplate-map-b.vueif you only want one screen (filename = theprofilename). Nothing else. Check it:bun run dev→ your map renders athttp://localhost:5173/app-profiles/<your-map>/index.html.
- the folder name (= bundle name = output file
- List what your map needs — data, colors, controls (legend, search, share, fullscreen…).
- Pick pieces from
../../docs/reference.mdand import them by reference (@map/…) — never copy library code into your folder. - Put your own code in
src/— screens, components, hooks, helpers. - Set colors in
src/colors/colors.json(plain hex, no code). For color that varies by data, use a strategy.jsinsrc/colors/(copyexample-mode.js). - Build —
bun run build(or just this one:BUNDLE=<your-map> bun run build:bundle).
What's in this folder
template-bundle/
├── index.js ← bundle entry: registers <template-bundle>, globs ./*.vue
├── index.html ← dev staging page (the build needs it to find the bundle)
├── template-map-a.vue ← profile "template-map-a" ← FLAT at the bundle root
├── template-map-b.vue ← profile "template-map-b" ← FLAT at the bundle root
└── src/ ← YOUR SANDBOX (each subfolder has its own README)
├── api/ colors/ components/ composables/ utils/
The flat rule: profile .vue files sit directly in the bundle folder — there is no
profiles/ subfolder, because the entry discovers them with a flat glob
(import.meta.glob('./*.vue')). A .vue inside a profiles/ subfolder would NOT be found. Keep
your profile screens flat; the small pieces they're built from live in src/.
Everything builds into one file: public/doxa-maps/template-bundle/template-bundle.js.
The two ways you import
- Reuse from the library → the
@map/…alias:import { useMapInstance } from '@map/composables/useMapInstance.js' - Your own sandbox code → a relative path:
import colors from './src/colors/colors.json'
There's no alias for your sandbox — your code is always relative. That boundary keeps it private.
Embed it
<script src="/doxa-maps/template-bundle/template-bundle.js"></script>
<template-bundle profile-config='{"profile":"template-map-a"}'></template-bundle>
<template-bundle profile-config='{"profile":"template-map-b"}'></template-bundle>
(profile must match a .vue filename in this folder, without .vue. Add a third profile by
dropping another flat .vue next to these and rebuilding — no config to edit.)
See also
src/README.md— sandbox layout ·../README.md— the app-profiles authoring guide../../docs/tutorial.md— 3 zones + 3 rules in one page ·../../docs/reference.md— the@map/…menu../doxa-simple-map/index.js— a fuller, real-map reference entry