iOS 타깃을 제거했다. Apple Developer Program 연 $99 와 맥이 필요한데 아이폰은 기존 웹 PWA 로 이미 커버되므로 비용 대비 실익이 없다고 판단했다. commonMain 중심 구조는 그대로라 iosTarget 만 다시 넣으면 복구된다. 멀티·리그전/커스텀 카드에 '준비 중' 배지를 붙였다. 구현되지 않은 모드가 스토어 스크린샷에서 동작하는 것처럼 보이면 Play 의 허위 표시 정책에 걸린다. store/ 에 Play Console 제출 자산을 모았다: 등록정보 문구, 데이터 보안 설문 답안(릴리스 APK 에 INTERNET 권한이 없음을 aapt2 로 확인), 개인정보처리방침, 피처 그래픽 1024x500, 스토어 아이콘 512x512, 폰 4장 + 태블릿 3장 스크린샷.
81 lines
2.3 KiB
Python
81 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Play Console 피처 그래픽(1024x500) 생성.
|
|
|
|
앱 팔레트(NEOBRUTAL)를 그대로 써서 로고 + 테트로미노 악센트를 배치한다.
|
|
가장자리는 스토어에서 잘릴 수 있으므로 핵심 요소는 가운데로 모았다.
|
|
|
|
python3 store/make_feature_graphic.py
|
|
"""
|
|
from pathlib import Path
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
OUT = ROOT / "store" / "feature_graphic.png"
|
|
|
|
W, H = 1024, 500
|
|
BONE = (0xED, 0xE7, 0xDA)
|
|
INK = (0x17, 0x16, 0x1B)
|
|
SAFETY = (0xFF, 0x4E, 0x11)
|
|
SUB = (0x6E, 0x6A, 0x5E)
|
|
PIECES = {
|
|
"I": (0x3E, 0xC1, 0xB6),
|
|
"O": (0xF5, 0xC5, 0x31),
|
|
"T": (0xA7, 0x6B, 0xF2),
|
|
"S": (0x7F, 0xCC, 0x4C),
|
|
"Z": (0xF2, 0x5C, 0x4C),
|
|
"J": (0x4C, 0x7D, 0xF2),
|
|
"L": (0xF2, 0x91, 0x3D),
|
|
}
|
|
|
|
img = Image.new("RGB", (W, H), BONE)
|
|
d = ImageDraw.Draw(img)
|
|
|
|
# 은은한 격자
|
|
for x in range(0, W, 32):
|
|
d.line([(x, 0), (x, H)], fill=(0xE3, 0xDC, 0xCD), width=1)
|
|
for y in range(0, H, 32):
|
|
d.line([(0, y), (W, y)], fill=(0xE3, 0xDC, 0xCD), width=1)
|
|
|
|
|
|
def block(x, y, s, color):
|
|
"""네오브루탈 블록: 오렌지 그림자 + 잉크 테두리."""
|
|
d.rounded_rectangle([x + 5, y + 5, x + s + 5, y + s + 5], radius=6, fill=SAFETY)
|
|
d.rounded_rectangle([x, y, x + s, y + s], radius=6, fill=color, outline=INK, width=3)
|
|
|
|
|
|
# 오른쪽: 쌓인 스택 실루엣
|
|
S = 44
|
|
stack = [
|
|
(0, 0, "I"), (1, 0, "I"), (2, 0, "I"),
|
|
(1, 1, "T"), (2, 1, "L"),
|
|
(0, 2, "J"), (1, 2, "O"), (2, 2, "O"),
|
|
(0, 3, "S"), (1, 3, "Z"), (2, 3, "Z"),
|
|
]
|
|
bx, by = 778, 145
|
|
for cx, cy, p in stack:
|
|
block(bx + cx * (S + 6), by + cy * (S + 6), S, PIECES[p])
|
|
|
|
# 로고
|
|
logo = Image.open(ROOT / "tetrig-logo.png").convert("RGBA")
|
|
lw = 640
|
|
logo = logo.resize((lw, int(logo.height * lw / logo.width)), Image.LANCZOS)
|
|
img.paste(logo, (62, 92), logo)
|
|
|
|
|
|
def font(size, bold=True):
|
|
name = "DejaVuSansMono-Bold.ttf" if bold else "DejaVuSansMono.ttf"
|
|
return ImageFont.truetype(f"/usr/share/fonts/truetype/dejavu/{name}", size)
|
|
|
|
|
|
# 태그라인 바
|
|
tag = "SPRINT · TIME ATTACK · ENDLESS"
|
|
f = font(24)
|
|
tw = d.textlength(tag, font=f)
|
|
tx, ty = 80, 352
|
|
d.rectangle([tx + 6, ty + 6, tx + tw + 36, ty + 48], fill=SAFETY)
|
|
d.rectangle([tx, ty, tx + tw + 30, ty + 42], fill=INK)
|
|
d.text((tx + 15, ty + 9), tag, font=f, fill=BONE)
|
|
|
|
img.save(OUT)
|
|
print(OUT, img.size)
|