feat: Agent Office — AI 에이전트 가상 오피스 (#2)
## Summary - Canvas 2D 픽셀아트 오피스 렌더링 (SpriteSheet + TileMap + AgentSprite) - WebSocket 실시간 에이전트 상태 동기화 (useAgentManager) - ChatPanel (명령/승인) + TaskHistory (작업 이력) UI - 다크 테마 + glassmorphism 패널 ## Changes (7 commits) - API helpers + route + Lab entry - Canvas engine: SpriteSheet, TileMap, AgentSprite, OfficeRenderer - React hooks: useAgentManager, useOfficeCanvas - Components: ChatPanel, TaskHistory - Main page + CSS - Code review fixes: claude agent 참조 제거, rejected 배지 추가 Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
62
src/pages/agent-office/hooks/useOfficeCanvas.js
Normal file
62
src/pages/agent-office/hooks/useOfficeCanvas.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import { useRef, useEffect, useCallback } from 'react';
|
||||
import { OfficeRenderer } from '../canvas/OfficeRenderer';
|
||||
import officeMap from '../assets/office-map.json';
|
||||
|
||||
export function useOfficeCanvas(containerRef, onAgentClick) {
|
||||
const rendererRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current) return;
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.style.display = 'block';
|
||||
canvas.style.width = '100%';
|
||||
canvas.style.height = '100%';
|
||||
canvas.style.imageRendering = 'pixelated';
|
||||
containerRef.current.appendChild(canvas);
|
||||
|
||||
const renderer = new OfficeRenderer(canvas, officeMap);
|
||||
rendererRef.current = renderer;
|
||||
|
||||
const resize = () => {
|
||||
const rect = containerRef.current.getBoundingClientRect();
|
||||
renderer.resize(rect.width, rect.height);
|
||||
};
|
||||
|
||||
resize();
|
||||
renderer.start();
|
||||
|
||||
renderer.setOnClick((agentId) => {
|
||||
if (onAgentClick) onAgentClick(agentId);
|
||||
});
|
||||
|
||||
const handleClick = (e) => {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = e.clientX - rect.left;
|
||||
const y = e.clientY - rect.top;
|
||||
renderer.handleClick(x, y);
|
||||
};
|
||||
|
||||
canvas.addEventListener('click', handleClick);
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
return () => {
|
||||
renderer.stop();
|
||||
canvas.removeEventListener('click', handleClick);
|
||||
window.removeEventListener('resize', resize);
|
||||
if (containerRef.current && canvas.parentNode === containerRef.current) {
|
||||
containerRef.current.removeChild(canvas);
|
||||
}
|
||||
};
|
||||
}, [containerRef, onAgentClick]);
|
||||
|
||||
const updateAgentState = useCallback((agentId, state, detail) => {
|
||||
rendererRef.current?.updateAgentState(agentId, state, detail);
|
||||
}, []);
|
||||
|
||||
const moveAgent = useCallback((agentId, target) => {
|
||||
rendererRef.current?.moveAgent(agentId, target);
|
||||
}, []);
|
||||
|
||||
return { updateAgentState, moveAgent };
|
||||
}
|
||||
Reference in New Issue
Block a user