Skip to content

Map-scale preview: show the pattern on a territory - #6

Merged
timbogdanov merged 1 commit into
mainfrom
feat/map-scale-preview
Aug 19, 2026
Merged

Map-scale preview: show the pattern on a territory#6
timbogdanov merged 1 commit into
mainfrom
feat/map-scale-preview

Conversation

@timbogdanov

Copy link
Copy Markdown
Owner

Phase 2 of the v0.2.0 plan — OpenFront fidelity.

OpenFront paints a pattern onto territory in absolute world coordinates, so what a player sees depends on where the territory sits on the map. The editor showed a 3×3 repeat of the bitmap, which cannot express that — patterns were being designed against a preview that did not model the thing they are for.

tools/preview_prototype.py has verified the sampling rule since before the editor existed, and the suite has run it on every commit without the app ever using it. It is ported now, with a Map view that renders the pattern inside a territory shape at its real scale. Drag it and the pattern's phase moves with it.

The trap, and proof the test catches it

JavaScript's % is a remainder whose sign follows the dividend, so a naive (x >> scale) % width returns a negative index the moment the territory is dragged left of the origin — reading before the start of the bit array. That is the likeliest way for this port to be wrong, so 661 of the 1,161 probes are at negative coordinates.

I reintroduced the bare % to check the suite isn't vacuous. It failed 6 cases, first disagreement at (-9,-9). Driving the real app, a drag reaches world offset −48,−53 and renders correctly.

The oracle

tests/fixtures/sampler.json — 56 patterns across all eight scales, each probed 1,161 times, every expectation generated against an independently written decoder that unpacks bits a different way, so a self-consistent bug cannot hide.

Scale coverage is synthesised: the committed corpus is 1,117 patterns at scale 0 and one or two at each of the rest, because it was built for width, height and bit packing. Nothing here comes from the game's cosmetics.json — it is CC BY-SA 4.0 and deliberately not redistributed.

Beyond per-probe agreement, the suite pins the property that makes this a map preview: a shift of one full scaled period must be invisible, and a shift of one world tile must not be. 15 of 28 structured patterns change under a one-tile shift; none change under a full period.

Two things the port exposed

  • The scale readout was wrong. It showed the slider position, so scale 3 read "3×" directly above a sentence saying "One pixel covers 8×8 map tiles". scale is an exponent; the readout is now the magnification.
  • The brace-matching extractor had been copied into two suites and was about to be copied into a third — one edit away from two suites disagreeing about what the editor's source says. It now lives in tools/lib/extract.js; verify-codec.js uses it, 28 duplicated lines gone.

Verification

./tools/verify-all.sh green, now including sampler oracle and editor sampler vs oracle. Drove the real app: picked a duotone, set map scale, toggled Map, dragged into negative world space, and confirmed the territory renders the pattern clipped to its shape.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UCrKKTD2mwHx8Fm1EnJiQ3

OpenFront paints a pattern onto territory in absolute world coordinates, so what
a player sees depends on where the territory sits on the map. The editor showed
a 3x3 repeat of the bitmap, which cannot express that at all — patterns were
being designed against a preview that did not model the thing they are for.

tools/preview_prototype.py has verified the sampling rule since before the editor
existed, and the suite has been running it on every commit without the app ever
using it. It is ported now: floorMod and ofPrimaryAt, plus territoryMask, and a
Map view that renders the pattern inside a territory shape at its real scale.
Drag it and the pattern's phase moves, because the position is what decides which
part of the pattern lands where.

JS `%` is a remainder whose sign follows the dividend, so a naive
`(x >> scale) % width` returns a negative index the moment the territory is
dragged left of the origin, reading before the start of the bit array. That is
the single likeliest way for this port to be wrong, so 661 of the 1,161 probes
are at negative coordinates. Reintroducing the bare `%` fails 6 cases with the
first disagreement at (-9,-9), so the suite is known to catch it rather than
assumed to.

tests/fixtures/sampler.json is the oracle: 56 patterns across all eight scales,
each probed 1,161 times, generated against an independently written decoder. The
committed corpus is 1,117 patterns at scale 0 and one or two at each of the rest
— built for width, height and bit packing — so scale coverage is synthesised
here. Nothing comes from the game's cosmetics.json; it is CC BY-SA 4.0 and not
redistributed.

Two things the port exposed:

The map scale readout showed the slider position, so scale 3 read "3x" directly
above a sentence saying "One pixel covers 8x8 map tiles". scale is an exponent;
the readout is now the magnification.

The brace-matching extractor had been copied into two suites and was about to be
copied into a third, which is one edit from two suites disagreeing about what the
editor's source says. It lives in tools/lib/extract.js now, and verify-codec.js
uses it — 28 duplicated lines gone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UCrKKTD2mwHx8Fm1EnJiQ3
@timbogdanov
timbogdanov merged commit 5ef510e into main Aug 19, 2026
5 checks passed
@timbogdanov
timbogdanov deleted the feat/map-scale-preview branch August 19, 2026 01:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant