+
+
+ {building.emoji} {building.name} Lv{building.level}
+
+
+ 필요 적성: {APTITUDE_LABEL[building.aptitude]}
+
+
+
+ 생산 속도 {totalRate.toFixed(2)}/초
+
+
+
+ {assignedCats.map((cat) => (
+
+ ))}
+ {Array.from({ length: emptySlots }).map((_, i) => (
+
+ ))}
+
+
+
+
+ );
+}
+
+function CatCard({
+ cat,
+ buildings,
+ selected,
+ onSelect,
+}: {
+ cat: Cat;
+ buildings: Building[];
+ selected: boolean;
+ onSelect: () => void;
+}) {
+ const workplace = buildings.find((b) => b.id === cat.assignedTo);
+ const expNeeded = cat.level * 60;
+
+ return (
+
+ );
+}
diff --git a/src/hooks/useGame.ts b/src/hooks/useGame.ts
new file mode 100644
index 0000000..8db7c6b
--- /dev/null
+++ b/src/hooks/useGame.ts
@@ -0,0 +1,55 @@
+"use client";
+
+import { useCallback, useEffect, useState } from "react";
+import { engine } from "@/lib/game/engine";
+import type { GameState } from "@/lib/game/types";
+
+const SYNC_INTERVAL_MS = 300;
+const SAVE_INTERVAL_MS = 5000;
+const MAX_DT_SEC = 60;
+
+/**
+ * 게임 상태는 엔진(모듈 싱글턴)이 rAF + 델타 타임으로 계산하고,
+ * React에는 300ms 간격으로만 스냅샷을 동기화한다 (리렌더 최소화).
+ */
+export function useGame() {
+ const [state, setState] = useState