Doxa Maps — the map bundler, 7 production plugins and the Experimental shelf
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
|
||||
136
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
# (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.
|
||||
#
|
||||
# ⚠ THIS BLOCK USED TO SAY "what actually ships is the exported subset in
|
||||
# public/assets/ (see export-public.mjs)". BOTH HALVES OF THAT WERE STALE, and
|
||||
# the sentence is why 80.7 MB sat committed twice:
|
||||
# - export-public.mjs does NOT write public/assets/. It writes a SIBLING OF THE
|
||||
# REPO (../../../../upg-100-posters, or $DOXA_PUBLIC), and says so in its own
|
||||
# header — explicitly "NOT inside public/, because capacitor packages public/
|
||||
# whole and these are 52 MB that must not ship in the APK".
|
||||
# - public/assets/<name> is now a GENERATED MIRROR of the tracked data/<name>,
|
||||
# rewritten by generate-tree.mjs on every `bun run tree`. It is derived, not
|
||||
# exported, so it is ignored in public/.gitignore — which carries the
|
||||
# measurements and the one exception (previews/, which has no data/ source
|
||||
# and must stay tracked).
|
||||
# The tracked source for shipped assets is data/<name>.
|
||||
|
||||
# Private datasets never live in this repo (see DOXA_PRIVATE_DIR in
|
||||
# library/scripts/research/build-tabulator-tables.mjs). Guard against re-creation.
|
||||
data-private/
|
||||
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.
|
||||
236
README.md
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
# dx-maps — one build, maps that embed everywhere
|
||||
|
||||
**Write a map once in `plugin-designs/<your-map>/`, run one build, and drop it on any site** —
|
||||
iframe, script embed, mobile app — or open every map at once as one app. Five plugin
|
||||
capabilities, five deployment methods, one shared library, one build.
|
||||
|
||||
| What dx-maps set out to do | Proof |
|
||||
|---|---|
|
||||
| **One build → one folder** you can drop on any host | `bun run check:drop` |
|
||||
| **Every map embeddable** from a copy-paste snippet | [deployment methods](#the-5-deployment-methods) · `bun run check:embed-targets` |
|
||||
| **Every map interoperable** through props and events | `bun run verify:interop` |
|
||||
| **One app nests every map** — and each stays embeddable on its own | [capability 5](#capability-5--app-shell-the-research-gallery) · `bun run check:composite-reg` |
|
||||
| **5 capabilities × 5 deployment methods** | `bun run verify:5-caps` |
|
||||
| **Shared library, private plugins** — reuse without breaking each other | `bun run check:library-index` |
|
||||
| **One agent per plugin, one shepherd, one green `main`** | [agent swarm](#build-it-with-an-agent-swarm) |
|
||||
|
||||
---
|
||||
|
||||
## The 5 plugin capabilities
|
||||
|
||||
A capability is **how much a plugin nests**, from one element (1) to an app of apps (5). Every
|
||||
screenshot is a real bundle from this repo's build.
|
||||
|
||||
### Capability 5 — app shell: the Research Gallery
|
||||
|
||||
One plugin, one element (`<doxa-maps-spa>`), and every tab inside it is a real plugin from a lower
|
||||
tier that you can still embed on its own. `plugin-designs/doxa-maps-spa/`
|
||||
|
||||

|
||||
|
||||
<details>
|
||||
<summary><b>What the Research Gallery is made of — seven production maps, an Experimental shelf, all five capabilities in one plugin</b></summary>
|
||||
|
||||
```text
|
||||
Research Gallery <doxa-maps-spa> capability 5
|
||||
├─ Dashboards
|
||||
│ ├─ Big Picture dashboard-plus-grid capability 4
|
||||
│ │ ├─ research dashboard research-dashboard capability 3
|
||||
│ │ └─ people-groups grid people-groups-grid capability 2
|
||||
│ ├─ Simple Research research-map-plus-grid capability 4
|
||||
│ │ ├─ research map doxa-research-map capability 3
|
||||
│ │ └─ people-groups grid people-groups-grid capability 2
|
||||
│ └─ Regions regions-mfe capability 4
|
||||
│ ├─ regions list regions-list capability 1
|
||||
│ └─ region dashboards region-dashboards capability 1
|
||||
├─ Prayer Mobilization
|
||||
│ ├─ UPG-100 List upg-100-mfe capability 4
|
||||
│ │ ├─ list upg-100-list capability 1
|
||||
│ │ └─ poster wall poster-wall capability 1
|
||||
│ └─ Prayer Progress doxa-simple-map capability 2
|
||||
├─ Gospel Research
|
||||
│ ├─ Cities with Internet connectivity-map capability 1
|
||||
│ └─ Gospel Resources resources-map capability 1
|
||||
└─ Experimental (a folded shelf, filled automatically from manifest.json)
|
||||
├─ prayer walk planner prayer-walk-planner capability 1
|
||||
├─ UPG neighbor upg-neighbor capability 3
|
||||
├─ all people groups all-people-groups capability 1
|
||||
├─ country posters country-posters capability 4
|
||||
└─ vision card doxa-vision-card capability 2
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Capability 4 — composite: plugins wired together
|
||||
|
||||
Nests lower-tier plugins and wires them with props and events. `plugin-designs/my-upg-100-list/`
|
||||
|
||||

|
||||
|
||||
| List (cap 1, embeddable alone) | Poster wall (cap 1, embeddable alone) |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|
||||
### Capability 3 — multi-view: many views, one element
|
||||
|
||||
`plugin-designs/doxa-research-map/`
|
||||
|
||||

|
||||
|
||||
### Capability 2 — presets: one plugin, many maps
|
||||
|
||||
One `root.vue` plus a preset table. `plugin-designs/doxa-simple-map/`
|
||||
|
||||
| Prayer | Engagement | Adoption |
|
||||
|--------|------------|----------|
|
||||
|  |  |  |
|
||||
|
||||
### Capability 1 — single element
|
||||
|
||||
One folder, one `.vue`, one element. `plugin-designs/all-people-groups/`
|
||||
|
||||

|
||||
|
||||
> Which bundle sits at which tier is generated, not remembered:
|
||||
> [documentation/reference-capability-exemplars.md](./documentation/reference-capability-exemplars.md).
|
||||
|
||||
---
|
||||
|
||||
## The 5 deployment methods
|
||||
|
||||
### 1. iframe — the prayer map on any site ✅ production
|
||||
|
||||
One `<iframe>` tag, no build step. Each plugin's exact snippet is `embed.iframe` in `manifest.json`:
|
||||
|
||||
```html
|
||||
<iframe src="https://YOUR_HOST/doxa-maps/doxa-simple-map/doxa-simple-map/prayer/index.html?utm_source=YOUR_SOURCE"
|
||||
width="100%" height="600" style="border:none;border-radius:12px;" allowfullscreen></iframe>
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 2. Mobile app — UPG-100 on a phone ✅ built
|
||||
|
||||
The UPG-100 prayer lists and posters, shipped on their own as a Capacitor app: one poster per row,
|
||||
print options that wrap to fit. `bun run check:mobile` · `bun run phone` (needs Android SDK + JDK 17)
|
||||
|
||||
<p align="center"><img src="documentation/readme-images/deploy2-mobile-upg100.png" alt="Method 2 — the UPG-100 list at phone size" width="320"></p>
|
||||
|
||||
### 3. JavaScript embed — the Research Gallery on dx-life ✅ production
|
||||
|
||||
The whole capability-5 app on the dx-life research page, from one `<script src>` and one element —
|
||||
replacing the separate research map, list and regions dashboards the page used to carry. The exact
|
||||
snippet is `embed.script` in `manifest.json`; copy its `integrity` hash from there, as it changes with
|
||||
every build:
|
||||
|
||||
```html
|
||||
<script>window.MAP_APP_API_URL="https://pray.doxa.life";</script>
|
||||
<script src="https://YOUR_HOST/doxa-maps/doxa-maps-spa/doxa-maps-spa.js"
|
||||
integrity="sha384-…" crossorigin="anonymous"></script>
|
||||
<doxa-maps-spa profile-config='{"profile":"doxa-maps-spa","tk":"YOUR_MAPBOX_TOKEN","utmSource":"YOUR_SOURCE","assetsBase":"https://YOUR_HOST/doxa-maps/assets"}'></doxa-maps-spa>
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 4. WordPress / Disciple Tools plugin — 🧪 proof of concept
|
||||
|
||||
A shortcode + block plugin in `deployment/wordpress/`; its contract test passes
|
||||
(`bun run check:wp-embed`). Proven, not production-ready.
|
||||
|
||||

|
||||
|
||||
### 5. Desktop app (Tauri) — 🧪 proof of concept
|
||||
|
||||
A desktop binary and `.deb` build from `deployment/src-tauri/` (`bun run check:tauri`). Proven,
|
||||
not production-ready.
|
||||
|
||||

|
||||
|
||||
<sub>WordPress and Tauri marks from [Simple Icons](https://simpleicons.org) (CC0); the trademarks belong to their owners.</sub>
|
||||
|
||||
> **Mapbox token:** the dev server bakes one in; built pages take `?tk=pk.…`, a pasted token, or a
|
||||
> token endpoint. Or skip Mapbox entirely: `provider: "maplibre"` on any instance renders on MapLibre
|
||||
> with no key. Every command and prerequisite:
|
||||
> [documentation/README-SECTION-3-cli-commands.md](./documentation/README-SECTION-3-cli-commands.md).
|
||||
|
||||
---
|
||||
|
||||
## Build it with an agent swarm
|
||||
|
||||
Every plugin has **one agent** responsible for building it, working in its own git worktree. The
|
||||
plugins live together in the **Plugin Studio** — one repo, one shared library — and **one shepherd**
|
||||
makes sure every agent is doing its job well. Changes land on `main` through a **merge queue** (the
|
||||
model behind GitHub's merge queue and GitLab's merge trains): one at a time, rebased and gated.
|
||||
|
||||

|
||||
|
||||
```bash
|
||||
# one worktree + one agent per plugin
|
||||
git worktree add -b regions/work ../dx-maps-regions main
|
||||
git worktree add -b upg100/work ../dx-maps-upg100 main
|
||||
|
||||
# one dev server per agent, each on its own port
|
||||
bun x vite --port 5301 --strictPort
|
||||
|
||||
# land through the queue: one at a time, rebased, gated
|
||||
flock /tmp/dx-maps-main.lock sh -c '
|
||||
git fetch origin && git rebase origin/main &&
|
||||
bun run gates:pre && git push origin HEAD:main'
|
||||
```
|
||||
|
||||
One agent owns the full build (it wipes the shared output first); everyone else checks their own
|
||||
bundle with `BUNDLE=<name> bun x vite build`. How to contribute, and the bar for shared code:
|
||||
[documentation/CONTRIBUTING.md](./documentation/CONTRIBUTING.md).
|
||||
Diagram source: [`delegation-model.svg`](./documentation/readme-images/src/delegation-model.svg).
|
||||
|
||||
---
|
||||
|
||||
## The Plugin Studio — ★ where you work
|
||||
|
||||
Every plugin in one place, sorted by capability. Pick any plugin to run it live, see what it is
|
||||
composed of, and copy its embed code. Tell your agent which plugins to **group**, and it composes
|
||||
them into a higher-capability plugin with props, events and a layout — that is how the Research
|
||||
Gallery was built. *(The studio is being redesigned; this screenshot tracks it.)*
|
||||
|
||||

|
||||
|
||||
### Get it running
|
||||
|
||||
You need **git**, **[Bun](https://bun.sh)** and **Node ≥ 18**.
|
||||
|
||||
```bash
|
||||
git clone https://git.nuxtbase.app/doxa-open/doxa-maps.git
|
||||
cd doxa-maps
|
||||
bun install --frozen-lockfile
|
||||
bun run dev # → http://localhost:5173/ is the Plugin Studio
|
||||
```
|
||||
|
||||
No build needed first — the built tree is committed. To start a plugin, copy
|
||||
`plugin-designs/template-bundle/` to `plugin-designs/<your-map>/`; the studio finds it automatically.
|
||||
|
||||
| Command | What it does |
|
||||
|---|---|
|
||||
| `bun run dev` | The Plugin Studio, hot-reloading, at http://localhost:5173 |
|
||||
| `BUNDLE=<name> bun x vite build` | Build one bundle only |
|
||||
| `BUILD_ALLOW=1 bun run build` | The full deployable tree in `public/doxa-maps/` (~4 min; refuses without the flag, to protect a shared tree) |
|
||||
| `bun run serve` | Serve the built tree at http://localhost:4173 |
|
||||
| `bun run check:settled` | Exit 0 = the built tree is safe to measure right now |
|
||||
| `bun run gates:pre` · `bun run gates:post` | The verification gates |
|
||||
| `bun run shots` | Regenerate these screenshots (`ONLY=<name>` for one) |
|
||||
|
||||
---
|
||||
|
||||
## Repository layout
|
||||
|
||||
```text
|
||||
plugin-designs/ YOUR maps — one folder per plugin, a free zone
|
||||
library/ the SHARED toolkit (layouts, components, composables) — a high bar
|
||||
public/doxa-maps/ the build output: the drop-anywhere tree + manifest.json
|
||||
deployment/ Capacitor · WordPress · Tauri
|
||||
internal/ the build generator and the gates
|
||||
documentation/ tutorial · how-to · reference · architecture — start at documentation/README.md
|
||||
```
|
||||
|
||||
> **Maps should be open source, run everywhere, and multiply.** One build makes each map a
|
||||
> self-contained file for your site, your partners' sites and a phone. 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
355
data/posters/andean-caribbean.html
Normal file
BIN
data/posters/andean-caribbean.webp
Normal file
|
After Width: | Height: | Size: 217 KiB |
355
data/posters/asia-china-tibet-autonomous-region.html
Normal file
BIN
data/posters/asia-china-tibet-autonomous-region.webp
Normal file
|
After Width: | Height: | Size: 184 KiB |
355
data/posters/asia-china-yunnan-province.html
Normal file
BIN
data/posters/asia-china-yunnan-province.webp
Normal file
|
After Width: | Height: | Size: 235 KiB |
355
data/posters/asia-india-andhra-pradesh.html
Normal file
BIN
data/posters/asia-india-andhra-pradesh.webp
Normal file
|
After Width: | Height: | Size: 230 KiB |
355
data/posters/asia-india-gujarat.html
Normal file
BIN
data/posters/asia-india-gujarat.webp
Normal file
|
After Width: | Height: | Size: 216 KiB |
355
data/posters/asia-india-karnataka.html
Normal file
BIN
data/posters/asia-india-karnataka.webp
Normal file
|
After Width: | Height: | Size: 220 KiB |
355
data/posters/asia-india-kerala.html
Normal file
BIN
data/posters/asia-india-kerala.webp
Normal file
|
After Width: | Height: | Size: 232 KiB |
355
data/posters/asia-india-madhya-pradesh.html
Normal file
BIN
data/posters/asia-india-madhya-pradesh.webp
Normal file
|
After Width: | Height: | Size: 219 KiB |
355
data/posters/asia-india-odisha.html
Normal file
BIN
data/posters/asia-india-odisha.webp
Normal file
|
After Width: | Height: | Size: 219 KiB |
355
data/posters/asia-india-rajasthan.html
Normal file
BIN
data/posters/asia-india-rajasthan.webp
Normal file
|
After Width: | Height: | Size: 240 KiB |
355
data/posters/asia-india-tamil-nadu.html
Normal file
BIN
data/posters/asia-india-tamil-nadu.webp
Normal file
|
After Width: | Height: | Size: 219 KiB |
355
data/posters/asia-india-uttarakhand.html
Normal file
BIN
data/posters/asia-india-uttarakhand.webp
Normal file
|
After Width: | Height: | Size: 223 KiB |
355
data/posters/asia-india-west-bengal.html
Normal file
BIN
data/posters/asia-india-west-bengal.webp
Normal file
|
After Width: | Height: | Size: 224 KiB |
355
data/posters/brazil.html
Normal file
BIN
data/posters/brazil.webp
Normal file
|
After Width: | Height: | Size: 238 KiB |
355
data/posters/central-africa.html
Normal file
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 |