From 3c17245c73310e80a832210a1d097589ca53328d Mon Sep 17 00:00:00 2001 From: doxa-maps-88655c70 <88627970+doxa-maps-88655c70@users.noreply.github.com> Date: Thu, 24 Sep 2026 14:33:29 +0000 Subject: [PATCH 1/7] packets: give CI something to check, instead of a sweep that always SKIPs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check:packets-all is in gates:post. CI runs it on every build. It has SKIPped every single time, because library/scripts/posters/out/ is gitignored — both the records cache and every generated packet — so a clean checkout has none. Every packet assertion in this tree has therefore never once been evaluated there: the 12 prayer points, the wheel's 12 labels, page 1's geography paths, the print layer, the build stamp. Several ticks of work accumulating on a gate that had only ever graded files in my own working tree. A SKIP that is always taken is indistinguishable from an unwired gate — and the wave-membership census cannot tell them apart, because membership measures invocation, not evaluation. That census is how check:packets-all was created in the first place, which makes this the same class recurring one level up. I raised this at the end of the last tick and deferred it on the premise that closing it "adds a live-API call to every build". The premise was wrong. packet.mjs already had an OFFLINE mode, and a fixture needs no network at all. The fixture is the smallest zone — Tibet, 43 slugs, 20KB — with image_url stripped so CI can never fetch 43 photos from someone else's CDN. It is DERIVED, not hand-maintained: membership comes from the committed clusters.json, so check:packet-fixture regenerates and content-compares it. Re-adding an image_url fails; dropping a record fails naming the slug. A fixture packet stamps itself "fixture", and "fixture nomap" in CI, which has no poster sources either. `fixture` implies nophotos in the gate — without that it reported "every source record carries an image_url", a true sentence about real records and a false one about this packet. A real bug in my own change, caught only by running the script through its REAL invocation path: packet.mjs fails closed on a missing VITE_API_BASE_URL BEFORE loadRecords() ever looks at PACKET_RECORDS, so `bun run packet:ci` exited 1 on a tree that had everything it needed. Every hand-test had passed because I was supplying a dummy host. The guard now exempts fixture builds and still fails closed otherwise. From a genuinely clean state — the whole out/ directory moved away — the sweep now reports "1 packet(s) checked, 1 passed". i18n verified through that same path: a partial block (1 string, 5/12 points, 3/12 rhythms) renders 12 points, 12/12 wheel labels, wheel 3 translated and 9 English, 0 blanks. check:packet-fixture joins gates:post (34 -> 35), README quote re-synced in the same commit. Wave 35/35, packets-all 11/11 here and 2/2 in the studio. --- .forgejo/workflows/build.yml | 15 +++ .../README-SECTION-3-cli-commands.md | 2 +- internal/check-packet-render.mjs | 4 +- internal/generate-packet-fixture.mjs | 112 ++++++++++++++++++ .../posters/fixtures/records-tibet.json | 1 + library/scripts/posters/packet.mjs | 33 +++++- package.json | 5 +- 7 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 internal/generate-packet-fixture.mjs create mode 100644 library/scripts/posters/fixtures/records-tibet.json diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml index a3643970b..727b28260 100644 --- a/.forgejo/workflows/build.yml +++ b/.forgejo/workflows/build.yml @@ -83,6 +83,21 @@ jobs: - name: Install dependencies (locked) run: bun install --frozen-lockfile + # ★ BUILD ONE PACKET BEFORE THE GATES, so check:packets-all has something to check. + # library/scripts/posters/out/ is gitignored — both the records cache and every + # generated packet — so a clean CI checkout had NONE, that sweep SKIPped on every + # single build, and every packet assertion in this tree (the 12 prayer points, the + # wheel's 12 labels, page 1's geography, the print layer) was never once evaluated + # here. A SKIP that is always taken is indistinguishable from an unwired gate. + # It builds from a 20KB COMMITTED fixture: no API, no network, no photo fetch. The + # packet stamps itself "fixture nomap" (CI has no poster sources either), which the + # gate reads and accepts as declared — while still asserting everything that does + # not depend on live data. It runs BEFORE build:unlocked because gates:post is + # inside that script. + - name: Build one packet from the committed fixture + run: bun run packet:ci + + # THE AUTHORITATIVE BUILD. build:unlocked is the real chain (clean -> token # -> per-bundle vite -> tree -> drop/parse checks -> verify -> gallery). We # call :unlocked, NOT `bun run build`, because CI IS the single builder now — diff --git a/documentation/README-SECTION-3-cli-commands.md b/documentation/README-SECTION-3-cli-commands.md index d144255e3..958e61f31 100644 --- a/documentation/README-SECTION-3-cli-commands.md +++ b/documentation/README-SECTION-3-cli-commands.md @@ -49,7 +49,7 @@ The scripts these commands are grounded in (from this branch's `package.json`): "build": "bash internal/build-lock.sh", "build:unlocked": "bun run gates:pre && bun run library-index && bun run check:library-index && bun run clean && bun run token && bun run build:bundles && bun run tree && bun run gates:post && bun run gallery", "gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:wp-embed check:doc-scripts", -"gates:post": "node internal/run-parallel.mjs --label=post -- check:drop check:parse verify check:sri check:public-hygiene check:label-joins check:facet-cascade check:facet-one-field check:heartbeat check:kpi-unit check:composite-reg check:descriptions check:no-abs-paths check:no-codename check:dep-names check:composite-srcs check:embed-targets check:nested-token check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars", +"gates:post": "node internal/run-parallel.mjs --label=post -- check:drop check:parse verify check:sri check:public-hygiene check:label-joins check:facet-cascade check:facet-one-field check:heartbeat check:kpi-unit check:composite-reg check:descriptions check:no-abs-paths check:no-codename check:dep-names check:composite-srcs check:embed-targets check:nested-token check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars check:packet-fixture", "build:bundles": "node internal/run-parallel.mjs --bundles", // the 22 vite builds, 4 at a time "preview": "bun x vite preview", "serve": "node internal/serve-strict.mjs", // 404s a directory, like production diff --git a/internal/check-packet-render.mjs b/internal/check-packet-render.mjs index 1c450e7b2..f2139d203 100644 --- a/internal/check-packet-render.mjs +++ b/internal/check-packet-render.mjs @@ -346,7 +346,9 @@ if (r.cards && r.imgs + r.nophoto !== r.cards) { } // The packet's own stamp is authoritative; the env var stays as an override for // artefacts generated before data-packet-build existed. -const expectPhotos = process.env.PACKET_EXPECT_PHOTOS !== '0' && !/\bnophotos\b/.test(build) +// `fixture` implies no photos: a fixture packet is built from a committed records subset +// with image_url stripped precisely so CI never fetches ~43 images from someone else's CDN. +const expectPhotos = process.env.PACKET_EXPECT_PHOTOS !== '0' && !/\b(nophotos|fixture)\b/.test(build) if (r.cards && expectPhotos && r.imgs === 0) { fails.push(`${r.cards} people cards and NOT ONE photo — the packet spec is "20 per page ` + 'WITH IMAGES", and every source record carries an image_url, so this is a skipped or ' diff --git a/internal/generate-packet-fixture.mjs b/internal/generate-packet-fixture.mjs new file mode 100644 index 000000000..b29a0fd1c --- /dev/null +++ b/internal/generate-packet-fixture.mjs @@ -0,0 +1,112 @@ +#!/usr/bin/env node +// generate-packet-fixture — a small COMMITTED records subset, so CI can build a packet. +// +// ★ WHY THIS EXISTS. library/scripts/posters/out/ is gitignored — both the records cache +// and every generated packet — so on a clean checkout check:packets-all finds nothing and +// SKIPs. MEASURED 2026-09-24: CI runs that sweep on every build through gates:post, and it +// has SKIPped every time. Every packet assertion in this tree — the 12 prayer points, the +// wheel's 12 labels, page 1's geography paths, the print layer, the build stamp — has never +// once been evaluated in CI. A SKIP that is always taken is indistinguishable from an +// unwired gate, and the wave-membership census cannot tell them apart because membership +// measures INVOCATION, not EVALUATION. +// +// ★ WHY A FIXTURE RATHER THAN A LIVE FETCH. Building a real packet needs 2,107 records +// (887KB, live data that goes stale) and, with photos, ~95 CDN requests. Neither belongs in +// every CI run. This carries ONE zone's records — the smallest, Tibet at 43 slugs, 20KB — +// with image_url stripped so it can never reach for a photo. +// +// ★ AND IT IS DERIVED, NOT HAND-MAINTAINED. Membership comes from clusters.json, which IS +// committed, so this can be regenerated and content-compared (check:packet-fixture) exactly +// like the capability-exemplar table. A fixture nobody can verify is a fixture that rots. +// +// ⚠ IT IS NOT A SUBSTITUTE FOR REAL PACKETS. PACKET_RECORDS is opt-in and never the default: +// a fixture packet proves the RENDERER and the GATE work end to end, not that today's live +// data is sound. The 11-locale sweep against real records stays the real verification. +// +// Usage: node internal/generate-packet-fixture.mjs [--check] +// (reads the live records cache; run after a normal `node library/scripts/posters/packet.mjs`) +import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs' +import { resolve, dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' + +const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..') +const CACHE = join(ROOT, 'library/scripts/posters/out/_records.json') +const CLUSTERS = join(ROOT, 'plugin-designs/my-upg-100-list/data/clusters.json') +const OUT_DIR = join(ROOT, 'library/scripts/posters/fixtures') +const OUT = join(OUT_DIR, 'records-tibet.json') +// The smallest zone by slug count, so the fixture stays small. Its membership lives in +// clusters.json; if that zone is ever renamed this script fails loudly rather than +// silently emitting an empty fixture. +const ZONE = 'asia-china-tibet-autonomous-region' + +const CHECK = process.argv.includes('--check') + +if (!existsSync(CLUSTERS)) { + console.log('PACKET-FIXTURE: SKIP — no clusters.json.') + process.exit(0) +} +const clusters = JSON.parse(readFileSync(CLUSTERS, 'utf8')) +const zones = [...(clusters.lists || []), ...(clusters.asia_lists || []), ...(clusters.uncovered_lists || [])] +const zone = zones.find((z) => z && z.id === ZONE) +if (!zone || !zone.selector || zone.selector.type !== 'pg_slugs') { + console.error(`PACKET-FIXTURE: FAIL — ${ZONE} is not a pg_slugs zone in clusters.json.`) + console.error(' The fixture is keyed to that zone; pick another and update ZONE here.') + process.exit(1) +} +const want = new Set(zone.selector.values || []) + +// ── CHECK MODE: the committed fixture must still match clusters.json ──────── +if (CHECK) { + if (!existsSync(OUT)) { + console.error(`PACKET-FIXTURE: FAIL — ${OUT.slice(ROOT.length + 1)} does not exist.`) + console.error(' Fix: node internal/generate-packet-fixture.mjs (then commit it)') + process.exit(1) + } + const have = JSON.parse(readFileSync(OUT, 'utf8')) + const haveSlugs = new Set(have.map((r) => r.slug)) + const missing = [...want].filter((s) => !haveSlugs.has(s)) + const extra = [...haveSlugs].filter((s) => !want.has(s)) + const withPhotos = have.filter((r) => r.image_url).length + console.log(`PACKET-FIXTURE: ${have.length} record(s) for ${ZONE}.`) + const fails = [] + if (missing.length) fails.push(`${missing.length} slug(s) in clusters.json are absent: ${missing.slice(0, 4).join(', ')}`) + if (extra.length) fails.push(`${extra.length} record(s) are no longer in the zone: ${extra.slice(0, 4).join(', ')}`) + // image_url must stay stripped, or CI starts fetching ~43 photos from someone else's CDN. + if (withPhotos) fails.push(`${withPhotos} record(s) still carry image_url — the fixture must never fetch photos`) + if (fails.length) { + console.error(`\nPACKET-FIXTURE: FAIL — ${fails.length} problem(s)`) + for (const f of fails) console.error(' - ' + f) + console.error('\n Fix: node internal/generate-packet-fixture.mjs (then commit it)') + process.exit(1) + } + console.log('PACKET-FIXTURE: PASS — the committed fixture matches clusters.json and fetches no photos.') + process.exit(0) +} + +// ── GENERATE ──────────────────────────────────────────────────────────────── +if (!existsSync(CACHE)) { + console.error('PACKET-FIXTURE: FAIL — no records cache to derive from.') + console.error(` Expected ${CACHE.slice(ROOT.length + 1)}.`) + console.error(' Run a normal packet build first: node library/scripts/posters/packet.mjs') + process.exit(1) +} +const recs = JSON.parse(readFileSync(CACHE, 'utf8')) +const subset = (Array.isArray(recs) ? recs : recs.records || []).filter((r) => r && want.has(r.slug)) +if (subset.length !== want.size) { + console.error(`PACKET-FIXTURE: FAIL — matched ${subset.length} of ${want.size} slug(s) in the cache.`) + console.error(' The cache is stale or partial; re-run a full packet build and try again.') + process.exit(1) +} +// STRIP image_url. A fixture that carries photo URLs would make CI fetch ~43 images from +// Joshua Project's CDN on every build, which is both slow and rude; the packet degrades to +// typographic cards, which is exactly what a fixture should exercise. +const lean = subset.map((r) => { + const c = { ...r } + delete c.image_url + c.has_photo = false + return c +}) +mkdirSync(OUT_DIR, { recursive: true }) +writeFileSync(OUT, JSON.stringify(lean)) +const kb = (JSON.stringify(lean).length / 1024).toFixed(0) +console.log(`[packet-fixture] wrote ${OUT.slice(ROOT.length + 1)} — ${lean.length} records for ${ZONE}, ${kb}KB`) diff --git a/library/scripts/posters/fixtures/records-tibet.json b/library/scripts/posters/fixtures/records-tibet.json new file mode 100644 index 000000000..c780d503f --- /dev/null +++ b/library/scripts/posters/fixtures/records-tibet.json @@ -0,0 +1 @@ +[{"slug":"adi","name":"Adi","country_code":"CHN","population":"1400","religion":"E","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://flickr.com/photos/ramesh_lalwani/8169468855/","text":"Ramesh Lalwani - Flickr"}],"latitude":"29.24961200","longitude":"95.17182400","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion"},{"slug":"ainu-china","name":"Ainu","country_code":"CHN","population":"11000","religion":"MSN","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"38.93020500","longitude":"76.16959600","country_code_label":"People's Republic of China","religion_label":"Islam - Sunni"},{"slug":"alxa-mongols","name":"Alxa Mongols","country_code":"CHN","population":"35500","religion":"MSN","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"39.20798700","longitude":"101.67522000","country_code_label":"People's Republic of China","religion_label":"Islam - Sunni"},{"slug":"bogar-lhoba","name":"Bogar Lhoba","country_code":"CHN","population":"5300","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By bojum"}],"latitude":"28.74470000","longitude":"93.64580000","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"bogol","name":"Bogol","country_code":"CHN","population":"1400","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"48.46892600","longitude":"124.48821300","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"boyu-tibetans","name":"Boyu Tibetans","country_code":"CHN","population":"5400","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"33.36236100","longitude":"104.58044400","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"bunan","name":"Bunan","country_code":"CHN","population":"2500","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"31.79607000","longitude":"78.90344000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"buryat","name":"Buryat","country_code":"CHN","population":"170000","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://commons.wikimedia.org/wiki/File:Me_and_a_Buryat.jpg","text":"Telaneo - Wikimedia"}],"latitude":"48.75926000","longitude":"117.78630000","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"butuo-nosu","name":"Butuo Nosu","country_code":"CHN","population":"337000","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By Anonymous"}],"latitude":"27.60452900","longitude":"102.87518600","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"cona-monba","name":"Cona Monba","country_code":"CHN","population":"58500","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of Joshua Project by Anonymous"}],"latitude":"27.89404900","longitude":"92.20691400","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"darang-deng","name":"Darang Deng","country_code":"CHN","population":"12500","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"28.37980000","longitude":"97.02930000","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"enger-yugur","name":"Enger Yugur","country_code":"CHN","population":"5500","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://flickr.com/photos/mke1963/154213183/","text":"Mark mke1963 - Flickr"}],"latitude":"37.98815000","longitude":"101.76214000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"ersu","name":"Ersu","country_code":"CHN","population":"48000","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"29.23558500","longitude":"102.35591600","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"geman-deng","name":"Geman Deng","country_code":"CHN","population":"16500","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"28.47324000","longitude":"97.04437000","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"heishui","name":"Heishui","country_code":"CHN","population":"48500","religion":"BLA","has_photo":false,"picture_credit":null,"latitude":"32.19164300","longitude":"103.03860100","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"henan-mongols","name":"Henan Mongols","country_code":"CHN","population":"43000","religion":"BLA","has_photo":false,"picture_credit":null,"latitude":"34.73230000","longitude":"101.60860000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"keji","name":"Keji","country_code":"CHN","population":"2600","religion":"MSN","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.paulnoll.com/China/Minorities/China-Nationalities.html","text":"Paul Noll"}],"latitude":"29.65355100","longitude":"91.12095900","country_code_label":"People's Republic of China","religion_label":"Islam - Sunni"},{"slug":"kyrgyz","name":"Kyrgyz","country_code":"CHN","population":"195000","religion":"MOF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://commons.wikimedia.org/wiki/File:Kyrgyz_women_offering_butter_and_salt.jpg","text":"Theklan - Wikimedia"}],"latitude":"38.01774000","longitude":"76.09630000","country_code_label":"People's Republic of China","religion_label":"Islam - Folk"},{"slug":"luzu","name":"Luzu","country_code":"CHN","population":"1600","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"28.33754000","longitude":"101.35823900","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"manyak","name":"Manyak","country_code":"CHN","population":"3000","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"29.67090000","longitude":"101.59510000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"medog-monba","name":"Medog Monba","country_code":"CHN","population":"11000","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"29.46300000","longitude":"95.74060000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"miguba","name":"Miguba","country_code":"CHN","population":"100","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"29.29621200","longitude":"95.31208900","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"ming","name":"Ming","country_code":"CHN","population":"15500","religion":"NAT","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"31.53976000","longitude":"103.68679500","country_code_label":"People's Republic of China","religion_label":"Unaffiliated - Atheism"},{"slug":"minyak","name":"Minyak","country_code":"CHN","population":"35000","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.pesquisas.org.br/","text":"COMIBAM / Sepal"}],"latitude":"29.65400600","longitude":"101.52975300","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"naju","name":"Naju","country_code":"CHN","population":"2500","religion":"EAN","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"27.67805600","longitude":"101.46272000","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Animism"},{"slug":"namuyi","name":"Namuyi","country_code":"CHN","population":"11500","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"28.59085000","longitude":"101.89760000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"nghari-tibetans","name":"Nghari Tibetans","country_code":"CHN","population":"82500","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Peoples of the Buddhist World, Asia Harvest"}],"latitude":"30.97696000","longitude":"81.21100500","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"olot","name":"Olot","country_code":"CHN","population":"2400","religion":"ESM","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"47.87897700","longitude":"124.33623400","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Shamanism"},{"slug":"ongkor","name":"Ongkor","country_code":"CHN","population":"25","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://english.cri.cn/811/2005/08/24/48@13403.htm","text":"CRIENGLISH"}],"latitude":"43.98811800","longitude":"81.23009100","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"puroik","name":"Puroik","country_code":"CHN","population":"450","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By Anonymous"}],"latitude":"28.42033000","longitude":"93.10505600","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"saman","name":"Saman","country_code":"CHN","population":"2600","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"47.46389900","longitude":"124.11668900","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"saragh-yugur","name":"Saragh Yugur","country_code":"CHN","population":"10500","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"38.97160000","longitude":"99.50310000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"sarikoli-tajiks","name":"Sarikoli Tajiks","country_code":"CHN","population":"20500","religion":"MIS","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By Anonymous"}],"latitude":"37.90501000","longitude":"75.14486000","country_code_label":"People's Republic of China","religion_label":"Islam - Shia Imami Ismaili"},{"slug":"shixing","name":"Shixing","country_code":"CHN","population":"4100","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By Christopher Timmons"}],"latitude":"28.28800000","longitude":"100.65700000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"suodi-nosu","name":"Suodi Nosu","country_code":"CHN","population":"305000","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"26.86570200","longitude":"102.37629200","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"tongren-bonan","name":"Tongren Bonan","country_code":"CHN","population":"8900","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://flickr.com/photos/ding_zhou/15612978268/","text":"Joe Tym - Flickr"}],"latitude":"35.14500000","longitude":"102.18300000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"uzbeks","name":"Uzbeks","country_code":"CHN","population":"12500","religion":"MSN","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://commons.wikimedia.org/wiki/File:Uzbek_people_(4934182297).jpg","text":"Fulvio Spada - Wikimedia"}],"latitude":"44.14145000","longitude":"90.29497000","country_code_label":"People's Republic of China","religion_label":"Islam - Sunni"},{"slug":"wakhi-china","name":"Wakhi","country_code":"CHN","population":"9600","religion":"MSH","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://flickr.com/photos/100415065@N06/50312622062","text":"Robertino Radovix - Flickr"}],"latitude":"37.38000000","longitude":"75.40200000","country_code_label":"People's Republic of China","religion_label":"Islam - Shia"},{"slug":"western-xibe","name":"Western Xibe","country_code":"CHN","population":"35500","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By Epel - Shutterstock"}],"latitude":"43.80236300","longitude":"80.79151000","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"wutun","name":"Wutun","country_code":"CHN","population":"3800","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"35.57300000","longitude":"102.05400000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"},{"slug":"yidu-lhoba","name":"Yidu Lhoba","country_code":"CHN","population":"12000","religion":"ESM","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By Mow Sunil"}],"latitude":"28.97230000","longitude":"96.63810000","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Shamanism"},{"slug":"yinuo-nosu","name":"Yinuo Nosu","country_code":"CHN","population":"810000","religion":"ECF","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By Anonymous"}],"latitude":"28.04378200","longitude":"102.44427000","country_code_label":"People's Republic of China","religion_label":"Ethnoreligion - Chinese Folk Religion"},{"slug":"za","name":"Za","country_code":"CHN","population":"3400","religion":"BLA","has_photo":false,"picture_credit":[{"link":null,"text":"Photo courtesy of "},{"link":"https://www.joshuaproject.net","text":"Joshua Project"},{"link":null,"text":". By "},{"link":"https://www.asiaharvest.org","text":"Operation China, Asia Harvest"}],"latitude":"28.47990000","longitude":"97.07920000","country_code_label":"People's Republic of China","religion_label":"Buddhism - Tibetan"}] \ No newline at end of file diff --git a/library/scripts/posters/packet.mjs b/library/scripts/posters/packet.mjs index 1699f5a57..f51825f17 100644 --- a/library/scripts/posters/packet.mjs +++ b/library/scripts/posters/packet.mjs @@ -52,8 +52,14 @@ const LANG = process.env.PACKET_LANG || 'en'; const ONLY = process.env.ONLY || ''; const NOPHOTOS = process.env.NOPHOTOS === '1'; const API = process.env.VITE_API_BASE_URL || process.env.MAP_APP_API_URL; -if (!API) { - console.error('[packet] No API base — set VITE_API_BASE_URL. Failing closed.'); +// FAIL CLOSED without an API — EXCEPT when records come from a committed fixture, which +// is the one case where no API is needed at all. Measured 2026-09-24: this guard runs +// BEFORE loadRecords() ever looks at PACKET_RECORDS, so `bun run packet:ci` exited 1 on a +// tree that had everything it needed. It only passed in hand-testing because I had been +// supplying a dummy host — the real invocation path is what exposed it. +if (!API && !process.env.PACKET_RECORDS) { + console.error('[packet] No API base — set VITE_API_BASE_URL, or PACKET_RECORDS for a fixture build.'); + console.error(' Failing closed.'); process.exit(1); } @@ -109,6 +115,21 @@ const { evaluate } = await import(join(DATA, 'selector-evaluator.js')); const { normalizeRecords, extractRecords } = await import(join(DATA, 'normalize.js')); async function loadRecords() { + // ★ A COMMITTED FIXTURE, so CI can build a packet at all. out/ is gitignored — both the + // records cache AND every generated packet — so on a clean checkout check:packets-all + // finds nothing and SKIPs. MEASURED 2026-09-24: CI runs the sweep on EVERY build via + // gates:post and it has SKIPped every single time, which means every packet assertion in + // this tree (the 12 points, the wheel labels, page 1's geography, the print layer, the + // build stamp) has never once been evaluated there. A SKIP that is always taken is + // indistinguishable from an unwired gate, and the wave-membership census cannot see the + // difference because membership measures INVOCATION, not EVALUATION. + // PACKET_RECORDS points at a small committed subset instead of the live API or the + // gitignored cache. It is deliberately NOT the default: real packets must use real data. + const fixture = process.env.PACKET_RECORDS; + if (fixture) { + if (!existsSync(fixture)) throw new Error(`PACKET_RECORDS set but missing: ${fixture}`); + return JSON.parse(readFileSync(fixture, 'utf8')); + } const cache = join(__dirname, 'out', '_records.json'); if (process.env.OFFLINE && existsSync(cache)) return JSON.parse(readFileSync(cache, 'utf8')); const fields = 'slug,name,country_code,population,religion,image_url,has_photo,picture_credit,latitude,longitude'; @@ -232,7 +253,13 @@ for (const z of zones) { // session, packet-strings.json was 303s newer than the packets while being byte-identical // to HEAD, because a probe restored it from backup. Record the INTENT, which is a fact // about the build, not the clock. - const provenance = [NOPHOTOS ? 'nophotos' : null, mapMiss ? 'nomap' : null] + // `fixture` is a build fact like the others: a fixture packet is built from a committed + // records subset with image_url stripped, so it legitimately has no photos and its + // records are not today's live data. Without this the gate reports "every source record + // carries an image_url, so this is a skipped or failed photo fetch" — a true sentence + // about real records and a false one about this packet. + const provenance = [process.env.PACKET_RECORDS ? 'fixture' : null, + NOPHOTOS ? 'nophotos' : null, mapMiss ? 'nomap' : null] .filter(Boolean).join(' ') || 'full'; const stamped = html.replace('.html for page 1's map, which `bun run posters` writes — without it the packet still builds and page 1 is simply BLANK, so the script now warns per-zone AND in its summary. PACKET_LANG= for one language, ONLY= for one zone, NOPHOTOS=1 to skip the photo fetch.", + "packet-fixture": "node internal/generate-packet-fixture.mjs # regenerate the committed records subset (smallest zone, image_url stripped) that lets CI build a packet at all — out/ is gitignored, so a clean checkout has neither the records cache nor any packet.", + "check:packet-fixture": "node internal/generate-packet-fixture.mjs --check # the committed fixture must still match clusters.json and must never carry image_url (CI would fetch 43 photos from someone else's CDN).", + "packet:ci": "sh -c 'F=\"$PWD/library/scripts/posters/fixtures/records-tibet.json\"; PACKET_RECORDS=\"$F\" ONLY=asia-china-tibet-autonomous-region node library/scripts/posters/packet.mjs' # build ONE packet from the committed fixture, no network. This is what makes check:packets-all evaluate something in CI instead of SKIPping, as it had on every build.", "token": "node internal/write-token.mjs", "smoke": "node internal/smoke.mjs", "smoke:embeds": "node internal/embed-smoke.mjs", @@ -154,7 +157,7 @@ "check:doc-scripts:self-test": "node internal/check-doc-quotes-scripts.mjs --self-test", "check:legend-source": "node internal/check-legend-matches-source.mjs # the numbers the maps SHOW must match the numbers the live SOURCE has. Every other gate checks INTERNAL consistency — a page can agree with itself perfectly while its legend has stopped describing reality. Offline SKIPs (exit 0); only a reachable endpoint that disagrees fails.", "gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:wp-embed check:doc-scripts", - "gates:post": "node internal/run-parallel.mjs --label=post -- check:drop check:parse verify check:sri check:public-hygiene check:label-joins check:facet-cascade check:facet-one-field check:heartbeat check:kpi-unit check:composite-reg check:descriptions check:no-abs-paths check:no-codename check:dep-names check:composite-srcs check:embed-targets check:nested-token check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars", + "gates:post": "node internal/run-parallel.mjs --label=post -- check:drop check:parse verify check:sri check:public-hygiene check:label-joins check:facet-cascade check:facet-one-field check:heartbeat check:kpi-unit check:composite-reg check:descriptions check:no-abs-paths check:no-codename check:dep-names check:composite-srcs check:embed-targets check:nested-token check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars check:packet-fixture", "build:bundles": "node internal/run-parallel.mjs --bundles", "check:maplibre-drops": "node internal/check-maplibre-layer-drops.mjs", "check:tabs-localized": "node internal/check-tabs-localized.mjs # a chosen locale must CHANGE the rendered tab text. check:i18n-parity compares catalogs to each OTHER, so it cannot tell a shipped translation from a dead one; tabs.json is reached only via a DYNAMIC key (SemanticTreeLegend.vue:40), invisible to any grep. Renders it and reads the result.", From 9a05d5218e70cd8b6642c1685c058d1f7b3f3f7f Mon Sep 17 00:00:00 2001 From: doxa-maps-88655c70 <88627970+doxa-maps-88655c70@users.noreply.github.com> Date: Thu, 24 Sep 2026 14:34:10 +0000 Subject: [PATCH 2/7] Make Back retrace the whole chain, and Forward work at all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drilling All Regions to Africa to Angola and then pressing Back: the first press returned to Africa, the second stayed on Africa, and Forward never did anything. history.length sat at 4 the whole time, which is the tell — every Back was pushing a replacement entry, discarding the forward stack and pinning the position. The guard against that could never have worked. onPopState set a flag, assigned the selection and cleared the flag synchronously, while the watcher it guards is flush:'post' and runs after the DOM update — by which time the flag was already false. So the flag is gone rather than patched: writeUrl now compares the URL it would write against the one the address bar already holds and returns early when they match. After a popstate there is nothing to write, so no entry is created. A one-step check could not have caught this. The existing assertion picks a region, clears it, and presses Back once — and one step is exactly the depth at which the bug still looks correct. --- .../regions-dashboard/region-dashboards.vue | 31 +++++-- public/doxa-maps/index.html | 2 +- public/doxa-maps/manifest.json | 8 +- .../region-dashboards/index.html | 2 +- .../regions-dashboard/regions-dashboard.js | 92 +++++++++---------- .../regions-dashboard/regions-list/index.html | 2 +- .../regions-dashboard/regions-mfe/index.html | 2 +- 7 files changed, 79 insertions(+), 60 deletions(-) diff --git a/plugin-designs/regions-dashboard/region-dashboards.vue b/plugin-designs/regions-dashboard/region-dashboards.vue index 4b3006e12..1dcf51650 100644 --- a/plugin-designs/regions-dashboard/region-dashboards.vue +++ b/plugin-designs/regions-dashboard/region-dashboards.vue @@ -489,6 +489,22 @@ function writeUrl(push) { if (!URL_SYNC) return const slug = currentSlug() const url = window.location.pathname + window.location.search + (slug ? '#' + encodeURIComponent(slug) : '') + // WRITE ONLY WHEN THE URL WOULD ACTUALLY CHANGE. This is what makes Back and Forward work, and + // it replaces a flag that could not do the job. MEASURED before the fix, drilling + // All Regions -> Africa -> Angola and then pressing Back three times and Forward twice: + // back 1 -> Africa (correct) + // back 2 -> Africa (WRONG, should be All Regions) + // back 3 -> Africa + // forward 1 -> Africa (WRONG, should be Angola) + // history.length stayed 4 throughout: every Back pushed a REPLACEMENT entry, which discards the + // forward stack and pins the position — the classic loop the note below warns about. + // The old guard set applyingHistory=true, assigned sel, then cleared it SYNCHRONOUSLY, while + // the watcher that calls this is { flush: 'post' } and therefore runs after the DOM update, + // by which time the flag was already false. A scheduling-dependent flag cannot guarantee this; + // comparing the URL can. After a popstate the address bar already holds the target, so there is + // nothing to write and no entry is created. + const current = window.location.pathname + window.location.search + window.location.hash + if (url === current) { syncTitle(); return } try { push ? history.pushState({ slug }, '', url) : history.replaceState({ slug }, '', url) } catch (_) {} syncTitle() } @@ -508,20 +524,23 @@ function syncTitle() { try { document.title = t && t !== allLabel ? t + ' — ' + suffix : suffix } catch (_) {} } -// popstate WRITES the selection, so the watcher below must not turn around and push a new -// entry for it — that is the classic history loop where Back appears to do nothing. -let applyingHistory = false +// popstate WRITES the selection, and the watcher below then runs — but it can no longer create an +// entry for it, because writeUrl() refuses to write a URL the address bar already holds. The flag +// that used to guard this is GONE rather than patched: it was cleared synchronously while the +// watcher it guarded is { flush: 'post' }, so it was never in effect when it mattered. function onPopState() { - applyingHistory = true sel.value = selectionForSlug(slugFromHash()) syncTitle() - applyingHistory = false } // One watcher rather than a writeUrl() call at each of the five places a selection is made // (tab-1 event, table row, region dropdown, country dropdown, back-link) — those would drift. watch(() => [sel.value.regionSlug, sel.value.countrySlug], () => { - if (applyingHistory) return + // No guard needed: writeUrl() is idempotent, so the call this watcher makes after a popstate + // writes nothing. (Deleting the declaration while leaving `if (applyingHistory) return` here + // threw a ReferenceError inside the watcher, which silently stopped the URL being written at + // all — the hash never changed and Back left the page. Caught by re-running the measurement + // rather than by trusting the fix.) writeUrl(true) }, { flush: 'post' }) diff --git a/public/doxa-maps/index.html b/public/doxa-maps/index.html index a48cfcaf8..d042950ff 100644 --- a/public/doxa-maps/index.html +++ b/public/doxa-maps/index.html @@ -130,7 +130,7 @@ header.top .sub { margin-top: 3px; font: 12px/1.4 var(--sans); color: var(--mut) + window.FORGE.manifest = {"schema":"doxa-maps-manifest@1","generatedFrom":"plugin-designs/*/*.vue","embedBase":".","bundleCount":22,"profileCount":34,"bundles":[{"bundle":"all-people-groups","scriptUrl":"./all-people-groups/all-people-groups.js","output":"doxa-maps/all-people-groups/all-people-groups.js","integrity":"sha384-i96PE57CadLUnW5NkxS+kl+dUU8sSeLDuVKQ1so5onLfyHZIXJgoaEXss6+1VAnh","elements":["all-people-groups"],"profiles":[{"profile":"all-people-groups","file":"all-people-groups.vue","description":"All 12,379 people groups (peoplegroups.org) in four colors — reached,","element":"all-people-groups","type":"single","isMap":true,"iframeUrl":"./all-people-groups/all-people-groups/index.html","scriptUrl":"./all-people-groups/all-people-groups.js","embed":{"iframe":"\u003ciframe src=\"./all-people-groups/all-people-groups/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./all-people-groups/all-people-groups.js\" integrity=\"sha384-i96PE57CadLUnW5NkxS+kl+dUU8sSeLDuVKQ1so5onLfyHZIXJgoaEXss6+1VAnh\" crossorigin=\"anonymous\">\u003c/script>\n\u003call-people-groups profile-config='{\"profile\":\"all-people-groups\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/all-people-groups>"},"bundle":"all-people-groups"}]},{"bundle":"big-picture","scriptUrl":"./big-picture/big-picture.js","output":"doxa-maps/big-picture/big-picture.js","integrity":"sha384-3I1mBK8C0GOMsEJyYTyztMqFnvn4EGg3F2KFhYSVie+o2YKplcSFcOxWI4L2+cmr","elements":["bp-big-picture","bp-research-header","people-groups-grid"],"composes":["bp-research-header","people-groups-grid"],"profiles":[{"profile":"big-picture","file":"big-picture.vue","description":"The Cat-4 composite that PAIRS the two real capability elements of the","element":"bp-big-picture","type":"nested-elements-mfe","isMap":false,"iframeUrl":"./big-picture/big-picture/index.html","scriptUrl":"./big-picture/big-picture.js","embed":{"iframe":"\u003ciframe src=\"./big-picture/big-picture/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./big-picture/big-picture.js\" integrity=\"sha384-3I1mBK8C0GOMsEJyYTyztMqFnvn4EGg3F2KFhYSVie+o2YKplcSFcOxWI4L2+cmr\" crossorigin=\"anonymous\">\u003c/script>\n\u003cbp-big-picture profile-config='{\"profile\":\"big-picture\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/bp-big-picture>"},"instances":[{"id":"big-picture","title":"Big Picture — research header ↔ people-groups grid (composite)","apiBaseUrl":"","props":{"profile":"big-picture","provider":"maplibre","instanceId":"bp-big-picture"},"element":"bp-big-picture","iframeUrl":"./big-picture/big-picture/big-picture/index.html","embed":{"iframe":"\u003ciframe src=\"./big-picture/big-picture/big-picture/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"frontier","title":"Big Picture — frontier accent","apiBaseUrl":"","props":{"profile":"big-picture","provider":"maplibre","instanceId":"bp-big-picture-frontier","accent":"#22d3ee","title":"Big Picture — Frontier Focus"},"element":"bp-big-picture","iframeUrl":"./big-picture/big-picture/frontier/index.html","embed":{"iframe":"\u003ciframe src=\"./big-picture/big-picture/frontier/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}],"bundle":"big-picture"}]},{"bundle":"cities-internet","scriptUrl":"./cities-internet/cities-internet.js","output":"doxa-maps/cities-internet/cities-internet.js","integrity":"sha384-nzv5X2WdO5IqlVUqnmsDPDSq2uHRbJGyoDIEjHz915D7nAeS428kzYSeaRyAIEf2","elements":["cities-internet-map"],"profiles":[{"profile":"connectivity-list","file":"connectivity-list.vue","description":"Countries where DX people groups live, grouped by region, showing measured internet penetration","element":"cities-internet-map","type":"single","isMap":false,"iframeUrl":"./cities-internet/connectivity-list/index.html","scriptUrl":"./cities-internet/cities-internet.js","embed":{"iframe":"\u003ciframe src=\"./cities-internet/connectivity-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./cities-internet/cities-internet.js\" integrity=\"sha384-nzv5X2WdO5IqlVUqnmsDPDSq2uHRbJGyoDIEjHz915D7nAeS428kzYSeaRyAIEf2\" crossorigin=\"anonymous\">\u003c/script>\n\u003ccities-internet-map profile-config='{\"profile\":\"connectivity-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/cities-internet-map>"}},{"profile":"connectivity-map","file":"connectivity-map.vue","description":"Every country shaded by measured internet penetration, with its named carriers and dominant","element":"cities-internet-map","type":"single","isMap":true,"iframeUrl":"./cities-internet/connectivity-map/index.html","scriptUrl":"./cities-internet/cities-internet.js","embed":{"iframe":"\u003ciframe src=\"./cities-internet/connectivity-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./cities-internet/cities-internet.js\" integrity=\"sha384-nzv5X2WdO5IqlVUqnmsDPDSq2uHRbJGyoDIEjHz915D7nAeS428kzYSeaRyAIEf2\" crossorigin=\"anonymous\">\u003c/script>\n\u003ccities-internet-map profile-config='{\"profile\":\"connectivity-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/cities-internet-map>"}},{"profile":"data-tables","file":"data-tables.vue","description":"Four validated research tables, one tab each, with sortable and filterable columns, CSV and JSON","element":"cities-internet-map","type":"single","isMap":false,"iframeUrl":"./cities-internet/data-tables/index.html","scriptUrl":"./cities-internet/cities-internet.js","embed":{"iframe":"\u003ciframe src=\"./cities-internet/data-tables/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./cities-internet/cities-internet.js\" integrity=\"sha384-nzv5X2WdO5IqlVUqnmsDPDSq2uHRbJGyoDIEjHz915D7nAeS428kzYSeaRyAIEf2\" crossorigin=\"anonymous\">\u003c/script>\n\u003ccities-internet-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/cities-internet-map>"}}]},{"bundle":"country-posters","scriptUrl":"./country-posters/country-posters.js","output":"doxa-maps/country-posters/country-posters.js","integrity":"sha384-+uSJg/LdhuPzecJG34oeevbtghdX7Pqaop+MyNzs4tyqd3/1frmrwQimIJgcv/yo","elements":["country-posters-map"],"composes":["country-posters/country-poster-wall","country-posters/countries-map"],"profiles":[{"profile":"countries-map","file":"countries-map.vue","description":"The researcher's workbench retargeted from people groups to COUNTRIES — region","element":"country-posters-map","type":"single","isMap":true,"iframeUrl":"./country-posters/countries-map/index.html","scriptUrl":"./country-posters/country-posters.js","embed":{"iframe":"\u003ciframe src=\"./country-posters/countries-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./country-posters/country-posters.js\" integrity=\"sha384-+uSJg/LdhuPzecJG34oeevbtghdX7Pqaop+MyNzs4tyqd3/1frmrwQimIJgcv/yo\" crossorigin=\"anonymous\">\u003c/script>\n\u003ccountry-posters-map profile-config='{\"profile\":\"countries-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/country-posters-map>"}},{"profile":"country-poster-wall","file":"country-poster-wall.vue","description":"One printable card per country, grouped into COLLAPSIBLE regional sections so the","element":"country-posters-map","type":"single","isMap":false,"iframeUrl":"./country-posters/country-poster-wall/index.html","scriptUrl":"./country-posters/country-posters.js","embed":{"iframe":"\u003ciframe src=\"./country-posters/country-poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./country-posters/country-posters.js\" integrity=\"sha384-+uSJg/LdhuPzecJG34oeevbtghdX7Pqaop+MyNzs4tyqd3/1frmrwQimIJgcv/yo\" crossorigin=\"anonymous\">\u003c/script>\n\u003ccountry-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/country-posters-map>"}},{"profile":"country-posters-mfe","file":"country-posters-mfe.vue","description":"Country Posters as ONE two-tab element — the countries map and the printable","element":"country-posters-mfe","type":"nested-elements-mfe","isMap":true,"iframeUrl":"./country-posters/country-posters-mfe/index.html","scriptUrl":"./country-posters/country-posters.js","embed":{"iframe":"\u003ciframe src=\"./country-posters/country-posters-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./country-posters/country-posters.js\" integrity=\"sha384-+uSJg/LdhuPzecJG34oeevbtghdX7Pqaop+MyNzs4tyqd3/1frmrwQimIJgcv/yo\" crossorigin=\"anonymous\">\u003c/script>\n\u003ccountry-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/country-posters-map>"}}]},{"bundle":"dashboard-plus-grid","scriptUrl":"./dashboard-plus-grid/dashboard-plus-grid.js","output":"doxa-maps/dashboard-plus-grid/dashboard-plus-grid.js","integrity":"sha384-DeycKqMhqP8L6jFju+eMZScfLINhp2ElOfegTpl04TxS4NXLVHcbNvD+OBdprpWY","elements":["dashboard-plus-grid"],"composes":["research-dashboard","people-groups-grid"],"profiles":[{"profile":"dashboard-plus-grid","file":"dashboard-plus-grid.vue","description":"Both children are IMPORTED DIRECTLY (compiled into this ONE bundle — no runtime bundle","element":"dashboard-plus-grid","type":"nested-elements-mfe","isMap":true,"iframeUrl":"./dashboard-plus-grid/dashboard-plus-grid/index.html","scriptUrl":"./dashboard-plus-grid/dashboard-plus-grid.js","embed":{"iframe":"\u003ciframe src=\"./dashboard-plus-grid/dashboard-plus-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./dashboard-plus-grid/dashboard-plus-grid.js\" integrity=\"sha384-DeycKqMhqP8L6jFju+eMZScfLINhp2ElOfegTpl04TxS4NXLVHcbNvD+OBdprpWY\" crossorigin=\"anonymous\">\u003c/script>\n\u003cdashboard-plus-grid profile-config='{\"profile\":\"dashboard-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/dashboard-plus-grid>"},"instances":[{"id":"default","title":"default","apiBaseUrl":"","props":{"profile":"dashboard-plus-grid"},"element":"dashboard-plus-grid","iframeUrl":"./dashboard-plus-grid/dashboard-plus-grid/default/index.html","embed":{"iframe":"\u003ciframe src=\"./dashboard-plus-grid/dashboard-plus-grid/default/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]},{"bundle":"demo-map","scriptUrl":"./demo-map/demo-map.js","output":"doxa-maps/demo-map/demo-map.js","integrity":"sha384-5oWLIcgctfjngRp9QntcaJusDwsKHBv84Pleb62gIr7ZkXeFT/+DlhsLFYdiZrac","elements":["demo-map"],"profiles":[{"profile":"demo-map","file":"demo-map.vue","description":"Simple two-tab demo map. Tab 1 colors pins by religion (shared","element":"demo-map","type":"parameterized","isMap":true,"iframeUrl":"./demo-map/demo-map/index.html","scriptUrl":"./demo-map/demo-map.js","embed":{"iframe":"\u003ciframe src=\"./demo-map/demo-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./demo-map/demo-map.js\" integrity=\"sha384-5oWLIcgctfjngRp9QntcaJusDwsKHBv84Pleb62gIr7ZkXeFT/+DlhsLFYdiZrac\" crossorigin=\"anonymous\">\u003c/script>\n\u003cdemo-map profile-config='{\"profile\":\"demo-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/demo-map>"},"instances":[{"id":"maplibre","title":"Demo map — MapLibre (token-free)","apiBaseUrl":"","props":{"profile":"demo-map","provider":"maplibre","instanceId":"demo-maplibre"},"element":"demo-map","iframeUrl":"./demo-map/demo-map/maplibre/index.html","embed":{"iframe":"\u003ciframe src=\"./demo-map/demo-map/maplibre/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}],"bundle":"demo-map"}]},{"bundle":"doxa-maps-spa","scriptUrl":"./doxa-maps-spa/doxa-maps-spa.js","output":"doxa-maps/doxa-maps-spa/doxa-maps-spa.js","integrity":"sha384-1f+/rBSGo/1jyUmRmGg34CIU/PcGkB7M3jah1DO0ocb5O0zj81wpUemXcz4WAFz8","elements":["doxa-maps-spa"],"composes":["bp-big-picture","doxa-research-map","doxa-simple-map","cities-internet-map","gospel-resources-map","my-upg-100-list-map"],"profiles":[{"profile":"doxa-maps-spa","file":"doxa-maps-spa.vue","description":"The DX-maps app itself: one element whose vertical-tab rail nests every other","element":"doxa-maps-spa","type":"nested-mfe-spa","isMap":false,"iframeUrl":"./doxa-maps-spa/doxa-maps-spa/index.html","scriptUrl":"./doxa-maps-spa/doxa-maps-spa.js","embed":{"iframe":"\u003ciframe src=\"./doxa-maps-spa/doxa-maps-spa/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-1f+/rBSGo/1jyUmRmGg34CIU/PcGkB7M3jah1DO0ocb5O0zj81wpUemXcz4WAFz8\" crossorigin=\"anonymous\">\u003c/script>\n\u003cdoxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/doxa-maps-spa>"},"instances":[{"id":"app","title":"DX-Maps SPA — Big Picture + every research map (app-shell)","apiBaseUrl":"","props":{"profile":"doxa-maps-spa","provider":"maplibre","instanceId":"doxa-maps-spa-app","title":"DX-Maps"},"element":"doxa-maps-spa","iframeUrl":"./doxa-maps-spa/doxa-maps-spa/app/index.html","embed":{"iframe":"\u003ciframe src=\"./doxa-maps-spa/doxa-maps-spa/app/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]},{"bundle":"doxa-research-map","scriptUrl":"./doxa-research-map/doxa-research-map.js","output":"doxa-maps/doxa-research-map/doxa-research-map.js","integrity":"sha384-hCsiL74WyyjIlg577zCcAhG7fD0iUzqdvsnZMGvpiS3ra3NpSEoDczoHMWK2eF6x","elements":["doxa-research-map"],"profiles":[{"profile":"research-map","file":"research-map.vue","description":"The researcher's workbench: every piece a missiologist, demographer or","element":"doxa-research-map","type":"monolithic","isMap":true,"iframeUrl":"./doxa-research-map/research-map/index.html","scriptUrl":"./doxa-research-map/doxa-research-map.js","embed":{"iframe":"\u003ciframe src=\"./doxa-research-map/research-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./doxa-research-map/doxa-research-map.js\" integrity=\"sha384-hCsiL74WyyjIlg577zCcAhG7fD0iUzqdvsnZMGvpiS3ra3NpSEoDczoHMWK2eF6x\" crossorigin=\"anonymous\">\u003c/script>\n\u003cdoxa-research-map profile-config='{\"profile\":\"research-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/doxa-research-map>"},"instances":[{"id":"maplibre","title":"Research map — MapLibre (token-free, no search bar)","apiBaseUrl":"","props":{"profile":"research-map","provider":"maplibre","instanceId":"research-map-maplibre"},"element":"doxa-research-map","iframeUrl":"./doxa-research-map/research-map/maplibre/index.html","embed":{"iframe":"\u003ciframe src=\"./doxa-research-map/research-map/maplibre/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]},{"bundle":"doxa-simple-map","scriptUrl":"./doxa-simple-map/doxa-simple-map.js","output":"doxa-maps/doxa-simple-map/doxa-simple-map.js","integrity":"sha384-FtEGLeSRNfBCdmK26IURIxCldSnfKphxRT74XgjftFGzNpvube+ov/EVBFi2gXjo","elements":["doxa-map","doxa-simple-map"],"profiles":[{"profile":"doxa-simple-map","file":"doxa-simple-map.vue","description":"The simple world map, shipped as three presets off ONE prop table —","element":"doxa-map","type":"parameterized","isMap":true,"iframeUrl":"./doxa-simple-map/doxa-simple-map/index.html","scriptUrl":"./doxa-simple-map/doxa-simple-map.js","embed":{"iframe":"\u003ciframe src=\"./doxa-simple-map/doxa-simple-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./doxa-simple-map/doxa-simple-map.js\" integrity=\"sha384-FtEGLeSRNfBCdmK26IURIxCldSnfKphxRT74XgjftFGzNpvube+ov/EVBFi2gXjo\" crossorigin=\"anonymous\">\u003c/script>\n\u003cdoxa-map profile-config='{\"profile\":\"doxa-simple-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/doxa-map>"},"instances":[{"id":"prayer","title":"Prayer Map","apiBaseUrl":"https://pray.doxa.life","props":{"profile":"doxa-simple-map","instanceId":"embed-prayer","dataSource":"pray-tools","tabs":[{"id":"prayer","colorStrategy":"prayer","legend":"prayer","popup":"prayer"}]},"element":"doxa-map","iframeUrl":"./doxa-simple-map/doxa-simple-map/prayer/index.html","embed":{"iframe":"\u003ciframe src=\"./doxa-simple-map/doxa-simple-map/prayer/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"engagement","title":"Engagement Map","apiBaseUrl":"https://pray.doxa.life","props":{"profile":"doxa-simple-map","instanceId":"embed-engagement","dataSource":"pray-tools","tabs":[{"id":"engagement","colorStrategy":"engagement","legend":"engagement","popup":"engagement"}]},"element":"doxa-map","iframeUrl":"./doxa-simple-map/doxa-simple-map/engagement/index.html","embed":{"iframe":"\u003ciframe src=\"./doxa-simple-map/doxa-simple-map/engagement/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"adoption","title":"Adoption Map","apiBaseUrl":"https://pray.doxa.life","props":{"profile":"doxa-simple-map","instanceId":"embed-adoption","dataSource":"pray-tools","tabs":[{"id":"adoption","colorStrategy":"adoption","legend":"adoption","popup":"adoption"}]},"element":"doxa-map","iframeUrl":"./doxa-simple-map/doxa-simple-map/adoption/index.html","embed":{"iframe":"\u003ciframe src=\"./doxa-simple-map/doxa-simple-map/adoption/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]},{"bundle":"doxa-vision-card","scriptUrl":"./doxa-vision-card/doxa-vision-card.js","output":"doxa-maps/doxa-vision-card/doxa-vision-card.js","integrity":"sha384-2mza3cltN5LQQIrlENG/IVL6Icd9zzcFve3E8R8VWuCdYOGW9uGKFvxcbu6eFfwn","elements":["doxa-vision-card"],"profiles":[{"profile":"doxa-vision-card","file":"doxa-vision-card.vue","description":"The Capability-1 example: ONE folder -> ONE bundle -> ONE element.","element":"doxa-vision-card","type":"parameterized","isMap":false,"iframeUrl":"./doxa-vision-card/doxa-vision-card/index.html","scriptUrl":"./doxa-vision-card/doxa-vision-card.js","embed":{"iframe":"\u003ciframe src=\"./doxa-vision-card/doxa-vision-card/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./doxa-vision-card/doxa-vision-card.js\" integrity=\"sha384-2mza3cltN5LQQIrlENG/IVL6Icd9zzcFve3E8R8VWuCdYOGW9uGKFvxcbu6eFfwn\" crossorigin=\"anonymous\">\u003c/script>\n\u003cdoxa-vision-card profile-config='{\"profile\":\"doxa-vision-card\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/doxa-vision-card>"},"instances":[{"id":"default","title":"Vision card — reach at a glance","apiBaseUrl":"","props":{"profile":"doxa-vision-card","provider":"maplibre","instanceId":"vision-card-default"},"element":"doxa-vision-card","iframeUrl":"./doxa-vision-card/doxa-vision-card/default/index.html","embed":{"iframe":"\u003ciframe src=\"./doxa-vision-card/doxa-vision-card/default/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"frontier","title":"Vision card — frontier accent","apiBaseUrl":"","props":{"profile":"doxa-vision-card","provider":"maplibre","instanceId":"vision-card-frontier","accent":"#22d3ee","title":"The last frontier of the gospel.","tagline":"Frontier people groups — where fewer than one in a thousand follow Jesus.","stats":[{"value":"1,910","label":"Frontier groups","note":"under 0.1% believers"},{"value":"2.1B","label":"People","note":"living in frontier settings"},{"value":"0.1%","label":"Christian","note":"or fewer, in each group"}]},"element":"doxa-vision-card","iframeUrl":"./doxa-vision-card/doxa-vision-card/frontier/index.html","embed":{"iframe":"\u003ciframe src=\"./doxa-vision-card/doxa-vision-card/frontier/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}],"bundle":"doxa-vision-card"}]},{"bundle":"golden-path-check","scriptUrl":"./golden-path-check/golden-path-check.js","output":"doxa-maps/golden-path-check/golden-path-check.js","integrity":"sha384-1V/sT5SkV0U9yTCK9ELIOFfU1ZIJkInIF6nG3UllJ4dxax3RsEAupSGLJEFK6e14","elements":["golden-path-check"],"profiles":[{"profile":"golden-path-check","file":"golden-path-check.vue","description":"A live self-test of the develop-a-plugin-and-see-it-live path: it reads the built","element":"golden-path-check","type":"single","isMap":false,"iframeUrl":"./golden-path-check/golden-path-check/index.html","scriptUrl":"./golden-path-check/golden-path-check.js","embed":{"iframe":"\u003ciframe src=\"./golden-path-check/golden-path-check/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./golden-path-check/golden-path-check.js\" integrity=\"sha384-1V/sT5SkV0U9yTCK9ELIOFfU1ZIJkInIF6nG3UllJ4dxax3RsEAupSGLJEFK6e14\" crossorigin=\"anonymous\">\u003c/script>\n\u003cgolden-path-check profile-config='{\"profile\":\"golden-path-check\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/golden-path-check>"}}]},{"bundle":"gospel-resources","scriptUrl":"./gospel-resources/gospel-resources.js","output":"doxa-maps/gospel-resources/gospel-resources.js","integrity":"sha384-r2AwOhX5crwXsnT2MsiQN8+nn2Ea/l2rYdsVL5BGTKR12W9+u7ggkHtDzv7neAPz","elements":["gospel-resources-map"],"profiles":[{"profile":"charts","file":"charts.vue","description":"The gap by LANGUAGE (ISO 639-3) rather than by people group — because one translation serves every","element":"gospel-resources-map","type":"single","isMap":false,"iframeUrl":"./gospel-resources/charts/index.html","scriptUrl":"./gospel-resources/gospel-resources.js","embed":{"iframe":"\u003ciframe src=\"./gospel-resources/charts/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-r2AwOhX5crwXsnT2MsiQN8+nn2Ea/l2rYdsVL5BGTKR12W9+u7ggkHtDzv7neAPz\" crossorigin=\"anonymous\">\u003c/script>\n\u003cgospel-resources-map profile-config='{\"profile\":\"charts\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/gospel-resources-map>"}},{"profile":"data-tables","file":"data-tables.vue","description":"Two validated tables: what resources exist per people group, and whether that access is keeping","element":"gospel-resources-map","type":"single","isMap":false,"iframeUrl":"./gospel-resources/data-tables/index.html","scriptUrl":"./gospel-resources/gospel-resources.js","embed":{"iframe":"\u003ciframe src=\"./gospel-resources/data-tables/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-r2AwOhX5crwXsnT2MsiQN8+nn2Ea/l2rYdsVL5BGTKR12W9+u7ggkHtDzv7neAPz\" crossorigin=\"anonymous\">\u003c/script>\n\u003cgospel-resources-map profile-config='{\"profile\":\"data-tables\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/gospel-resources-map>"}},{"profile":"resources-list","file":"resources-list.vue","description":"Which DX people groups have scripture in their own language, and which have none. The zero-resource","element":"gospel-resources-map","type":"single","isMap":false,"iframeUrl":"./gospel-resources/resources-list/index.html","scriptUrl":"./gospel-resources/gospel-resources.js","embed":{"iframe":"\u003ciframe src=\"./gospel-resources/resources-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-r2AwOhX5crwXsnT2MsiQN8+nn2Ea/l2rYdsVL5BGTKR12W9+u7ggkHtDzv7neAPz\" crossorigin=\"anonymous\">\u003c/script>\n\u003cgospel-resources-map profile-config='{\"profile\":\"resources-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/gospel-resources-map>"}},{"profile":"resources-map","file":"resources-map.vue","description":"Every country shaded by how much of its unengaged population has NO gospel resource in their own","element":"gospel-resources-map","type":"single","isMap":true,"iframeUrl":"./gospel-resources/resources-map/index.html","scriptUrl":"./gospel-resources/gospel-resources.js","embed":{"iframe":"\u003ciframe src=\"./gospel-resources/resources-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./gospel-resources/gospel-resources.js\" integrity=\"sha384-r2AwOhX5crwXsnT2MsiQN8+nn2Ea/l2rYdsVL5BGTKR12W9+u7ggkHtDzv7neAPz\" crossorigin=\"anonymous\">\u003c/script>\n\u003cgospel-resources-map profile-config='{\"profile\":\"resources-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/gospel-resources-map>"}}]},{"bundle":"my-upg-100-list","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","output":"doxa-maps/my-upg-100-list/my-upg-100-list.js","integrity":"sha384-KF3XG9q4VdSvuLQEeK0P1gsKg1cpNOvkLYK5MAIMCUwSsO07z5dI4ffGuc4U6Y+p","elements":["my-upg-100-list-map"],"composes":["my-upg-100-list/upg-100-list","my-upg-100-list/poster-wall"],"profiles":[{"profile":"poster-wall","file":"poster-wall.vue","description":"A wall of printable poster cards, one per 100-list entry, each with a \"Show on map\"","element":"my-upg-100-list-map","type":"single","isMap":false,"iframeUrl":"./my-upg-100-list/poster-wall/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-KF3XG9q4VdSvuLQEeK0P1gsKg1cpNOvkLYK5MAIMCUwSsO07z5dI4ffGuc4U6Y+p\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}},{"profile":"upg-100-list","file":"upg-100-list.vue","description":"A personal unreached-people-groups list painted as true boundary polygons —","element":"my-upg-100-list-map","type":"single","isMap":true,"iframeUrl":"./my-upg-100-list/upg-100-list/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/upg-100-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-KF3XG9q4VdSvuLQEeK0P1gsKg1cpNOvkLYK5MAIMCUwSsO07z5dI4ffGuc4U6Y+p\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}},{"profile":"upg-100-mfe","file":"upg-100-mfe.vue","description":"The standalone, shareable and embeddable composite of the my-upg-100-list family — it nests the map","element":"my-upg-100-list-map","type":"nested-elements-mfe","isMap":true,"iframeUrl":"./my-upg-100-list/upg-100-mfe/index.html","scriptUrl":"./my-upg-100-list/my-upg-100-list.js","embed":{"iframe":"\u003ciframe src=\"./my-upg-100-list/upg-100-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-KF3XG9q4VdSvuLQEeK0P1gsKg1cpNOvkLYK5MAIMCUwSsO07z5dI4ffGuc4U6Y+p\" crossorigin=\"anonymous\">\u003c/script>\n\u003cmy-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/my-upg-100-list-map>"}}]},{"bundle":"people-groups-grid","scriptUrl":"./people-groups-grid/people-groups-grid.js","output":"doxa-maps/people-groups-grid/people-groups-grid.js","integrity":"sha384-8B2T2ckH+v8p2hEnkGruUg4Do5ZFsh31QSxYJYMj4/PN/ccHdgaIyK4dyW2GlUAR","elements":["people-groups-grid"],"profiles":[{"profile":"people-groups-grid","file":"people-groups-grid.vue","description":"The people-groups grid as an owned custom element: card list, search and four","element":"people-groups-grid","type":"parameterized","isMap":false,"iframeUrl":"./people-groups-grid/people-groups-grid/index.html","scriptUrl":"./people-groups-grid/people-groups-grid.js","embed":{"iframe":"\u003ciframe src=\"./people-groups-grid/people-groups-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./people-groups-grid/people-groups-grid.js\" integrity=\"sha384-8B2T2ckH+v8p2hEnkGruUg4Do5ZFsh31QSxYJYMj4/PN/ccHdgaIyK4dyW2GlUAR\" crossorigin=\"anonymous\">\u003c/script>\n\u003cpeople-groups-grid profile-config='{\"profile\":\"people-groups-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/people-groups-grid>"},"instances":[{"id":"people-groups-grid","title":"People Groups Grid — standalone (own search + 4 dropdowns)","apiBaseUrl":"","props":{"profile":"people-groups-grid","provider":"maplibre","instanceId":"people-groups-grid","pray-base-url":"https://pray.doxa.life"},"element":"people-groups-grid","iframeUrl":"./people-groups-grid/people-groups-grid/people-groups-grid/index.html","embed":{"iframe":"\u003ciframe src=\"./people-groups-grid/people-groups-grid/people-groups-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"driven","title":"People Groups Grid — externally driven (controls off, props/events)","apiBaseUrl":"","props":{"profile":"people-groups-grid","provider":"maplibre","instanceId":"people-groups-grid-driven","pray-base-url":"https://pray.doxa.life","show-search":"false","show-filters":"false"},"element":"people-groups-grid","iframeUrl":"./people-groups-grid/people-groups-grid/driven/index.html","embed":{"iframe":"\u003ciframe src=\"./people-groups-grid/people-groups-grid/driven/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]},{"bundle":"plugin-studio","scriptUrl":"./plugin-studio/plugin-studio.js","output":"doxa-maps/plugin-studio/plugin-studio.js","integrity":"sha384-2RlLFRU2XdjBN7w+FPguj8INgj57JFg4IFT2AmdefGnR9QQLehbiiAffV45LcsFH","elements":["plugin-studio"],"composes":["bp-big-picture","people-groups-grid","doxa-research-map","doxa-simple-map","cities-internet-map","gospel-resources-map","my-upg-100-list-map","doxa-vision-card","all-people-groups","research-dashboard"],"profiles":[{"profile":"plugin-studio","file":"plugin-studio.vue","description":"The developer's viewing surface: a sidebar that is the composability ladder","element":"plugin-studio","type":"nested-mfe-spa","isMap":false,"iframeUrl":"./plugin-studio/plugin-studio/index.html","scriptUrl":"./plugin-studio/plugin-studio.js","embed":{"iframe":"\u003ciframe src=\"./plugin-studio/plugin-studio/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-2RlLFRU2XdjBN7w+FPguj8INgj57JFg4IFT2AmdefGnR9QQLehbiiAffV45LcsFH\" crossorigin=\"anonymous\">\u003c/script>\n\u003cplugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/plugin-studio>"},"instances":[{"id":"studio","title":"Plugin Studio — every element by capability 5 -> 1 (developer studio)","apiBaseUrl":"","props":{"profile":"plugin-studio","provider":"maplibre","instanceId":"plugin-studio","title":"Plugin Studio"},"element":"plugin-studio","iframeUrl":"./plugin-studio/plugin-studio/studio/index.html","embed":{"iframe":"\u003ciframe src=\"./plugin-studio/plugin-studio/studio/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]},{"bundle":"prayer-walk-planner","scriptUrl":"./prayer-walk-planner/prayer-walk-planner.js","output":"doxa-maps/prayer-walk-planner/prayer-walk-planner.js","integrity":"sha384-GVjVAmXugEnWIxdGeZzNW34E1lX2qVo499lQnrmFPq+MLbRmADUtgO5P4gmhHnvW","elements":["prayer-walk-planner"],"profiles":[{"profile":"prayer-walk-planner","file":"prayer-walk-planner.vue","description":"A simple polygon-drawing tool for planning prayer-walking routes.","element":"prayer-walk-planner","type":"single","isMap":true,"iframeUrl":"./prayer-walk-planner/prayer-walk-planner/index.html","scriptUrl":"./prayer-walk-planner/prayer-walk-planner.js","embed":{"iframe":"\u003ciframe src=\"./prayer-walk-planner/prayer-walk-planner/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./prayer-walk-planner/prayer-walk-planner.js\" integrity=\"sha384-GVjVAmXugEnWIxdGeZzNW34E1lX2qVo499lQnrmFPq+MLbRmADUtgO5P4gmhHnvW\" crossorigin=\"anonymous\">\u003c/script>\n\u003cprayer-walk-planner profile-config='{\"profile\":\"prayer-walk-planner\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/prayer-walk-planner>"}}]},{"bundle":"regions-dashboard","scriptUrl":"./regions-dashboard/regions-dashboard.js","output":"doxa-maps/regions-dashboard/regions-dashboard.js","integrity":"sha384-oXKY7GNXVKcivqGSmhcCZeEPtmSfjR+UNiGyvnqBrJ/gZtJD61rOA8T+SA0SlHQj","elements":["regions-dashboard"],"composes":["regions-dashboard/regions-list","regions-dashboard/region-dashboards"],"profiles":[{"profile":"region-dashboards","file":"region-dashboards.vue","description":"The dashboard half of the Driver's 2-tab Regions element: given a region (or a","element":"regions-dashboard","type":"single","isMap":true,"iframeUrl":"./regions-dashboard/region-dashboards/index.html","scriptUrl":"./regions-dashboard/regions-dashboard.js","embed":{"iframe":"\u003ciframe src=\"./regions-dashboard/region-dashboards/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-oXKY7GNXVKcivqGSmhcCZeEPtmSfjR+UNiGyvnqBrJ/gZtJD61rOA8T+SA0SlHQj\" crossorigin=\"anonymous\">\u003c/script>\n\u003cregions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/regions-dashboard>"}},{"profile":"regions-list","file":"regions-list.vue","description":"A refactor of DX-life's /regions index page (app/pages/regions/index.vue) into","element":"regions-dashboard","type":"single","isMap":true,"iframeUrl":"./regions-dashboard/regions-list/index.html","scriptUrl":"./regions-dashboard/regions-dashboard.js","embed":{"iframe":"\u003ciframe src=\"./regions-dashboard/regions-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-oXKY7GNXVKcivqGSmhcCZeEPtmSfjR+UNiGyvnqBrJ/gZtJD61rOA8T+SA0SlHQj\" crossorigin=\"anonymous\">\u003c/script>\n\u003cregions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/regions-dashboard>"}},{"profile":"regions-mfe","file":"regions-mfe.vue","description":"The composite the Driver asked for: ONE element carrying the SELECT VIEW switcher","element":"regions-dashboard","type":"nested-elements-mfe","isMap":true,"iframeUrl":"./regions-dashboard/regions-mfe/index.html","scriptUrl":"./regions-dashboard/regions-dashboard.js","embed":{"iframe":"\u003ciframe src=\"./regions-dashboard/regions-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-oXKY7GNXVKcivqGSmhcCZeEPtmSfjR+UNiGyvnqBrJ/gZtJD61rOA8T+SA0SlHQj\" crossorigin=\"anonymous\">\u003c/script>\n\u003cregions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/regions-dashboard>"}}]},{"bundle":"research-dashboard","scriptUrl":"./research-dashboard/research-dashboard.js","output":"doxa-maps/research-dashboard/research-dashboard.js","integrity":"sha384-HVfViEpV0E4gkPZ4l3ez6k1tayRop7UE6ypGrwBXE9iPB6icB3kz4zzih0x2aoLK","elements":["research-dashboard-map"],"profiles":[{"profile":"research-dashboard","file":"research-dashboard.vue","description":"Coordinated-Multiple-Views research dashboard for 10/40-window UPGs (live pray.doxa.life): docked facet rail + map-as-hero + linked table/charts, brushing-and-linking over one in-memory store.","element":"research-dashboard-map","type":"monolithic","isMap":true,"iframeUrl":"./research-dashboard/research-dashboard/index.html","scriptUrl":"./research-dashboard/research-dashboard.js","embed":{"iframe":"\u003ciframe src=\"./research-dashboard/research-dashboard/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./research-dashboard/research-dashboard.js\" integrity=\"sha384-HVfViEpV0E4gkPZ4l3ez6k1tayRop7UE6ypGrwBXE9iPB6icB3kz4zzih0x2aoLK\" crossorigin=\"anonymous\">\u003c/script>\n\u003cresearch-dashboard-map profile-config='{\"profile\":\"research-dashboard\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/research-dashboard-map>"},"bundle":"research-dashboard"}]},{"bundle":"research-map-plus-grid","scriptUrl":"./research-map-plus-grid/research-map-plus-grid.js","output":"doxa-maps/research-map-plus-grid/research-map-plus-grid.js","integrity":"sha384-sOkaMV0UFr2uNXfoJpRvaD+gHD6xFlkmpR7MzEwwFdarYdid8aN9Nj1Y8TqQJuFo","elements":["research-map-plus-grid"],"composes":["doxa-research-map","people-groups-grid"],"profiles":[{"profile":"research-map-plus-grid","file":"research-map-plus-grid.vue","description":"The monolithic 7-tab research map (cap-3) on top, the People Groups grid beneath,","element":"research-map-plus-grid","type":"nested-elements-mfe","isMap":false,"iframeUrl":"./research-map-plus-grid/research-map-plus-grid/index.html","scriptUrl":"./research-map-plus-grid/research-map-plus-grid.js","embed":{"iframe":"\u003ciframe src=\"./research-map-plus-grid/research-map-plus-grid/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./research-map-plus-grid/research-map-plus-grid.js\" integrity=\"sha384-sOkaMV0UFr2uNXfoJpRvaD+gHD6xFlkmpR7MzEwwFdarYdid8aN9Nj1Y8TqQJuFo\" crossorigin=\"anonymous\">\u003c/script>\n\u003cresearch-map-plus-grid profile-config='{\"profile\":\"research-map-plus-grid\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/research-map-plus-grid>"},"instances":[{"id":"default","title":"default","apiBaseUrl":"","props":{"profile":"research-map-plus-grid"},"element":"research-map-plus-grid","iframeUrl":"./research-map-plus-grid/research-map-plus-grid/default/index.html","embed":{"iframe":"\u003ciframe src=\"./research-map-plus-grid/research-map-plus-grid/default/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]},{"bundle":"stack-demo","scriptUrl":"./stack-demo/stack-demo.js","output":"doxa-maps/stack-demo/stack-demo.js","integrity":"sha384-gnwM6s+puf1K60Nl7crQcC2QC+9BxwpkaTx4OepLZ8VUCraZc+aRlWpsb6nj6Gyf","elements":["stack-demo"],"composes":["research-dashboard-map","people-groups-grid"],"profiles":[{"profile":"stack-demo","file":"stack-demo.vue","description":"Groups TWO independent elements TOP-TO-BOTTOM so you can embed the pair on a page and","element":"stack-demo","type":"nested-elements-mfe","isMap":false,"iframeUrl":"./stack-demo/stack-demo/index.html","scriptUrl":"./stack-demo/stack-demo.js","embed":{"iframe":"\u003ciframe src=\"./stack-demo/stack-demo/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./stack-demo/stack-demo.js\" integrity=\"sha384-gnwM6s+puf1K60Nl7crQcC2QC+9BxwpkaTx4OepLZ8VUCraZc+aRlWpsb6nj6Gyf\" crossorigin=\"anonymous\">\u003c/script>\n\u003cstack-demo profile-config='{\"profile\":\"stack-demo\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/stack-demo>"},"instances":[{"id":"pair","title":"pair","apiBaseUrl":"","props":{"profile":"stack-demo"},"element":"stack-demo","iframeUrl":"./stack-demo/stack-demo/pair/index.html","embed":{"iframe":"\u003ciframe src=\"./stack-demo/stack-demo/pair/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]},{"bundle":"template-bundle","scriptUrl":"./template-bundle/template-bundle.js","output":"doxa-maps/template-bundle/template-bundle.js","integrity":"sha384-NMZXoWa3ftpVtTmjkFkmur7MNsVAg39osy+tKt1cBiLpxYPD+3AsON4iE1hCgDeu","elements":["template-bundle"],"profiles":[{"profile":"template-map-a","file":"template-map-a.vue","description":"Minimal example profile A — a colored placeholder, no Mapbox or data.","element":"template-bundle","type":"single","isMap":false,"iframeUrl":"./template-bundle/template-map-a/index.html","scriptUrl":"./template-bundle/template-bundle.js","embed":{"iframe":"\u003ciframe src=\"./template-bundle/template-map-a/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./template-bundle/template-bundle.js\" integrity=\"sha384-NMZXoWa3ftpVtTmjkFkmur7MNsVAg39osy+tKt1cBiLpxYPD+3AsON4iE1hCgDeu\" crossorigin=\"anonymous\">\u003c/script>\n\u003ctemplate-bundle profile-config='{\"profile\":\"template-map-a\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/template-bundle>"},"bundle":"template-bundle"},{"profile":"template-map-b","file":"template-map-b.vue","description":"Minimal example profile B — a second profile in the same bundle.","element":"template-bundle","type":"single","isMap":false,"iframeUrl":"./template-bundle/template-map-b/index.html","scriptUrl":"./template-bundle/template-bundle.js","embed":{"iframe":"\u003ciframe src=\"./template-bundle/template-map-b/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./template-bundle/template-bundle.js\" integrity=\"sha384-NMZXoWa3ftpVtTmjkFkmur7MNsVAg39osy+tKt1cBiLpxYPD+3AsON4iE1hCgDeu\" crossorigin=\"anonymous\">\u003c/script>\n\u003ctemplate-bundle profile-config='{\"profile\":\"template-map-b\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/template-bundle>"},"bundle":"template-bundle"}]},{"bundle":"upg-neighbor","scriptUrl":"./upg-neighbor/upg-neighbor.js","output":"doxa-maps/upg-neighbor/upg-neighbor.js","integrity":"sha384-JDJr4qoVZuiSi/rvgdzeuUNrzf7vjPdyh/g8dg7X8RHkZk/Y+tYXIQ3gpEzrU07q","elements":["upg-neighbor"],"profiles":[{"profile":"upg-neighbor","file":"upg-neighbor.vue","description":"Rescues the five pre-bundler experimental maps that live inside the legacy","element":"upg-neighbor","type":"parameterized","isMap":false,"iframeUrl":"./upg-neighbor/upg-neighbor/index.html","scriptUrl":"./upg-neighbor/upg-neighbor.js","embed":{"iframe":"\u003ciframe src=\"./upg-neighbor/upg-neighbor/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>","script":"\u003cscript>window.MAP_APP_API_URL=\"https://pray.doxa.life\";\u003c/script>\n\u003cscript src=\"./upg-neighbor/upg-neighbor.js\" integrity=\"sha384-JDJr4qoVZuiSi/rvgdzeuUNrzf7vjPdyh/g8dg7X8RHkZk/Y+tYXIQ3gpEzrU07q\" crossorigin=\"anonymous\">\u003c/script>\n\u003cupg-neighbor profile-config='{\"profile\":\"upg-neighbor\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'>\u003c/upg-neighbor>"},"instances":[{"id":"send-map","title":"Send Map (legacy)","apiBaseUrl":"","props":{"profile":"upg-neighbor","legacyElement":"send-map","legacyTitle":"Send Map"},"element":"upg-neighbor","iframeUrl":"./upg-neighbor/upg-neighbor/send-map/index.html","embed":{"iframe":"\u003ciframe src=\"./upg-neighbor/upg-neighbor/send-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"upg-neighbors","title":"UPG Neighbors (legacy)","apiBaseUrl":"","props":{"profile":"upg-neighbor","legacyElement":"upg-neighbors","legacyTitle":"UPG Neighbors"},"element":"upg-neighbor","iframeUrl":"./upg-neighbor/upg-neighbor/upg-neighbors/index.html","embed":{"iframe":"\u003ciframe src=\"./upg-neighbor/upg-neighbor/upg-neighbors/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"lang-cluster","title":"Language Clusters (legacy)","apiBaseUrl":"","props":{"profile":"upg-neighbor","legacyElement":"lang-cluster","legacyTitle":"Language Clusters"},"element":"upg-neighbor","iframeUrl":"./upg-neighbor/upg-neighbor/lang-cluster/index.html","embed":{"iframe":"\u003ciframe src=\"./upg-neighbor/upg-neighbor/lang-cluster/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"bloom-cockpit","title":"Bloom Cockpit (legacy)","apiBaseUrl":"","props":{"profile":"upg-neighbor","legacyElement":"bloom-cockpit","legacyTitle":"Bloom Cockpit"},"element":"upg-neighbor","iframeUrl":"./upg-neighbor/upg-neighbor/bloom-cockpit/index.html","embed":{"iframe":"\u003ciframe src=\"./upg-neighbor/upg-neighbor/bloom-cockpit/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}},{"id":"flower-mesh","title":"Flower Mesh (legacy)","apiBaseUrl":"","props":{"profile":"upg-neighbor","legacyElement":"flower-mesh","legacyTitle":"Flower Mesh"},"element":"upg-neighbor","iframeUrl":"./upg-neighbor/upg-neighbor/flower-mesh/index.html","embed":{"iframe":"\u003ciframe src=\"./upg-neighbor/upg-neighbor/flower-mesh/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen>\u003c/iframe>"}}]}]}]}; \n\n" + "script": "\n\n" } }, { @@ -890,7 +890,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n" + "script": "\n\n" } }, { @@ -904,7 +904,7 @@ "scriptUrl": "./regions-dashboard/regions-dashboard.js", "embed": { "iframe": "", - "script": "\n\n" + "script": "\n\n" } } ] diff --git a/public/doxa-maps/regions-dashboard/region-dashboards/index.html b/public/doxa-maps/regions-dashboard/region-dashboards/index.html index 23c89d1d4..4600e1440 100644 --- a/public/doxa-maps/regions-dashboard/region-dashboards/index.html +++ b/public/doxa-maps/regions-dashboard/region-dashboards/index.html @@ -29,7 +29,7 @@ - + - + - +