document current world and chunk semantics
This commit is contained in:
parent
5a9723440c
commit
aea2c9d56b
1 changed files with 186 additions and 0 deletions
186
docs/refactor/world-and-chunk-semantics.md
Normal file
186
docs/refactor/world-and-chunk-semantics.md
Normal file
|
|
@ -0,0 +1,186 @@
|
||||||
|
# World And Chunk Semantics
|
||||||
|
|
||||||
|
This document describes the **current** `WorldShaper` world/chunk behavior as of Arc 1.
|
||||||
|
|
||||||
|
It is a compatibility and refactor aid, not an endorsement of the long-term model.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
These notes summarize the behavior currently implemented in:
|
||||||
|
|
||||||
|
- `src/worldChunking.ts`
|
||||||
|
- `src/components/worldshaperShared.ts`
|
||||||
|
- regression tests in:
|
||||||
|
- `src/worldChunking.test.ts`
|
||||||
|
- `src/components/worldshaperShared.test.ts`
|
||||||
|
|
||||||
|
## Coordinate Model
|
||||||
|
|
||||||
|
### Chunk Dimensions
|
||||||
|
|
||||||
|
- chunk width and height are normalized with `normalizeChunkDimension`
|
||||||
|
- values are floored to integers
|
||||||
|
- invalid values fall back to `DEFAULT_WORLD_CHUNK_SIZE`
|
||||||
|
- normalized dimensions are clamped to a minimum of `1`
|
||||||
|
|
||||||
|
### World To Chunk Coordinates
|
||||||
|
|
||||||
|
- chunk coordinates use floor division
|
||||||
|
- this applies on both positive and negative world coordinates
|
||||||
|
- examples with chunk size `32`:
|
||||||
|
- `0 -> chunk 0`
|
||||||
|
- `31 -> chunk 0`
|
||||||
|
- `32 -> chunk 1`
|
||||||
|
- `-1 -> chunk -1`
|
||||||
|
- `-33 -> chunk -2`
|
||||||
|
|
||||||
|
This means negative coordinates behave as mathematical grid cells, not truncation toward zero.
|
||||||
|
|
||||||
|
### World To Local Coordinates
|
||||||
|
|
||||||
|
- local coordinates are derived from the resolved chunk coordinate
|
||||||
|
- formula: `world - (chunk * chunkSize)`
|
||||||
|
- result stays in the half-open range `[0, chunkSize)`
|
||||||
|
- examples with chunk size `32`:
|
||||||
|
- `31 -> local 31`
|
||||||
|
- `32 -> local 0`
|
||||||
|
- `-1 -> local 31`
|
||||||
|
- `-33 -> local 31`
|
||||||
|
|
||||||
|
### Local To World Coordinates
|
||||||
|
|
||||||
|
- formula: `(chunkCoord * chunkSize) + localCoord`
|
||||||
|
- examples with chunk size `32`:
|
||||||
|
- `chunk -2, local 31 -> world -33`
|
||||||
|
|
||||||
|
### Address Resolution
|
||||||
|
|
||||||
|
`resolveWorldChunkAddress` returns:
|
||||||
|
|
||||||
|
- `chunkX`
|
||||||
|
- `chunkY`
|
||||||
|
- `localX`
|
||||||
|
- `localY`
|
||||||
|
- `chunkKey` in `x:y` form
|
||||||
|
- `fileName` in `x_y.json` form
|
||||||
|
|
||||||
|
## Chunk Identity And Storage
|
||||||
|
|
||||||
|
- chunk keys use `buildChunkKey(chunkX, chunkY)`
|
||||||
|
- chunk filenames use `buildChunkFileName(chunkX, chunkY)`
|
||||||
|
- filenames preserve negative signs, for example `-3_4.json`
|
||||||
|
|
||||||
|
## Empty Chunk Defaults
|
||||||
|
|
||||||
|
`createEmptyChunk` currently creates:
|
||||||
|
|
||||||
|
- schema version `1`
|
||||||
|
- top-level `backgroundTileId`
|
||||||
|
- `roomLayers[0]` filled with `.` characters
|
||||||
|
- `roomLayers[1]` filled with spaces
|
||||||
|
- empty `heightLayers`
|
||||||
|
- empty `instances`
|
||||||
|
|
||||||
|
This establishes the current meaning that:
|
||||||
|
|
||||||
|
- `.` in layer `0` is the default empty background cell encoding
|
||||||
|
- spaces in non-background layers represent empty overlay cells
|
||||||
|
|
||||||
|
## Background Tile Behavior
|
||||||
|
|
||||||
|
`getMapBackgroundTileId` currently resolves background tiles in this order:
|
||||||
|
|
||||||
|
1. top-level `backgroundTileId`
|
||||||
|
2. legacy nested `tiles.backgroundTileId`
|
||||||
|
3. empty string fallback
|
||||||
|
|
||||||
|
Arc 1 should treat the nested `tiles.backgroundTileId` shape as compatibility baggage.
|
||||||
|
|
||||||
|
## Room Layer Semantics
|
||||||
|
|
||||||
|
`parseRoomLayers` currently does the following:
|
||||||
|
|
||||||
|
- parses `record.roomLayers` if present
|
||||||
|
- ignores malformed entries
|
||||||
|
- requires a numeric `layer`
|
||||||
|
- sorts output by ascending `layer`
|
||||||
|
- normalizes row sizes to map bounds
|
||||||
|
- uses `.` fill for layer `0`
|
||||||
|
- uses space fill for non-zero layers
|
||||||
|
- filters blank `instanceIds`
|
||||||
|
|
||||||
|
If no explicit layer `0` exists:
|
||||||
|
|
||||||
|
- a synthetic layer `0` is created from top-level `record.rows`
|
||||||
|
|
||||||
|
If there are no usable layers at all:
|
||||||
|
|
||||||
|
- a single synthetic layer `0` is returned from top-level `record.rows`
|
||||||
|
|
||||||
|
### Current `zIndex` Behavior
|
||||||
|
|
||||||
|
- layer `0` always gets `zIndex: 0`
|
||||||
|
- non-zero layers preserve provided `zIndex` if present
|
||||||
|
- otherwise non-zero layers default to `0`
|
||||||
|
- non-zero `zIndex` values are clamped into `[0, 5]`
|
||||||
|
|
||||||
|
This is an important current behavior to preserve during Arc 1, but it looks at least partly accidental because non-zero layers do **not** derive `zIndex` from layer number.
|
||||||
|
|
||||||
|
## Height Patch Semantics
|
||||||
|
|
||||||
|
`parseHeightLayers` currently treats height patches as sparse row-based overlays.
|
||||||
|
|
||||||
|
### Input Interpretation
|
||||||
|
|
||||||
|
- `rows` are string arrays
|
||||||
|
- `.` is interpreted as empty space
|
||||||
|
- empty margins are trimmed away
|
||||||
|
- patches are clipped to map bounds
|
||||||
|
|
||||||
|
### Normalization Rules
|
||||||
|
|
||||||
|
- duplicate patch ids are dropped after the first occurrence
|
||||||
|
- `z` is clamped to a minimum of `1`
|
||||||
|
- `x` and `y` are floored to integers
|
||||||
|
- rows completely outside bounds become empty
|
||||||
|
- leading/trailing empty rows are removed
|
||||||
|
- leading/trailing empty columns are removed by cropping to occupied content
|
||||||
|
- trailing whitespace inside retained rows is stripped
|
||||||
|
|
||||||
|
### Resulting Meaning
|
||||||
|
|
||||||
|
The current height patch encoding behaves more like a cropped sparse stamp than a fixed-size tile layer.
|
||||||
|
|
||||||
|
That is useful to document now because any future redesign needs to decide whether this sparse behavior is intentional or just a side effect of the current editor implementation.
|
||||||
|
|
||||||
|
## Chunk Instance Semantics
|
||||||
|
|
||||||
|
Arc 1 has not redesigned chunk instances yet, but the current shape is:
|
||||||
|
|
||||||
|
- `id`
|
||||||
|
- optional `templateId`
|
||||||
|
- `layer`
|
||||||
|
- `x`
|
||||||
|
- `y`
|
||||||
|
- `record`
|
||||||
|
|
||||||
|
The semantics of `templateId + record` are still under-specified and should be treated as a known redesign target for later arcs.
|
||||||
|
|
||||||
|
## Likely Accidental Or Under-Specified Behavior
|
||||||
|
|
||||||
|
These behaviors are currently preserved, but should not be treated as settled architecture:
|
||||||
|
|
||||||
|
- non-background layers default to `zIndex: 0` instead of deriving depth from layer number
|
||||||
|
- duplicate height patch ids are silently dropped after the first occurrence
|
||||||
|
- top-level `rows` still act as a fallback source for synthesized background layers
|
||||||
|
- nested `tiles.backgroundTileId` is still accepted
|
||||||
|
- layer `0` empties use `.` while non-zero layer empties use spaces
|
||||||
|
- chunk instance meaning is still implicit rather than explicitly modeled
|
||||||
|
|
||||||
|
## Arc 2+ Questions
|
||||||
|
|
||||||
|
- Should negative-coordinate behavior remain floor-based, or should world addressing be modeled differently at a higher level?
|
||||||
|
- Should layer depth be derived from `layer`, `zIndex`, or a clearer world-space model?
|
||||||
|
- Should height data remain sparse text rows, or become a more explicit numeric structure?
|
||||||
|
- Should background tiles stay top-level, or belong to a clearer terrain/base-layer contract?
|
||||||
|
- What is the correct long-term meaning of chunk instances, templates, and per-instance overrides?
|
||||||
Loading…
Add table
Add a link
Reference in a new issue