feat(assets): import authored biome props as statics, scattered per biome (#137) #184

Merged
marco merged 2 commits from feat/biome-props into main 2026-07-25 17:40:28 +02:00
Collaborator

Summary

Imports the authored biome props (rocks and vegetation) as statics and scatters them across the biome each belongs to, so the world reads as dressed terrain rather than bare ground. Unblocks the prop half of #137 and clears the prerequisite for the per-biome scatter (#140).

The blocker recorded on #137 was "the source PNGs are RGB with no alpha, and props need a transparent cut-out (project forbids colour-key)". That turned out to be recoverable: the sources are fake-opaque — alpha is 255 everywhere and the transparency checkerboard is baked into the RGB, plus a soft grey drop-shadow painted under each object. Both are separable analytically, so no colour-key is involved.

What changed

  • 13 props cut out of the E:\Asset sources into art/static/*.png, named to the asset HARD GATE (<material>_<kind>): volcanic_rock_black, mossy_boulder, mossy_rock, salt_crystal, leafy_bush, dead_bush, desert_cactus, yellow_flower_patch, rotten_tree_stump, frosted_shrub, wheat_tuft, young_pine_tree, marsh_mushrooms.
  • Anchor rule — scenery statics now anchor bottom-centre so they stand on their tile (a pine must grow upward from it, not straddle it). Previously only static/tree* did. static/item_* keeps the centre anchor, since those are carryable item icons drawn like a dropped thing. Covered by a new test. Note: this also re-anchors the existing static/lily and static/reeds, which is the correct reading for ground scenery.
  • tiledata — one static <id> <blocks> row each. Bulky things you can't walk through block (rocks, boulder, salt crystal, cactus, pine, stump); low ground cover is walkable decoration (small rock, bushes, flowers, wheat, mushrooms).
  • Placement — 169 instances scattered into the biome each prop belongs to (volcanic rock in the caldera, cactus in the desert sand, salt crystal on the salt plain, frosted shrub in tundra, pine in northern grassland, mushrooms in marsh…), kept 3 tiles apart and clear of spawn.

The cut-out pipeline (why the first attempts had white rims)

Worth recording, because it bit repeatedly: an achromatic pixel is only part of the object when it is genuinely dark. Classifying "anything below mid-value" as object swallowed the painted drop-shadow (a grey ~190-250 band) and rendered it as an opaque pale ring around every base. The fix is core = saturated OR very dark, holes filled (so pale interiors like salt facets survive), and everything outside the core un-matted against the white backdrop — which turns the painted shadow into a real translucent contact shadow that composites over any terrain.

How it was tested

  • Whole solution builds 0 warnings; all tests green (7/7 projects), including the new OwnArt anchor test.
  • Ran the client (debug harness, fresh DB): walked to the showcase and toured desert, tundra, volcanic, marsh, northern grassland and salt plain. Props stand on their tiles at plausible scale (the pine overtops the player, the cactus matches him, bushes are low) and show no pale halo at game scale.

Cut-outs over grass

prop cut-outs

In-game detail — the bottom-centre anchor puts every prop on its tile.

in-game detail

Biome tour — each prop in the biome it belongs to.

biome tour

Notes / follow-ups

  • Placement here is authored rows in world.statics. The generative per-biome scatter is still #140 — this PR unblocks it by supplying the art it was waiting on.
  • marsh mushrooms.png in the source folder has a space in its filename; the pack entry normalises it to marsh_mushrooms.
## Summary Imports the **authored biome props** (rocks and vegetation) as statics and scatters them across the biome each belongs to, so the world reads as dressed terrain rather than bare ground. Unblocks the prop half of #137 and clears the prerequisite for the per-biome scatter (#140). The blocker recorded on #137 was *"the source PNGs are RGB with no alpha, and props need a transparent cut-out (project forbids colour-key)"*. That turned out to be recoverable: the sources are **fake-opaque** — alpha is 255 everywhere and the transparency checkerboard is baked into the RGB, plus a **soft grey drop-shadow painted under each object**. Both are separable analytically, so no colour-key is involved. ## What changed - **13 props** cut out of the `E:\Asset` sources into `art/static/*.png`, named to the asset HARD GATE (`<material>_<kind>`): `volcanic_rock_black`, `mossy_boulder`, `mossy_rock`, `salt_crystal`, `leafy_bush`, `dead_bush`, `desert_cactus`, `yellow_flower_patch`, `rotten_tree_stump`, `frosted_shrub`, `wheat_tuft`, `young_pine_tree`, `marsh_mushrooms`. - **Anchor rule** — scenery statics now anchor **bottom-centre** so they stand *on* their tile (a pine must grow upward from it, not straddle it). Previously only `static/tree*` did. `static/item_*` keeps the centre anchor, since those are carryable item icons drawn like a dropped thing. Covered by a new test. *Note: this also re-anchors the existing `static/lily` and `static/reeds`, which is the correct reading for ground scenery.* - **tiledata** — one `static <id> <blocks>` row each. Bulky things you can't walk through block (rocks, boulder, salt crystal, cactus, pine, stump); low ground cover is walkable decoration (small rock, bushes, flowers, wheat, mushrooms). - **Placement** — 169 instances scattered into the biome each prop belongs to (volcanic rock in the caldera, cactus in the desert sand, salt crystal on the salt plain, frosted shrub in tundra, pine in northern grassland, mushrooms in marsh…), kept 3 tiles apart and clear of spawn. ### The cut-out pipeline (why the first attempts had white rims) Worth recording, because it bit repeatedly: an achromatic pixel is only part of the object when it is **genuinely dark**. Classifying "anything below mid-value" as object swallowed the painted drop-shadow (a grey ~190-250 band) and rendered it as an **opaque pale ring** around every base. The fix is `core = saturated OR very dark`, holes filled (so pale *interiors* like salt facets survive), and everything outside the core un-matted against the white backdrop — which turns the painted shadow into a real translucent contact shadow that composites over any terrain. ## How it was tested - Whole solution builds **0 warnings**; all tests green (7/7 projects), including the new `OwnArt` anchor test. - **Ran the client** (debug harness, fresh DB): walked to the showcase and toured desert, tundra, volcanic, marsh, northern grassland and salt plain. Props stand on their tiles at plausible scale (the pine overtops the player, the cactus matches him, bushes are low) and show no pale halo at game scale. **Cut-outs over grass** ![prop cut-outs](https://git.homelab.devncode.it/attachments/1823391f-04f1-4906-a4cf-c78a18361228) **In-game detail** — the bottom-centre anchor puts every prop on its tile. ![in-game detail](https://git.homelab.devncode.it/attachments/21b8039d-1010-4e02-89d7-b29d44007090) **Biome tour** — each prop in the biome it belongs to. ![biome tour](https://git.homelab.devncode.it/attachments/4df13cd9-7b77-4fb1-8f9c-3a89831eb368) ## Notes / follow-ups - Placement here is **authored rows** in `world.statics`. The generative per-biome scatter is still #140 — this PR unblocks it by supplying the art it was waiting on. - `marsh mushrooms.png` in the source folder has a space in its filename; the pack entry normalises it to `marsh_mushrooms`.
feat(assets): import authored biome props as statics, scattered per biome (#137)
All checks were successful
ci / Lint & Test (pull_request) Successful in 2m50s
a801f97077
feat(content): 66 authored biome props, forests, and a 256x192 biome world (#137)
All checks were successful
ci / Lint & Test (pull_request) Successful in 1m40s
89d2478c23
Author
Collaborator

Second pass: the full prop set, forests, and a reforged world

The branch now carries the whole authored prop set (66 kinds) rather than the first 13, the trees grow as forests, and the world was reforged four times larger with clearly separated biomes so it can actually be toured.

World — regenerated at 256 x 192 = 49,152 tiles (4x the old map) via scripts/genmap.py, with a majority filter that consolidates the noise classification into one contiguous region per biome. Distribution: tundra 21%, northern grassland 15%, desert and marsh 13% each, grass 10%, rocky + mountain 16%, salt plain 6%, savanna 5%, plus the volcanic caldera. The caldera is now constrained inland and nothing is placed within 8 tiles of the border ring, so no region is left clipped by the edge.

Forests — trees are no longer sprinkled evenly: 32 groves of mixed species with tight in-grove spacing (7 pine woods in the northern grassland, 6 in tundra, 6 dead woods in savanna, 5 on rocky ground, 7 cactus stands, 1 burnt grove on the volcano). 1,344 props placed in total.

Scale — every prop is now sized against the measured human sprite (22x61 px). Trees were previously sized by width, which is why they looked stunted; they are now sized by height in human multiples: the snowy pine at 4.0x (5.5 tiles tall), young pine 2.9x, dead trees ~2.8x, cacti 1.7-1.8x. The pines are the only living trees in the set, so they deliberately tower over everything.

Cut-out fixes found by review

  • White between the bones — hole-filling recovered pale interiors (salt crystal facets) but also filled the gaps between ribs with background white. Filling is now enabled per-prop and only for genuinely solid pale bodies; skeletons, the gibbet cage and twiggy bushes keep their see-through gaps.
  • Bone scale — bones were arbitrary; they now derive from the human sprite (human skeleton 1.0x, deer 1.35x, horse 1.6x, bird 0.36x, dragon fossil 2.2x).
  • Snow in the wrong biomes — two props were misfiled: a snow-laden conifer scattered on temperate grass (renamed snowy_pine) and a frosted bush placed in the desert (renamed frosted_twig_bush). Anything carrying snow or frost is now restricted to the cold biomes.

Marked for the forest work — the 71 static rows in content/tiledata.txt are grouped into 7 labelled categories, with the tree block headed as forest material, so #140 knows where to draw from. This is a readable grouping, not yet a machine-queryable column.

world tour

trees scaled

bones transparency

props batch 2

props batch 3

props batch 4

Whole solution builds 0 warnings; all tests green (7/7 projects). Verified in the client on a fresh DB.

Known, tracked separately (rendering, not content): a yellow seam on the marsh / dry-savanna border, and square-block banding inside a biome where its 4 ground variants meet.

### Second pass: the full prop set, forests, and a reforged world The branch now carries the **whole authored prop set** (66 kinds) rather than the first 13, the trees grow as **forests**, and the world was **reforged four times larger** with clearly separated biomes so it can actually be toured. **World** — regenerated at **256 x 192 = 49,152 tiles** (4x the old map) via `scripts/genmap.py`, with a majority filter that consolidates the noise classification into one contiguous region per biome. Distribution: tundra 21%, northern grassland 15%, desert and marsh 13% each, grass 10%, rocky + mountain 16%, salt plain 6%, savanna 5%, plus the volcanic caldera. The caldera is now constrained inland and nothing is placed within 8 tiles of the border ring, so no region is left clipped by the edge. **Forests** — trees are no longer sprinkled evenly: **32 groves** of mixed species with tight in-grove spacing (7 pine woods in the northern grassland, 6 in tundra, 6 dead woods in savanna, 5 on rocky ground, 7 cactus stands, 1 burnt grove on the volcano). **1,344 props** placed in total. **Scale** — every prop is now sized against the measured human sprite (22x61 px). Trees were previously sized by *width*, which is why they looked stunted; they are now sized by **height in human multiples**: the snowy pine at **4.0x** (5.5 tiles tall), young pine 2.9x, dead trees ~2.8x, cacti 1.7-1.8x. The pines are the only living trees in the set, so they deliberately tower over everything. **Cut-out fixes found by review** - *White between the bones* — hole-filling recovered pale interiors (salt crystal facets) but also filled the gaps **between ribs** with background white. Filling is now enabled per-prop and only for genuinely solid pale bodies; skeletons, the gibbet cage and twiggy bushes keep their see-through gaps. - *Bone scale* — bones were arbitrary; they now derive from the human sprite (human skeleton 1.0x, deer 1.35x, horse 1.6x, bird 0.36x, dragon fossil 2.2x). - *Snow in the wrong biomes* — two props were misfiled: a snow-laden conifer scattered on temperate grass (renamed **`snowy_pine`**) and a frosted bush placed in the desert (renamed **`frosted_twig_bush`**). Anything carrying snow or frost is now restricted to the cold biomes. **Marked for the forest work** — the 71 static rows in `content/tiledata.txt` are grouped into 7 labelled categories, with the tree block headed as forest material, so #140 knows where to draw from. This is a readable grouping, not yet a machine-queryable column. ![world tour](https://git.homelab.devncode.it/attachments/a27ab3f7-42c3-4bd9-8818-f3d7dc4d8374) ![trees scaled](https://git.homelab.devncode.it/attachments/a8af1592-a789-473f-a654-86858a5f472b) ![bones transparency](https://git.homelab.devncode.it/attachments/e71c9bd6-7d41-4365-bc5f-800b1069c2b1) ![props batch 2](https://git.homelab.devncode.it/attachments/2f3e78d6-5598-4cde-aa05-031959c88394) ![props batch 3](https://git.homelab.devncode.it/attachments/cbbaa7f6-465a-470a-8bf6-2cfc09b10682) ![props batch 4](https://git.homelab.devncode.it/attachments/d1bc49e4-2562-42af-a4a9-5ce96da4a958) Whole solution builds **0 warnings**; all tests green (7/7 projects). Verified in the client on a fresh DB. **Known, tracked separately** (rendering, not content): a yellow seam on the marsh / dry-savanna border, and square-block banding *inside* a biome where its 4 ground variants meet.
marco approved these changes 2026-07-25 17:40:25 +02:00
marco left a comment

Approved by the owner — merging per owner decision. (Scope/description notes captured in review; body under-describes the change: 4x world regen + necropolis set + 66 assets vs the stated 13 props.)

Approved by the owner — merging per owner decision. (Scope/description notes captured in review; body under-describes the change: 4x world regen + necropolis set + 66 assets vs the stated 13 props.)
marco merged commit cdc1254c6d into main 2026-07-25 17:40:28 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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
marco/IsoMmo!184
No description provided.