If you've ever tried to ship a real-time dashboard inside an embedded WebView, or let an AI agent generate a live admin panel, you know the pain: React here, Chart.js there, D3 for one chart, a diagram library for topology, and suddenly your "simple HMI" is a 2 MB bundle that won't even run on Chromium 49 in a car infotainment stack.
LightDraw.js is a different bet. It's a zero-dependency, JSON-first 2D graphics engine for the browser — dashboards, automotive clusters, network diagrams, and form-style UI controls, all from one API. Canvas when you need speed. SVG when you need vectors. HTML when you need accessibility or legacy WebView support.
In this guide, I'll walk through what LightDraw actually is, how to get started in under five minutes, and five real-world use cases with code you can copy, tweak, and run today.
What Problem Does LightDraw Solve?
Building interactive 2D graphics in the browser usually means stacking tools:
| Typical stack | The pain |
|---|---|
| React + Chart.js + D3 + diagram lib | Huge bundle, framework lock-in, four APIs to learn |
| Raw Canvas API | No scene graph, manual hit-testing, no animation timeline |
| Low-code / AI UI generators | Output is React/JSX — hard to embed in WebView or validate |
| Automotive HMI tools | Expensive, closed, or not web-native |
LightDraw replaces that stack with one engine:
- Retained-mode scene graph — add, move, and animate nodes; the renderer redraws efficiently
- Three renderers — Canvas (performance), SVG (vectors), HTML (accessibility + old WebViews)
- JSON scenes — load, validate, export; ideal for AI agents and config-driven UIs
- Domain modules — dashboard widgets, automotive cluster, diagrams, UI components — same API
- ES5 legacy build — ship to Chromium 49+ infotainment without a runtime transpiler
Bundle sizes (gzip): core ~26 KB, full bundle ~101 KB, dashboard plugin ~32 KB, automotive ~29 KB. You only load what you need.
Who Is This For?
✅ Great fit:
- IoT / ops dashboards on factory tablets or NOC wall displays
- Automotive digital cockpits fed by CAN or simulator data
- AI-generated admin panels where the agent outputs JSON, not JSX
- Network topology and architecture diagrams in docs or incident boards
- Embedded control panels on Raspberry Pi kiosks — single HTML file, no npm on device
❌ Not the right tool:
- Full SPA with routing and SSR — use React/Vue for the shell; embed LightDraw in a panel
- 3D games — use Three.js or Babylon
- Google Docs–class document editing
- Native mobile UI — Swift/Kotlin territory
Step 1: Install LightDraw
Option A — npm (modern apps)
npm install lightdraw
import LightDraw from 'lightdraw';
const app = LightDraw.createApp('#app', {
width: 800,
height: 600,
renderer: 'auto', // canvas | svg | html
background: '#1e293b'
});
Option B — CDN (no build step)
Perfect for embedded devices, kiosks, or quick prototypes:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lightdraw@1/dist/lightdraw.min.css">
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/lightdraw@1/dist/lightdraw.min.js"></script>
<script>
const app = LightDraw.createApp('#app', { width: 800, height: 600, renderer: 'html' });
</script>
Expected output after Step 1: An empty canvas (or HTML surface) with your chosen background color. No errors in the console. You're ready to draw.
Step 2: Draw Your First Scene (JavaScript API)
LightDraw uses a retained-mode scene graph. You create nodes, add them to the stage, and the engine handles redraws, hit-testing, and animation.
const app = LightDraw.createApp('#app', {
width: 800,
height: 600,
renderer: 'canvas',
background: '#1e293b'
});
const circle = app.circle({
x: 200,
y: 200,
radius: 50,
fill: '#2563eb',
draggable: true
});
app.add(circle);
circle.on('click', () => {
circle.animate({
scale: 1.5,
duration: 300,
easing: 'easeOutBounce'
});
});
Output:
What you'll see: A blue circle on a dark slate background. Click it — it bounces to 1.5× scale. Drag it — it moves with your pointer. That's the scene graph and interaction layer working without you writing a single requestAnimationFrame loop by hand.
Step 3: Build UIs from JSON (The AI-Friendly Path)
This is where LightDraw diverges from most canvas libraries. Instead of imperative drawing calls, you can describe an entire UI as JSON and load it in one line:
app.loadJSON({
type: 'group',
children: [
{ type: 'thermometer', props: { value: 72, x: 24, y: 24 } },
{
type: 'lineChart',
props: {
data: [18, 22, 31, 28, 35],
width: 400,
height: 160,
x: 24,
y: 120
}
},
{ type: 'gauge', props: { value: 68, size: 110, x: 480, y: 40 } },
{
type: 'statusBar',
props: {
segments: ['Connected', 'MQTT', '1.2k msg/s'],
x: 24,
y: 300
}
}
]
});
Output:
What you'll see: A mini ops dashboard — thermometer at 72°, a line chart with five data points, a gauge at 68%, and a status bar showing connection info. No React. No Chart.js import. One JSON object.
To update live data:
const gauge = app.stage.findOne('gauge');
gauge.set('value', 85);
app.requestRender();
Step 4: Validate JSON Before Rendering (Critical for AI)
When an LLM generates your UI, you must validate before rendering. LightDraw ships schema docs and a built-in validator:
const scene = await fetch('/api/agent/scene.json').then(r => r.json());
const { valid, errors } = LightDraw.validateSceneJSON(scene);
if (!valid) {
console.error('Scene validation failed:', errors);
// Example error output:
// ["Unknown type 'gague' — did you mean 'gauge'?"]
return;
}
app.clear();
app.loadJSON(scene);
app.setUiTheme({ preset: 'slate', mode: 'dark' });
Expected output when valid: A themed dark UI renders immediately (see AI admin panel example below).
Expected output when invalid: valid: false and a human-readable errors array — no half-broken UI on screen.
The validation pipeline for AI:
User prompt → LLM + schema docs → scene JSON → validateSceneJSON → loadJSON → live UI
Step 5: Pick the Right Renderer
| Renderer | Best for | Trade-off |
|---|---|---|
canvas | 60 FPS animations, 1000+ nodes, automotive cluster | Raster — export as PNG |
svg | Crisp vectors, zoom-friendly diagrams | DOM-heavy at very large node counts |
html | Form controls, accessibility, legacy WebViews | Not ideal for 5000-node particle systems |
auto | Let LightDraw pick based on context | Good default for prototyping |
Benchmark snapshot (canvas renderer, 1000 nodes): render ~0.46 ms per frame — enough headroom for 60 FPS on mid-range hardware.
Real-World Use Cases (With Code and Screenshots)
Use Case 1: IoT / Factory Floor Dashboard
Scenario: A tablet on the factory floor shows live sensor readings from MQTT. No React build pipeline on the device.
const app = LightDraw.createApp('#dashboard', {
width: 1024,
height: 600,
renderer: 'canvas'
});
app.loadJSON({
type: 'group',
children: [
{ type: 'thermometer', props: { value: 72, x: 24, y: 24, label: 'Line 3 Temp' } },
{ type: 'gauge', props: { value: 68, size: 120, x: 200, y: 24, label: 'Humidity %' } },
{
type: 'lineChart',
props: {
data: [18, 22, 31, 28, 35, 42, 38],
width: 500,
height: 180,
x: 24,
y: 180,
title: 'Throughput (units/hr)'
}
},
{
type: 'statusBar',
props: {
segments: ['● Connected', 'MQTT', '1.2k msg/s'],
x: 24,
y: 400
}
}
]
});
Output:
What operators see: Gauges and charts update in real time. Status bar shows broker health. Entire UI fits in ~101 KB gzip (full bundle via CDN).
Use Case 2: Automotive Digital Cockpit
Scenario: An instrument cluster in an infotainment WebView, updating at 30–60 FPS from CAN bus or a driving simulator.
const app = LightDraw.createApp('#cluster', {
width: 800,
height: 480,
renderer: 'canvas'
});
app.loadJSON({
type: 'instrumentCluster',
props: {
theme: 'classic',
width: 800,
height: 480,
speed: 0,
rpm: 800,
fuel: 100
}
});
const cluster = app.stage.children[0];
function onDriveTick(canData) {
LightDraw.applyDriveState(cluster, {
speed: canData.speed,
rpm: canData.rpm,
fuel: canData.fuelPercent
});
app.requestRender();
}
Output:
What the driver sees: Speedometer at 95, tach at 3200 RPM, fuel at 68%. Smooth updates because render stays sub-millisecond for typical cluster node counts.
Use Case 3: AI-Generated Admin Panel
Scenario: Your internal copilot receives "Build a server health dashboard with CPU chart and acknowledge button." It outputs JSON, not React.
const app = LightDraw.createApp('#app', {
width: 960,
height: 540,
renderer: 'html'
});
const scene = await agentResponse.json();
if (LightDraw.validateSceneJSON(scene).valid) {
app.loadJSON(scene);
app.setUiTheme({ preset: 'slate', mode: 'dark' });
}
Example LLM output (scene JSON):
{
"type": "group",
"children": [
{ "type": "card", "props": { "title": "Server health", "x": 16, "y": 16, "width": 420, "height": 200 } },
{ "type": "lineChart", "props": { "data": [22,35,28,48,41,55], "x": 32, "y": 56, "width": 380, "height": 140 } },
{ "type": "button", "props": { "label": "Acknowledge", "variant": "primary", "x": 480, "y": 200 } }
]
}
Output:
What the user sees: A card titled "Server health", CPU line chart trending upward, and a primary "Acknowledge" button — rendered in seconds, no codegen pipeline.
Use Case 4: Network / Architecture Diagram
Scenario: An SRE pastes an LLM-generated topology into an incident board during an outage.
app.loadJSON({
type: 'networkTopology',
props: {
data: {
nodes: [
{ id: 'gw', label: 'Gateway', type: 'router', x: 400, y: 40 },
{ id: 'api', label: 'API', type: 'server', x: 200, y: 160 },
{ id: 'db', label: 'Database', type: 'server', x: 400, y: 160 },
{ id: 'cache', label: 'Redis', type: 'server', x: 600, y: 160 }
],
edges: [
{ from: 'gw', to: 'api' },
{ from: 'gw', to: 'db' },
{ from: 'api', to: 'cache' }
]
}
}
});
Output:
What you see: Router at top, three servers below, connectors auto-routed between nodes — not hand-drawn SVG paths.
Use Case 5: Embedded Control Panel (CDN, Zero Build)
Scenario: A Raspberry Pi kiosk controls industrial pumps. Firmware team delivers one HTML file. No npm on the device.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/lightdraw@1/dist/lightdraw.min.css">
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/lightdraw@1/dist/lightdraw.min.js"></script>
<script>
const app = LightDraw.createApp('#app', { width: 480, height: 320, renderer: 'html' });
app.loadJSON({
type: 'group',
children: [
{ type: 'toggle', props: { label: 'Pump A', value: true, x: 20, y: 20 } },
{ type: 'slider', props: { value: 60, width: 200, x: 20, y: 70, label: 'Flow rate %' } },
{ type: 'button', props: { label: 'Emergency stop', variant: 'danger', x: 20, y: 130 } },
{ type: 'statusBar', props: { segments: ['PLC Online', 'Pump A: RUN'], x: 20, y: 200 } }
]
});
</script>
Output:
What the operator sees: Toggle for Pump A (on), slider at 60%, red emergency stop button, status bar showing PLC state.
Console output on interaction:
Control changed: toggle true
Control changed: slider 73
Control changed: button (click event)
How LightDraw Compares
| LightDraw | React + Chart.js | D3.js | GoJS / commercial | |
|---|---|---|---|---|
| Runtime deps | 0 | React + chart lib | D3 | License + lib |
| Full HMI in one package | ✅ | ❌ assemble yourself | ❌ data-viz focus | Partial |
| JSON → live UI | ✅ | ❌ usually codegen | ❌ | Some import/export |
| Canvas 60 FPS scene | ✅ | Via chart canvas | Manual | Varies |
| ES5 / old WebView | ✅ legacy build | ❌ needs build | ❌ | Varies |
| AI agent friendly | ✅ schema docs | ❌ outputs JSX | ❌ | ❌ |
| License | MIT | MIT | ISC | Often paid |
LightDraw is not a React replacement. It's a graphics engine you embed inside any page or framework.
Try It Yourself
- Playground: rakeshrajena.github.io/lightDraw
- GitHub: github.com/rakeshrajena/lightDraw
- npm: npmjs.com/package/lightdraw
- Getting started: docs/getting-started.md
- AI integration: docs/ai-integration-guide.md
git clone https://github.com/rakeshrajena/lightDraw.git
cd lightDraw
npm install
npm run build
npm run dev:website # → http://localhost:5173
Wrapping Up
If your project touches embedded web, real-time dashboards, automotive HMIs, or AI-generated UIs, the usual "assemble five libraries" approach costs you bundle size, validation complexity, and WebView compatibility headaches.
LightDraw gives you one scene graph, three renderers, JSON-first loading with validation, and domain modules that cover the widgets you'd otherwise glue together yourself. Start with a CDN script tag and loadJSON — you can have a working dashboard on screen before your npm install finishes elsewhere.
MIT licensed. Built for embedded web, dashboards, and AI-built UIs.






























