# dsh-visualize

> Render interactive cards directly in DSH model conversations, displaying charts, simulators, comparison panels, and UI mockups as HTML snippets.

## Metadata

- Author: [@Nagi-ovo](https://github.com/Nagi-ovo)
- Repo: <https://github.com/Nagi-ovo/dsh-visualize.git>
- GitHub: [Nagi-ovo/dsh-visualize](https://github.com/Nagi-ovo/dsh-visualize)
- Stars: 191
- Language: TypeScript
- License: [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html)
- Topics: `data-visualization`, `deepseek-harness`, `dsh-plugin`, `interactive-visualization`
- Forks: 5
- Open Issues: 3
- Last push: 2026-08-17T16:27:54.000Z
- Added: 2026-08-13T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:Nagi-ovo/dsh-visualize
```

## Wiki

## One-Line Positioning
Upgrades DSH model responses from plain text to interactive visualization cards within conversations. The model passes an HTML fragment directly as a parameter to the `visualize` tool, and the host Web UI renders a clickable, adjustable, draggable card in the response to display charts, simulators, comparison panels, and UI mockups.

## Core Capabilities
- **Register `visualize` tool**: The model passes an entire embedded HTML fragment (markup + styles + scripts) as the `fragment` parameter, and the host renders it directly as an in-conversation card without generating intermediate files
- **Companion `visualize` skill**: Automatically loads fragment authoring specifications before the model's first call, defining fragment structure, theme variables, byte limits, and allowed CDN whitelist
- **Supports `action: "create"` and `action: "update"`**: create renders a new card; update performs precise old_str→new_str partial replacement on already-rendered cards, more efficient for small modifications
- **Streaming preview**: During model generation, a work-in-progress card is displayed in real-time below the conversation input area, with already-written scripts executing immediately; preview disappears after the call ends, regular conversation cards take over
- **Sandboxed rendering**: Each card runs in an opaque-origin `<iframe sandbox="allow-scripts">` with built-in CSP, blocking external requests, nested pages, and form submissions; external static resources can only load from whitelisted CDNs
- **Follows host theme**: Cards read DSH's whale blue and other design variables and inject them into the frame, re-rendering in real-time when light/dark theme switches or OS appearance changes

## Technical Implementation
- **Language**: TypeScript (including .tsx browser-side components)
- **Key dependencies**: `@deepseek-ai/cordis` (host injection), `@deepseek-ai/dsh-tools` (register visualize tool), `@deepseek-ai/dsh-skill` (register visualization skill provider), `@deepseek-ai/dsh-client-runtime` and `@deepseek-ai/dsh-client-ui-tool` (browser-side runtime)
- **Architecture pattern**: Plugin split into "server-side half + browser-side half". Server-side half injects three host services via Cordis: `tools`, `skills`, `fs` to register visualization tool and embedded skill; browser-side half injects `slots`, registers card component with key `visualize` on `tool.call.toolview`, and mounts streaming preview component on `conversation.input.dock`. TUI/headless clients without browser-side registration fallback to plain text tool results per documentation conventions
- **Entry files**: `src/index.ts` (server-side Cordis plugin entry) → `src/tool.ts` (visualize tool definition) → `src/skill.ts` (visualize skill provider) → `src/client/index.tsx` (browser-side slot registration) → `src/client/VisualizeCard.tsx` and `src/client/StreamingPreview.tsx` (React components)

## Use Cases
Use when you need to display an interactive chart in conversation, a simulator with sliders for parameter adjustment, side-by-side comparison of multiple versions, or a product page mockup, without leaving DSH to open external BI/drawing tools. Best suited for "user asks one question, model replies with one actionable card" scenarios; purely static relational diagrams are more efficiently done with Mermaid fences.

## Prerequisites & Compatibility
| Dependency | Minimum Version | Description |
|---|---|---|
| DSH (cordis / dsh-tools / dsh-skill / dsh-fs / dsh-llm / dsh-sandbox-policy / dsh-session) | ^0.1.0-rc.6 | Plugin injects three host services via Cordis: `tools`/`skills`/`fs`; all peerDependencies are ^0.1.0-rc.6 |
| Browser-side runtime (@deepseek-ai/dsh-client-runtime / dsh-client-ui-tool / dsh-client-ui-conversation) | ^0.1.0-rc.6 | Only required for Web UI; TUI/headless auto-fallback to tool result text when missing |
| React | ^18.2.0 | Browser-side component framework; injected by host |
| Node.js | Not declared | package.json does not declare engines field; DSH 0.1.0-rc.6 host includes required runtime |
| Platform | Cross-platform | No os/cpu restrictions; card rendering happens on browser side |

## Installation
```bash
dsh plugin --profile web add github:Nagi-ovo/dsh-visualize
```

## Configuration Options
| Config | Type | Description | Default |
|---|---|---|---|
| `maxFragmentBytes` | Integer (natural number) | Maximum bytes allowed per card (including markup/style/script). Tool rejects and prompts to trim inline data when exceeded. | `1000000` (~1 MB) |

## FAQ

**Q: Model still replies with text after installation, how to make model call visualize?**

A: Model needs to load the `visualize` skill in the session to write fragments. If it doesn't trigger in a new session, restart dsh web once to let skill registration take effect; or directly say "use visualize card to draw XX" in your question.

**Q: Tool prompts "fragment contains a document-skeleton tag", how to fix?**

A: Don't write outer tags like `<!doctype>`, `<html>`, `<head>`, `<body>` in fragments; the host card provides its own document skeleton, styles, and theme—fragments should only contain body structure.

**Q: fetch, XHR, WebSocket in card not responding?**

A: Cards run in a sandboxed iframe with opaque origin; CSP prohibits connect-src external connections, only allowing static resources from whitelisted CDNs (like Chart.js, D3). When needing to fetch data, model should write data directly into fragment.

**Q: Buttons in card don't respond, how to send messages back to conversation?**

A: Current version doesn't support card buttons sending follow-up messages to main conversation; when needing to redraw, model must call visualize again. For "Apply" and similar buttons, tell the model directly.

**Q: Use update or recreate for partial modifications?**

A: Use `action: "update"` for old_str→new_str replacement when modifications are within 20 lines, 5 places, and no more than 4 responses—more efficient. Structural changes or larger revisions should recreate a card. Each update reloads the card, resetting slider inputs and other control states to initial values.

**Q: Why don't TUI and headless clients display?**

A: Interactive cards currently only render in Web UI; TUI and headless clients only see a confirmation text "Rendered ... (X bytes; workspace copy at ...)", fragment files still exist, need to open dsh web in browser to see cards.

**Q: What's the maximum size for a single card?**

A: Default single fragment limit is 1,000,000 bytes (~1 MB), adjustable via `maxFragmentBytes` in dsh profile config. Exceeding triggers direct error with prompts to reduce lines or lower precision.

**Q: How to completely uninstall?**

A: `dsh plugin --profile web remove github:Nagi-ovo/dsh-visualize`, restart dsh web. Cards in already-rendered sessions will revert to plain tool result text.

## Difficulty Level
Beginner — No configuration needed for regular users; model-side syntax is automatically learned via built-in skill; users only need to describe desired visualization content in prompts. Developers need familiarity with Cordis plugin protocol, DSH tool/skill registration flow, and React for secondary development.

## Known Issues & Limitations
- Only Web UI renders interactive cards: TUI and headless clients lack browser-side half, will fallback to plain text tool results (`README.md:44`)
- Card buttons cannot send follow-up messages to main conversation (`README.md:44`)
- Card height has limits: inline mode 800px, wide mode 1200px, internal scrolling when exceeded (`src/client/VisualizeCard.tsx:27`)
- `update` operation has frequency and scope limits: max 4 times per response, each modification under 20 lines / 5 places; recommend recreate when exceeded (`assets/visualize-skill.md:51-53`)
- Each card update reloads, temporary states of sliders, input boxes and other controls reset to initial values (`assets/visualize-skill.md:63`)
- External static resources only allowed from fixed whitelist CDNs: cdnjs.cloudflare.com, cdn.jsdelivr.net, esm.sh, unpkg.com, fonts.bunny.net, fonts.googleapis.com, fonts.gstatic.com (`src/shell.ts:20-28`)
- Model must not include document skeleton tags in fragments (`<!doctype>` / `<html>` / `<head>` / `<body>`), otherwise tool errors directly (`src/fragment.ts:55-74`)
- Fragment byte limit default is 1 MB; need to increase `maxFragmentBytes` config for large data scenarios (`src/index.ts:36-38`)

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-visualize](https://deepseek-plugin.org/plugins/Nagi-ovo/dsh-visualize)
Wiki generated by AI (model: `MiniMax-M2.5`)
