Getting started
Show one scene file in a React app, then add clicks and live state. Isora draws isometric scenes as plain SVG React components, so it fits anywhere a React component does — a product page, an operations dashboard, a digital-twin floor view.
1. Install
bash
npm install @isora/core @isora/react @isora/assets- React 18 or 19. No bundler setup (Vite, Next.js, webpack) is needed. ESM only.
@isora/reactdoes not depend on MUI. It draws a single SVG.
2. Make a scene
A scene is a .isora.json file. There are two ways to make one.
- Studio (GUI scene editor): run
pnpm devin this repo, or in your app folder runpnpm isora init --dir ../my-app→pnpm isora studio --dir ../my-app. The UI is English or Korean — switch with the language menu in the top bar (or open with?lang=ko). Try it in the browser. Drag assets from the palette, seat people on chairs, pick their routines, and save. - Code: make an empty scene with
createScene()and add objects toobjects.
ts
import { createRegistry, createScene, createSceneBuilder } from '@isora/core'
import { officialPacks } from '@isora/assets'
const registry = createRegistry(officialPacks)
const scene = createScene({ id: 'lab', name: 'Lab', width: 10, depth: 8 })
const b = createSceneBuilder(scene, registry)
b.floor('isora/common/floor-wood', 0, 0, 10, 8) // 80 floor tiles
const desk = b.add('isora/office/desk', 2, 2) // footprint corner (2, 2). Returns the id 'desk-1'
b.add('isora/office/monitor', 2.75, 2.25, 0, { state: 'code' }) // height is worked out: the desk top
const chair = b.add('isora/office/chair', 2.75, 3, 180) // in front of the desk (+y), facing it
b.sit('isora/people/developer', chair, 0, { id: 'kim', behavior: { routine: 'office', desk: chair } })addsets the height with the same stacking rules Studio uses when you drop an object, and throws on an unknown asset.- To place by center instead,
placeAt(scene, registry, assetId, [cx, cy], rotation)works out the corner and height.
3. Show it
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'
// A JSON import widens the types, so validate it to get a Scene. Throws SceneValidationError (with an errors list) if invalid.
const scene = parseScene(sceneJson)
// Pass only the packs the scene uses. Keep this outside the component so it is not a new array on every render.
const packs = [common, office, people]
export function Office() {
return <IsoScene scene={scene} packs={packs} style={{ height: 480 }} />
}IsoScene fills its parent with the SVG (width and height 100%). Put it inside a parent that has a height.
4. Clicks and live state
tsx
const [states, setStates] = useState<Record<string, string>>({})
useEffect(() => {
// Say equipment states arrive over a WebSocket: object id → a state name defined by the asset
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} // beacon alarm, monitor off …
onObjectClick={(obj) => openPanel(obj.id)} // object click
playTimelines // conveyor cargo, robot arm keyframes
/>- State names come from the asset (
asset.states). Check them in the Studio properties panel or withregistry.get(id).states. To show a state's display name in another language, usestateLabel(asset, state, 'ko')(Languages). statesfrom the app win over states set by behavior playback (such as turning off the monitor on an empty desk).
5. Move people
Give a person object behavior: { routine: 'office', desk: 'chair-3' } and turn on playBehaviors, and they work, rest and wander according to the routine. To send people yourself from the app, use commands (command) in Moving people.
tsx
<IsoScene scene={scene} packs={packs} playBehaviors behaviorSpeed={2} showActivities />6. Next.js App Router
- Component and hook files ship with
'use client'. ImportIsoScenedirectly in a server component and the server renders the SVG; animation continues after hydration. - Pass function props such as
onObjectClickfrom inside a'use client'file. - Passing
packsfrom a server component puts the pack data in the RSC payload (all official packs are about 340 kB of JSON, 38 kB gzipped). Pass only the packs you need.
Next
- Concepts — coordinates and time
- Moving people — commands, routines, reading positions
- Rendering — overlays, click coordinates, drawing it yourself