에셋 정리 + 원본 보관 + 건물 일러스트 적용

- 미사용 에셋 삭제: 구 오렌지 태비 4프레임(품종 시트로 대체), create-next-app svg
- assets-src/: AI 생성 원본(품종 시트 8장·잔디·강물·도구·건물 시트) 프로젝트로 이동
- build.png 슬라이스: 어두운 글로우 배경을 밝기 기반 플러드필로 제거 →
  부두(선착장+보트)·벌목장·채석장(광산)·부엌(모닥불) 4종
- 마을 캔버스·상점·패널 아이콘에 건물 일러스트 적용 (도구 아이콘은 폴백)
- 배치 고스트도 건물 일러스트, 히트 영역 확장, 삭제된 루트 프레임 404 폴백 제거

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
이 커밋은 다음에 포함됨:
kjs
2026-08-13 15:40:42 +09:00
co-authored by Claude Fable 5
부모 e5c58b3d6a
커밋 e19dab49f5
36개의 변경된 파일과 50개의 추가작업 그리고 27개의 파일을 삭제
+4 -3
파일 보기
@@ -14,6 +14,7 @@ import {
APTITUDE_LABEL,
BREEDS,
BUILD_DEFS,
BUILDING_IMG,
catSprite,
HALL_LEVELS,
KITCHEN_UPGRADE_COST,
@@ -199,7 +200,7 @@ export default function Game() {
{openedBuilding && (
<SidePanel
title={`${openedBuilding.name} Lv${openedBuilding.level}`}
icon={TOOL_IMG[openedBuilding.aptitude]}
icon={BUILDING_IMG[openedBuilding.type] ?? TOOL_IMG[openedBuilding.aptitude]}
onClose={() => setPanel(null)}
>
<BuildingPanel
@@ -399,9 +400,9 @@ function ShopPanel({
>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={TOOL_IMG[def.aptitude]}
src={BUILDING_IMG[def.type] ?? TOOL_IMG[def.aptitude]}
alt={def.name}
className={`h-12 w-12 shrink-0 object-contain ${built || !hallOk ? "opacity-40" : ""}`}
className={`h-14 w-14 shrink-0 object-contain ${built || !hallOk ? "opacity-40" : ""}`}
/>
<div className="min-w-0 flex-1">
<div className="font-jua text-[15px] text-[#3f2c14]">{def.name}</div>
+25 -19
파일 보기
@@ -5,6 +5,7 @@ import { engine, catRate, canPlaceAt } from "@/lib/game/engine";
import {
BOARD_COLS,
BOARD_ROWS,
BUILDING_IMG,
catSprite,
HALL_TILE,
TOOL_IMG,
@@ -536,22 +537,29 @@ export default function VillageView({
const stored = Math.floor(b.stored);
const isKitchen = b.type === "kitchen";
// 건물 본체 → 정보 패널
hitRectsRef.current.push({ id: b.id, kind: "open", x: x - 30, y: y - 38, w: 60, h: 66 });
hitRectsRef.current.push({ id: b.id, kind: "open", x: x - 44, y: y - 52, w: 88, h: 80 });
// 배지 → 빠른 회수 (생산 건물만)
if (!isKitchen && stored > 0)
hitRectsRef.current.push({ id: b.id, kind: "collect", x: x - 40, y: y - 62, w: 80, h: 26 });
sprites.push({
y,
draw: () => {
shadow(x, y + 6, 24);
const img = toolImagesRef.current.get(b.aptitude);
if (img) {
// 세로가 긴 일러스트 — 높이 56px 기준으로 비율 유지
const h = 56;
const w = (img.width / img.height) * h;
ctx.drawImage(img, x - w / 2, y + 8 - h, w, h);
const bImg = getImage(BUILDING_IMG[b.type]);
if (bImg) {
// 건물 일러스트 (자체 잔디 베이스 포함 — 그림자 불필요)
const w = 96;
const h = (bImg.height / bImg.width) * w;
ctx.drawImage(bImg, x - w / 2, y + 14 - h, w, h);
} else {
drawEmoji(b.emoji, x, y + 8, 42);
shadow(x, y + 6, 24);
const img = toolImagesRef.current.get(b.aptitude);
if (img) {
const h = 56;
const w = (img.width / img.height) * h;
ctx.drawImage(img, x - w / 2, y + 8 - h, w, h);
} else {
drawEmoji(b.emoji, x, y + 8, 42);
}
}
ctx.font = `13px ${juaFamily}`;
ctx.textAlign = "center";
@@ -597,14 +605,10 @@ export default function VillageView({
? "walk1"
: "walk2"
: "idle";
// 품종 스프라이트 → (cook 없으면 work) → 기본 스프라이트 순 폴백
// 품종 스프라이트 → (cook 없으면 work) → 이모지 순 폴백
let sprite = getImage(catSprite(cat.breed, frameName));
if (!sprite && frameName === "cook")
sprite = getImage(catSprite(cat.breed, "work"));
if (!sprite)
sprite = getImage(
catSprite("", frameName === "cook" ? "work" : frameName),
);
if (sprite) {
const sh = 42;
const sw = (sprite.width / sprite.height) * sh;
@@ -658,12 +662,14 @@ export default function VillageView({
// 고스트 건물
const gx = isoX(hover.i, hover.j);
const gy = isoY(hover.i, hover.j) + TH / 2;
const img = toolImagesRef.current.get(placing.aptitude);
const gImg =
getImage(BUILDING_IMG[placing.type]) ??
toolImagesRef.current.get(placing.aptitude);
ctx.globalAlpha = 0.75;
if (img) {
const h = 56;
const w = (img.width / img.height) * h;
ctx.drawImage(img, gx - w / 2, gy + 8 - h, w, h);
if (gImg) {
const w = 96;
const h = (gImg.height / gImg.width) * w;
ctx.drawImage(gImg, gx - w / 2, gy + 14 - h, w, h);
} else {
drawEmoji("🏗️", gx, gy + 8, 40);
}
+8
파일 보기
@@ -23,6 +23,14 @@ export function catSprite(breed: string, frame: CatFrame): string {
return dir ? `/assets/cats/${dir}/${frame}.png` : `/assets/cats/${frame}.png`;
}
// 건물 일러스트 (public/assets/buildings/)
export const BUILDING_IMG: Record<string, string> = {
dock: "/assets/buildings/dock.png",
lumberyard: "/assets/buildings/lumberyard.png",
quarry: "/assets/buildings/quarry.png",
kitchen: "/assets/buildings/kitchen.png",
};
// 적성별 도구 일러스트 (public/assets/tools/)
export const TOOL_IMG: Record<AptitudeKey, string> = {
fishing: "/assets/tools/fishing.png",