{"_id":"@atlas.agents/a2ui-canvas","_rev":"2-0ccd39dbe260ba2f8646c49983c9d3a6","name":"@atlas.agents/a2ui-canvas","dist-tags":{"latest":"0.2.1"},"versions":{"0.2.0":{"name":"@atlas.agents/a2ui-canvas","version":"0.2.0","keywords":["react","canvas","visualization","a2ui","ai-native","streaming","d3","timeline","chart","knowledge-graph","component","ui","dynamic","langchain","agent"],"author":"","license":"MIT","_id":"@atlas.agents/a2ui-canvas@0.2.0","maintainers":[{"name":"davincidreams","email":"lisamegawatts@gmail.com"}],"dist":{"shasum":"1634aa9513d89caebe3213782a99595dbe7a076f","tarball":"https://registry.npmjs.org/@atlas.agents/a2ui-canvas/-/a2ui-canvas-0.2.0.tgz","fileCount":120,"integrity":"sha512-9Nf9bOXTBIeg1LwFCiP+wWRsmkldblv0ZqhEMJiptQ+ttsE2FBlaQjlj6VSMdsd8gzyAVlViqPaIuBqAWLexvQ==","signatures":[{"sig":"MEUCICwIgjFZJ5fdZOoqbSbenKwj8TSZrndpikgQSrYdNQGGAiEAknnHpo/xI6oujc2YcC2kRRMbBMmlDloUZbgHgWjwKNo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":200329},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js","require":"./dist/schema.cjs"},"./renderers/map":{"types":"./dist/renderers/MapRenderer.d.ts","import":"./dist/renderers/map.js","require":"./dist/renderers/map.cjs"},"./renderers/code":{"types":"./dist/renderers/CodeRenderer.d.ts","import":"./dist/renderers/code.js","require":"./dist/renderers/code.cjs"},"./renderers/chart":{"types":"./dist/renderers/ChartRenderer.d.ts","import":"./dist/renderers/chart.js","require":"./dist/renderers/chart.cjs"},"./renderers/media":{"types":"./dist/renderers/MediaRenderer.d.ts","import":"./dist/renderers/media.js","require":"./dist/renderers/media.cjs"},"./renderers/artifact":{"types":"./dist/renderers/ArtifactRenderer.d.ts","import":"./dist/renderers/artifact.js","require":"./dist/renderers/artifact.cjs"},"./renderers/document":{"types":"./dist/renderers/DocumentRenderer.d.ts","import":"./dist/renderers/document.js","require":"./dist/renderers/document.cjs"},"./renderers/timeline":{"types":"./dist/renderers/TimelineRenderer.d.ts","import":"./dist/renderers/timeline.js","require":"./dist/renderers/timeline.cjs"},"./renderers/knowledge-graph":{"types":"./dist/renderers/KnowledgeGraphRenderer.d.ts","import":"./dist/renderers/knowledge-graph.js","require":"./dist/renderers/knowledge-graph.cjs"}},"gitHead":"6972d54619077aff93d6cbfcdf9a77ec01cd997e","scripts":{"dev":"vite","test":"vitest run","build":"vite build","test:watch":"vitest","type-check":"tsc --noEmit"},"_npmUser":{"name":"davincidreams","email":"lisamegawatts@gmail.com"},"_npmVersion":"10.8.2","description":"A2UI-native dynamic canvas component for React — interoperable with LangChain, 3dchat, Microsoft Agent Framework, and any A2UI-speaking client","directories":{},"_nodeVersion":"20.20.0","dependencies":{"zustand":"^5.0.0","lucide-react":"^0.400.0"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^7.3.1","jsdom":"^28.0.0","vitest":"^4.0.18","typescript":"^5.5.0","@types/react":"^18.3.0","vite-plugin-dts":"^4.0.0","@types/react-dom":"^18.3.0","@vitejs/plugin-react":"^4.3.0","@testing-library/react":"^16.3.2","@testing-library/jest-dom":"^6.9.1"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"peerDependenciesMeta":{"d3":{"optional":true},"shiki":{"optional":true},"resium":{"optional":true},"remark-gfm":{"optional":true},"@cesium/engine":{"optional":true},"react-markdown":{"optional":true},"react-force-graph-2d":{"optional":true},"react-force-graph-3d":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/a2ui-canvas_0.2.0_1770371127538_0.9134049417272783","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@atlas.agents/a2ui-canvas","version":"0.2.1","type":"module","description":"A2UI-native dynamic canvas component for React — interoperable with LangChain, 3dchat, Microsoft Agent Framework, and any A2UI-speaking client","main":"dist/index.cjs","module":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./schema":{"types":"./dist/schema.d.ts","import":"./dist/schema.js","require":"./dist/schema.cjs"},"./renderers/chart":{"types":"./dist/renderers/ChartRenderer.d.ts","import":"./dist/renderers/chart.js","require":"./dist/renderers/chart.cjs"},"./renderers/timeline":{"types":"./dist/renderers/TimelineRenderer.d.ts","import":"./dist/renderers/timeline.js","require":"./dist/renderers/timeline.cjs"},"./renderers/knowledge-graph":{"types":"./dist/renderers/KnowledgeGraphRenderer.d.ts","import":"./dist/renderers/knowledge-graph.js","require":"./dist/renderers/knowledge-graph.cjs"},"./renderers/map":{"types":"./dist/renderers/MapRenderer.d.ts","import":"./dist/renderers/map.js","require":"./dist/renderers/map.cjs"},"./renderers/media":{"types":"./dist/renderers/MediaRenderer.d.ts","import":"./dist/renderers/media.js","require":"./dist/renderers/media.cjs"},"./renderers/document":{"types":"./dist/renderers/DocumentRenderer.d.ts","import":"./dist/renderers/document.js","require":"./dist/renderers/document.cjs"},"./renderers/code":{"types":"./dist/renderers/CodeRenderer.d.ts","import":"./dist/renderers/code.js","require":"./dist/renderers/code.cjs"},"./renderers/artifact":{"types":"./dist/renderers/ArtifactRenderer.d.ts","import":"./dist/renderers/artifact.js","require":"./dist/renderers/artifact.cjs"}},"scripts":{"build":"vite build","dev":"vite","type-check":"tsc --noEmit","test":"vitest run","test:watch":"vitest"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0"},"peerDependenciesMeta":{"d3":{"optional":true},"react-force-graph-2d":{"optional":true},"react-force-graph-3d":{"optional":true},"react-markdown":{"optional":true},"remark-gfm":{"optional":true},"shiki":{"optional":true},"@cesium/engine":{"optional":true},"resium":{"optional":true}},"dependencies":{"lucide-react":"^0.400.0","zustand":"^5.0.0"},"devDependencies":{"@testing-library/jest-dom":"^6.9.1","@testing-library/react":"^16.3.2","@types/react":"^18.3.0","@types/react-dom":"^18.3.0","@vitejs/plugin-react":"^4.3.0","jsdom":"^28.0.0","typescript":"^5.5.0","vite":"^7.3.1","vite-plugin-dts":"^4.0.0","vitest":"^4.0.18"},"keywords":["react","canvas","visualization","a2ui","ai-native","streaming","d3","timeline","chart","knowledge-graph","component","ui","dynamic","langchain","agent"],"author":"","license":"MIT","_id":"@atlas.agents/a2ui-canvas@0.2.1","gitHead":"1b7c38b4e25ac785d8721fbdf09a3f1962a4698b","_nodeVersion":"20.20.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-CO1D6EZmb3+6WjCneNmMx2Lt6m4TAKCSWDK3D5q6f7hLNuQgFaFzSSsJrbZKLacxomPMUnVK/NlsVaqQqekVQw==","shasum":"1763d668bd09c375447a37c78b0fa33fffece17a","tarball":"https://registry.npmjs.org/@atlas.agents/a2ui-canvas/-/a2ui-canvas-0.2.1.tgz","fileCount":120,"unpackedSize":200159,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHb2djXusT0pnu/8qSXQ27/f9mYr9RVi2OUAw50lofamAiEAoec0zxfmnDNLnKz6I/6q5ZBchgAz7akqlVqKuY5tnKg="}]},"_npmUser":{"name":"davincidreams","email":"lisamegawatts@gmail.com"},"directories":{},"maintainers":[{"name":"davincidreams","email":"lisamegawatts@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/a2ui-canvas_0.2.1_1770371408713_0.7080489302008695"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-06T09:45:27.403Z","modified":"2026-02-06T09:50:09.027Z","0.2.0":"2026-02-06T09:45:27.726Z","0.2.1":"2026-02-06T09:50:08.871Z"},"license":"MIT","keywords":["react","canvas","visualization","a2ui","ai-native","streaming","d3","timeline","chart","knowledge-graph","component","ui","dynamic","langchain","agent"],"description":"A2UI-native dynamic canvas component for React — interoperable with LangChain, 3dchat, Microsoft Agent Framework, and any A2UI-speaking client","maintainers":[{"name":"davincidreams","email":"lisamegawatts@gmail.com"}],"readme":"# @atlas.agents/a2ui-canvas\n\nA2UI-native dynamic canvas component for React. Renders streaming, agent-driven visuals from any A2UI-speaking source — LangChain agents, Microsoft Agent Framework, or direct JSON.\n\n## Features\n\n- **A2UI Protocol**: Native support for the Agent-to-UI message protocol (createSurface, updateDataModel, updateComponents, etc.)\n- **9 Renderers**: Chart, Timeline, KnowledgeGraph, Map, Media, Document, Code, Artifact, Custom\n- **Streaming**: JSONL, SSE, WebSocket, and direct message ingestion with batched updates\n- **Lazy Loading**: Heavy renderers (D3, Cesium, shiki) loaded on demand with SVG fallbacks\n- **Schema-Only Export**: Zero-React-dependency `./schema` entry point for server-side / non-JS consumers\n- **Multi-Entry Build**: Tree-shake individual renderers via `./renderers/chart`, `./renderers/map`, etc.\n- **Theme System**: Built-in light/dark themes with full customization\n- **Type Safe**: Full TypeScript support with discriminated union component types\n- **Backward Compatible**: Legacy `CanvasProvider`, `useCanvas`, `useCanvasContent` hooks still work\n\n## Installation\n\n```bash\nnpm install @atlas.agents/a2ui-canvas\n```\n\n### Optional Peer Dependencies\n\nInstall only the renderers you need:\n\n```bash\n# Charts (D3)\nnpm install d3\n\n# Documents (Markdown)\nnpm install react-markdown remark-gfm\n\n# Code (syntax highlighting)\nnpm install shiki\n\n# Knowledge Graph (force-directed)\nnpm install react-force-graph-2d\n# or for 3D:\nnpm install react-force-graph-3d\n\n# Map (Cesium globe)\nnpm install @cesium/engine resium\n```\n\nAll renderers include built-in SVG/HTML fallbacks when their optional deps are not installed.\n\n## Quick Start\n\n### A2UI Messages (recommended)\n\nFeed A2UI JSON messages from your AI agent and the canvas renders automatically:\n\n```tsx\nimport { useA2UISurface, RendererResolver } from '@atlas.agents/a2ui-canvas';\n\nfunction AgentCanvas() {\n  const { activeSurface, getComponents, resolveData, store } = useA2UISurface({\n    sseUrl: '/api/agent/stream',\n  });\n\n  if (!activeSurface) return <div>Waiting for agent...</div>;\n\n  return (\n    <div>\n      {getComponents(activeSurface.id).map((component) => (\n        <RendererResolver\n          key={component.id}\n          component={component}\n          data={resolveData(activeSurface.id, '/')}\n          theme=\"dark\"\n        />\n      ))}\n    </div>\n  );\n}\n```\n\n### Direct Messages\n\nProcess A2UI messages directly without a stream:\n\n```tsx\nimport { useA2UISurface } from '@atlas.agents/a2ui-canvas';\n\nconst messages = [\n  { createSurface: { surfaceId: 's1' } },\n  {\n    updateDataModel: {\n      surfaceId: 's1',\n      path: '/chart',\n      value: { labels: ['Jan', 'Feb', 'Mar'], values: [10, 25, 18] },\n    },\n  },\n  {\n    updateComponents: {\n      surfaceId: 's1',\n      components: [\n        {\n          id: 'c1',\n          component: 'Chart',\n          chartType: 'bar',\n          data: '/chart',\n        },\n      ],\n    },\n  },\n];\n\nfunction App() {\n  const { activeSurface, getComponents } = useA2UISurface({ messages });\n  // ...render components\n}\n```\n\n### WebSocket / Fetch Stream\n\n```tsx\n// WebSocket\nconst result = useA2UISurface({ wsUrl: 'wss://agent.example.com/stream' });\n\n// Fetch (JSONL body)\nconst result = useA2UISurface({\n  streamUrl: '/api/agent/generate',\n  streamInit: { method: 'POST', body: JSON.stringify({ prompt: '...' }) },\n});\n```\n\n### Legacy API\n\nThe original `CanvasProvider` / `useCanvas` API still works:\n\n```tsx\nimport { CanvasProvider, useCanvas, themes } from '@atlas.agents/a2ui-canvas';\n\nfunction App() {\n  return (\n    <CanvasProvider initialTheme={themes.dark}>\n      <MyApp />\n    </CanvasProvider>\n  );\n}\n\nfunction MyApp() {\n  const { content, setContent } = useCanvas();\n  // ...\n}\n```\n\n## A2UI Protocol\n\nThe library speaks the A2UI (Agent-to-UI) protocol. Agents send JSON messages to create surfaces, populate data models, and attach components:\n\n### Envelope Messages\n\n| Message | Description |\n|---------|-------------|\n| `createSurface` | Create a new UI surface (canvas) |\n| `destroySurface` | Remove a surface |\n| `updateDataModel` | Set data at a JSON Pointer path |\n| `updateComponents` | Set or replace components on a surface |\n| `removeComponents` | Remove components by ID |\n| `appendData` | Append items to an array (streaming convenience) |\n| `patchDataModel` | JSON merge-patch the data model |\n\n### Component Types\n\n| Component | Description | Optional Dep |\n|-----------|-------------|-------------|\n| `Chart` | Bar, line, scatter, pie, area, donut charts | `d3` |\n| `Timeline` | Events with alternating/grouped layouts | — |\n| `KnowledgeGraph` | Force-directed node-edge graph | `react-force-graph-2d` |\n| `Map` | Globe with markers | `@cesium/engine` + `resium` |\n| `Media` | Image, video, audio | — |\n| `Document` | Markdown/HTML documents | `react-markdown` |\n| `Code` | Syntax-highlighted code blocks | `shiki` |\n| `Artifact` | Sandboxed iframe (HTML/CSS/JS) | — |\n| `Custom` | Registry-key based escape hatch | — |\n\n### Example: Streaming a Chart\n\n```jsonl\n{\"createSurface\":{\"surfaceId\":\"s1\",\"title\":\"Sales Dashboard\"}}\n{\"updateDataModel\":{\"surfaceId\":\"s1\",\"path\":\"/sales\",\"value\":{\"labels\":[\"Q1\",\"Q2\",\"Q3\",\"Q4\"],\"values\":[120,340,250,410]}}}\n{\"updateComponents\":{\"surfaceId\":\"s1\",\"components\":[{\"id\":\"chart1\",\"component\":\"Chart\",\"chartType\":\"bar\",\"data\":\"/sales\",\"title\":\"Quarterly Sales\"}]}}\n```\n\n### Example: Streaming a Timeline\n\n```jsonl\n{\"createSurface\":{\"surfaceId\":\"s1\"}}\n{\"updateDataModel\":{\"surfaceId\":\"s1\",\"path\":\"/events\",\"value\":[{\"date\":\"2024-01-15\",\"title\":\"Project Started\",\"description\":\"Kickoff meeting\"},{\"date\":\"2024-06-01\",\"title\":\"v1.0 Release\",\"description\":\"First public release\"}]}}\n{\"updateComponents\":{\"surfaceId\":\"s1\",\"components\":[{\"id\":\"t1\",\"component\":\"Timeline\",\"events\":\"/events\",\"layout\":\"alternating\"}]}}\n```\n\n## Schema-Only Import\n\nFor server-side validation or non-React consumers (Python, C#, etc.), import types and validation without React:\n\n```ts\nimport {\n  validateMessage,\n  validateComponent,\n  isA2UIMessage,\n  DYNAMIC_CANVAS_CATALOG,\n  type A2UIMessage,\n  type A2UIComponent,\n} from '@atlas.agents/a2ui-canvas/schema';\n\nconst msg = { createSurface: { surfaceId: 's1' } };\nconst result = validateMessage(msg);\n// { valid: true, messageType: 'createSurface' }\n```\n\n## API Reference\n\n### Hooks\n\n#### `useA2UISurface(options?)`\n\nPrimary hook — connects to a stream and manages surfaces.\n\n```ts\ninterface UseA2UISurfaceOptions {\n  sseUrl?: string;           // SSE endpoint\n  wsUrl?: string;            // WebSocket endpoint\n  streamUrl?: string;        // Fetch stream URL\n  streamInit?: RequestInit;  // Fetch init options\n  messages?: A2UIMessage[];  // Direct messages\n  batchWindow?: number;      // Batch window in ms (default: 50)\n  onError?: (error: Error) => void;\n  store?: StoreApi<SurfaceManagerStore>; // Shared store\n}\n```\n\nReturns: `surfaces`, `activeSurface`, `setActiveSurface`, `processMessage`, `processMessages`, `resolveData`, `getComponents`, `store`\n\n#### `useStreamingContent(options)`\n\nSubscribe to a single surface's streaming updates.\n\n```ts\nconst { surface, components, dataModel, resolveData, updatedAt } = useStreamingContent({\n  store,       // from useA2UISurface\n  surfaceId,   // surface to watch\n});\n```\n\n### Individual Renderer Imports\n\nTree-shake by importing only what you need:\n\n```ts\nimport ChartRenderer from '@atlas.agents/a2ui-canvas/renderers/chart';\nimport TimelineRenderer from '@atlas.agents/a2ui-canvas/renderers/timeline';\nimport KnowledgeGraphRenderer from '@atlas.agents/a2ui-canvas/renderers/knowledge-graph';\nimport MapRenderer from '@atlas.agents/a2ui-canvas/renderers/map';\nimport MediaRenderer from '@atlas.agents/a2ui-canvas/renderers/media';\nimport DocumentRenderer from '@atlas.agents/a2ui-canvas/renderers/document';\nimport CodeRenderer from '@atlas.agents/a2ui-canvas/renderers/code';\nimport ArtifactRenderer from '@atlas.agents/a2ui-canvas/renderers/artifact';\n```\n\n### Content Analyzer\n\nAuto-detect content type from raw text and convert to A2UI messages:\n\n```ts\nimport { ContentAnalyzer } from '@atlas.agents/a2ui-canvas';\n\n// Detect content type\nContentAnalyzer.detectType('```js\\nconsole.log(\"hi\")\\n```'); // 'code'\nContentAnalyzer.detectType('# Hello World');                  // 'document'\nContentAnalyzer.detectType('2024-01-01 Project Start');       // 'timeline'\n\n// Convert to A2UI messages\nconst messages = ContentAnalyzer.toA2UIMessages('```python\\nprint(\"hello\")\\n```');\n// Returns: [createSurface, updateComponents with Code component]\n```\n\n## Theming\n\n```tsx\nimport { themes } from '@atlas.agents/a2ui-canvas';\n\n// Built-in themes\nthemes.light\nthemes.dark\nthemes.default\n\n// Custom theme\nconst myTheme = {\n  colors: {\n    background: '#0a0a0a',\n    surface: '#1a1a2e',\n    primary: '#0ea5e9',\n    secondary: '#6366f1',\n    text: '#e2e8f0',\n    muted: '#64748b',\n    border: '#334155',\n    highlight: '#1e293b',\n  },\n  // ...spacing, typography, borderRadius, shadows\n};\n```\n\n## Custom Renderers\n\nRegister custom renderers by key:\n\n```tsx\nimport { ComponentRegistry } from '@atlas.agents/a2ui-canvas';\n\nconst registry = new ComponentRegistry();\nregistry.register('MyWidget', () => import('./MyWidget'));\n\n// Then in A2UI messages:\n{\n  updateComponents: {\n    surfaceId: 's1',\n    components: [{ id: 'w1', component: 'Custom', rendererKey: 'MyWidget', props: { foo: 'bar' } }]\n  }\n}\n```\n\n## Architecture\n\n```\nAI Agent → A2UI JSON → StreamProcessor → SurfaceManager → RendererResolver → React Renderers\n               (JSONL/SSE/WS)    (zustand store)     (Suspense + ErrorBoundary)\n                                                                    ↓\n                                    Chart | Timeline | Graph | Map | Media | Doc | Code | Artifact | Custom\n```\n\n- **StreamProcessor**: Parses JSONL, SSE, WebSocket, or direct JSON arrays\n- **SurfaceManager**: Zustand store managing surfaces, data models, and components\n- **RendererResolver**: Suspense + ErrorBoundary wrapper for lazy-loaded renderers\n- **ComponentRegistry**: Maps component type strings to React renderer factories\n\n## Bundle Size\n\n| Entry | Gzip |\n|-------|------|\n| Schema only (`./schema`) | ~2 KB |\n| Core + all renderers (`.`) | ~8 KB |\n| Individual renderers | 0.4–2.5 KB each |\n\nHeavy dependencies (D3, Cesium, shiki) are loaded on demand when a component requires them.\n\n## Development\n\n```bash\nnpm install\nnpm run dev          # Start Vite dev server\nnpm run build        # Build library (ES + CJS)\nnpm run type-check   # TypeScript check\nnpm test             # Run tests (124 tests)\nnpm run test:watch   # Watch mode\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}