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