BurningTimesAi/공유/기획/FirstRising/리뉴얼/tools/make_mockups.py

88 lines
5.6 KiB
Python

# FirstRising 리뉴얼 기획서용 목업 — (1) 작업표시줄 상주 컨셉 합성 (2) 디아블로식 아이템 툴팁 예시
# 입력: 시스템분석\img\capture_01_wave_combat.jpg (FirstRising 실캡처)
# 출력: 리뉴얼\img\mock_taskbar_concept.png · mock_item_tooltip.png
import os
from PIL import Image, ImageDraw, ImageFont, ImageFilter
BASE = r"E:\BurningTimes\공유\기획\FirstRising"
OUT = os.path.join(BASE, "리뉴얼", "img"); os.makedirs(OUT, exist_ok=True)
F = lambda s, b=False: ImageFont.truetype(r"C:\Windows\Fonts\malgunbd.ttf" if b else r"C:\Windows\Fonts\malgun.ttf", s)
# ---------- (1) 작업표시줄 컨셉 ----------
W, H = 1920, 1080
bg = Image.new("RGB", (W, H), (14, 17, 25))
d = ImageDraw.Draw(bg)
for y in range(H): # 세로 그라데이션 바탕화면
t = y / H
d.line([(0, y), (W, y)], fill=(int(28 - 12 * t), int(36 - 16 * t), int(56 - 28 * t)))
# 업무 창(예시)
def window(x0, y0, x1, y1, title):
d.rectangle([x0 + 8, y0 + 10, x1 + 8, y1 + 10], fill=(8, 10, 14))
d.rectangle([x0, y0, x1, y1], fill=(244, 245, 247))
d.rectangle([x0, y0, x1, y0 + 40], fill=(222, 225, 231))
d.text((x0 + 16, y0 + 8), title, font=F(20), fill=(60, 64, 72))
for i, w in enumerate((0.82, 0.9, 0.7, 0.86, 0.6, 0.88, 0.75, 0.5)):
yy = y0 + 80 + i * 44
if yy > y1 - 40: break
d.rounded_rectangle([x0 + 40, yy, x0 + 40 + int((x1 - x0 - 80) * w), yy + 16], 6, fill=(205, 209, 216))
window(170, 70, 1270, 700, "업무 문서.docx — 예시")
window(1330, 140, 1830, 560, "메신저 — 예시")
# 전투 스트립(FirstRising 실캡처 가로 띠)
src = Image.open(os.path.join(BASE, "시스템분석", "img", "capture_01_wave_combat.jpg")).convert("RGB")
band = src.crop((0, 300, 1600, 620)).resize((1260, 252), Image.LANCZOS)
mask = Image.new("L", band.size, 255); md = ImageDraw.Draw(mask)
for y in range(60): # 위쪽 가장자리를 투명하게 → 바탕화면 위에 떠 있는 느낌
md.line([(0, y), (band.width, y)], fill=int(255 * y / 60))
sx, sy = 330, H - 48 - band.height - 2
bg.paste(band, (sx, sy), mask)
d = ImageDraw.Draw(bg)
# HUD
for i in range(3):
hx = sx + 520 + i * 70
d.rectangle([hx, sy + 70, hx + 52, sy + 78], fill=(30, 30, 30)); d.rectangle([hx, sy + 70, hx + 40 - i * 6, sy + 78], fill=(92, 214, 110))
d.rounded_rectangle([sx + 20, sy + 70, sx + 96, sy + 104], 8, fill=(20, 22, 30)); d.text((sx + 34, sy + 72), "2-7", font=F(22, True), fill=(240, 240, 240))
d.ellipse([sx + 1010, sy + 72, sx + 1036, sy + 98], fill=(242, 190, 58)); d.text((sx + 1044, sy + 70), "12,845,210", font=F(22, True), fill=(250, 236, 180))
d.rounded_rectangle([sx + 1190, sy + 140, sx + 1244, sy + 194], 8, fill=(60, 36, 24), outline=(200, 150, 80), width=3)
for i in range(3):
d.line([(sx + 1202, sy + 156 + i * 11), (sx + 1232, sy + 156 + i * 11)], fill=(240, 220, 170), width=4)
d.rounded_rectangle([sx + 880, sy + 128, sx + 940, sy + 176], 6, fill=(96, 62, 30), outline=(230, 190, 110), width=3) # 상자
d.text((sx + 868, sy + 180), "상자 3", font=F(18, True), fill=(250, 236, 180))
# 작업표시줄
d.rectangle([0, H - 48, W, H], fill=(24, 26, 32))
for i in range(4):
d.rectangle([20 + (i % 2) * 12, H - 38 + (i // 2) * 12, 30 + (i % 2) * 12, H - 28 + (i // 2) * 12], fill=(90, 160, 240))
for i in range(7):
d.rounded_rectangle([90 + i * 56, H - 40, 126 + i * 56, H - 8], 6, fill=(62, 66, 78))
d.text((W - 110, H - 40), "오후 3:24", font=F(18), fill=(220, 222, 228))
# 표기
d.rounded_rectangle([20, 16, 700, 58], 10, fill=(0, 0, 0))
d.text((34, 22), "컨셉 목업 — 합성 이미지(실제 구현 화면 아님)", font=F(22, True), fill=(242, 163, 58))
d.text((sx + 10, sy - 34), "▼ 작업표시줄 위 3D 전투 스트립 (FirstRising 실캡처 가로 띠 합성)", font=F(20, True), fill=(242, 163, 58))
bg.save(os.path.join(OUT, "mock_taskbar_concept.png"))
# ---------- (2) 아이템 툴팁 예시 ----------
tw, th = 560, 640
tt = Image.new("RGB", (tw, th), (16, 14, 12)); d = ImageDraw.Draw(tt)
d.rectangle([4, 4, tw - 5, th - 5], outline=(160, 110, 40), width=3)
d.text((24, 20), "망자의 군주 대검", font=F(30, True), fill=(242, 152, 48))
d.text((24, 64), "전설 · 양손 대검 · 아이템 레벨 45", font=F(19), fill=(200, 190, 170))
d.line([(24, 100), (tw - 24, 100)], fill=(90, 70, 40), width=2)
d.text((24, 112), "공격력 312 ~ 355", font=F(24, True), fill=(240, 240, 240))
d.text((24, 146), "공격 속도 1.10", font=F(20), fill=(210, 210, 210))
d.line([(24, 184), (tw - 24, 184)], fill=(90, 70, 40), width=2)
aff = [("+18% 치명타 피해", "T3"), ("+42 최대 체력", "T5"), ("+12% 화염 저항", "T7"), ("+6% 공격 속도", "T4")]
for i, (t, tier) in enumerate(aff):
y = 198 + i * 40
d.text((24, y), t, font=F(22), fill=(110, 160, 255)); d.text((tw - 70, y + 2), tier, font=F(18, True), fill=(140, 140, 150))
d.line([(24, 364), (tw - 24, 364)], fill=(90, 70, 40), width=2)
d.text((24, 378), "고유 옵션", font=F(18, True), fill=(242, 152, 48))
d.text((24, 404), "회전 베기가 화염 속성으로 바뀌고", font=F(21), fill=(242, 190, 120))
d.text((24, 434), "범위가 20% 넓어진다", font=F(21), fill=(242, 190, 120))
d.text((24, 478), "장식 슬롯 ◇ ◇", font=F(21), fill=(200, 200, 210))
d.line([(24, 520), (tw - 24, 520)], fill=(90, 70, 40), width=2)
d.text((24, 534), "● 거래 가능 (Steam 장터)", font=F(21, True), fill=(92, 214, 110))
d.text((24, 568), "후가공(장식) 시 거래 불가 · 분해 시 골드 2,590", font=F(17), fill=(150, 150, 150))
d.text((24, 604), "목업 — 이름·수치는 예시", font=F(15), fill=(120, 120, 120))
tt.save(os.path.join(OUT, "mock_item_tooltip.png"))
print("saved mockups ->", OUT)