@elucim/dsl 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,6 +59,10 @@ Validates the DSL document and renders it as React components. If validation fai
59
59
  - `dsl: ElucimDocument` — The DSL document to render
60
60
  - `className?: string` — CSS class for the wrapper div
61
61
  - `style?: CSSProperties` — Inline styles for the wrapper div
62
+ - `theme?: 'light' | 'dark'` — Override the color theme
63
+ - `poster?: number` — Frame number to display as a static poster before playback
64
+ - `onError?: (errors: ValidationError[]) => void` — Callback for validation errors
65
+ - `ref?: React.Ref<DslRendererRef>` — Imperative handle for programmatic control
62
66
 
63
67
  ### `validate(doc: unknown): ValidationResult`
64
68
 
@@ -74,6 +78,27 @@ if (!result.valid) {
74
78
  }
75
79
  ```
76
80
 
81
+ ### `renderToSvgString(doc, frame, options?)`
82
+
83
+ Renders a DSL document to an SVG string without a browser DOM — useful for server-side rendering, thumbnails, and static export.
84
+
85
+ ```ts
86
+ import { renderToSvgString } from '@elucim/dsl';
87
+ const svg = renderToSvgString(myDoc, 0);
88
+ ```
89
+
90
+ Uses `react-dom/server` under the hood. Validates the DSL and throws on invalid input.
91
+
92
+ ### `DslRendererRef`
93
+
94
+ Imperative handle exposed via `ref` on `<DslRenderer>`. Methods:
95
+
96
+ - `getSvgElement()` — Returns the underlying `SVGSVGElement`
97
+ - `seekToFrame(frame)` — Jump to a specific frame
98
+ - `getTotalFrames()` — Total frame count of the document
99
+ - `play()` / `pause()` — Control playback
100
+ - `isPlaying()` — Whether the animation is currently playing
101
+
77
102
  ### `compileExpression(expr: string)`
78
103
 
79
104
  Compile a math expression string into a callable function.
@@ -115,6 +140,8 @@ Every document has this structure:
115
140
  | `player` | Interactive player with controls, scrub bar, play/pause |
116
141
  | `presentation` | Slide-based presentation with transitions |
117
142
 
143
+ 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.
144
+
118
145
  ### Element Types
119
146
 
120
147
  #### Primitives
@@ -125,6 +152,7 @@ Every document has this structure:
125
152
  | `arrow` | `x1`, `y1`, `x2`, `y2` | Line with arrowhead |
126
153
  | `rect` | `x`, `y`, `width`, `height` | Rectangle |
127
154
  | `polygon` | `points` (array of [x,y]) | Polygon/polyline |
155
+ | `bezierCurve` | `x1`, `y1`, `cx1`, `cy1`, `x2`, `y2` | Quadratic/cubic Bezier curve |
128
156
  | `text` | `x`, `y`, `content` | Text element |
129
157
  | `image` | `src`, `x`, `y`, `width`, `height` | Embed external images (PNG, SVG, etc.) |
130
158
  | `barChart` | `bars` | Animated bar chart with labels and colors |
@@ -222,6 +250,10 @@ When instructing an LLM to create Elucim diagrams:
222
250
  5. **Wrap elements in animation nodes** (`fadeIn`, `draw`, `stagger`) for entrance effects
223
251
  6. **Use math expression strings** for function plots and vector fields
224
252
 
253
+ **Tips:**
254
+ - Use `poster` on `<DslRenderer>` to show a static preview frame before playback starts
255
+ - Use `renderToSvgString(doc, frame)` to generate SVG previews server-side — ideal for thumbnails and social cards
256
+
225
257
  Example prompt:
226
258
  > "Create an Elucim DSL JSON document that shows a coordinate system with sin(x) and cos(x) plotted,
227
259
  > with the sin curve drawing first, then the cos curve drawing 30 frames later,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { default as default_2 } from 'react';
2
- import { JSX as JSX_2 } from 'react/jsx-runtime';
3
2
 
4
3
  export declare interface ArrowNode {
5
4
  type: 'arrow';
@@ -80,6 +79,33 @@ export declare interface BarChartNode {
80
79
  zIndex?: number;
81
80
  }
82
81
 
82
+ export declare interface BezierCurveNode {
83
+ type: 'bezierCurve';
84
+ id?: string;
85
+ x1: number;
86
+ y1: number;
87
+ cx1: number;
88
+ cy1: number;
89
+ cx2?: number;
90
+ cy2?: number;
91
+ x2: number;
92
+ y2: number;
93
+ stroke?: string;
94
+ strokeWidth?: number;
95
+ fill?: string;
96
+ strokeDasharray?: string;
97
+ opacity?: number;
98
+ fadeIn?: number;
99
+ fadeOut?: number;
100
+ draw?: number;
101
+ easing?: EasingSpec;
102
+ rotation?: number;
103
+ rotationOrigin?: [number, number];
104
+ scale?: number | [number, number];
105
+ translate?: [number, number];
106
+ zIndex?: number;
107
+ }
108
+
83
109
  export declare interface CircleNode {
84
110
  type: 'circle';
85
111
  id?: string;
@@ -139,12 +165,36 @@ export declare interface DrawNode {
139
165
  children: ElementNode[];
140
166
  }
141
167
 
142
- export declare function DslRenderer({ dsl, className, style }: DslRendererProps): JSX_2.Element;
168
+ export declare const DslRenderer: default_2.ForwardRefExoticComponent<DslRendererProps & default_2.RefAttributes<DslRendererRef>>;
143
169
 
144
170
  export declare interface DslRendererProps {
145
171
  dsl: ElucimDocument;
146
172
  className?: string;
147
173
  style?: default_2.CSSProperties;
174
+ /** Inject theme colors as CSS custom properties (e.g. --elucim-foreground) */
175
+ theme?: ElucimTheme;
176
+ /** Render a static frame instead of interactive player. 'first' | 'last' | frame number */
177
+ poster?: 'first' | 'last' | number;
178
+ /** Callback fired when DSL validation fails */
179
+ onError?: (errors: Array<{
180
+ path: string;
181
+ message: string;
182
+ }>) => void;
183
+ }
184
+
185
+ export declare interface DslRendererRef {
186
+ /** Get the underlying SVG element */
187
+ getSvgElement(): SVGSVGElement | null;
188
+ /** Seek to a specific frame */
189
+ seekToFrame(frame: number): void;
190
+ /** Get total frames count */
191
+ getTotalFrames(): number;
192
+ /** Start playback */
193
+ play(): void;
194
+ /** Pause playback */
195
+ pause(): void;
196
+ /** Whether currently playing */
197
+ isPlaying(): boolean;
148
198
  }
149
199
 
150
200
  /** An easing function maps progress (0→1) to an eased value (typically 0→1) */
@@ -154,7 +204,7 @@ declare type EasingName = 'linear' | 'easeInQuad' | 'easeOutQuad' | 'easeInOutQu
154
204
 
155
205
  export declare type EasingSpec = EasingName | SpringEasing | CubicBezierEasing;
156
206
 
157
- export declare type ElementNode = SequenceNode | GroupNode | CircleNode | LineNode | ArrowNode | RectNode | PolygonNode | TextNode | ImageNode | AxesNode | FunctionPlotNode | VectorNode | VectorFieldNode | MatrixNode | GraphNode | LaTeXNode | BarChartNode | FadeInNode | FadeOutNode | DrawNode | WriteNode | TransformNode | MorphNode | StaggerNode | ParallelNode | PlayerNode | SceneNode;
207
+ export declare type ElementNode = SequenceNode | GroupNode | BezierCurveNode | CircleNode | LineNode | ArrowNode | RectNode | PolygonNode | TextNode | ImageNode | AxesNode | FunctionPlotNode | VectorNode | VectorFieldNode | MatrixNode | GraphNode | LaTeXNode | BarChartNode | FadeInNode | FadeOutNode | DrawNode | WriteNode | TransformNode | MorphNode | StaggerNode | ParallelNode | PlayerNode | SceneNode;
158
208
 
159
209
  export declare interface ElucimDocument {
160
210
  /** JSON Schema URL for editor autocomplete */
@@ -165,6 +215,13 @@ export declare interface ElucimDocument {
165
215
  root: RootNode;
166
216
  }
167
217
 
218
+ export declare interface ElucimTheme {
219
+ foreground?: string;
220
+ background?: string;
221
+ accent?: string;
222
+ [key: string]: string | undefined;
223
+ }
224
+
168
225
  export declare interface FadeInNode {
169
226
  type: 'fadeIn';
170
227
  duration?: number;
@@ -358,6 +415,7 @@ export declare interface ParallelNode {
358
415
 
359
416
  export declare interface PlayerNode {
360
417
  type: 'player';
418
+ preset?: ScenePreset;
361
419
  width?: number;
362
420
  height?: number;
363
421
  fps?: number;
@@ -369,6 +427,21 @@ export declare interface PlayerNode {
369
427
  children: ElementNode[];
370
428
  }
371
429
 
430
+ declare interface PlayerRef {
431
+ /** Get the underlying SVG element */
432
+ getSvgElement(): SVGSVGElement | null;
433
+ /** Seek to a specific frame */
434
+ seekToFrame(frame: number): void;
435
+ /** Get total frames count */
436
+ getTotalFrames(): number;
437
+ /** Start playback */
438
+ play(): void;
439
+ /** Pause playback */
440
+ pause(): void;
441
+ /** Whether currently playing */
442
+ isPlaying(): boolean;
443
+ }
444
+
372
445
  export declare interface PolygonNode {
373
446
  type: 'polygon';
374
447
  id?: string;
@@ -436,6 +509,7 @@ export declare class PresentationBuilder {
436
509
 
437
510
  export declare interface PresentationNode {
438
511
  type: 'presentation';
512
+ preset?: ScenePreset;
439
513
  width?: number;
440
514
  height?: number;
441
515
  background?: string;
@@ -481,6 +555,37 @@ export declare interface RectNode {
481
555
  zIndex?: number;
482
556
  }
483
557
 
558
+ export declare function renderElement(node: ElementNode, key: number): default_2.ReactNode;
559
+
560
+ export declare function renderPlayer(node: PlayerNode, overrides?: RenderRootOverrides): default_2.ReactNode;
561
+
562
+ export declare function renderPresentation(node: PresentationNode): default_2.ReactNode;
563
+
564
+ export declare function renderRoot(node: SceneNode | PlayerNode | PresentationNode, overrides?: RenderRootOverrides): default_2.ReactNode;
565
+
566
+ export declare interface RenderRootOverrides {
567
+ frame?: number;
568
+ playerRef?: default_2.RefObject<PlayerRef | null>;
569
+ }
570
+
571
+ export declare function renderScene(node: SceneNode, overrides?: RenderRootOverrides): default_2.ReactNode;
572
+
573
+ export declare function renderSlide(node: SlideNode, key: number): default_2.ReactNode;
574
+
575
+ /**
576
+ * Render a DSL document to an SVG string at a specific frame, without mounting to the DOM.
577
+ * Uses react-dom/server's renderToStaticMarkup.
578
+ *
579
+ * Note: This renders the scene at the given frame by overriding the root node's properties.
580
+ * For 'player' roots, it converts to a 'scene' internally (no controls needed for static output).
581
+ */
582
+ export declare function renderToSvgString(dsl: ElucimDocument, frame: number, options?: RenderToSvgStringOptions): string;
583
+
584
+ export declare interface RenderToSvgStringOptions {
585
+ width?: number;
586
+ height?: number;
587
+ }
588
+
484
589
  /**
485
590
  * Resolve an EasingSpec (string name or spring/cubicBezier object) to an EasingFunction.
486
591
  * Returns undefined if the spec is undefined.
@@ -492,6 +597,7 @@ export declare type RootNode = SceneNode | PlayerNode | PresentationNode;
492
597
 
493
598
  export declare interface SceneNode {
494
599
  type: 'scene';
600
+ preset?: ScenePreset;
495
601
  width?: number;
496
602
  height?: number;
497
603
  fps?: number;
@@ -500,6 +606,9 @@ export declare interface SceneNode {
500
606
  children: ElementNode[];
501
607
  }
502
608
 
609
+ /** Preset dimensions for common scene sizes */
610
+ export declare type ScenePreset = 'card' | 'slide' | 'square';
611
+
503
612
  export declare interface SequenceNode {
504
613
  type: 'sequence';
505
614
  from: number;