@elucim/dsl 0.3.0 → 0.4.1

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';
@@ -166,12 +165,36 @@ export declare interface DrawNode {
166
165
  children: ElementNode[];
167
166
  }
168
167
 
169
- export declare function DslRenderer({ dsl, className, style }: DslRendererProps): JSX_2.Element;
168
+ export declare const DslRenderer: default_2.ForwardRefExoticComponent<DslRendererProps & default_2.RefAttributes<DslRendererRef>>;
170
169
 
171
170
  export declare interface DslRendererProps {
172
171
  dsl: ElucimDocument;
173
172
  className?: string;
174
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;
175
198
  }
176
199
 
177
200
  /** An easing function maps progress (0→1) to an eased value (typically 0→1) */
@@ -192,6 +215,13 @@ export declare interface ElucimDocument {
192
215
  root: RootNode;
193
216
  }
194
217
 
218
+ export declare interface ElucimTheme {
219
+ foreground?: string;
220
+ background?: string;
221
+ accent?: string;
222
+ [key: string]: string | undefined;
223
+ }
224
+
195
225
  export declare interface FadeInNode {
196
226
  type: 'fadeIn';
197
227
  duration?: number;
@@ -385,6 +415,7 @@ export declare interface ParallelNode {
385
415
 
386
416
  export declare interface PlayerNode {
387
417
  type: 'player';
418
+ preset?: ScenePreset;
388
419
  width?: number;
389
420
  height?: number;
390
421
  fps?: number;
@@ -396,6 +427,21 @@ export declare interface PlayerNode {
396
427
  children: ElementNode[];
397
428
  }
398
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
+
399
445
  export declare interface PolygonNode {
400
446
  type: 'polygon';
401
447
  id?: string;
@@ -463,6 +509,7 @@ export declare class PresentationBuilder {
463
509
 
464
510
  export declare interface PresentationNode {
465
511
  type: 'presentation';
512
+ preset?: ScenePreset;
466
513
  width?: number;
467
514
  height?: number;
468
515
  background?: string;
@@ -508,6 +555,37 @@ export declare interface RectNode {
508
555
  zIndex?: number;
509
556
  }
510
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
+
511
589
  /**
512
590
  * Resolve an EasingSpec (string name or spring/cubicBezier object) to an EasingFunction.
513
591
  * Returns undefined if the spec is undefined.
@@ -519,6 +597,7 @@ export declare type RootNode = SceneNode | PlayerNode | PresentationNode;
519
597
 
520
598
  export declare interface SceneNode {
521
599
  type: 'scene';
600
+ preset?: ScenePreset;
522
601
  width?: number;
523
602
  height?: number;
524
603
  fps?: number;
@@ -527,6 +606,9 @@ export declare interface SceneNode {
527
606
  children: ElementNode[];
528
607
  }
529
608
 
609
+ /** Preset dimensions for common scene sizes */
610
+ export declare type ScenePreset = 'card' | 'slide' | 'square';
611
+
530
612
  export declare interface SequenceNode {
531
613
  type: 'sequence';
532
614
  from: number;