summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 09:21:24 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 09:21:24 +0800
commit590f3d8d5cc031c0909241b329ad7f7f18035991 (patch)
tree40b158de9188a1039d86ad0429cf706b4ac60478 /scripts
parent383ed44d22c318a44e7f54a652cd0f825f3962d7 (diff)
downloadliving-village-590f3d8d5cc031c0909241b329ad7f7f18035991.tar.gz
feat(desktop): P26 民居立面第二变体(挑檐/木格栅窗/院门)沿河沿路交替
Diffstat (limited to 'scripts')
-rw-r--r--scripts/make-jiangnan-art.py65
1 files changed, 62 insertions, 3 deletions
diff --git a/scripts/make-jiangnan-art.py b/scripts/make-jiangnan-art.py
index 9abb4b8..54805ab 100644
--- a/scripts/make-jiangnan-art.py
+++ b/scripts/make-jiangnan-art.py
@@ -2,7 +2,7 @@
"""Deterministic pixel-art atlases for LivingVillage.Desktop.
Generates three RGBA PNGs into src/LivingVillage.Desktop/Assets:
- jiangnan-world.png 800x32 (25 ground/prop tiles, 32px each)
+ jiangnan-world.png 992x32 (31 ground/prop tiles, 32px each)
jiangnan-characters.png 3840x48 (5 variants x 4 directions x 6 frames, 32x48 cells)
jiangnan-interior.png 392x96 (variable-size bottom-aligned interior cells)
@@ -99,7 +99,7 @@ def verify_png(path, expected_w, expected_h):
def build_world_atlas():
- c = Canvas(896, 32)
+ c = Canvas(992, 32)
tile = 32
def slot(index):
@@ -547,6 +547,65 @@ def build_world_atlas():
c.rect(x0 + 3, 23, 26, 6, (83, 52, 39, 255))
c.outline(x0, 0, 32, 32)
+ # --- P26 house facade variant B: projecting eave, lattice window, courtyard gate.
+ # Same baked-atlas pipeline as every other tile; the renderer only blits these cells.
+
+ # slot(28) 屋檐挑出 (projecting eave): tiled roof band over an exposed wooden lip.
+ x0 = slot(28)
+ c.rect(x0, 0, 32, 13, roof_dark)
+ for x in range(0, 32, 8):
+ c.rect(x0 + x, 0, 1, 13, roof)
+ for x in range(4, 32, 8):
+ c.rect(x0 + x, 0, 1, 13, roof)
+ c.rect(x0, 2, 32, 1, roof_light)
+ c.rect(x0, 12, 32, 1, roof)
+ c.rect(x0, 13, 32, 3, wood)
+ c.rect(x0, 13, 32, 1, wood_light)
+ c.rect(x0, 15, 32, 1, wood_dark)
+ for rx in (3, 10, 17, 24):
+ c.rect(x0 + rx, 13, 2, 5, wood_dark)
+ c.rect(x0, 18, 32, 4, (23, 31, 34, 80))
+
+ # slot(29) 木格栅窗 (lattice window): wooden posts + fine grid muntins.
+ x0 = slot(29)
+ c.rect(x0, 0, 32, 32, wall)
+ c.rect(x0, 0, 32, 3, wood)
+ c.rect(x0, 0, 32, 1, wood_light)
+ c.rect(x0, 3, 32, 1, wood_dark)
+ for post_x in (0, 29):
+ c.rect(x0 + post_x, 0, 3, 32, wood)
+ c.rect(x0 + post_x, 0, 1, 32, wood_light)
+ c.rect(x0 + post_x + 2, 0, 1, 32, wood_dark)
+ c.rect(x0 + 6, 7, 20, 18, (94, 66, 40, 255))
+ c.rect(x0 + 8, 9, 16, 14, (61, 45, 49, 255))
+ for lx in (12, 16, 20):
+ c.rect(x0 + lx, 9, 1, 14, wall_seam)
+ for ly in (14, 18):
+ c.rect(x0 + 8, ly, 16, 1, wall_seam)
+ c.rect(x0 + 6, 7, 20, 1, wood_light)
+ c.rect(x0 + 3, 28, 26, 4, (128, 128, 126, 255))
+ c.rect(x0 + 3, 28, 26, 1, (150, 150, 146, 255))
+
+ # slot(30) 院门 (courtyard gate): tiled lintel cap, double doors, brass rings.
+ x0 = slot(30)
+ c.rect(x0, 0, 32, 32, wall)
+ c.rect(x0, 0, 32, 3, wood)
+ c.rect(x0, 0, 32, 1, wood_light)
+ c.rect(x0, 3, 32, 1, wood_dark)
+ c.rect(x0 + 3, 4, 26, 4, roof_dark)
+ c.rect(x0 + 3, 4, 26, 1, roof_light)
+ c.rect(x0 + 1, 8, 30, 2, roof)
+ c.rect(x0 + 1, 9, 30, 1, roof_dark)
+ c.rect(x0 + 5, 10, 22, 18, (94, 66, 40, 255))
+ c.rect(x0 + 7, 12, 18, 16, wood)
+ c.rect(x0 + 7, 12, 18, 1, wood_light)
+ c.rect(x0 + 15, 12, 2, 16, wood_dark)
+ c.rect(x0 + 9, 15, 5, 4, wood_dark)
+ c.rect(x0 + 18, 15, 5, 4, wood_dark)
+ c.rect(x0 + 13, 20, 2, 2, (196, 158, 74, 255))
+ c.rect(x0 + 17, 20, 2, 2, (196, 158, 74, 255))
+ c.rect(x0 + 6, 28, 20, 3, (83, 52, 39, 255))
+
return c
@@ -884,7 +943,7 @@ def build_interior_atlas():
def main():
ASSET_DIR.mkdir(parents=True, exist_ok=True)
targets = [
- ("jiangnan-world.png", build_world_atlas(), 896, 32),
+ ("jiangnan-world.png", build_world_atlas(), 992, 32),
("jiangnan-characters.png", build_character_atlas(), 3840, 48),
("jiangnan-interior.png", build_interior_atlas(), 392, 96),
]