TWO FIXES FROM A BROWSER RUN I COULD NOT DO MYSELF. rega measured page 2 in print media and found the opposite of the defect I feared: no overflow, but the four global steps ended at y~330 of 1056 while "43 · are in THIS packet" sat alone at y~965, leaving the middle ~60% of the sheet empty so the reader's own step read as a detached footer. And it had NO BAR, so the funnel never visibly narrowed to "yours" — a funnel whose final term is not drawn as part of the funnel fails at the one thing it is for. So the five steps are now ONE list with the reader's included, and it has a bar like the others: 1080 -> 640 -> 415 -> 184 -> 26px, the last two tinted so the network's list and the reader's list read as one thought. The 26px floor is what keeps the smallest list a visible sliver rather than a hairline. THE ROW RHYTHM IS DERIVED FROM MEASURED ROW HEIGHTS, not guessed. A first attempt subtracted a magic 118px as "about one row" and left 418px of dead space at the foot — rega's emptiness, just redistributed. Summing the real heights closes it to ~298px. AND IT KEEPS DELIBERATE SLACK, because two runtime facts are unknowable at layout time: whether a step carries a population line, and how many LINES its translated label wraps to. Arabic and Hindi labels are far longer than the English, so LINE_SLACK reserves one extra wrapped line per row. Computed: 298px headroom normally, 196px even if EVERY label wraps an extra line. Tight-packing this page would trade "60% empty" for an overflow in the locales I cannot eyeball. ── AND A GATE HOLE A NEAR-MISS EXPOSED ────────────────────────────────────── regions-plugin reported, unprompted, that a merge resolved with `git checkout --ours` silently deleted the printPacket call site supplying the funnel data — 60 lines — AND EVERY GATE STAYED GREEN. They filed it as merge discipline. It is also gate design, and that half is mine: the funnel page is OPTIONAL by design (buildPacket omits it when the arg is null), so a packet without page 2 is not malformed, just smaller. My own choice made the deletion invisible. --expect-funnel closes it. The wrong fix is to always require the page: the 11 pre-funnel laos packets and any host with no funnel data would go red, and a false red costs as much as a false green. Instead the CALLER, which knows whether this packet was built with funnel data, declares it. An absence is then either DECLARED (no flag, fine) or a FAILURE (flag passed, page missing) — never a silent nothing. Verified: all 16 generated packets satisfy the sheet arithmetic, 0 failures, including the 11 laos packets that have no funnel page. fixture-tibet renders 5 rows with 5 bars ending in 43. Arabic regenerated: 7 sheets, dir="rtl", 5 rows, 5 bars, ZERO Eastern-Arabic digits on the sheet. Mutation-tested --expect-funnel three ways: baseline+flag PASS, funnel-sheet-deleted+flag FAILS, deleted without the flag PASSES. Flag filtered from the positional read, so a bare --expect-funnel is not eaten as the packet path (that trap has bitten this repo three times). BUNDLE=my-upg-100-list vite build clean, +141 bytes vs main. NOT re-verified in a browser: check:packet-render needs Chromium, reserved to rega. The geometry above is computed, not rendered — the print-media layout is exactly what rega's eyes caught that my arithmetic did not, so this wants one more look. |
||
|---|---|---|
| .. | ||
| api | ||
| colors | ||
| components | ||
| composables | ||
| constants | ||
| data | ||
| i18n | ||
| layouts | ||
| lists | ||
| maps | ||
| packet | ||
| scripts | ||
| stores | ||
| styles | ||
| utils | ||
| index.js | ||
| ProfileLoader.vue | ||
| README.md | ||
library/ (@map) — the shared map template
The other half of the architecture (see ../plugin-designs/README.md):
every map in plugin-designs/<your-map>/ composes the reusable, parameterized pieces that live here.
Fix something here and every map benefits on the next build; break something here and every map
breaks — read components/WARNING.md before touching shared pieces.
| Folder | What lives there |
|---|---|
ProfileLoader.vue |
The root of every bundle: parses profile-config, loads the profile, provides the stores + config |
components/ |
Shared UI — map, legends, controls, popup (PeopleGroupDetail), tables, charts, hints (README) |
composables/ |
Shared logic — map engine (useMapInstance), provider switch, shadow-DOM styles, theming |
stores/ |
Per-instance Pinia stores (ui / map / data) — provided by ProfileLoader, injected by children |
api/ |
Data-source registry (sources.json) + fetch layer — the JAMstack runtime wiring |
colors/ |
Color sets maps opt into via profile-config.colorSet |
i18n/ |
The shared string catalogs (all maps speak the same languages) |
data/ |
Small shared datasets baked at build time (big served data lives in ../data/) |
constants/ |
Shared constants |
scripts/ |
Maintainer pipelines (posters, research) — not part of any bundle |
The rule of thumb (same as WARNING.md): custom code in your app-profile, reusable code here — and things only move from the first to the second once they've earned it.