diff --git a/brand/gen-store-assets.mjs b/brand/gen-store-assets.mjs new file mode 100644 index 0000000..c0a941a --- /dev/null +++ b/brand/gen-store-assets.mjs @@ -0,0 +1,93 @@ +// Play Console 스토어 그래픽 생성기. +// 입력: brand/logo-1024.png (사용자가 저장한 1024x1024 돈돼지 마스터 아트) +// 출력: brand/store/icon-512.png (스토어 고해상도 아이콘 512x512, 불투명) +// brand/store/feature-1024x500.png (피처 그래픽 — 텍스트 없음, 항상 안정) +// brand/store/feature-1024x500-text.png(피처 그래픽 — 한글 텍스트 포함, best-effort) +// +// 실행: node brand/gen-store-assets.mjs [입력경로] +import sharp from 'sharp' +import { mkdirSync, existsSync } from 'node:fs' +import { fileURLToPath } from 'node:url' +import { dirname, join, resolve } from 'node:path' + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const SRC = resolve(process.argv[2] || join(__dirname, 'logo-1024.png')) +const OUT = join(__dirname, 'store') + +// 브랜드 색 (아이콘 배경의 크림/옐로 계열) +const CREAM = '#FBF7E9' +const YELLOW = '#F2C94C' +const BROWN = '#B8860B' + +if (!existsSync(SRC)) { + console.error(`\n[!] 마스터 아트가 없습니다: ${SRC}`) + console.error(` 1024x1024 돈돼지 PNG 를 위 경로에 저장한 뒤 다시 실행하세요.\n`) + process.exit(1) +} +mkdirSync(OUT, { recursive: true }) + +const log = (f) => console.log(' ✓', f) + +// 1) 스토어 아이콘 512x512 — 불투명 크림 배경 위에 마스터를 합성(투명 PNG 대비) +async function icon512() { + const logo = await sharp(SRC).resize(512, 512, { fit: 'contain', background: CREAM }).png().toBuffer() + const out = join(OUT, 'icon-512.png') + await sharp({ create: { width: 512, height: 512, channels: 4, background: CREAM } }) + .composite([{ input: logo }]) + .flatten({ background: CREAM }) + .png() + .toFile(out) + log('store/icon-512.png (512x512, 불투명)') +} + +// 공통: 1024x500 배경 — 피그가 놓일 우측(크림)에서 좌측(옐로 살짝)으로. +// 중심을 피그 쪽 크림으로 두어 마스터의 크림 배경 사각이 자연스럽게 녹도록 한다. +function bgSvg(cx = '80%') { + return Buffer.from(` + + + + + + + + + `) +} + +// 2) 피처 그래픽 (텍스트 없음) — 가운데 큼직하게, 박스 없이 녹아들게 +async function featurePlain() { + const bg = await sharp(bgSvg('50%')).png().toBuffer() + const pig = await sharp(SRC).resize(420, 420, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }).png().toBuffer() + const out = join(OUT, 'feature-1024x500.png') + await sharp(bg).composite([{ input: pig, top: 40, left: 302 }]).png().toFile(out) + log('store/feature-1024x500.png (텍스트 없음)') +} + +// 3) 피처 그래픽 (한글 텍스트) — 좌측 텍스트 / 우측 피그, 겹침 없도록 간격 조정. +async function featureWithText() { + const bg = await sharp(bgSvg('82%')).png().toBuffer() + const pig = await sharp(SRC).resize(380, 380, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }).png().toBuffer() + const text = Buffer.from(` + + 돈돼지 가계부 + 슬림하게 관리하는 + 가계부 · 자산 · 예산 + `) + const out = join(OUT, 'feature-1024x500-text.png') + await sharp(bg) + .composite([{ input: pig, top: 60, left: 630 }, { input: text }]) + .png() + .toFile(out) + log('store/feature-1024x500-text.png (한글 텍스트, 폰트 렌더 확인 필요)') +} + +console.log(`\n[스토어 에셋 생성] 입력: ${SRC}\n`) +await icon512() +await featurePlain() +await featureWithText() +console.log(`\n완료 → ${OUT}\n`) diff --git a/brand/logo-1024.png b/brand/logo-1024.png new file mode 100644 index 0000000..09953d7 Binary files /dev/null and b/brand/logo-1024.png differ diff --git a/brand/store/feature-1024x500-text.png b/brand/store/feature-1024x500-text.png new file mode 100644 index 0000000..9c3bb72 Binary files /dev/null and b/brand/store/feature-1024x500-text.png differ diff --git a/brand/store/feature-1024x500.png b/brand/store/feature-1024x500.png new file mode 100644 index 0000000..d15238e Binary files /dev/null and b/brand/store/feature-1024x500.png differ diff --git a/brand/store/icon-512.png b/brand/store/icon-512.png new file mode 100644 index 0000000..6545432 Binary files /dev/null and b/brand/store/icon-512.png differ