The pin spreading on a dense country lets the page repaint as it works (a frame every 26 of its 260 passes, only when the print shows its progress); every sheet stays byte-identical

This commit is contained in:
Doxa Maps 2026-10-03 15:23:28 +00:00
parent 1a8d9da8d9
commit 9bf90cc1a4
2 changed files with 8 additions and 2 deletions

View file

@ -2,13 +2,13 @@
// The sha384 of library/packet/poster-render.js. The browser fetches the served copy of that file
// (<assets>/lib/poster-render.js), hashes it, and runs it only when it matches this pin: code loaded at
// print time is integrity-pinned like every embed, because it executes on partner pages.
export const POSTER_RENDER_SHA384 = 'sha384-AM43ejAFlUq5/1D5V/vIhQhohlg/xU6SmM3CRn53/AbULq+lVj+D/M9ylfd3+3ry'
export const POSTER_RENDER_SHA384 = 'sha384-BovEYinyxyuBbZKenKq3jVNmVXHZG1qpEdznmgol7ceumR6r6KiKQhAQVg5Fs6yn'
// The sha384 of library/scripts/posters/data/ne-places.json, served at <assets>/boundaries/ne-places.json.
// Data, not code, but pinned the same way: a sheet uses the places only when they are the pinned ones.
export const NE_PLACES_SHA384 = 'sha384-Qtz2q8mcnA9Ei8Kwa2MRMyX95hSbSnUXjXdtsy8rHTX++mgSCih4LO4Rdrb2MIQy'
// The sha384 of the classic-script copy (<assets>/lib/poster-render.global.js, globalVariant of the file above),
// loaded with <script integrity> where a page's policy forbids importing a blob: of the verified text.
export const POSTER_RENDER_GLOBAL_SHA384 = 'sha384-3tatEkji15fqJiSe+XdnRxXotDEXRSnAq5rrwiqpx4UHd7vzJbidUvILn0YGe0rT'
export const POSTER_RENDER_GLOBAL_SHA384 = 'sha384-p3Ua3UsjgZMKvcmxIsqFwdpqjtj+4DGNHSaA6+EqFqCPL27g3rrVRunEXeG7Qbaj'
// The sha384 of library/scripts/posters/packet-strings.json, served at <assets>/lib/packet-strings.json. The
// packet, list and card text in every language, fetched at print time (packet/packetStrings.js) and used only
// when it matches; otherwise the print falls back to the bundled English block.

View file

@ -44,6 +44,11 @@ const __step = onStep
return new Promise((r) => (typeof requestAnimationFrame === 'function' ? requestAnimationFrame(() => setTimeout(r, 0)) : setTimeout(r, 0)));
}
: () => undefined;
// A yield WITHOUT a new step, for a long loop inside one stage (the pin relaxation): the page repaints (the elapsed
// seconds tick) and the work resumes. A no-op without onStep, so the sheet is unchanged.
const __yield = onStep
? () => new Promise((r) => (typeof requestAnimationFrame === 'function' ? requestAnimationFrame(() => setTimeout(r, 0)) : setTimeout(r, 0)))
: () => undefined;
// ── PIN BBOX: antimeridian-aware, outlier-trimmed ───────────────────────────
// Two independent failure modes made three posters render the WHOLE GLOBE:
//
@ -1515,6 +1520,7 @@ async function renderPoster(zone, pins, zoneFC) {
const ITERS = 260;
for (const it of prePins) { it._ox = it._px; it._oy = it._py; }
for (let pass = 0; pass < ITERS; pass++) {
if (pass && pass % 26 === 0) await __yield(); // ~10 repaints across the relaxation (dense countries: seconds on a phone)
let moved = false;
for (let i = 0; i < prePins.length; i++) {
for (let j = i + 1; j < prePins.length; j++) {