Scene Graph & Yugma Scene Language
SceneObject (Core Type)
Every object in the 3D scene is a SceneObject:
interface SceneObject {
id: string // nanoid(10), stable forever
name: string // Semantic: "wall_north", "hero_sphere"
type: GeometryType // box|sphere|cylinder|plane|torus|cone|
// capsule|tetrahedron|dodecahedron|custom_gltf
transform: {
position: [number, number, number] // meters, Y-up, world space
rotation: [number, number, number] // degrees, Euler XYZ
scale: [number, number, number] // multiplier (1 = default)
}
material: {
color: string // hex "#rrggbb"
roughness: number // 0.0 (mirror) → 1.0 (chalk)
metalness: number // 0.0 (plastic) → 1.0 (metal)
opacity: number // 0.0 → 1.0
wireframe: boolean
emissive: string // hex, "#000000" = off
emissiveIntensity: number // 0 = off, 1-10 = glow
}
geometry: GeometryParams // Type-specific (width, radius, etc.)
tags: string[] // Semantic: ["wall", "structural"]
parentId: string | null // Group hierarchy
visible: boolean
locked: boolean
castShadow: boolean
receiveShadow: boolean
// YSL v1.5 additive fields
userData?: Record<string, unknown> // Extension point
semanticRole?: string // "wall", "floor", "hero", "prop"
relationships?: { // Soft scene-graph links
parentOf?: string[]
nextTo?: string[]
supports?: string[]
references?: string[]
}
createdAt: number
updatedAt: number
}
Coordinate System
| Axis | Direction | Convention |
|---|---|---|
| +X | Right | Three.js / WebGL |
| +Y | Up | |
| -Z | Forward | |
| Units | Meters | Human ≈ 1.8m, door ≈ 2.1m |
| Rotation | Degrees | Euler XYZ order |
| Colors | Hex | "#rrggbb" |
Geometry Types
| Type | Params |
|---|---|
box | width, height, depth |
sphere | radius, widthSegments, heightSegments |
cylinder | radiusTop, radiusBottom, cylinderHeight, radialSegments |
cone | radius, cylinderHeight, radialSegments |
torus | torusRadius, tube, torusSegments |
plane | width, height |
capsule | radius, cylinderHeight |
tetrahedron | radius, detail |
dodecahedron | radius, detail |
custom_gltf | gltfUrl |
Scene Environment
interface SceneEnvironment {
hdriPreset: string // city, sunset, dawn, night, forest, studio, warehouse, apartment
backgroundColor: string // hex
ambientIntensity: number // 0-2
fogEnabled: boolean
fogColor: string
fogNear: number
fogFar: number
}
YSL — Yugma Scene Language
YSL is a compact text format designed for LLM context windows. Key properties:
| Metric | YSL | USD | GLTF JSON |
|---|---|---|---|
| Tokens/object | ~45 | ~400 | ~300 |
| 50-obj scene | ~2,400 tokens | ~20,000 tokens | ~15,000 tokens |
| LLM-parseable | Yes | Partially | No |
YSL Output Example
[★ hero_sphere] sphere id=abc pos=[2,0.5,0] rot=[0,0,0] s=[1,1,1]
mat=#ff0000 r=0.3 m=0.8 e=#000000 ei=0 op=1 tags=[hero,accent]
role=hero nextTo=[def456]
★ marks the currently selected object. The serializer (aiSerializer.ts) outputs all objects in hierarchy order.
Schema Evolution
| Version | Added | Breaking? |
|---|---|---|
| v1.0 | Core SceneObject, tags, material, geometry | N/A |
| v1.5 | userData, semanticRole, relationships | No — all optional, additive-only |
| v2.0 (planned) | Constraints, physics bodies, LOD, animations | No — additive |
All evolution is additive-only. Existing documents load unchanged. New fields default to undefined.
State Management
The scene graph lives in useSceneStore (Zustand). Key actions:
| Action | Effect |
|---|---|
addObject(type, overrides?) | Create new object, auto-select, return ID |
updateObject(id, patch) | Deep merge with special handling for tags, material, transform, relationships |
removeObject(id) | Delete + deselect if selected |
duplicateObject(id) | Clone with +1m X offset |
reparentObject(id, parentId) | Set parent for grouping |
selectObject(id) | Set selection |
setCameraTarget(target) | Trigger smooth camera tween |
setEnvironment(patch) | Update HDRI, fog, ambient |
clearScene() | Remove all objects |
loadScene(objects, order, env) | Bulk load |