시작하기
씬 파일 하나를 React 앱에 띄우고, 클릭과 실시간 상태를 붙이는 데까지.
1. 설치
bash
npm install @isora/core @isora/react @isora/assets- React 18·19, 번들러(Vite·Next.js·webpack) 설정은 따로 필요 없다. ESM 전용이다.
@isora/react는 MUI 에 의존하지 않는다. SVG 한 장을 그린다.
2. 씬 만들기
씬은 .isora.json 파일이다. 두 가지 방법이 있다.
- Studio(GUI): 저장소에서
pnpm dev, 또는 앱 폴더에서pnpm isora init --dir ../my-app→pnpm isora studio --dir ../my-app. 화면은 영어·한국어이고 위쪽 막대의 언어 메뉴로 바꾼다(?lang=ko로 열어도 된다). 브라우저에서 써 보기. 팔레트에서 에셋을 끌어다 놓고, 사람을 의자에 앉히고, 루틴을 정한 뒤 저장한다. - 코드:
createScene()으로 빈 씬을 만들고objects에 오브젝트를 넣는다.
ts
import { createRegistry, createScene, createSceneBuilder } from '@isora/core'
import { officialPacks } from '@isora/assets'
const registry = createRegistry(officialPacks)
const scene = createScene({ id: 'lab', name: '실험실', width: 10, depth: 8 })
const b = createSceneBuilder(scene, registry)
b.floor('isora/common/floor-wood', 0, 0, 10, 8) // 바닥 80칸
const desk = b.add('isora/office/desk', 2, 2) // 발자국 모서리 (2, 2). id 'desk-1' 을 돌려준다
b.add('isora/office/monitor', 2.75, 2.25, 0, { state: 'code' }) // 높이는 알아서 책상 윗면
const chair = b.add('isora/office/chair', 2.75, 3, 180) // 책상 앞(+y)에서 책상을 본다
b.sit('isora/people/developer', chair, 0, { id: 'kim', behavior: { routine: 'office', desk: chair } })add는 높이를 Studio 에서 놓을 때와 같은 쌓기 규칙으로 정하고, 모르는 에셋이면 에러를 던진다.- 가운데 좌표로 놓고 싶으면
placeAt(scene, registry, assetId, [cx, cy], rotation)이 모서리·높이를 계산해 준다.
3. 띄우기
tsx
import { parseScene } from '@isora/core'
import { IsoScene } from '@isora/react'
import { common } from '@isora/assets/common'
import { office } from '@isora/assets/office'
import { people } from '@isora/assets/people'
import sceneJson from './scenes/main.isora.json'
// JSON import 는 타입이 넓어지므로 검증해서 Scene 을 얻는다. 틀리면 SceneValidationError(errors 목록).
const scene = parseScene(sceneJson)
// 씬이 쓰는 팩만 넘긴다. 컴포넌트 밖에 두어 렌더마다 새 배열이 되지 않게 한다.
const packs = [common, office, people]
export function Office() {
return <IsoScene scene={scene} packs={packs} style={{ height: 480 }} />
}IsoScene 은 부모 크기에 맞춰 SVG 를 채운다 (width·height 100%). 높이를 가진 부모 안에 둔다.
4. 클릭과 실시간 상태
tsx
const [states, setStates] = useState<Record<string, string>>({})
useEffect(() => {
// 설비 상태가 WebSocket 으로 온다고 치자. 오브젝트 id → 에셋의 상태 이름
const ws = new WebSocket('wss://example/telemetry')
ws.onmessage = (e) => setStates((s) => ({ ...s, ...JSON.parse(e.data) })) // { 'line-a/beacon': 'alarm' }
return () => ws.close()
}, [])
<IsoScene
scene={scene}
packs={packs}
states={states} // 경광등 alarm, 모니터 off …
onObjectClick={(obj) => openPanel(obj.id)} // 오브젝트 클릭
playTimelines // 컨베이어 화물·로봇 팔 키프레임
/>- 상태 이름은 에셋이 정한다 (
asset.states). Studio 속성 패널이나registry.get(id).states로 확인한다. - 앱이 준
states는 행동 재생이 정한 상태(빈 책상 모니터 끄기 등)보다 우선한다.
5. 사람을 움직이기
사람 오브젝트에 behavior: { routine: 'office', desk: 'chair-3' } 를 주고 playBehaviors 를 켜면 루틴대로 일하고 쉬고 돌아다닌다. 앱이 직접 보내려면 사람 움직이기 의 명령(command)을 쓴다.
tsx
<IsoScene scene={scene} packs={packs} playBehaviors behaviorSpeed={2} showActivities />6. Next.js App Router
- 컴포넌트·훅 파일에
'use client'가 붙어 배포된다. 서버 컴포넌트에서IsoScene을 바로 import 하면 서버에서 SVG 까지 그리고, 하이드레이션 뒤 애니메이션이 이어진다. onObjectClick같은 함수 prop 을 넘길 때는'use client'파일 안에서 쓴다.- 서버 컴포넌트에서
packs를 넘기면 팩 데이터가 RSC 페이로드에 실린다 (공식 팩 전체 JSON 약 340 kB, gzip 38 kB). 필요한 팩만 넘긴다.