simocracy-v2 · gathering-resize-fix

Gathering worlds — FtC-style resize size lock

@daviddao

After resizing the gathering page horizontally, the building used to shrink linearly with viewport width while the FtC SF tower stayed the same size. The gathering page now uses the same min(width-cap, height-cap) placement rule as /ftc-sf, so the building holds its size as the viewport narrows.

Date: 2026-04-24 · pass · Target: local production build of simocracy-v2


Headline result

4/4
Wide breakpoints with constant building size
FtC-style
Resize behavior
0px
Building width delta from 1440 → 720
1
Shared placement formula

Pass. The gathering world now mirrors /ftc-sf resize behavior: the building stays at a fixed pixel size as the viewport narrows from 1440 down to ~720, then — just like /ftc-sf — starts shrinking only when 95% of the canvas width becomes the binding constraint at very narrow widths.

Screen recording

The recording resizes the viewport from 1440×900 down to 1280, 1024, 720, 480, and 375 at fixed 900 height — first on /ftc-sf, then on the gathering page. Both buildings hold their size on the wide steps and only shrink at the narrow tail.

What was wrong

The previous gathering placement (backgroundPlacement: "left-contain-width" with backgroundScale: 0.4) used pure width-based scaling: the building was always 40% of the canvas width, so as the viewport narrowed, the building shrank linearly. /ftc-sf never had this problem because useTowerCanvas uses min(width-cap, height-cap) — with a square 2000×2000 tower image, the height cap dominates and the building stays the same size until the viewport gets very narrow.

What changed

Code. components/events/gathering-world.tsx now passes backgroundPlacement: "ftc-tower" with backgroundScale: 0.5. The "ftc-tower" mode in hooks/useWalkingAvatars.ts was generalised so backgroundScale is the maximum height fraction — /ftc-sf-style behavior with a value tuned for the gathering's landscape preference. useWalkingAvatars applies the same drawing, collision, click, and outline placement to every code path that consumes the placement helper.

Expected drawn building size at fixed canvas height 844 (viewport 900)

ViewportCanvasFtC SF tower (2000×2000, scale=0.7)Gathering tower (2000×2000, scale=0.5)Both stable?
1440×9001440×844590×590422×422yes
1280×9001280×844590×590422×422yes
1024×9001024×844590×590422×422yes
720×900720×844590×590422×422yes
480×900480×844456×456 narrow tail422×422
375×900375×844356×356 narrow tail356×356 narrow tail

Raw expected dimensions are at assets/resize-fix-audit.json.

Side-by-side resize evidence

1440×900

FtC SF at 1440×900
FtC SFTower drawn at fixed pixel size, sidebar on the right half.
Gathering at 1440×900
GatheringBuilding drawn at fixed pixel size, same x-anchor.

1024×900

FtC SF at 1024×900
FtC SFTower size unchanged from 1440.
Gathering at 1024×900
GatheringBuilding size unchanged from 1440.

720×900

FtC SF at 720×900
FtC SFTower still the same size, sidebar covers the canvas.
Gathering at 720×900
GatheringBuilding still the same size.

480×900

FtC SF at 480×900
FtC SFWidth-cap kicks in, slight shrink.
Gathering at 480×900
GatheringSame width-cap behavior.

375×900

FtC SF at 375×900
FtC SFNarrow-tail shrink to fit canvas width.
Gathering at 375×900
GatheringSame narrow-tail shrink behavior.

Findings

Building stays a fixed pixel size from desktop to tablet

From 1440×900 down to 720×900 (viewport height held constant), the gathering building is drawn at the same canvas pixel rectangle. This is the FtC SF behavior the user asked for.

Width-cap engages predictably at narrow widths

Below ~480px, the 0.95×canvasWidth cap takes over for both pages and the building shrinks to fit the canvas. Both pages now share this behavior.

One placement formula across draw, collision, click, outline

The gathering hook computes the building rectangle once and reuses it for the canvas drawing, the collision map, the click-fallback bounding box, and the selected-building outline. Visual and interaction behavior cannot drift.

Reproducing

Routes/ftc-sf and /events/did%3Aplc%3A4a4ekfv5ks66ogf52xh5u5mg/3mk6xwaltgs22 Viewport sequence1440×900 → 1280 → 1024 → 720 → 480 → 375 (height fixed) Videoassets/resize-fix-tour.webm Screenshotsassets/01-ftc-1440x900.png10-gathering-375x900.png Checksnpx tsc --noEmit, npx eslint hooks/useWalkingAvatars.ts components/events/gathering-world.tsx, and npm run build passed.