Tune large battle map render resolution

This commit is contained in:
2026-07-09 17:49:10 +09:00
parent 6020fcd96e
commit c62ce6fce3
17 changed files with 31 additions and 4 deletions

View File

@@ -11,9 +11,16 @@ The first thirty campaign battles now use the same hand-painted tactical map pip
- Roads, forests, rivers, camps, villages, cliffs, and forts should be recognizable by silhouette and texture, not by high saturation. - Roads, forests, rivers, camps, villages, cliffs, and forts should be recognizable by silhouette and texture, not by high saturation.
- The grid remains subtle and embedded in the paint grade, so it helps targeting without becoming the main visual layer. - The grid remains subtle and embedded in the paint grade, so it helps targeting without becoming the main visual layer.
## Resolution Policy
- Battles 1-25 keep the original 224px hand-painted tile target.
- Large maps starting at battle 26 use a 192px tile target through `LARGE_MAP_TILE_SIZE` in the generator.
- Re-evaluate the tile target before a generated map's longest edge exceeds roughly 16,384px at 192px per tile.
- Use `--tile-size` only for controlled comparisons; commit the selected production size in the map config.
## Generator ## Generator
`scripts/generate-handpaint-map-sample.py` reads terrain and unit positions from `src/game/data/scenario.ts`, then outputs a WebP map and documentation previews. `scripts/generate-handpaint-map-sample.py` reads terrain and unit positions from `src/game/data/scenario.ts`, then outputs a WebP map and documentation previews. Map configs can set `tile_size`; otherwise the default is 224px.
Example: Example:
@@ -49,6 +56,12 @@ python scripts/generate-handpaint-map-sample.py --map twenty-ninth --webp-qualit
python scripts/generate-handpaint-map-sample.py --map thirtieth --webp-quality 90 python scripts/generate-handpaint-map-sample.py --map thirtieth --webp-quality 90
``` ```
Comparison example:
```powershell
python scripts/generate-handpaint-map-sample.py --map thirtieth --tile-size 192 --out tmp\thirtieth-battle-map-192-test.webp --comparison tmp\thirtieth-battle-map-192-test-before-after.png --preview tmp\thirtieth-battle-map-192-test-preview.png --webp-quality 90
```
## Current Assets ## Current Assets
- `src/assets/images/battle/first-battle-map.webp` - `src/assets/images/battle/first-battle-map.webp`

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -15,7 +15,9 @@ SCENARIO_FILE = ROOT / "src" / "game" / "data" / "scenario.ts"
BATTLE_IMAGE_DIR = ROOT / "src" / "assets" / "images" / "battle" BATTLE_IMAGE_DIR = ROOT / "src" / "assets" / "images" / "battle"
DOCS_DIR = ROOT / "docs" DOCS_DIR = ROOT / "docs"
TILE = 224 DEFAULT_TILE_SIZE = 224
LARGE_MAP_TILE_SIZE = 192
TILE = DEFAULT_TILE_SIZE
RNG = random.Random(240704) RNG = random.Random(240704)
MAP_CONFIGS = { MAP_CONFIGS = {
@@ -252,6 +254,7 @@ MAP_CONFIGS = {
"out": BATTLE_IMAGE_DIR / "twenty-sixth-battle-map.webp", "out": BATTLE_IMAGE_DIR / "twenty-sixth-battle-map.webp",
"before": BATTLE_IMAGE_DIR / "twenty-sixth-battle-map.svg", "before": BATTLE_IMAGE_DIR / "twenty-sixth-battle-map.svg",
"seed": 240954, "seed": 240954,
"tile_size": LARGE_MAP_TILE_SIZE,
}, },
"twenty-seventh": { "twenty-seventh": {
"slug": "twenty-seventh-battle-map", "slug": "twenty-seventh-battle-map",
@@ -261,6 +264,7 @@ MAP_CONFIGS = {
"out": BATTLE_IMAGE_DIR / "twenty-seventh-battle-map.webp", "out": BATTLE_IMAGE_DIR / "twenty-seventh-battle-map.webp",
"before": BATTLE_IMAGE_DIR / "twenty-seventh-battle-map.svg", "before": BATTLE_IMAGE_DIR / "twenty-seventh-battle-map.svg",
"seed": 240964, "seed": 240964,
"tile_size": LARGE_MAP_TILE_SIZE,
}, },
"twenty-eighth": { "twenty-eighth": {
"slug": "twenty-eighth-battle-map", "slug": "twenty-eighth-battle-map",
@@ -270,6 +274,7 @@ MAP_CONFIGS = {
"out": BATTLE_IMAGE_DIR / "twenty-eighth-battle-map.webp", "out": BATTLE_IMAGE_DIR / "twenty-eighth-battle-map.webp",
"before": BATTLE_IMAGE_DIR / "twenty-eighth-battle-map.svg", "before": BATTLE_IMAGE_DIR / "twenty-eighth-battle-map.svg",
"seed": 240974, "seed": 240974,
"tile_size": LARGE_MAP_TILE_SIZE,
}, },
"twenty-ninth": { "twenty-ninth": {
"slug": "twenty-ninth-battle-map", "slug": "twenty-ninth-battle-map",
@@ -279,6 +284,7 @@ MAP_CONFIGS = {
"out": BATTLE_IMAGE_DIR / "twenty-ninth-battle-map.webp", "out": BATTLE_IMAGE_DIR / "twenty-ninth-battle-map.webp",
"before": BATTLE_IMAGE_DIR / "twenty-ninth-battle-map.svg", "before": BATTLE_IMAGE_DIR / "twenty-ninth-battle-map.svg",
"seed": 240984, "seed": 240984,
"tile_size": LARGE_MAP_TILE_SIZE,
}, },
"thirtieth": { "thirtieth": {
"slug": "thirtieth-battle-map", "slug": "thirtieth-battle-map",
@@ -288,6 +294,7 @@ MAP_CONFIGS = {
"out": BATTLE_IMAGE_DIR / "thirtieth-battle-map.webp", "out": BATTLE_IMAGE_DIR / "thirtieth-battle-map.webp",
"before": BATTLE_IMAGE_DIR / "thirtieth-battle-map.svg", "before": BATTLE_IMAGE_DIR / "thirtieth-battle-map.svg",
"seed": 240994, "seed": 240994,
"tile_size": LARGE_MAP_TILE_SIZE,
}, },
} }
@@ -846,8 +853,9 @@ def add_subtle_grid_and_grade(canvas: Image.Image, terrain: list[list[str]]) ->
def build_map(config: dict[str, object]) -> Image.Image: def build_map(config: dict[str, object]) -> Image.Image:
global RNG global RNG, TILE
RNG = random.Random(int(config["seed"])) RNG = random.Random(int(config["seed"]))
TILE = int(config.get("tile_size", DEFAULT_TILE_SIZE))
terrain = parse_battle_terrain(str(config["terrain_export"])) terrain = parse_battle_terrain(str(config["terrain_export"]))
ally_positions_export = config["ally_positions_export"] ally_positions_export = config["ally_positions_export"]
units = parse_battle_units(str(config["units_export"]), None if ally_positions_export is None else str(ally_positions_export)) units = parse_battle_units(str(config["units_export"]), None if ally_positions_export is None else str(ally_positions_export))
@@ -920,10 +928,15 @@ def main() -> None:
parser.add_argument("--before", type=Path) parser.add_argument("--before", type=Path)
parser.add_argument("--comparison", type=Path) parser.add_argument("--comparison", type=Path)
parser.add_argument("--preview", type=Path) parser.add_argument("--preview", type=Path)
parser.add_argument("--tile-size", type=int)
parser.add_argument("--webp-quality", type=int, default=90) parser.add_argument("--webp-quality", type=int, default=90)
args = parser.parse_args() args = parser.parse_args()
config = MAP_CONFIGS[args.map] config = dict(MAP_CONFIGS[args.map])
if args.tile_size is not None:
if args.tile_size < 160:
raise ValueError("--tile-size must be 160 or greater")
config["tile_size"] = args.tile_size
out_path = args.out or Path(config["out"]) out_path = args.out or Path(config["out"])
before_path = args.before or Path(config["before"]) before_path = args.before or Path(config["before"])
comparison_path = args.comparison or (DOCS_DIR / f"{config['slug']}-handpaint-before-after.png") comparison_path = args.comparison or (DOCS_DIR / f"{config['slug']}-handpaint-before-after.png")
@@ -950,6 +963,7 @@ def main() -> None:
print( print(
{ {
"map": args.map, "map": args.map,
"tile_size": TILE,
"out": str(out_path), "out": str(out_path),
"size": after.size, "size": after.size,
"comparison": str(comparison_path), "comparison": str(comparison_path),

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 MiB

After

Width:  |  Height:  |  Size: 5.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 MiB

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 MiB

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 MiB

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 MiB

After

Width:  |  Height:  |  Size: 2.7 MiB