Skip to content

DSL Overview

The @elucim/dsl package lets agents, content pipelines, and React applications describe Elucim visuals as normalized JSON, YAML, or canonical JSX documents. Elucim documents are normalized scene graphs with explicit elements, timelines, and optional state machines.

Every DSL document is an ElucimDocument object:

import type {
ElucimDocument,
ElucimElement,
ElucimMetadata,
ElucimScene,
ElucimStateMachine,
ElucimTimeline,
} from '@elucim/dsl';
interface ElucimDocument {
$schema?: string; // Optional JSON Schema URL for editor autocomplete
version: '2.0'; // Current document format version
scene: ElucimScene; // Root scene/player settings
elements: Record<string, ElucimElement>;
timelines?: Record<string, ElucimTimeline>;
stateMachines?: Record<string, ElucimStateMachine>;
defaultStateMachine?: string;
metadata?: ElucimMetadata;
}

The scene chooses the render surface and references top-level element IDs. Elements are stored by ID so timelines and state machines can target stable objects directly.

{
"version": "2.0",
"scene": {
"type": "player",
"width": 800,
"height": 600,
"fps": 30,
"background": "#0a0a1e",
"children": ["orb"]
},
"elements": {
"orb": {
"id": "orb",
"type": "circle",
"props": {
"type": "circle",
"cx": 400,
"cy": 300,
"r": 60,
"stroke": "$accent",
"strokeWidth": 3,
"opacity": 0
}
}
},
"timelines": {
"intro": {
"id": "intro",
"duration": 30,
"tracks": [
{
"target": "orb",
"property": "opacity",
"keyframes": [
{ "frame": 0, "value": 0 },
{ "frame": 30, "value": 1 }
]
}
]
}
},
"defaultStateMachine": "main",
"stateMachines": {
"main": {
"id": "main",
"entry": "intro",
"states": { "intro": { "timeline": "intro" } },
"transitions": [
{ "id": "entry-start", "from": "entry", "to": "intro", "trigger": "onStart" }
]
}
}
}

The same document in YAML — parsed with fromYaml():

version: "2.0"
scene:
type: player
width: 800
height: 600
fps: 30
background: "#0a0a1e"
children: [orb]
elements:
orb:
id: orb
type: circle
props:
type: circle
cx: 400
cy: 300
r: 60
stroke: "$accent"
strokeWidth: 3
opacity: 0
timelines:
intro:
id: intro
duration: 30
tracks:
- target: orb
property: opacity
keyframes:
- { frame: 0, value: 0 }
- { frame: 30, value: 1 }
defaultStateMachine: main
stateMachines:
main:
id: main
entry: intro
states:
intro: { timeline: intro }
transitions:
- { id: entry-start, from: entry, to: intro, trigger: onStart }
import { fromYaml } from '@elucim/dsl';
const doc = fromYaml(yamlString);
// doc is a validated ElucimDocument

Every node has a "type" field. The full set of supported types:

SectionDescription
sceneRoot scene/player settings with top-level child element IDs
elementsID-keyed primitive/group definitions
timelinesExplicit property tracks, keyframes, and procedural effects
stateMachinesEntry/state/transition controllers for interactive playback
TypeDescription
circleSVG circle (cx, cy, r, fill, stroke)
lineSVG line or straight connector (x1, y1, x2, y2, lineStyle, startCap, endCap)
bezierCurveSmooth connector/path (x1, y1, cx1, cy1, cx2, cy2, x2, y2, startCap, endCap)
rectRectangle (x, y, width, height, rx, ry)
polygonPolygon from a points array
textText label (x, y, content, fontSize)
TypeDescription
axes2D coordinate system with ticks and optional grid
functionPlotPlot a math expression as a curve
vectorArrow from origin to a point, with optional label
vectorFieldGrid of vectors computed from an expression
matrixBracketed matrix display
graphNode-and-edge graph visualization
latexLaTeX expression rendered via KaTeX
barChartLabeled bar chart

Animation is represented by timeline tracks and state-machine transitions, not wrapper nodes like fadeIn or sequence. This keeps generated documents inspectable and gives the editor/viewer a single motion model.