@elucim/dsl 0.6.0 → 0.8.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,9 +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
62
+ - `theme?: ElucimTheme` Custom color tokens as CSS custom properties (e.g. `{ foreground: '#fff', background: '#000' }`)
63
+ - `colorScheme?: 'light' | 'dark' | 'auto'` — Inject light/dark theme variables automatically. `'auto'` detects from `prefers-color-scheme`. DSL docs using `$token` syntax adapt automatically.
64
+ - `poster?: 'first' | 'last' | number` — Render a static frame instead of interactive player
65
+ - `onError?: (errors: Array<{ path: string; message: string }>) => void` — Callback for validation errors
65
66
  - `ref?: React.Ref<DslRendererRef>` — Imperative handle for programmatic control
66
67
 
67
68
  ### `validate(doc: unknown): ValidationResult`
@@ -230,6 +231,59 @@ Used in `functionPlot.fn` and `vectorField.fn`. Safe evaluation — no `eval()`.
230
231
  - `"[-y, x]"` — Rotation vector field
231
232
  - `"[sin(y), cos(x)]"` — Wave vector field
232
233
 
234
+ ## Semantic Color Tokens
235
+
236
+ Use `$token` syntax in your DSL JSON to create theme-adaptive visualizations:
237
+
238
+ ```json
239
+ {
240
+ "type": "player",
241
+ "background": "$background",
242
+ "children": [
243
+ { "type": "text", "x": 400, "y": 300, "content": "Hello", "fill": "$foreground" },
244
+ { "type": "circle", "cx": 200, "cy": 200, "r": 50, "stroke": "$accent" }
245
+ ]
246
+ }
247
+ ```
248
+
249
+ **Available tokens:**
250
+
251
+ | Token | Dark default | Light default | Usage |
252
+ |-------|-------------|---------------|-------|
253
+ | `$foreground` | `#c8d6e5` | `#334155` | Body text |
254
+ | `$background` | `#0a0a1e` | `#f8fafc` | Slide/scene background |
255
+ | `$title` | `#e0e7ff` | `#1e293b` | Heading text (brighter than foreground) |
256
+ | `$subtitle` | `#94a3b8` | `#64748b` | Secondary/subtitle text |
257
+ | `$muted` | `#64748b` | `#94a3b8` | Annotations, faint text |
258
+ | `$primary` | `#4fc3f7` | `#2563eb` | Primary accent |
259
+ | `$secondary` | `#a78bfa` | `#7c3aed` | Secondary accent |
260
+ | `$tertiary` | `#f472b6` | `#db2777` | Tertiary accent |
261
+ | `$success` | `#34d399` | `#16a34a` | Positive / success |
262
+ | `$warning` | `#fbbf24` | `#d97706` | Warning / highlight |
263
+ | `$error` | `#f87171` | `#dc2626` | Error / negative |
264
+ | `$surface` | `#1e293b` | `#f8fafc` | Panel backgrounds |
265
+ | `$border` | `#334155` | `#334155` | Borders, grid lines |
266
+ | `$accent` | `#4fc3f7` | `#2563eb` | Alias for primary |
267
+
268
+ Tokens resolve to CSS custom properties (`$background` → `var(--elucim-background, #0a0a1e)`). Pair with `colorScheme` to auto-adapt:
269
+
270
+ ```tsx
271
+ <DslRenderer dsl={doc} colorScheme="auto" />
272
+ ```
273
+
274
+ | colorScheme | Behavior |
275
+ |-------------|----------|
276
+ | `'dark'` | Injects dark palette variables |
277
+ | `'light'` | Injects light palette variables |
278
+ | `'auto'` | Detects `prefers-color-scheme` media query |
279
+ | _(omitted)_ | Tokens fall back to built-in defaults (dark) |
280
+
281
+ You can also override individual tokens with the `theme` prop:
282
+
283
+ ```tsx
284
+ <DslRenderer dsl={doc} colorScheme="auto" theme={{ accent: '#ff6600' }} />
285
+ ```
286
+
233
287
  ## Examples
234
288
 
235
289
  See the [`examples/`](./examples/) directory:
@@ -281,6 +335,7 @@ const doc = presentation(darkTheme)
281
335
  ## Related
282
336
 
283
337
  - **[@elucim/core](https://www.npmjs.com/package/@elucim/core)** — The React rendering engine (peer dependency)
338
+ - **[@elucim/editor](https://www.npmjs.com/package/@elucim/editor)** — Visual canvas editor for Elucim animations
284
339
  - **[Elucim Docs](https://elucim.com)** — Full docs with live interactive examples
285
340
 
286
341
  ## License
package/dist/index.d.ts CHANGED
@@ -173,6 +173,17 @@ export declare interface DslRendererProps {
173
173
  style?: default_2.CSSProperties;
174
174
  /** Inject theme colors as CSS custom properties (e.g. --elucim-foreground) */
175
175
  theme?: ElucimTheme;
176
+ /**
177
+ * Color scheme for semantic token resolution.
178
+ * - `'dark'` — inject dark theme CSS variables
179
+ * - `'light'` — inject light theme CSS variables
180
+ * - `'auto'` — detect from `prefers-color-scheme` media query
181
+ *
182
+ * DSL documents using `$token` syntax (e.g. `$background`, `$foreground`)
183
+ * will automatically adapt. Explicit `theme` values take priority over
184
+ * colorScheme defaults.
185
+ */
186
+ colorScheme?: 'light' | 'dark' | 'auto';
176
187
  /** Render a static frame instead of interactive player. 'first' | 'last' | frame number */
177
188
  poster?: 'first' | 'last' | number;
178
189
  /** Callback fired when DSL validation fails */
@@ -566,12 +577,47 @@ export declare function renderRoot(node: SceneNode | PlayerNode | PresentationNo
566
577
  export declare interface RenderRootOverrides {
567
578
  frame?: number;
568
579
  playerRef?: default_2.RefObject<PlayerRef | null>;
580
+ /** CSS color-scheme to pass to Scene/Player. When set, overrides browser prefers-color-scheme. */
581
+ colorScheme?: 'light' | 'dark' | 'light dark';
569
582
  }
570
583
 
571
584
  export declare function renderScene(node: SceneNode, overrides?: RenderRootOverrides): default_2.ReactNode;
572
585
 
573
586
  export declare function renderSlide(node: SlideNode, key: number): default_2.ReactNode;
574
587
 
588
+ /**
589
+ * Render a DSL document at a specific frame directly to PNG bytes.
590
+ *
591
+ * Goes from DSL JSON → SVG string → PNG without requiring a mounted DOM
592
+ * element, blob URLs, or manual Image loading. Uses data URIs internally
593
+ * to avoid CSP issues in restricted webview contexts (e.g. Tauri).
594
+ *
595
+ * Works in any browser environment. Does NOT work in Node.js (needs
596
+ * canvas + Image APIs).
597
+ *
598
+ * @example
599
+ * ```ts
600
+ * import { renderToPng } from '@elucim/dsl';
601
+ *
602
+ * const png = await renderToPng(myDocument, 0);
603
+ * // png is a Uint8Array of PNG bytes
604
+ *
605
+ * // Save as file download:
606
+ * const blob = new Blob([png], { type: 'image/png' });
607
+ * const url = URL.createObjectURL(blob);
608
+ * ```
609
+ */
610
+ export declare function renderToPng(dsl: ElucimDocument, frame: number, options?: RenderToPngOptions): Promise<Uint8Array>;
611
+
612
+ export declare interface RenderToPngOptions {
613
+ /** Output width in pixels (default: document width) */
614
+ width?: number;
615
+ /** Output height in pixels (default: document height) */
616
+ height?: number;
617
+ /** Device pixel ratio for retina output (default: 2) */
618
+ scale?: number;
619
+ }
620
+
575
621
  /**
576
622
  * Render a DSL document to an SVG string at a specific frame, without mounting to the DOM.
577
623
  * Uses react-dom/server's renderToStaticMarkup.
@@ -991,6 +1037,7 @@ export declare interface ValidationResult {
991
1037
 
992
1038
  export declare interface VectorFieldNode {
993
1039
  type: 'vectorField';
1040
+ id?: string;
994
1041
  /** Vector expression string, e.g. "[-y, x]" */
995
1042
  fn: string;
996
1043
  domain?: [number, number];