Doxa Maps — public snapshot
Seven production prayer/mission maps + the Plugin Studio, built as compiled Vue custom elements: 5 plugin capabilities x 5 deployment methods. One build emits the whole drop-anywhere doxa-maps/ tree; see README.md and documentation/.
4
.env.example
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Mapbox token used in dev. Production hosts pass the token via profile-config.tk
|
||||
# on the host page; never bake into the IIFE bundle.
|
||||
VITE_MAPBOX_TOKEN=pk.your_dev_token_here
|
||||
VITE_API_BASE_URL=https://pray.doxa.life
|
||||
37
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Normalise line endings on commit. Everything here is authored on LF; declaring it
|
||||
# keeps a Windows checkout from rewriting whole files and producing diffs that are
|
||||
# entirely invisible whitespace.
|
||||
* text=auto eol=lf
|
||||
|
||||
# Binaries git must never line-ending-convert or try to diff. The repo carries ~77 MB
|
||||
# of poster imagery, so a wrong guess here corrupts art rather than reformatting text.
|
||||
*.webp binary
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.ico binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
*.ttf binary
|
||||
*.jar binary
|
||||
*.jks binary
|
||||
*.keystore binary
|
||||
*.apk binary
|
||||
*.aab binary
|
||||
|
||||
# Executables keep LF regardless of platform, or the shebang breaks.
|
||||
*.sh text eol=lf
|
||||
gradlew text eol=lf
|
||||
|
||||
# ── What GitHub should NOT count as this project's source ────────────────────
|
||||
# public/ is the served web-root and is committed, which means 4.1 MB of the repo's
|
||||
# 4.9 MB of JavaScript is BUILT bundles. Left alone, the language bar reports this
|
||||
# as a pile of minified JS instead of the Vue and JS someone actually maintains,
|
||||
# and the generated staging pages do the same to HTML.
|
||||
public/doxa-maps/** linguist-generated=true
|
||||
library/scripts/*/snapshots/** linguist-generated=true
|
||||
bun.lock linguist-generated=true -diff
|
||||
|
||||
# Committed research data and imagery: real content, but not code anyone reads.
|
||||
public/assets/** linguist-vendored=true
|
||||
plugin-designs/*/data/** linguist-vendored=true
|
||||
88
.github/workflows/pages.yml
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Build the served web-root and publish it to GitHub Pages.
|
||||
#
|
||||
# public/ is committed, but the bundles inside it are not: public/<name>/ is
|
||||
# regenerated on every push so what ships always matches source. The rest of the
|
||||
# folder — the shell and the pre-generated posters the app fetches at runtime —
|
||||
# comes straight from the checkout.
|
||||
#
|
||||
# MAPBOX_TOKEN is a repository secret. The build turns it into the static token
|
||||
# endpoint at public/api/maps/token.json, which is gitignored, so the credential
|
||||
# reaches the deployed site without ever entering git history. Rotating it means
|
||||
# changing the secret and re-running this workflow.
|
||||
name: Deploy to GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
# Read the repo, write a Pages deployment, and mint the OIDC token Pages requires.
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
# Never let two deploys race; let a newer push supersede an in-flight one.
|
||||
concurrency:
|
||||
group: pages
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- run: bun install --frozen-lockfile
|
||||
|
||||
# Emits public/<name>/ plus the token endpoint, then runs the build guards
|
||||
# (drop-portability, inline-parse, bundles-shipped and the rest). A guard
|
||||
# failure fails the deploy, which is the point of having them.
|
||||
- name: Build
|
||||
env:
|
||||
MAPBOX_TOKEN: ${{ secrets.MAPBOX_TOKEN }}
|
||||
run: bun run build
|
||||
|
||||
# Fail loudly rather than publishing a site whose maps cannot draw.
|
||||
- name: Assert the token endpoint exists
|
||||
run: |
|
||||
test -s public/api/maps/token.json || {
|
||||
echo "::error::public/api/maps/token.json is missing or empty — set the MAPBOX_TOKEN repository secret, or every basemap will render blank."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# A public web-root must never carry the local staging credential.
|
||||
- name: Assert no local credential is being published
|
||||
run: |
|
||||
if [ -e public/token.local.js ]; then
|
||||
echo "::error::public/token.local.js is present in the web-root and must not be published."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Artefact checks cannot tell whether the site WORKS. This boots the built
|
||||
# public/ in a real browser and fails if the shell cannot resolve a token,
|
||||
# no bundle registers its element, or any same-origin request 404s.
|
||||
- name: Install the browser the smoke test drives
|
||||
run: bunx playwright install --with-deps chromium
|
||||
|
||||
- name: Smoke-test the built site
|
||||
run: bun run smoke
|
||||
|
||||
- uses: actions/configure-pages@v6
|
||||
- uses: actions/upload-pages-artifact@v5
|
||||
with:
|
||||
path: public
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- id: deployment
|
||||
uses: actions/deploy-pages@v5
|
||||
119
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# (The build no longer uses an intermediate app/ tree — vite writes straight into
|
||||
# public/<name>/, which is committed. See "THE SERVED WEB-ROOT" below.)
|
||||
|
||||
# Node
|
||||
node_modules/
|
||||
.npm/
|
||||
.pnpm-store/
|
||||
|
||||
# Vite cache
|
||||
.vite/
|
||||
dist/
|
||||
|
||||
# Editor
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
!.env.example
|
||||
|
||||
# Research dashboard — developed on its own branch (research-dashboard),
|
||||
# excluded from the map-only bundle. Do not track dashboard files here.
|
||||
|
||||
# Local build artifacts / deploy config — kept on disk, out of the map PR
|
||||
build-sizes-baseline.json
|
||||
|
||||
|
||||
_archive
|
||||
|
||||
# ── BUILD OUTPUT — regenerated by `bun run build`; one tree, three consumers ──
|
||||
# Not committed: it is derived. Railway builds it in CI; Capacitor copies it via
|
||||
# `cap sync`; staging serves it locally.
|
||||
|
||||
# ── Capacitor generated / machine-specific (the native projects THEMSELVES are
|
||||
# committed under capacitor/; only their build output is ignored) ──
|
||||
capacitor/android/app/src/main/assets/public/
|
||||
capacitor/android/app/src/main/assets/capacitor.config.json
|
||||
capacitor/android/app/src/main/assets/capacitor.plugins.json
|
||||
capacitor/android/build/
|
||||
capacitor/android/app/build/
|
||||
capacitor/android/.gradle/
|
||||
capacitor/android/local.properties
|
||||
capacitor/android/keystore.properties
|
||||
capacitor/ios/App/build/
|
||||
capacitor/ios/App/Pods/
|
||||
*.jks
|
||||
*.keystore
|
||||
|
||||
# ── THE SERVED WEB-ROOT — COMMITTED ───────────────────────────────────────────
|
||||
# public/ is the product: the shell, the built bundles and the pre-generated
|
||||
# posters the app fetches at runtime. It is committed whole so a clone (or a
|
||||
# static host, or the source-control service) has a working site without running
|
||||
# anything, and so CI regenerates only public/<name>/ in place rather than
|
||||
# assembling the folder from other directories.
|
||||
# The exceptions are BOTH Mapbox credentials: token.local.js (local staging, held
|
||||
# out by public/.gitignore) and api/maps/token.json, which the build writes from
|
||||
# the MAPBOX_TOKEN environment variable so the value lives in deployment settings
|
||||
# rather than in git history.
|
||||
public/api/maps/token.json
|
||||
# ★ AND the EXTENSIONLESS path — the client requests /api/maps/token (never .json), so
|
||||
# write-token.mjs emits BOTH. This line was missing when the bare file was added, which
|
||||
# would have made a live pk. token committable. Same secret, second path.
|
||||
public/api/maps/token
|
||||
|
||||
# ── stale dev-time bundle copies inside the wrapper ───────────────────────────
|
||||
# The wrapper mounts bundles from ./doxa-maps/ at the served root now; these were
|
||||
# hand-copied during bring-up and would silently go stale.
|
||||
layouts/*/profiles/
|
||||
layouts/*/js/
|
||||
|
||||
# ── POSTER GENERATOR OUTPUT ───────────────────────────────────────────────────
|
||||
# library/scripts/posters/ is source (the template + its snapshots); out/ is what
|
||||
# it renders — ~95 MB of HTML and 3000x3000 PNGs, all reproducible from source:
|
||||
# bun run posters && bun run posters:shoot && bun run posters:gallery
|
||||
|
||||
# ── EXCEPT the three inputs the build guards read ────────────────────────────
|
||||
# iso2-map, resource-join and tables-complete verify shipped data against these.
|
||||
# They are derived, but they are derived from NETWORK FETCHES, and the research
|
||||
# network policy forbids CI reaching out to those sources — so CI cannot rebuild
|
||||
# them and, without them committed, three guards fail on a clean clone and the
|
||||
# deploy dies. 2 MB of the 23 MB out/ tree; the rest stays ignored.
|
||||
# Visual-gate screenshots are OUTPUT, not fixtures. visual-gate.mjs and
|
||||
# palette-preview.mjs only ever page.screenshot() INTO this folder — the gate's own
|
||||
# rule is that it never reads a PNG back, it asserts against the live DOM. So these
|
||||
# are 11 MB of regenerable pictures of somebody's screen, and they bake build-slice
|
||||
# vocabulary into pixels where no text scrub can reach it.
|
||||
plugin-designs/*/data/visual-gate-shots/
|
||||
|
||||
library/scripts/*/out/**
|
||||
internal/*/out/**
|
||||
# EXCEPT the three inputs the build guards read. iso2-map, resource-join and
|
||||
# tables-complete verify shipped data against these. They are derived — but derived
|
||||
# from NETWORK FETCHES, and the research network policy forbids CI reaching those
|
||||
# sources, so CI cannot rebuild them. Without them committed, three guards fail on a
|
||||
# clean clone and the deploy dies. 2 MB of the 23 MB out/ tree; the rest stays out.
|
||||
# (Negations must follow the exclude: the last matching rule wins.)
|
||||
!library/scripts/research/out/arclight-languages.json
|
||||
!library/scripts/research/out/iso3-to-iso2.json
|
||||
!library/scripts/research/out/language-resources.json
|
||||
!library/scripts/research/out/ebible-translations.csv
|
||||
!library/scripts/research/out/tables/
|
||||
!library/scripts/research/out/tables/**
|
||||
|
||||
# ── INTERNAL DOCS — the split-plane rule ──────────────────────────────────────
|
||||
# Agent/internal working docs live here and are NEVER published. The repo's
|
||||
# public surface stays architecture + code + contributor docs; internal process
|
||||
# notes, lessons-learned and agent instructions stay out of it.
|
||||
internal-tracker/
|
||||
|
||||
# ── GENERATOR OUTPUT — regenerable render artifacts, never committed ──────────
|
||||
# internal/<tool>/out/ holds what the poster/research generators RENDER
|
||||
# (upg100-posters/out alone is ~619MB / 12,623 PNGs). The generators themselves
|
||||
# are source and ARE committed; their output is derived. What actually ships is
|
||||
# the exported subset in public/assets/ (see export-public.mjs).
|
||||
201
LICENSE
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2026 The Doxa Maps Starter Kit contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
386
README.md
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
# doxa-maps — one build, maps that embed everywhere
|
||||
|
||||
> **The map cruncher.** Many hand-built maps go in; one shared library, one repo and one build
|
||||
> come out — and every map fans out to five deployment targets from the same artifacts.
|
||||
>
|
||||
> ```text
|
||||
> map · map · map · map · map · map · map (7 production maps, once 7 codebases)
|
||||
> \ \ | | | / /
|
||||
> +----- plugin-designs/ ------+ one folder per plugin, free zone
|
||||
> |
|
||||
> library/ (@map) shared, parameterized, high-bar zone
|
||||
> |
|
||||
> ONE bun run build
|
||||
> |
|
||||
> doxa-maps/ (drop-anywhere tree: bundles + leaf pages + manifest.json)
|
||||
> / | \ \ \
|
||||
> iframe JS-embed mobile WordPress desktop
|
||||
> (proven) (proven) (built) (built) (built)
|
||||
> ```
|
||||
|
||||
|
||||
**A Vite bundler that turns each map into a self-contained web component.** Write a map in
|
||||
`plugin-designs/<your-map>/`, run one build, and get a folder you can drop on any host — iframe it,
|
||||
script-embed it, wrap it as a mobile app, or open every map at once as one SPA.
|
||||
|
||||
This README has three parts, in the order you need them:
|
||||
|
||||
1. **[The 5 plugin capabilities](#1-the-5-plugin-capabilities)** — what you can build, simplest to richest.
|
||||
2. **[The 5 deployment methods](#2-the-5-deployment-methods)** — where a plugin can run.
|
||||
3. **[The Plugin Studio](#3-the-plugin-studio)** — ★ where you *work*. Start here if you are new.
|
||||
|
||||
---
|
||||
|
||||
## 1. The 5 plugin capabilities — most advanced first
|
||||
|
||||
A "capability" is **how much a plugin nests** — not how hard it is to use. The tour below starts from
|
||||
the most advanced thing this repo produces (a whole app of apps) and walks down to the simplest
|
||||
(one element), because the top of the ladder is the point: every rung below it stays independently
|
||||
embeddable. Every screenshot is a real bundle from this repo's build output.
|
||||
|
||||
| # | Capability | What it is | Example bundle |
|
||||
|---|------------|------------|----------------|
|
||||
| 5 | **Nested-SPA / app shell** | Many SPAs nested into one deep-linkable app. | `doxa-maps-spa` |
|
||||
| 4 | **Nested-element SPA** | A composite that nests *other plugins* and wires them with props/events. | `big-picture` |
|
||||
| 3 | **Monolithic element** | One `root.vue` nests many views internally → one element. | `doxa-research-map` |
|
||||
| 2 | **Prop-table element** | One `root.vue` + a preset table → many maps from one plugin. | `doxa-simple-map` |
|
||||
| 1 | **Single element** | One folder → one bundle → one custom element. | `all-people-groups` |
|
||||
|
||||
> The tier is decided by the files, not by how simple a folder looks: an `*.instances.json` makes a
|
||||
> bundle **cap-2** however light it is, and a `meta.json` `type` declares tiers 3/4/5. The authoritative,
|
||||
> generated answer lives in
|
||||
> **[documentation/reference-capability-exemplars.md](./documentation/reference-capability-exemplars.md)**
|
||||
> — cite that file rather than remembering.
|
||||
|
||||
|
||||
|
||||
### Capability 5 — nested-SPA / app shell
|
||||
|
||||
Every plugin in one deep-linkable page. Two cap-5 apps ship, and the difference matters when you embed
|
||||
one: **`doxa-maps-spa` is what an end user gets; `plugin-studio` is what a developer works in.**
|
||||
|
||||
*`doxa-maps-spa` — the curated product SPA*, with tabs grouped by audience.
|
||||
|
||||

|
||||
|
||||
*`plugin-studio` — the developer studio*, grouping every built plugin by capability (5 → 1). It is
|
||||
auto-generated: the build discovers every folder in `plugin-designs/`, so a new plugin appears in the
|
||||
studio without any wiring. This is [section 3](#3-the-plugin-studio).
|
||||
|
||||

|
||||
|
||||
### Capability 4 — nested-element SPA
|
||||
|
||||
A composite that nests **lower-tier plugins** and wires them with props and events. Each inner plugin
|
||||
stays independently embeddable, and the composite is embeddable too. `plugin-designs/my-upg-100-list/`
|
||||
ships three leaves:
|
||||
|
||||
| Composite (`upg-100-mfe`) | List (`upg-100-list`) | Poster wall (`poster-wall`) |
|
||||
|---------------------------|-----------------------|-----------------------------|
|
||||
|  |  |  |
|
||||
|
||||
### Capability 3 — monolithic element
|
||||
|
||||
A whole multi-view map from one `root.vue`. The trade-off: you cannot embed just one of its tabs.
|
||||
|
||||

|
||||
|
||||
### Capability 2 — prop-table element
|
||||
|
||||
One `root.vue`, many maps. `plugin-designs/doxa-simple-map/` ships a preset prop-table
|
||||
(`simple-map.instances.json`) that renders it three ways — each a standalone embeddable page from the
|
||||
**same** code.
|
||||
|
||||
| Prayer | Engagement | Adoption |
|
||||
|--------|------------|----------|
|
||||
|  |  |  |
|
||||
|
||||
### Capability 1 — single element
|
||||
|
||||
One folder, one `.vue`, one embeddable element. `plugin-designs/all-people-groups/` shows every people
|
||||
group on one map.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 2. The 5 deployment methods
|
||||
|
||||
Ordered easiest to hardest. **Status is stated honestly** — "proven" means it has been run and seen, and
|
||||
nothing below is upgraded past what the files support.
|
||||
|
||||
| # | Method | Status | Command / install |
|
||||
|---|--------|--------|-------------------|
|
||||
| 1 | **iframe** on any site | ✅ **proven** | `bun run build`, then paste the `embed.iframe` snippet from `manifest.json` |
|
||||
| 2 | **Mobile app** (Capacitor, Android) | 🛠️ built, not shot | `bun run check:mobile` (no toolchain) · `bun run phone` needs Android SDK + JDK 17 + `adb` |
|
||||
| 3 | **JavaScript embed** (`<script src>` + SRI) | ✅ **proven** | `bun run build`, then paste the `embed.script` + `integrity` snippet |
|
||||
| 4 | **WordPress plugin** (shortcode + block) | 🛠️ built, contract-proven, not shot | `bun run check:wp-embed`, then install `deployment/wordpress/doxa-maps-embed/` |
|
||||
| 5 | **Desktop app** (Tauri) | 🛠️ built, not shot | `bun run check:tauri` (no toolchain) · `cargo tauri build` needs Rust + webview libs |
|
||||
|
||||
**What "not shot" means:** the code exists and its contract test passes, but nobody has captured it
|
||||
running on a real device or install. Each is blocked by a missing local toolchain, not by missing code —
|
||||
Android SDK for method 2, a live WordPress for method 4, and a GUI (this box is headless) for method 5.
|
||||
|
||||
Methods **1 and 3 are the two proven-live paths.** If you need a map on a site today, use one of those.
|
||||
|
||||
Both were **certified cross-origin on 2026-09-24** — the entire capability-5 app, embedded on a
|
||||
foreign host page, every inner plugin riding along (prove-the-whole = prove-the-parts):
|
||||
|
||||
| Method 1 — iframe on a host site | Method 3 — JS embed on a host site |
|
||||
|----------------------------------|-------------------------------------|
|
||||
|  |  |
|
||||
|
||||
> For a JS embed on another site the host page sets `window.MAP_TOKEN` (nested elements read it)
|
||||
> and the serving layer must send `Access-Control-Allow-Origin: *` — the tree is fetched
|
||||
> cross-origin by `manifest.json`-composed surfaces.
|
||||
|
||||
The full per-method command matrix, with every prerequisite, is in
|
||||
**[documentation/README-SECTION-3-cli-commands.md](./documentation/README-SECTION-3-cli-commands.md)**.
|
||||
|
||||
### The Mapbox token (read this before you file a bug)
|
||||
|
||||
The maps use Mapbox, which needs a `pk.` token. **The token works differently in dev than in the built
|
||||
tree**, and diagnosing one from the other is the most common way to lose an hour.
|
||||
|
||||
| Where | How it gets a token |
|
||||
|---|---|
|
||||
| **Dev server** (`bun run dev`) | Baked into the page for you — from `.env` (`VITE_MAPBOX_TOKEN`) if present, otherwise from `token` in `vite.doxa-maps-build-config.json`. |
|
||||
| **Built pages** (`bun run serve`, or hosted) | **Not baked.** Each page resolves a token at runtime: `?tk=<TOKEN>` on the URL, a token you paste into the page's own input box (kept in `localStorage`), or a token endpoint (`tokenUrl`). |
|
||||
|
||||
So on a built leaf page you typically need:
|
||||
|
||||
```
|
||||
http://localhost:4173/doxa-maps/demo-map/demo-map/index.html?tk=pk.your_token_here
|
||||
```
|
||||
|
||||
To use your own token in dev, create a `.env` — it is **gitignored** (`.gitignore` lines 21-24), so it
|
||||
never reaches the repo:
|
||||
|
||||
```bash
|
||||
printf 'VITE_MAPBOX_TOKEN=%s\n' 'pk.your_token_here' > .env
|
||||
```
|
||||
|
||||
**If a basemap is an empty grey void while the pins still draw, that is the token failing** — not a
|
||||
broken app.
|
||||
|
||||
**Why this is genuinely awkward:** the five deployment methods each handle the token differently, and a
|
||||
JAMstack embed has nowhere safe to keep a secret. The answer is not to hide the token but to make hiding
|
||||
it unnecessary: a public `pk.` token is restricted to specific URLs in the Mapbox dashboard. **MapLibre
|
||||
is being pursued to remove the per-embed token requirement entirely — that work is IN PROGRESS, not
|
||||
done** (`maplibre-gl` is a dependency and the page generator has a MapLibre path, but no plugin-design
|
||||
runs on it yet).
|
||||
|
||||
---
|
||||
|
||||
## The repo at a glance
|
||||
|
||||
```text
|
||||
doxa-maps/
|
||||
├── plugin-designs/ YOUR maps live here — one folder per plugin (the FREE zone).
|
||||
│ ├── doxa-maps-spa/ the capability-5 app (nests everything below)
|
||||
│ ├── dashboard-plus-grid/ capability-4 composite: dashboard + people-groups grid
|
||||
│ ├── my-upg-100-list/ capability-4: UPG-100 lists + poster wall + map
|
||||
│ ├── doxa-simple-map/ capability-2: one root.vue, three preset maps
|
||||
│ └── template-bundle/ copy this to start a new plugin
|
||||
├── library/ the SHARED zone (@map) — reusable, parameterized only.
|
||||
│ │ A change here reaches EVERY bundle: high bar, see
|
||||
│ │ documentation/contributing/.
|
||||
│ ├── components/ map controls, legends, search, poster, detail panels
|
||||
│ ├── composables/ useMapInstance, shadow styles, print-in-place, retry
|
||||
│ └── styles/ colors/ data/ style registry, palettes, lookup tables
|
||||
├── data/ the public datasets the maps ship with
|
||||
├── documentation/ tutorial · how-to · reference · explanation + architecture
|
||||
├── internal/ the build generator + the verification gates
|
||||
└── public/doxa-maps/ the BUILD OUTPUT — the drop-anywhere tree (bundles,
|
||||
leaf pages, manifest.json). What gets served + embedded.
|
||||
```
|
||||
|
||||
## 3. The Plugin Studio
|
||||
|
||||
★ **This is where you work — and the keyword is INTEROPERABILITY.**
|
||||
|
||||
The Plugin Studio is one place to **view all of your plugins at once** and **edit all of them in one
|
||||
place using your agent**. Every plugin appears in a single view, sorted **highest capability down to
|
||||
lowest**, so you can see the whole catalogue instead of hunting through folders.
|
||||
|
||||
That sorting is the point. Once you can see every plugin side by side, you can tell your agent **which
|
||||
ones to group together** — any number of them — and compose them into **higher-capability plugins**
|
||||
using **props, events and layouts**. Group cap-1 and cap-2 elements and you get a cap-4 nested-element
|
||||
SPA; group those and you get a cap-5 app shell. That is what makes the studio the right place to build
|
||||
map plugins, rather than a gallery you merely look at.
|
||||
|
||||
**Why this matters.** Without a working studio, a developer *sees the fruit but not the deeper
|
||||
strategy* — they get the maps, but they cannot reproduce or extend them. The studio is what turns a set
|
||||
of finished maps into something you can build on.
|
||||
|
||||
### Get it running
|
||||
|
||||
Four steps from nothing to every map in one place.
|
||||
|
||||
```bash
|
||||
# 1. Clone (the repo root IS the studio — there is no subfolder to cd into).
|
||||
# This host is PRIVATE: it will prompt for your the forge username + token.
|
||||
git clone --branch doxa-maps-plugin-studio https://the-git-host/the-source-repository.git
|
||||
cd doxa-maps
|
||||
|
||||
# 2. Install dependencies (installs 206 packages; needs Node >= 18)
|
||||
bun install --frozen-lockfile
|
||||
|
||||
# 3. Optional — your own Mapbox token for dev (see section 2)
|
||||
printf 'VITE_MAPBOX_TOKEN=%s\n' 'pk.your_token_here' > .env
|
||||
|
||||
# 4. Open the Plugin Studio
|
||||
bun run dev
|
||||
```
|
||||
|
||||
Then open **http://localhost:5173/** — that root URL *is* the Plugin Studio, with every plugin in one
|
||||
spot. (If port 5173 is busy Vite picks another one and prints it; read the line it logs.)
|
||||
|
||||
> **You do not need to build first.** The build output in `public/` is committed, so a fresh clone has
|
||||
> plugins to show the moment the dev server starts.
|
||||
|
||||
> **If step 1 fails with `remote: Unauthorized`,** the clone is not broken — `the-git-host` is a
|
||||
> private self-hosted the forge and anonymous cloning is refused. Ask for an account, then use your
|
||||
> username plus a the forge **access token** (not your password) when git prompts.
|
||||
|
||||
Two things worth knowing:
|
||||
|
||||
- **`/` is the studio; `/__gallery` is the old staging gallery**, kept but demoted to an explicit URL.
|
||||
- **Edits hot-reload.** The studio mounts the real `plugin-studio` custom element through its own
|
||||
`index.js` — the same path the built bundle takes — so what you see is the real element, not a preview.
|
||||
|
||||
### Work with your agent
|
||||
|
||||
The studio's companion is your coding agent. The loop:
|
||||
|
||||
1. Open the studio (`bun run dev`) and look at the catalogue, sorted cap-5 → cap-1.
|
||||
2. Tell your agent which plugins to **group** — e.g. *"combine the research map and the people-groups
|
||||
grid into one composite."*
|
||||
3. The agent writes a new folder in `plugin-designs/<name>/`, wiring the children with props, events and
|
||||
a layout from `library/layouts/`.
|
||||
4. Refresh the studio. The new, higher-capability plugin is there.
|
||||
|
||||
**The whole contract is: write your app inside `plugin-designs/<your-map>/`.** There is no registration
|
||||
step and no per-plugin wiring — the build discovers every folder under `plugin-designs/`. Copy
|
||||
`plugin-designs/template-bundle/` to start a new one.
|
||||
|
||||
Two shared layouts do the composing, both in `library/layouts/`:
|
||||
|
||||
- **`VerticalTabsLayout`** — one element visible at a time, lazy-mounted on first open.
|
||||
- **`StackLayout`** — the opposite: elements stacked top-to-bottom at natural height, so the page
|
||||
scrolls through them.
|
||||
|
||||
### Working fast: use the dev server, not the build
|
||||
|
||||
A full `bun run build` rebuilds every bundle and takes minutes. **You do not need it to see a
|
||||
change.** The dev server hot-reloads:
|
||||
|
||||
```bash
|
||||
bun run dev # http://localhost:5173
|
||||
bun x vite --port 5299 --strictPort # any other port, when 5173 is taken
|
||||
```
|
||||
|
||||
★ **If more than one of you is working in this repo at once, EVERY dev server must name its own
|
||||
port, and must pass `--strictPort`.** Vite's default behaviour on a busy port is to silently move to
|
||||
the next one — 5173 becomes 5174 — and five gates (`check-facet-changes-map`,
|
||||
`plugin-gallery-smoke`, `smoke-studio`, `generate-gallery`, `check-scrim-covers-viewport`) have
|
||||
`5173` written into them. A second server without `--strictPort` therefore leaves those gates
|
||||
talking to somebody else's server, or to none, and reporting a confident wrong answer with no error.
|
||||
With `--strictPort` the duplicate exits non-zero instead of drifting — verified: port taken → exit 1.
|
||||
|
||||
Reach for the full build only when you need the deployable tree, an SRI-consistent leaf page, or a
|
||||
manifest. To check one bundle's compiled output without touching anyone else's:
|
||||
|
||||
```bash
|
||||
BUNDLE=<name> bun x vite build # this bundle only; does NOT clean the tree
|
||||
```
|
||||
|
||||
### Contributing changes
|
||||
|
||||
Commit and push to your fork or branch as usual; small, frequently pushed commits are
|
||||
preferred over large local ones.
|
||||
|
||||
|
||||
### The production build
|
||||
|
||||
The dev server is for working. When you want the deployable tree:
|
||||
|
||||
```bash
|
||||
bun run build # ~4 minutes; writes public/doxa-maps/
|
||||
bun run serve # serve the BUILT tree at http://localhost:4173
|
||||
```
|
||||
|
||||
`bun run build` takes a **lock**: if another build is already running it fails fast rather than
|
||||
corrupting the shared output. Set `BUILD_LOCK_WAIT=600` to queue behind it instead.
|
||||
|
||||
### Before you MEASURE the built tree — `bun run check:settled`
|
||||
|
||||
```bash
|
||||
bun run check:settled # exit 0 = safe to measure/publish; exit 1 = do not
|
||||
```
|
||||
|
||||
**The lock protects a second WRITER. It does not protect a READER.** Every build begins with
|
||||
`bun run clean`, which `rm -rf`s `public/doxa-maps/`, so while a build runs the tree is transiently
|
||||
near-empty — and anything reading it then gets a confident, wrong answer: "that bundle is missing",
|
||||
"the dashboard tab does not exist", "461 files were deleted". Those are not hypotheticals; each has
|
||||
happened here, and one nearly produced a bug report against a correct change.
|
||||
|
||||
So run this gate before any browser check, any publish, and any claim about what the tree contains.
|
||||
It reports `builders`, `waiters`, `churn(45s)`, `dirs`, `leaves` and `quietFor`, and **grade it by
|
||||
exit code** — like every gate here, it prints teaching prose after its verdict, so `| tail -1` will
|
||||
mislead you.
|
||||
|
||||
★ **Do not substitute a `pgrep` check for this.** A process list samples an INSTANT; the lock knows
|
||||
the QUEUE. Between one queued build finishing and the next acquiring the lock there is a real window
|
||||
where zero build processes exist and the tree is nonetheless about to be wiped — and a long quiet
|
||||
period makes that window look *more* convincing, not less, because the queue is idle precisely
|
||||
because it is between runs. Measured 2026-09-23: `pgrep` reported 0 builders while the gate reported
|
||||
`builders=1 waiters=1`, and `ps` confirmed a build had started 17 seconds earlier.
|
||||
|
||||
If you are one of several agents working this repo at once, the stronger rule is simply: **do not run
|
||||
`bun run build` at all.** Edit source, and let one owner run the single authoritative build. To
|
||||
sanity-check one bundle without touching anyone else's output, use
|
||||
`BUNDLE=<name> bun x vite build` — it does not clean the whole tree.
|
||||
|
||||
---
|
||||
|
||||
## Repository layout
|
||||
|
||||
Two directories matter to a plugin author:
|
||||
|
||||
```
|
||||
plugin-designs/ ← YOUR FREE ZONE. One folder per plugin. Copy template-bundle/ to start.
|
||||
library/ ← the SHARED toolkit (layouts, components, composables, colors, stores, i18n).
|
||||
```
|
||||
|
||||
Everything else is supporting cast: `internal/` (build + gates), `public/` (committed build output),
|
||||
`deployment/` (Capacitor, WordPress, Tauri), `documentation/`.
|
||||
|
||||
**`plugin-designs/` is a free zone.** Your plugin is its own application in its own folder, building to
|
||||
its own output. Nothing you do there can break another author's map.
|
||||
|
||||
**`library/` is a HIGH BAR.** It is multi-tenant — reused by many maps and authors — so every edit is a
|
||||
breaking-change risk to everyone. Only contribute here when a component is genuinely reusable *and*
|
||||
parameterized, so other maps can use it. Never widen or casually add. Keep map-specific,
|
||||
non-parameterized code in your own plugin-design.
|
||||
|
||||
---
|
||||
|
||||
## More docs
|
||||
|
||||
| Read this | When |
|
||||
|---|---|
|
||||
| **[documentation/develop-a-plugin-and-see-it-live.md](./documentation/develop-a-plugin-and-see-it-live.md)** | ★ the golden path — zero to a plugin live, in 6 steps |
|
||||
| **[documentation/README-SECTION-3-cli-commands.md](./documentation/README-SECTION-3-cli-commands.md)** | the full per-method CLI + install matrix |
|
||||
| **[documentation/reference-capability-exemplars.md](./documentation/reference-capability-exemplars.md)** | which bundle is the capability-N example (generated) |
|
||||
| **[documentation/reference-library-index.md](./documentation/reference-library-index.md)** | the menu of reusable `library/` pieces you can import |
|
||||
| **[documentation/why.md](./documentation/why.md)** | 2 min — the problem, the idea, one diagram |
|
||||
| **[documentation/tutorial.md](./documentation/tutorial.md)** | build your first map, step by step |
|
||||
| **[documentation/how-to.md](./documentation/how-to.md)** | task recipes (embed, data, mobile) |
|
||||
| **[documentation/architecture/](./documentation/architecture/)** | the deep end — embeddability, app-wrappers, file map |
|
||||
|
||||
---
|
||||
|
||||
> **Bottom line: maps should be open source, run everywhere, and multiply.** This bundler makes each map
|
||||
> a self-contained file that embeds on your site, your partners' sites, WordPress, and mobile — from one
|
||||
> build. The Plugin Studio is where you compose them into something bigger.
|
||||
BIN
bun.lock
generated
Normal file
39
capacitor.config.json
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"appId": "life.doxa.maps",
|
||||
"appName": "Doxa Maps",
|
||||
"//webDir": [
|
||||
"webDir = ./public \u2014 THE CDN WEB-ROOT. It is a POINTER, NOT A COPY.",
|
||||
"public/ is the single SERVED SURFACE, so the bundler IS the CDN: it serves its own bundles AND",
|
||||
"non-bundle assets (brand/logos, vendored libs, fonts) that belong to no single bundle.",
|
||||
" public/doxa-maps/<bundle>/ built bundles (vite outDir app/ + copied here by the build config's paths)",
|
||||
" public/assets/brand/ logos and brand imagery",
|
||||
" public/assets/vendor/ self-hosted libs (e.g. mapbox-gl) \u2014 no CDN, per the no-CDN rule",
|
||||
" public/assets/fonts/ Bebas Neue / Poppins (both SIL OFL, so self-hostable)",
|
||||
"ONE build, THREE consumers, all reading THIS root:",
|
||||
" 1. Railway / CDN \u2014 serve public/ statically; partner sites embed from stable URLs",
|
||||
" 2. Capacitor \u2014 this webDir; `cap sync` copies public/ into deployment/capacitor/android/app/src/main/assets/public/",
|
||||
" 3. local staging \u2014 `bun run serve` (public/ on :4173)",
|
||||
"NOTE the drop-portability gate still governs what goes INSIDE a bundle: bundle-internal refs must stay",
|
||||
"RELATIVE. public/ is the HOST root, which is a different layer \u2014 putting shared assets here does not",
|
||||
"make a bundle root-relative, so the gate stays green.",
|
||||
"\u26a0\ufe0f SOFT FAILURE: a wrong webDir yields an EMPTY assets/public and a BLANK WHITE SCREEN at launch, not an",
|
||||
"error. After every sync, verify deployment/capacitor/android/app/src/main/assets/public/index.html exists (`bun run cap:verify`)."
|
||||
],
|
||||
"webDir": "public",
|
||||
"server": {
|
||||
"//": [
|
||||
"Capacitor defaults are deliberately kept: iosScheme 'capacitor', androidScheme 'https', hostname",
|
||||
"'localhost'. Do NOT set a custom scheme \u2014 Capacitor docs warn that as of WebView 117 custom schemes",
|
||||
"cannot change the URL path and can break routing. Do NOT set server.url either; that is documented as",
|
||||
"live-reload/dev only, not production.",
|
||||
"CONSEQUENCE FOR US: the app origin is https://localhost, so the doxa.life token endpoint (tokenUrl) must",
|
||||
"send CORS headers permitting that origin. This is the single most likely runtime surprise, and the fix is",
|
||||
"a response header on doxa.life \u2014 not a change here."
|
||||
],
|
||||
"androidScheme": "https"
|
||||
},
|
||||
"android": {
|
||||
"//": "Native project lives in ./capacitor/android and is COMMITTED \u2014 `cap add` scaffolds it ONCE, then it is hand-edited source (manifest, icons, versionCode). It sits under deployment/capacitor/ rather than app/ because app/ is the BUNDLE OUTPUT tree: this repo emits several kinds of product, and Capacitor is one facet of them, not the whole. Only app/src/main/assets/public/ is generated and gitignored. An iOS project would join it at deployment/capacitor/ios (ios.path), scaffolded on a Mac.",
|
||||
"path": "deployment/capacitor/android"
|
||||
}
|
||||
}
|
||||
16
data/README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# data/ — the bundler's source-of-truth data
|
||||
|
||||
**The law: data lives here; `public/` is generated.** Every folder in `data/` is copied into the
|
||||
served web-root by the build (`internal/generate-tree.mjs`), exactly like the per-profile data in
|
||||
`plugin-designs/*/data/`. You should be able to `rm -rf public/` and get it all back with `bun run build`.
|
||||
|
||||
| Folder | Served at | What it is |
|
||||
|---|---|---|
|
||||
| `people-groups/` | `/assets/people-groups/` | People-group datasets (CSV/JSON) the maps read at runtime |
|
||||
| `vendor/` | `/assets/vendor/` | Third-party runtime assets (e.g. table libraries) |
|
||||
| `posters/` | `/assets/posters/` | Rendered poster webp set (heavy pipeline output; poster walls fetch these) |
|
||||
| `tables/` | `/assets/tables/` | The MERGED served table set (its index.json is the merge; per-profile `plugin-designs/*/data/tables` are build-time sources) |
|
||||
| `external-bundles/` | not served | Prebuilt map IIFEs vendored from sibling projects (not built here); only the optional `layouts/` shell mounted them, so the build no longer copies them into `public/` |
|
||||
|
||||
Don't edit anything under `public/` by hand — change it here (or in `plugin-designs/*/data/`,
|
||||
`layouts/*/assets/`) and rebuild.
|
||||
337
data/external-bundles/research-dashboard-map.js
Normal file
548
data/external-bundles/upg-neighbor.js
Normal file
1
data/people-groups/people-groups-slim.json
Normal file
12380
data/people-groups/people_groups.csv
Normal file
BIN
data/posters/andean-caribbean.webp
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
data/posters/asia-china-tibet-autonomous-region.webp
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
data/posters/asia-china-yunnan-province.webp
Normal file
|
After Width: | Height: | Size: 235 KiB |
BIN
data/posters/asia-india-andhra-pradesh.webp
Normal file
|
After Width: | Height: | Size: 230 KiB |
BIN
data/posters/asia-india-gujarat.webp
Normal file
|
After Width: | Height: | Size: 216 KiB |
BIN
data/posters/asia-india-karnataka.webp
Normal file
|
After Width: | Height: | Size: 220 KiB |
BIN
data/posters/asia-india-kerala.webp
Normal file
|
After Width: | Height: | Size: 232 KiB |
BIN
data/posters/asia-india-madhya-pradesh.webp
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
data/posters/asia-india-odisha.webp
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
data/posters/asia-india-rajasthan.webp
Normal file
|
After Width: | Height: | Size: 240 KiB |
BIN
data/posters/asia-india-tamil-nadu.webp
Normal file
|
After Width: | Height: | Size: 219 KiB |
BIN
data/posters/asia-india-uttarakhand.webp
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
data/posters/asia-india-west-bengal.webp
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
data/posters/brazil.webp
Normal file
|
After Width: | Height: | Size: 238 KiB |
BIN
data/posters/central-africa.webp
Normal file
|
After Width: | Height: | Size: 197 KiB |
BIN
data/posters/city-ago--8.8484-13.2535.webp
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
data/posters/city-bfa-9.7792--4.2879.webp
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
data/posters/city-brn-4.9234-114.9209.webp
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
data/posters/city-btn-27.75-91.2637.webp
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
data/posters/city-cod-3.5049-24.4533.webp
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
data/posters/city-idn--3.7191-127.9542.webp
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
data/posters/city-ind-10.1396-77.7883.webp
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
data/posters/city-ind-10.3796-78.8202.webp
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
data/posters/city-ind-10.5285-76.2146.webp
Normal file
|
After Width: | Height: | Size: 215 KiB |
BIN
data/posters/city-ind-10.7853-78.7051.webp
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
data/posters/city-ind-10.7855-76.6516.webp
Normal file
|
After Width: | Height: | Size: 168 KiB |
BIN
data/posters/city-ind-10.787-79.1378.webp
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
data/posters/city-ind-10.8469-76.2633.webp
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
data/posters/city-ind-11.0049-76.9626.webp
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
data/posters/city-ind-11.0546-78.6369.webp
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
data/posters/city-ind-11.06-76.0816.webp
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
data/posters/city-ind-11.0991-77.2807.webp
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
data/posters/city-ind-11.1271-78.6565.webp
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
data/posters/city-ind-11.253-76.2299.webp
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
data/posters/city-ind-11.3548-77.711.webp
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
data/posters/city-ind-11.4517-76.7145.webp
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
data/posters/city-ind-11.6234-92.7265.webp
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
data/posters/city-ind-11.6765-76.1741.webp
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
data/posters/city-ind-11.8745-75.3695.webp
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
data/posters/city-ind-11.9182-79.8085.webp
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
data/posters/city-ind-11.967-75.3663.webp
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
data/posters/city-ind-12.2973-75.7684.webp
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
data/posters/city-ind-12.3022-76.6423.webp
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
data/posters/city-ind-12.427-75.742.webp
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
data/posters/city-ind-12.4538-75.1701.webp
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
data/posters/city-ind-12.5102-74.9852.webp
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
data/posters/city-ind-12.5446-80.0193.webp
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
data/posters/city-ind-12.6867-79.9614.webp
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
data/posters/city-ind-12.8403-75.2483.webp
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
data/posters/city-ind-12.9125-79.3429.webp
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
data/posters/city-ind-12.964-74.837.webp
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
data/posters/city-ind-12.9789-77.5857.webp
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
data/posters/city-ind-13.0505-75.1773.webp
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
data/posters/city-ind-13.2174-79.101.webp
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
data/posters/city-ind-13.2466-80.2533.webp
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
data/posters/city-ind-13.3138-75.7731.webp
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
data/posters/city-ind-13.3389-74.7451.webp
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
data/posters/city-ind-13.4672-79.0137.webp
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
data/posters/city-ind-13.6192-79.4197.webp
Normal file
|
After Width: | Height: | Size: 139 KiB |
BIN
data/posters/city-ind-14.4428-79.9882.webp
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
data/posters/city-ind-14.494-78.7992.webp
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
data/posters/city-ind-14.7445-74.7282.webp
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
data/posters/city-ind-14.7811-74.6161.webp
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
data/posters/city-ind-14.8066-74.1305.webp
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
data/posters/city-ind-15.1518-75.4446.webp
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
data/posters/city-ind-15.2213-74.0714.webp
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
data/posters/city-ind-15.4573-75.0086.webp
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
data/posters/city-ind-15.4895-79.6006.webp
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
data/posters/city-ind-15.5127-77.9554.webp
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
data/posters/city-ind-15.8971-79.7392.webp
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
data/posters/city-ind-16.1786-81.1347.webp
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
data/posters/city-ind-16.3172-80.0518.webp
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
data/posters/city-ind-16.4355-80.0228.webp
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
data/posters/city-ind-16.5066-80.6501.webp
Normal file
|
After Width: | Height: | Size: 195 KiB |
BIN
data/posters/city-ind-16.6981-74.2441.webp
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
data/posters/city-ind-16.7107-81.0956.webp
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
data/posters/city-ind-16.8296-75.7135.webp
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
data/posters/city-ind-17.0598-74.68.webp
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
data/posters/city-ind-17.2551-78.4478.webp
Normal file
|
After Width: | Height: | Size: 140 KiB |
BIN
data/posters/city-ind-17.3189-82.4772.webp
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
data/posters/city-ind-17.4284-78.4492.webp
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
data/posters/city-ind-17.6602-75.908.webp
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
data/posters/city-ind-17.6921-83.2225.webp
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
data/posters/city-ind-17.9875-82.6791.webp
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
data/posters/city-ind-18.1063-83.3951.webp
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
data/posters/city-ind-18.1085-78.9859.webp
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
data/posters/city-ind-18.2978-83.9127.webp
Normal file
|
After Width: | Height: | Size: 116 KiB |