@elucim/dsl
v0.14.1
Published
JSON/YAML DSL for declarative Elucim animations — define visualizations without writing React code
Downloads
2,793
Maintainers
Readme
@elucim/dsl
Declarative JSON DSL for animated visualizations — perfect for AI agents.
@elucim/dsl lets you describe animated diagrams as JSON documents. An AI agent (or any code) produces a JSON object conforming to the schema, and the <DslRenderer> component renders it as a fully interactive Elucim visualization — no React knowledge required.
Install
npm install @elucim/dsl @elucim/core react react-dom
# or
pnpm add @elucim/dsl @elucim/core react react-domQuick Start
import { DslRenderer } from '@elucim/dsl';
import type { ElucimDocument } from '@elucim/dsl';
const myDiagram: ElucimDocument = {
version: '1.0',
root: {
type: 'player',
width: 800,
height: 600,
fps: 30,
durationInFrames: 90,
background: '#0d0d1a',
children: [
{
type: 'circle',
cx: 400,
cy: 300,
r: 100,
stroke: '#3b82f6',
strokeWidth: 3,
draw: 60,
},
],
},
};
function App() {
return <DslRenderer dsl={myDiagram} />;
}API
<DslRenderer dsl={doc} />
Validates the DSL document and renders it as React components. If validation fails, displays error messages.
Props:
dsl: ElucimDocument— The DSL document to renderclassName?: string— CSS class for the wrapper divstyle?: CSSProperties— Inline styles for the wrapper divtheme?: ElucimTheme— Custom color tokens as CSS custom properties (e.g.{ foreground: '#fff', background: '#000' })colorScheme?: 'light' | 'dark' | 'auto'— Inject light/dark theme variables automatically.'auto'detects fromprefers-color-scheme. DSL docs using$tokensyntax adapt automatically.poster?: 'first' | 'last' | number— Render a static frame instead of interactive playeronError?: (errors: Array<{ path: string; message: string }>) => void— Callback for validation errorsref?: React.Ref<DslRendererRef>— Imperative handle for programmatic control
validate(doc: unknown): ValidationResult
Validates a DSL document without rendering it.
import { validate } from '@elucim/dsl';
const result = validate(myDoc);
if (!result.valid) {
console.log(result.errors);
// [{ path: 'root.children[0].cx', message: 'Required numeric field "cx"...', severity: 'error' }]
}renderToSvgString(doc, frame, options?)
Renders a DSL document to an SVG string without a browser DOM — useful for server-side rendering, thumbnails, and static export.
import { renderToSvgString } from '@elucim/dsl';
const svg = renderToSvgString(myDoc, 0);Uses react-dom/server under the hood. Validates the DSL and throws on invalid input.
DslRendererRef
Imperative handle exposed via ref on <DslRenderer>. Methods:
getSvgElement()— Returns the underlyingSVGSVGElementseekToFrame(frame)— Jump to a specific framegetTotalFrames()— Total frame count of the documentplay()/pause()— Control playbackisPlaying()— Whether the animation is currently playing
compileExpression(expr: string)
Compile a math expression string into a callable function.
import { compileExpression } from '@elucim/dsl';
const fn = compileExpression('sin(x) * 2');
fn({ x: Math.PI / 2 }); // → 2compileVectorExpression(expr: string)
Compile a vector field expression returning [number, number].
import { compileVectorExpression } from '@elucim/dsl';
const fn = compileVectorExpression('[-y, x]');
fn({ x: 1, y: 2 }); // → [-2, 1]Document Schema
Every document has this structure:
{
"version": "1.0",
"root": { "type": "scene|player|presentation", ... }
}Root Types
| Type | Description |
|------|-------------|
| scene | Raw SVG scene (needs external frame control) |
| player | Interactive player with controls, scrub bar, play/pause |
| presentation | Slide-based presentation with transitions |
All root types accept an optional preset field: 'card' (640×360), 'slide' (1280×720), 'square' (600×600). When set, width and height are derived from the preset automatically.
Element Types
Primitives
| Type | Required Props | Description |
|------|---------------|-------------|
| circle | cx, cy, r | SVG circle |
| line | x1, y1, x2, y2 | SVG line |
| arrow | x1, y1, x2, y2 | Line with arrowhead |
| rect | x, y, width, height | Rectangle |
| polygon | points (array of [x,y]) | Polygon/polyline |
| bezierCurve | x1, y1, cx1, cy1, x2, y2 | Quadratic/cubic Bezier curve |
| text | x, y, content | Text element |
| image | src, x, y, width, height | Embed external images (PNG, SVG, etc.) |
| barChart | bars | Animated bar chart with labels and colors |
Math Visualizations
| Type | Required Props | Description |
|------|---------------|-------------|
| axes | — | Coordinate axes with grid/ticks |
| functionPlot | fn (expression) | Plot a function like "sin(x)" |
| vector | to ([x,y]) | Mathematical vector with label |
| vectorField | fn (vector expr) | Grid of arrows like "[-y, x]" |
| matrix | values (2D array) | Matrix with brackets |
| graph | nodes, edges | Graph theory visualization |
| latex | expression, x, y | LaTeX rendered via KaTeX |
Animation Wrappers
| Type | Key Props | Description |
|------|----------|-------------|
| fadeIn | duration, easing | Fade children in |
| fadeOut | duration, easing | Fade children out |
| draw | duration, easing | Progressive stroke drawing |
| write | duration, easing | Stroke draw + fill fade |
| transform | translate, scale, rotate, opacity | Animate position/scale/rotation |
| morph | fromColor, toColor, fromScale, toScale | Color/scale morphing |
| stagger | staggerDelay | Sequential delayed children |
| parallel | — | Children animate simultaneously |
Structural
| Type | Key Props | Description |
|------|----------|-------------|
| sequence | from, durationInFrames | Time-offset wrapper |
| group | children | Logical grouping with shared transforms (rotation, scale, translate) and zIndex sorting of children |
Inline Animation Props
All primitives support these optional animation props directly:
fadeIn?: number— Fade in over N framesfadeOut?: number— Fade out over N framesdraw?: number— Progressive stroke draw over N frameseasing?: string | { type, ... }— Easing function
Spatial Transform Props
All primitives and groups support these optional spatial transform props:
rotation?: number— Rotate element in degreesrotationOrigin?: [number, number]— Center of rotation [cx, cy]scale?: number— Uniform scale factortranslate?: [number, number]— Offset [dx, dy]zIndex?: number— Stacking order (higher renders on top)
Easing
Named easings: linear, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, easeInSine, easeOutSine, easeInOutSine, easeInExpo, easeOutExpo, easeInOutExpo, easeInBack, easeOutBack, easeOutElastic, easeOutBounce
Spring: { "type": "spring", "stiffness": 100, "damping": 10, "mass": 1 }
Cubic Bezier: { "type": "cubicBezier", "x1": 0.25, "y1": 0.1, "x2": 0.25, "y2": 1 }
Math Expressions
Used in functionPlot.fn and vectorField.fn. Safe evaluation — no eval().
Operators: +, -, *, /, ^ (power), unary -
Functions: sin, cos, tan, asin, acos, atan, atan2, sqrt, abs, log, ln, exp, floor, ceil, round, min, max, sign, pow
Constants: PI, E, TAU
Variables: x (FunctionPlot), x and y (VectorField)
Examples:
"sin(x)"— Sine wave"x^2 - 1"— Parabola"exp(-(x^2) / 2)"— Gaussian"[-y, x]"— Rotation vector field"[sin(y), cos(x)]"— Wave vector field
Semantic Color Tokens
Use $token syntax in your DSL JSON to create theme-adaptive visualizations:
{
"type": "player",
"background": "$background",
"children": [
{ "type": "text", "x": 400, "y": 300, "content": "Hello", "fill": "$foreground" },
{ "type": "circle", "cx": 200, "cy": 200, "r": 50, "stroke": "$accent" }
]
}Available tokens:
| Token | Dark default | Light default | Usage |
|-------|-------------|---------------|-------|
| $foreground | #c8d6e5 | #334155 | Body text |
| $background | #0a0a1e | #f8fafc | Slide/scene background |
| $title | #e0e7ff | #1e293b | Heading text (brighter than foreground) |
| $subtitle | #94a3b8 | #64748b | Secondary/subtitle text |
| $muted | #64748b | #94a3b8 | Annotations, faint text |
| $primary | #4fc3f7 | #2563eb | Primary accent |
| $secondary | #a78bfa | #7c3aed | Secondary accent |
| $tertiary | #f472b6 | #db2777 | Tertiary accent |
| $success | #34d399 | #16a34a | Positive / success |
| $warning | #fbbf24 | #d97706 | Warning / highlight |
| $error | #f87171 | #dc2626 | Error / negative |
| $surface | #1e293b | #f8fafc | Panel backgrounds |
| $border | #334155 | #334155 | Borders, grid lines |
| $accent | #4fc3f7 | #2563eb | Alias for primary |
Tokens resolve to CSS custom properties ($background → var(--elucim-background, #0a0a1e)). Pair with colorScheme to auto-adapt:
<DslRenderer dsl={doc} colorScheme="auto" />| colorScheme | Behavior |
|-------------|----------|
| 'dark' | Injects dark palette variables |
| 'light' | Injects light palette variables |
| 'auto' | Detects prefers-color-scheme media query |
| (omitted) | Tokens fall back to built-in defaults (dark) |
You can also override individual tokens with the theme prop:
<DslRenderer dsl={doc} colorScheme="auto" theme={{ accent: '#ff6600' }} />Examples
See the examples/ directory:
hello-circle.json— Minimal animated circlemath-demo.json— Axes, function plot, vector, LaTeXanimated-scene.json— FadeIn, Draw, Transform, Stagger, Morphpresentation.json— Multi-slide presentationfull-showcase.json— Every feature in one document
For AI Agents
When instructing an LLM to create Elucim diagrams:
- Ask it to produce JSON matching the
ElucimDocumentschema - Set
version: "1.0"as the first field - Choose a root type:
playerfor interactive,scenefor embedded,presentationfor slides - Use
sequencenodes to control timing (offsets in frames) - Wrap elements in animation nodes (
fadeIn,draw,stagger) for entrance effects - Use math expression strings for function plots and vector fields
Tips:
- Use
posteron<DslRenderer>to show a static preview frame before playback starts - Use
renderToSvgString(doc, frame)to generate SVG previews server-side — ideal for thumbnails and social cards
Example prompt:
"Create an Elucim DSL JSON document that shows a coordinate system with sin(x) and cos(x) plotted, with the sin curve drawing first, then the cos curve drawing 30 frames later, and a LaTeX label fading in at the end."
Fluent Builder API
Build presentations programmatically with a chainable TypeScript API:
import { presentation, darkTheme } from '@elucim/dsl';
const doc = presentation(darkTheme)
.size(1920, 1080)
.transition('fade', 500)
.slide('Welcome', (s) => {
s.title('Hello World');
})
.slide('Math', (s) => {
s.latex('e^{i\\pi} + 1 = 0', { x: 960, y: 500, fontSize: 48, color: '#fdcb6e' });
})
.build();Related
- @elucim/core — The React rendering engine (peer dependency)
- @elucim/editor — Visual canvas editor for Elucim animations
- Elucim Docs — Full docs with live interactive examples
