mirror of
https://github.com/sbuffkin/hexmaker.git
synced 2026-07-22 06:14:01 +00:00
The bug the user has been chasing for several sessions. Sandbox
repro at dev/coord-slip-sandbox.html, snapshot-coord-slip.mjs
captures the half-baked frame so we can SEE the slip.
Root cause: bakeZoom mutates the viewport font-size mid-function,
which triggers a layout reflow growing every em-based hex
dimension. The path-overlay SVG holds coord labels at pixel
positions computed against the PRE-bake hex sizes, so any paint
frame between the font-size change and the SVG rebuild shows the
labels at where the hexes USED to be — visibly shifted up-left of
the now-larger hexes. updatePathOverlay() further down in bakeZoom
eventually fixes it ("snap back into place"), but the intermediate
slip-then-snap is what the user reported across multiple zoom
sessions.
Fix: tear down the path / faction / region SVGs at the START of
bakeZoom, before the font-size mutation. The CSS rule
`.duckmage-svg-labels-active .duckmage-hex-label { visibility:
hidden }` is keyed off a class on the viewport — that class gets
removed alongside the SVG, so the intermediate paint falls back to
the HTML `.duckmage-hex-label` spans. Those live inside each hex's
own DOM tree, so they always track the hex's layout perfectly
across font-size changes. No slip.
The overlays are then re-rendered later in the function via the
existing updatePathOverlay() / updateFactionOverlay() /
updateRegionOverlay() / updateTokenLayer() calls. Net result: zero
extra rebuild work, just earlier tear-down.
Sandbox confirms:
buggy-mid: SVG labels visibly shifted up-left of small hexes
fixed-mid: HTML labels inside hexes, tracking correctly
351 unit tests / 18 e2e pass.
46 lines
1.8 KiB
JavaScript
46 lines
1.8 KiB
JavaScript
#!/usr/bin/env node
|
|
/** Capture the half-baked frame between font-size change and SVG rebuild
|
|
* in both the buggy order (SVG torn down last) and the fixed order
|
|
* (SVG torn down first). The 300ms setTimeout in the sandbox is the
|
|
* paint window — snapshot DURING that window, while the SVG is in its
|
|
* stale-vs-absent state, to see which one shows misplaced labels. */
|
|
import path from "node:path";
|
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
import fs from "node:fs/promises";
|
|
import { withBrowser } from "/mnt/c/Users/markr/work/tools/chromium-driver/lib/browser.mjs";
|
|
|
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
const sandbox = path.join(here, "coord-slip-sandbox.html");
|
|
const outDir = path.join(here, "out");
|
|
await fs.mkdir(outDir, { recursive: true });
|
|
|
|
await withBrowser(
|
|
async ({ page }) => {
|
|
await page.goto(pathToFileURL(sandbox).href, { waitUntil: "networkidle0" });
|
|
const snap = async (name) => {
|
|
const el = await page.$(".viewport");
|
|
await el.screenshot({ path: path.join(outDir, `${name}.png`) });
|
|
console.log(path.join(outDir, `${name}.png`));
|
|
};
|
|
|
|
await snap("slip-1-baseline");
|
|
|
|
await page.click("#reset");
|
|
await new Promise((r) => setTimeout(r, 100));
|
|
await page.click("#buggy-bake");
|
|
// Capture mid-transition — during the 300ms SVG-rebuild delay
|
|
await new Promise((r) => setTimeout(r, 100));
|
|
await snap("slip-2-buggy-mid");
|
|
await new Promise((r) => setTimeout(r, 400));
|
|
await snap("slip-3-buggy-final");
|
|
|
|
await page.click("#reset");
|
|
await new Promise((r) => setTimeout(r, 100));
|
|
await page.click("#fixed-bake");
|
|
await new Promise((r) => setTimeout(r, 100));
|
|
await snap("slip-4-fixed-mid");
|
|
await new Promise((r) => setTimeout(r, 400));
|
|
await snap("slip-5-fixed-final");
|
|
},
|
|
{ viewport: { width: 900, height: 600 } },
|
|
);
|