Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion art/stages/rusty-creek/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ The same place before the anomaly (clean campus architecture, nature layers iden
| 06 | Near rails | [png](images/06-near-rails-left.png) | [png](images/06-near-rails-center.png) | = left | Foreground 1.1, never collides |
| 07 | Near foliage | [png](images/07-foliage-left.png) | [png](images/07-foliage-center.png) | [png](images/07-foliage-right.png) | Foreground 1.15 |

"= left": shared scenery repeats on the right chunk and is stored once (alias in [media-sources.json](media-sources.json)). The clean architecture plates are [left](images/clean-architecture-left.png) and [centre](images/clean-architecture-center.png); right = left.
"= left": shared scenery repeats on the right chunk and is stored once (alias in [media-sources.json](media-sources.json)). In the game, layers 01, 06 and 07 come from one region-wide plate each ([layers/](layers/), `python scripts/depth_layers.py region art/stages/rusty-creek`, #150): per chunk they overlapped at 0.2 and left gaps at 1.1 and 1.15. The creek as the game draws it: [parallax.png](previews/parallax.png). The clean architecture plates are [left](images/clean-architecture-left.png) and [centre](images/clean-architecture-center.png); right = left.

## Route

Expand Down
98 changes: 83 additions & 15 deletions art/stages/rusty-creek/export.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,92 @@
{
"note": "Draw order follows creek_layers.py compose(): the plates are soft and blend, so the water is drawn last. z names the docs/04 role; loaders draw in list order.",
"note": "Draw order follows creek_layers.py compose(): the plates are soft and blend, so the water is drawn last. z names the docs/04 role; loaders draw in list order. 01-distance (0.2), 06-near-rails (1.1) and 07-foliage (1.15) are region-wide plates in chunk-wide tiles (depth_layers.py region, #150): per chunk they overlapped or left gaps.",
"chunks": {
"rc-0-0": {"x": 0, "y": 0, "name": "left"},
"rc-1-0": {"x": 1, "y": 0, "name": "center"},
"rc-2-0": {"x": 2, "y": 0, "name": "right"}
"rc-0-0": {
"x": 0,
"y": 0,
"name": "left"
},
"rc-1-0": {
"x": 1,
"y": 0,
"name": "center"
},
"rc-2-0": {
"x": 2,
"y": 0,
"name": "right"
}
},
"layers": {
"01-distance": {"file": "images/01-distance-{name}.png", "z": 1, "scroll": 0.2},
"03-bank": {"file": "images/03-bank-{name}.png", "z": 2, "scroll": 1.0},
"02-supports": {"file": "images/02-supports-{name}.png", "z": 3, "scroll": 1.0},
"clean-architecture": {"file": "images/clean-architecture-{name}.png", "z": 3, "scroll": 1.0},
"05-traversal": {"file": "images/05-traversal-{name}.png", "z": 5, "scroll": 1.0},
"06-near-rails": {"file": "images/06-near-rails-{name}.png", "z": 6, "scroll": 1.1},
"07-foliage": {"file": "images/07-foliage-{name}.png", "z": 7, "scroll": 1.15},
"04-water": {"file": "images/04-water-{name}.png", "z": 4, "scroll": 1.0}
"01-distance": {
"file": "layers/rusty-creek.01-distance.{tile}.png",
"z": 1,
"scroll": 0.2,
"region": true,
"rest": "art/stages/rusty-creek/images/01-distance-{name}.png"
},
"03-bank": {
"file": "images/03-bank-{name}.png",
"z": 2,
"scroll": 1.0
},
"02-supports": {
"file": "images/02-supports-{name}.png",
"z": 3,
"scroll": 1.0
},
"clean-architecture": {
"file": "images/clean-architecture-{name}.png",
"z": 3,
"scroll": 1.0
},
"05-traversal": {
"file": "images/05-traversal-{name}.png",
"z": 5,
"scroll": 1.0
},
"06-near-rails": {
"file": "layers/rusty-creek.06-near-rails.{tile}.png",
"z": 6,
"scroll": 1.1,
"region": true,
"rest": "art/stages/rusty-creek/images/06-near-rails-{name}.png"
},
"07-foliage": {
"file": "layers/rusty-creek.07-foliage.{tile}.png",
"z": 7,
"scroll": 1.15,
"region": true,
"rest": "art/stages/rusty-creek/images/07-foliage-{name}.png"
},
"04-water": {
"file": "images/04-water-{name}.png",
"z": 4,
"scroll": 1.0
}
},
"states": {
"anomaly": ["01-distance", "03-bank", "02-supports", "05-traversal", "06-near-rails", "07-foliage", "04-water"],
"clean": ["01-distance", "03-bank", "clean-architecture", "06-near-rails", "07-foliage", "04-water"]
"anomaly": [
"01-distance",
"03-bank",
"02-supports",
"05-traversal",
"06-near-rails",
"07-foliage",
"04-water"
],
"clean": [
"01-distance",
"03-bank",
"clean-architecture",
"06-near-rails",
"07-foliage",
"04-water"
]
},
"composed": {
"anomaly": "images/after-{name}.png",
"clean": "images/before-{name}.png"
},
"composed": {"anomaly": "images/after-{name}.png", "clean": "images/before-{name}.png"},
"aliases": "media-sources.json"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/stages/rusty-creek/previews/parallax.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/09-ART-PIPELINE.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ flowchart LR

- **The key only says which band, never which pixel.** It drifts a few pixels at fine edges, so near the sky the real pixel decides: open sky is ≈ (40–60, 120–140, 240) and hazy far treetops ≈ (80, 120, 180), so "sky" means blue above 200. Path, water and foreground keep their exact rectangles and colour rules, which run after the masks and win.
- **Fills never change the picture at rest.** A fill is kept only under the nearer layers, and the layer's own pixels are copied from the art, so `--verify` still rebuilds the chunk exactly. The camera only ever reveals painted scenery.
- **Several chunks: one plate per slow layer for the whole region.** Per chunk, plates at scroll *s* < 1 overlap by 2160 × (1 − *s*) and cut each other off with hard vertical edges; at *s* > 1 (the foreground) they spread apart and leave gaps. `depth_layers.py region` quilts each layer marked `"region": true` in `export.json` from the chunks' own plates (`"rest"`): chunk *i* at *i* × 2160 × *s*, each next plate taking over along a min-error path in a 192 px band and only where it has pixels; a foreground gap is filled with the earlier plate's edge mirrored. The first chunk carries the plate, so it lands at x = 0 under any placement rule, and `--verify` still rebuilds every chunk at rest from its own plates. The Hidden Garden's mid plate is 6992 px wide (8192 is the common WebGL limit).
- **Several chunks: one plate per slow layer for the whole region.** Per chunk, plates at scroll *s* < 1 overlap by 2160 × (1 − *s*) and cut each other off with hard vertical edges; at *s* > 1 (the foreground) they spread apart and leave gaps. `depth_layers.py region` quilts each layer marked `"region": true` in `export.json` from the chunks' own plates (`"rest"`): chunk *i* at *i* × 2160 × *s*, each next plate taking over along a min-error path in a 192 px band and only where it has pixels; a foreground gap is filled with the earlier plate's edge mirrored. The first chunk carries the plate, so it lands at x = 0 under any placement rule, and `--verify` still rebuilds every chunk at rest from its own plates. The Hidden Garden's mid plate is 6992 px wide, in four 2160 px tiles. Rusty Creek's distance (0.2), rails (1.1) and foliage (1.15) are quilted the same way ([#150](https://github.com/THD-AI/WinCS/issues/150)); shared plates ("= left") resolve through its aliases. `python scripts/compare.py parallax art/stages/<region>` shows any region as the game draws it.

## Prompting lessons (23 Oct, all runs)

Expand Down
9 changes: 8 additions & 1 deletion scripts/depth_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,11 +406,17 @@ def region_layers(region: Path) -> list[Path]:
"""Quilt every layer marked "region" in export.json from its chunks' "rest" plates into one plate each."""
export = json.loads((region / "export.json").read_text(encoding="utf-8"))
chunks = sorted(export["chunks"].items(), key=lambda kv: kv[1]["x"])
aliases = json.loads((region / export["aliases"]).read_text(encoding="utf-8")).get("aliases", {}) if export.get("aliases") else {}

def rest(layer: dict, chunk_id: str, chunk: dict) -> Path:
"""A chunk's own plate for a region layer; a shared plate (an alias, "= left") resolves to its file."""
path = ROOT / layer["rest"].format(name=chunk.get("name", chunk_id))
return path if path.exists() or path.name not in aliases else path.parent / aliases[path.name]
written = []
for layer_id, layer in export["layers"].items():
if not layer.get("region"):
continue
plates = [Image.open(ROOT / layer["rest"].format(name=c)).convert("RGBA") for c, _ in chunks]
plates = [Image.open(rest(layer, c, chunk)).convert("RGBA") for c, chunk in chunks]
plate = region_plate(plates, layer["scroll"], carry=layer.get("carry", False))
# A preview-free game plate: 256 colours keep it small; --verify checks the chunks' own plates ("rest").
alpha = plate.getchannel("A")
Expand All @@ -420,6 +426,7 @@ def region_layers(region: Path) -> list[Path]:
# factor then shows exactly the plate's column the camera is over, with any loader that places
# layers at their chunk's origin - and no file is wider than a chunk.
w, n = plates[0].width, len(plates)
(region / "layers").mkdir(exist_ok=True)
for old in (region / "layers").glob(f"{region.name}.{layer_id}.*.png"):
old.unlink()
for j in range(min(n, -(-plate.width // w))):
Expand Down
8 changes: 7 additions & 1 deletion scripts/export_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ def verify(region: Path, out: Path) -> list[str]:

config = json.loads((region / "export.json").read_text(encoding="utf-8"))
stage = json.loads((out / region.name / "stage.json").read_text(encoding="utf-8"))
aliases = json.loads((region / config["aliases"]).read_text(encoding="utf-8")).get("aliases", {}) if config.get("aliases") else {}

def rest(pattern: str, name: str) -> Path:
path = ROOT / pattern.format(name=name)
return path if path.exists() or path.name not in aliases else path.parent / aliases[path.name]

report = []
for chunk in stage["chunks"]:
name = config["chunks"][chunk["id"]].get("name", chunk["id"])
Expand All @@ -124,7 +130,7 @@ def verify(region: Path, out: Path) -> list[str]:
if not pattern:
continue
exported = {layer["id"]: out / region.name / layer["file"] for layer in content["layers"]}
rests = {lid: ROOT / L["rest"].format(name=name) for lid, L in config["layers"].items() if L.get("region")}
rests = {lid: rest(L["rest"], name) for lid, L in config["layers"].items() if L.get("region")}
if any(not path.exists() for path in rests.values()):
report.append(f"{chunk['id']}.{state} (not checked: its region plates' sources are not in tmp/)")
continue
Expand Down
Loading