All checks were successful
Deploy Addons / deploy (push) Successful in 14s
- camping: replace cube tent with A-frame slope panels (tent_panel_l/r) + cardinal_direction permutations; vote-skip sleep that mixes player.isSleeping bed sleepers with tent occupants and respects the playersSleepingPercentage gamerule; new weathered-canvas texture. - lobby: walk-through silverlabs:portal_field block (no collision, translucent swirl, cross-plane geo) auto-placed above each portal frame; invisible silverlabs:portal_label entity floats above each portal with the destination world name; transfer detection now scans down through the field to find the destination frame. - postal: regenerate post_office and mailbox block textures so they fill the full block face (brick + POST plaque, full red panel with slot/latch /flag/rivets) instead of small sprites floating on transparent. - dynamite + tow-boat: ship the addons (volumes wired into all four worlds; enabled_packs registers them into Mya's world). - art: build-textures.py extended; build-art-catalog.py added to project. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
112 lines
3.4 KiB
Python
112 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Build a contact sheet of every texture under art/ — each PNG upscaled
|
|
with nearest-neighbour (so pixels stay crisp) and labelled with its
|
|
relative path. Output: art/CATALOG.png
|
|
|
|
Run from repo root:
|
|
python3 scripts/build-art-catalog.py
|
|
"""
|
|
import os
|
|
from pathlib import Path
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
ART = REPO / "art"
|
|
OUT = ART / "CATALOG.png"
|
|
|
|
TILE = 128 # upscaled texture size
|
|
COLS = 6 # tiles per row
|
|
PAD_X = 20 # horizontal padding around each tile
|
|
PAD_Y = 60 # vertical padding (extra room for label below)
|
|
LABEL_PX = 14 # label font size
|
|
BG = (30, 30, 46) # dark background
|
|
FG = (230, 230, 240)
|
|
SECTION_BG = (50, 60, 90)
|
|
|
|
|
|
def load_font(size):
|
|
for cand in (
|
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
|
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",
|
|
"/mnt/c/Windows/Fonts/consola.ttf",
|
|
"/mnt/c/Windows/Fonts/arial.ttf",
|
|
):
|
|
if os.path.exists(cand):
|
|
return ImageFont.truetype(cand, size)
|
|
return ImageFont.load_default()
|
|
|
|
|
|
def collect():
|
|
"""Return {pack_name: [(relative_path, abs_path), ...]} grouped & sorted."""
|
|
groups = {}
|
|
for png in sorted(ART.rglob("*.png")):
|
|
if png.name == "CATALOG.png":
|
|
continue
|
|
rel = png.relative_to(ART)
|
|
pack = rel.parts[0]
|
|
groups.setdefault(pack, []).append((rel, png))
|
|
return groups
|
|
|
|
|
|
def upscale(png_path, size):
|
|
img = Image.open(png_path).convert("RGBA")
|
|
return img.resize((size, size), Image.NEAREST)
|
|
|
|
|
|
def main():
|
|
groups = collect()
|
|
if not groups:
|
|
print("No PNGs found under art/. Nothing to do.")
|
|
return
|
|
|
|
font_label = load_font(LABEL_PX)
|
|
font_section = load_font(LABEL_PX + 8)
|
|
|
|
# Calculate overall canvas size
|
|
section_height = LABEL_PX + 24
|
|
tile_block_h = TILE + PAD_Y
|
|
total_h = 40
|
|
for pack, items in groups.items():
|
|
rows = (len(items) + COLS - 1) // COLS
|
|
total_h += section_height + rows * tile_block_h + 20
|
|
total_w = COLS * (TILE + PAD_X) + PAD_X + 40
|
|
|
|
canvas = Image.new("RGBA", (total_w, total_h), BG)
|
|
draw = ImageDraw.Draw(canvas)
|
|
|
|
y = 20
|
|
for pack, items in groups.items():
|
|
# Section header
|
|
draw.rectangle([20, y, total_w - 20, y + section_height - 4], fill=SECTION_BG)
|
|
draw.text((32, y + 4), pack, font=font_section, fill=FG)
|
|
y += section_height + 6
|
|
|
|
# Tiles
|
|
for i, (rel, abs_path) in enumerate(items):
|
|
col = i % COLS
|
|
row = i // COLS
|
|
x = 20 + PAD_X // 2 + col * (TILE + PAD_X)
|
|
ty = y + row * tile_block_h
|
|
|
|
try:
|
|
tile = upscale(abs_path, TILE)
|
|
canvas.paste(tile, (x, ty), tile)
|
|
except Exception as e:
|
|
draw.rectangle([x, ty, x + TILE, ty + TILE], outline=(200, 80, 80), width=2)
|
|
draw.text((x + 4, ty + 4), f"ERR: {e}", font=font_label, fill=(255, 120, 120))
|
|
|
|
# Label: show subpath + filename below the tile
|
|
label = "/".join(rel.parts[1:]) # drop pack prefix
|
|
draw.text((x, ty + TILE + 4), label, font=font_label, fill=FG)
|
|
|
|
rows = (len(items) + COLS - 1) // COLS
|
|
y += rows * tile_block_h + 20
|
|
|
|
canvas.save(OUT)
|
|
print(f"Wrote {OUT} — {sum(len(v) for v in groups.values())} textures across {len(groups)} packs.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|