본문으로 건너뛰기

시작하기 ​

씬 파일 하나를 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). 필요한 팩만 넘긴다.

다음 ​

MIT 라이선스로 배포합니다.