84 lines
3.5 KiB
Python
84 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Build compact visual handoff boards for the RSK-001 production package."""
|
|
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
PAGE = ROOT / "docs/design-authority/pages/RSK-001-risk-board"
|
|
APPROVED = PAGE / "approved/v001/master.png"
|
|
STATIC = ROOT / "runtime/assets/entry/rsk_001_risk_board/risk-board-static-master.png"
|
|
ACTOR = ROOT / "runtime/assets/entry/recruit_stickers/pf_b01-512.png"
|
|
BOARD = PAGE / "reconstruction/v001/deconstruction-board.png"
|
|
CONTACT = PAGE / "reconstruction/v001/asset-contact-sheet.png"
|
|
|
|
|
|
def font(size: int):
|
|
for path in [
|
|
"/System/Library/Fonts/Supplemental/Arial Unicode.ttf",
|
|
"/System/Library/Fonts/Supplemental/Arial.ttf",
|
|
]:
|
|
if Path(path).exists():
|
|
return ImageFont.truetype(path, size)
|
|
return ImageFont.load_default()
|
|
|
|
|
|
def fit(image: Image.Image, width: int, height: int) -> Image.Image:
|
|
copy = image.copy()
|
|
copy.thumbnail((width, height), Image.Resampling.LANCZOS)
|
|
canvas = Image.new("RGB", (width, height), "#182a31")
|
|
canvas.paste(copy, ((width - copy.width) // 2, (height - copy.height) // 2))
|
|
return canvas
|
|
|
|
|
|
def deconstruction_board() -> None:
|
|
source = Image.open(APPROVED).convert("RGB")
|
|
canvas = fit(source, 1600, 900)
|
|
draw = ImageDraw.Draw(canvas, "RGBA")
|
|
labels = [
|
|
("WORLD", (0.01, 0.01, 0.98, 0.98), "#4c9baf"),
|
|
("PARTY SNAPSHOT", (0.24, 0.01, 0.74, 0.25), "#d49a3a"),
|
|
("THREE EQUAL OPTIONS", (0.07, 0.28, 0.89, 0.77), "#6c9c59"),
|
|
("COMMAND RAIL", (0.01, 0.82, 0.98, 0.99), "#a65350"),
|
|
]
|
|
title_font = font(26)
|
|
for label, bounds, colour in labels:
|
|
x0, y0, x1, y1 = [int(value * 1600) for value in bounds]
|
|
draw.rectangle((x0, y0, x1, y1), outline=colour, width=5)
|
|
draw.rounded_rectangle((x0 + 12, y0 + 10, x0 + 320, y0 + 48), 8, fill=colour)
|
|
draw.text((x0 + 22, y0 + 16), label, fill="white", font=title_font)
|
|
draw.rectangle((22, 22, 370, 76), fill="#101d27cc", outline="#e7c575", width=2)
|
|
draw.text((38, 34), "RSK-001 LAYER MAP", fill="#f8e7b0", font=font(24))
|
|
BOARD.parent.mkdir(parents=True, exist_ok=True)
|
|
canvas.save(BOARD)
|
|
|
|
|
|
def contact_sheet() -> None:
|
|
tiles = [
|
|
("approved master", Image.open(APPROVED).convert("RGB")),
|
|
("runtime clean master", Image.open(STATIC).convert("RGB")),
|
|
("recruit texture PF-B01", Image.open(ACTOR).convert("RGBA").convert("RGB")),
|
|
]
|
|
width, height = 1500, 920
|
|
canvas = Image.new("RGB", (width, height), "#16252d")
|
|
draw = ImageDraw.Draw(canvas)
|
|
draw.text((36, 28), "RSK-001 ASSET CONTACT SHEET", fill="#f8e7b0", font=font(30))
|
|
tile_w, tile_h = 700, 380
|
|
positions = [(40, 90), (760, 90), (40, 510)]
|
|
for (label, image), (x, y) in zip(tiles, positions):
|
|
draw.rounded_rectangle((x - 8, y - 8, x + tile_w + 8, y + tile_h + 44), 10, fill="#233842", outline="#b78e4c", width=2)
|
|
canvas.paste(fit(image, tile_w, tile_h), (x, y))
|
|
draw.text((x + 14, y + tile_h + 10), label, fill="#f8e7b0", font=font(22))
|
|
draw.text((760, 525), "Runtime policy", fill="#f8e7b0", font=font(24))
|
|
policy = "Static world/frame is reused.\nRecruit identity, labels, values, icons,\nselection and hit areas are engine-owned.\nNo new AI raster asset is required."
|
|
draw.multiline_text((760, 570), policy, fill="#e8eef0", font=font(22), spacing=12)
|
|
CONTACT.parent.mkdir(parents=True, exist_ok=True)
|
|
canvas.save(CONTACT)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
deconstruction_board()
|
|
contact_sheet()
|