Classic keeps a plot's Kenney kind where the kit holds a taller one #147

Owner

Tracker: #3791

Step 5 of plan #3561: Classic draws each plot's Kenney model by decision D8, in fill and in fall.

What it delivers

  • D8's model of a plot at a rank (src/client/render/cities.ts, classicModel). A Kenney model's kind is its name's stem: building, chimney, detail-tank, shipping-container, solar-panel, windmill or water-tower (KenneyKind). At rank 1 the plot's hash picks among rank 1's models. At each later rank, the plot's hash picks among that rank's models of the kind the plot drew at the rank below that draw taller than it drew, where any exist, and else among all of the rank's models. A model's drawn height is its top × classicRise of its rank, worked out once as the kit arrives. The model depends on the plot and the server's rank alone.
  • fill draws that model for every building, and the monument's tower step (towerStep) follows its drawn heights.
  • fall draws a fallen building as the model it stood as.
  • The server's catalogue, its model picks, the wire and the save do not change.

Tests

src/client/render/city-layers.test.ts, with a stand-in kit whose models differ in height (and in width, which names the drawn model in the merged mesh):

  • At rank 1 the drawn model is one of rank 1's. At each later rank it is one of that rank's same-kind models that draw taller than the plot's model drew at the rank below, where any exist, and else one of the rank's models. Over 64 plots and ranks 1–20 the test also asserts that the kit gives each fork: same-kind taller models that narrow the pick, same-kind models that are not taller, and ranks with no model of the kind.
  • It depends on the plot and the rank alone: a layer walked through ranks 1–20, a second layer presented each rank's layout afresh in the other order with a different server pick, and the first layer presented rank 10 again with another server pick, all draw the same model.
  • A fallen building falls as the model it stood as, and its collapse's block takes that model's drawn height and footprint, which decide its break, lean, debris and dust.
  • The monument's tower steps by the heights its plots' buildings draw at: 9 rank-3 plots whose server pick is the rank's first model raise the tower to 3.66, where the server picks' heights would give 1.91.

Mutation checks, run from whole-tree copies outside the checkout. The first five ran at 4456bad, where the control passed 14/14, and the last three at 1a5f2a2, where it passes 15/15. Each mutant fails the test aimed at it:

mutant fails
fill and fall draw the server's pick (main) the rule test and the fall test
kind only, without the taller test the rule test
taller only, of any kind the rule test
fall draws the server's pick the fall test
fill's pick depends on the server's pick the rule test and the fall test
fall's block height from the server's pick (topOf(kit.buildings[building.model]) * rise) the fall test
fall's footprint from the server's pick (footprintOf(kit.buildings[building.model])) the fall test
fill's tower heights from the server's pick (topOf(kit.buildings[building.model]) * classicRise(rank)) the tower step test

The last three passed the whole suite (1007/1007) before the block and tower tests, and they still pass the earlier version of city-layers.test.ts (14/14) beside the new one.

The real kit

The kit's OBJs from assets/kenney-industrial, parsed and fitted as loadKenney fits them, with D8 walked over a 64 × 64 grid of plots through ranks 1–20. It matches D8's list:

  • What a plot holds: rank 1 building-i, shipping-container-a or -b. Rank 2 chimney-medium or solar-panel-portrait. Rank 3 any rank-3 model. Rank 4 detail-tank-large or solar-panel-landscape-group. Rank 5 windmill-low. Rank 6 the windmill only. Ranks 7–20 the rank's buildings. At rank 20 building-r comes only from building-c, and building-a and -b take building-f or -l.
  • No plot draws the water tower.
  • Where a rank-up draws shorter: 1 → 2 building-i 0.42 → solar-panel-portrait 0.26. 2 → 3 chimney-medium 1.20 → every rank-3 model. 3 → 4 chimney-large 1.13 → detail-tank-large 0.69 or solar-panel-landscape-group 0.19; chimney-basic 0.67 and chimney-small 0.50 → solar-panel-landscape-group; solar-panel-portrait-group 0.27 → solar-panel-landscape-group. 6 → 7 windmill 1.86 → building-h 0.62. Then 8 → 9, 11 → 12, 13 → 14, 16 → 17 and 17 → 18, as on main.
  • The layer test's reference cities (grown(300) and grown(600) at 36,36, seed 7): the Classic tower step is 11 on main and 11 on the head for both. 17 of 19 and 20 of 22 buildings draw the server's pick.

Draw checks

The bench, the renders and the bundles below are of 4456bad. The head 1a5f2a2 changes only city-layers.test.ts over it: vite builds of mock/shore.html, mock/map.html, mock/wrecks.html and mock/cities.html from git archive trees of both heads give byte-identical dists, so these figures hold for the head. Review run 810's own bench at 4456bad (8 arms, 840 pages) matched these calls and triangles, with D10 paired head − base default −0.003 / +0.000 / +0.000 ms and full +0.003 / −0.003 / −0.013 ms.

Map Yard bench (src/bench/map.ts), every arm with ?finish=0, 8 arms in one map.ts 7 … call per session, 5 sessions × 7 runs (840 pages, 07:37–08:18 on s32). Base 9d318ec and head 4456bad were built from git archive trees and served with vite preview().

Calls and triangles per arm (1× · 0.5× · 0.25×):

arm calls triangles
base 71 · 92 · 131 587,878 · 653,028 · 841,376
head 71 · 92 · 131 586,614 · 652,556 · 840,296
base grown=full 71 · 95 · 131 662,133 · 1,050,523 · 2,023,475
head grown=full 71 · 95 · 131 663,289 · 1,051,991 · 2,015,923
head doom=battle 81 · 102 · 153 600,382–600,394 · 666,324–666,336 · 854,090–854,098
head doom=battle&spare 76 · 97 · 134 587,256 · 653,198 · 840,934
head doom=nuke 93 · 114 · 163 648,439 · 714,381 · 902,141
head doom=nuke&spare 84 · 105 · 144 623,738 · 689,680 · 877,420

D10, head − base, paired median (same session, run and view), with the phone estimate (7.5×) and map.ts's pooled medians:

view default growth grown=full
1× +0.000 ms (phone +0.000), pooled −0.007 +0.017 ms (phone +0.125), pooled +0.023
0.5× +0.003 ms (phone +0.025), pooled +0.010 +0.013 ms (phone +0.100), pooled +0.010
0.25× +0.003 ms (phone +0.025), pooled +0.030 −0.007 ms (phone −0.050), pooled −0.003

Calls are the base's at every view and growth. Every paired median is within D10's +0.05 ms.

The head's doom peaks against their spare arms (paired): battle +0.087 / +0.103 / +0.080 ms, nuke +0.103 / +0.107 / +0.107 ms at 1×, 0.5× and 0.25×.

While the bench ran, other projects' runs 782, 787, 788, 790 and 791 started on s32. A single-core sx build ran at about 95%, and two Android emulators ran, throughout.

Renders for the Reviewer

Attached to #3791:

  • 3791-classic-rank-line.png: the Wreck Yard's rankup scene in Classic at &zoom=3, frame −0.1 at &rank=1 through &rank=19, then frame 1.2 of &rank=19. That is the watched plot's line through ranks 1–20: building-i, solar-panel-portrait, solar-panel-portrait-group, solar-panel-landscape-group, windmill-low, windmill, then the buildings. Every page drew its 2 frames, added no program and threw no error.
  • The Map Yard overview and 1× in Classic, base and head, at default growth and with grown=full, under reduced motion (3791-map-*.png).
  • 3791-crop-1-city.png: the 1× city at the east, base then head at default growth, then base then head grown out. At default growth the base's water tower stands as a windmill on the head. Grown out, several plots draw other buildings.

Play

The esbuild bundles of src/ai/sim.ts (30ac6bf5…) and src/bench/net.ts (9178cad1…) are byte-identical between base and head, so the AI matches and npm run bench were not run.

Gates

  • sak-gate fast (tracker gate run 446) on 1a5f2a2: passed, npm test 1008/1008.
  • sak-gate full (tracker gate run 448) on 1a5f2a2, clean tree: passed, npm test 1008/1008 and test:phone 182/182.
  • On 4456bad: fast (tracker gate run 424) passed 1007/1007, and full (tracker gate run 431) passed, npm test 1007/1007 and test:phone 182/182.
Tracker: [#3791](https://sak.swipelab.com/tasks/3791) Step 5 of plan [#3561](https://sak.swipelab.com/tasks/3561): Classic draws each plot's Kenney model by decision D8, in `fill` and in `fall`. ## What it delivers - **D8's model of a plot at a rank** (src/client/render/cities.ts, `classicModel`). A Kenney model's kind is its name's stem: building, chimney, detail-tank, shipping-container, solar-panel, windmill or water-tower (`KenneyKind`). At rank 1 the plot's hash picks among rank 1's models. At each later rank, the plot's hash picks among that rank's models of the kind the plot drew at the rank below that draw taller than it drew, where any exist, and else among all of the rank's models. A model's drawn height is its top × `classicRise` of its rank, worked out once as the kit arrives. The model depends on the plot and the server's rank alone. - **`fill`** draws that model for every building, and the monument's tower step (`towerStep`) follows its drawn heights. - **`fall`** draws a fallen building as the model it stood as. - The server's catalogue, its model picks, the wire and the save do not change. ## Tests src/client/render/city-layers.test.ts, with a stand-in kit whose models differ in height (and in width, which names the drawn model in the merged mesh): - At rank 1 the drawn model is one of rank 1's. At each later rank it is one of that rank's same-kind models that draw taller than the plot's model drew at the rank below, where any exist, and else one of the rank's models. Over 64 plots and ranks 1–20 the test also asserts that the kit gives each fork: same-kind taller models that narrow the pick, same-kind models that are not taller, and ranks with no model of the kind. - It depends on the plot and the rank alone: a layer walked through ranks 1–20, a second layer presented each rank's layout afresh in the other order with a different server pick, and the first layer presented rank 10 again with another server pick, all draw the same model. - A fallen building falls as the model it stood as, and its collapse's block takes that model's drawn height and footprint, which decide its break, lean, debris and dust. - The monument's tower steps by the heights its plots' buildings draw at: 9 rank-3 plots whose server pick is the rank's first model raise the tower to 3.66, where the server picks' heights would give 1.91. Mutation checks, run from whole-tree copies outside the checkout. The first five ran at 4456bad, where the control passed 14/14, and the last three at 1a5f2a2, where it passes 15/15. Each mutant fails the test aimed at it: | mutant | fails | |---|---| | `fill` and `fall` draw the server's pick (main) | the rule test and the fall test | | kind only, without the taller test | the rule test | | taller only, of any kind | the rule test | | `fall` draws the server's pick | the fall test | | `fill`'s pick depends on the server's pick | the rule test and the fall test | | `fall`'s block height from the server's pick (`topOf(kit.buildings[building.model]) * rise`) | the fall test | | `fall`'s footprint from the server's pick (`footprintOf(kit.buildings[building.model])`) | the fall test | | `fill`'s tower heights from the server's pick (`topOf(kit.buildings[building.model]) * classicRise(rank)`) | the tower step test | The last three passed the whole suite (1007/1007) before the block and tower tests, and they still pass the earlier version of city-layers.test.ts (14/14) beside the new one. ## The real kit The kit's OBJs from assets/kenney-industrial, parsed and fitted as `loadKenney` fits them, with D8 walked over a 64 × 64 grid of plots through ranks 1–20. It matches D8's list: - **What a plot holds:** rank 1 building-i, shipping-container-a or -b. Rank 2 chimney-medium or solar-panel-portrait. Rank 3 any rank-3 model. Rank 4 detail-tank-large or solar-panel-landscape-group. Rank 5 windmill-low. Rank 6 the windmill only. Ranks 7–20 the rank's buildings. At rank 20 building-r comes only from building-c, and building-a and -b take building-f or -l. - **No plot draws the water tower.** - **Where a rank-up draws shorter:** 1 → 2 building-i 0.42 → solar-panel-portrait 0.26. 2 → 3 chimney-medium 1.20 → every rank-3 model. 3 → 4 chimney-large 1.13 → detail-tank-large 0.69 or solar-panel-landscape-group 0.19; chimney-basic 0.67 and chimney-small 0.50 → solar-panel-landscape-group; solar-panel-portrait-group 0.27 → solar-panel-landscape-group. 6 → 7 windmill 1.86 → building-h 0.62. Then 8 → 9, 11 → 12, 13 → 14, 16 → 17 and 17 → 18, as on main. - **The layer test's reference cities** (`grown(300)` and `grown(600)` at 36,36, seed 7): the Classic tower step is 11 on main and 11 on the head for both. 17 of 19 and 20 of 22 buildings draw the server's pick. ## Draw checks The bench, the renders and the bundles below are of 4456bad. The head 1a5f2a2 changes only city-layers.test.ts over it: vite builds of mock/shore.html, mock/map.html, mock/wrecks.html and mock/cities.html from `git archive` trees of both heads give byte-identical dists, so these figures hold for the head. Review run 810's own bench at 4456bad (8 arms, 840 pages) matched these calls and triangles, with D10 paired head − base default −0.003 / +0.000 / +0.000 ms and full +0.003 / −0.003 / −0.013 ms. Map Yard bench (src/bench/map.ts), every arm with `?finish=0`, 8 arms in one `map.ts 7 …` call per session, 5 sessions × 7 runs (840 pages, 07:37–08:18 on s32). Base 9d318ec and head 4456bad were built from `git archive` trees and served with vite `preview()`. Calls and triangles per arm (1× · 0.5× · 0.25×): | arm | calls | triangles | |---|---|---| | base | 71 · 92 · 131 | 587,878 · 653,028 · 841,376 | | head | 71 · 92 · 131 | 586,614 · 652,556 · 840,296 | | base `grown=full` | 71 · 95 · 131 | 662,133 · 1,050,523 · 2,023,475 | | head `grown=full` | 71 · 95 · 131 | 663,289 · 1,051,991 · 2,015,923 | | head `doom=battle` | 81 · 102 · 153 | 600,382–600,394 · 666,324–666,336 · 854,090–854,098 | | head `doom=battle&spare` | 76 · 97 · 134 | 587,256 · 653,198 · 840,934 | | head `doom=nuke` | 93 · 114 · 163 | 648,439 · 714,381 · 902,141 | | head `doom=nuke&spare` | 84 · 105 · 144 | 623,738 · 689,680 · 877,420 | D10, head − base, paired median (same session, run and view), with the phone estimate (7.5×) and map.ts's pooled medians: | view | default growth | `grown=full` | |---|---|---| | 1× | +0.000 ms (phone +0.000), pooled −0.007 | +0.017 ms (phone +0.125), pooled +0.023 | | 0.5× | +0.003 ms (phone +0.025), pooled +0.010 | +0.013 ms (phone +0.100), pooled +0.010 | | 0.25× | +0.003 ms (phone +0.025), pooled +0.030 | −0.007 ms (phone −0.050), pooled −0.003 | Calls are the base's at every view and growth. Every paired median is within D10's +0.05 ms. The head's doom peaks against their spare arms (paired): battle +0.087 / +0.103 / +0.080 ms, nuke +0.103 / +0.107 / +0.107 ms at 1×, 0.5× and 0.25×. While the bench ran, other projects' runs 782, 787, 788, 790 and 791 started on s32. A single-core `sx` build ran at about 95%, and two Android emulators ran, throughout. ## Renders for the Reviewer Attached to #3791: - `3791-classic-rank-line.png`: the Wreck Yard's `rankup` scene in Classic at `&zoom=3`, frame −0.1 at `&rank=1` through `&rank=19`, then frame 1.2 of `&rank=19`. That is the watched plot's line through ranks 1–20: building-i, solar-panel-portrait, solar-panel-portrait-group, solar-panel-landscape-group, windmill-low, windmill, then the buildings. Every page drew its 2 frames, added no program and threw no error. - The Map Yard overview and 1× in Classic, base and head, at default growth and with `grown=full`, under reduced motion (`3791-map-*.png`). - `3791-crop-1-city.png`: the 1× city at the east, base then head at default growth, then base then head grown out. At default growth the base's water tower stands as a windmill on the head. Grown out, several plots draw other buildings. ## Play The esbuild bundles of src/ai/sim.ts (30ac6bf5…) and src/bench/net.ts (9178cad1…) are byte-identical between base and head, so the AI matches and `npm run bench` were not run. ## Gates - `sak-gate fast` (tracker gate run 446) on 1a5f2a2: passed, `npm test` 1008/1008. - `sak-gate full` (tracker gate run 448) on 1a5f2a2, clean tree: passed, `npm test` 1008/1008 and `test:phone` 182/182. - On 4456bad: `fast` (tracker gate run 424) passed 1007/1007, and `full` (tracker gate run 431) passed, `npm test` 1007/1007 and `test:phone` 182/182.
agra merged commit 4d55866a38 into task/3561-a-growing-building-keeps-its-style-and-g 2026-10-25 14:20:19 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
agra/mini-alert!147
No description provided.