Kocoro Generative UI
You produce rich visual content — SVG diagrams and HTML interactive widgets —
that renders inline in the Kocoro Desktop conversation, token-by-token, in a
WKWebView sandbox.
Channel availability: This skill is only exposed to the LLM on Desktop /
TUI / direct API paths. The Kocoro daemon suppresses it on cloud-distributed
channels (Feishu, Lark, WeCom, Slack, LINE, Telegram, webhook) because their
clients render markdown but not html-artifact fences — see
internal/daemon/skill_filter.go (desktopOnlySkills).
Output Contract
Wrap every widget in a markdown fenced code block with info string
html-artifact:
```html-artifact title="Q1 revenue" id=art_a1 mime=text/html
<style>.bar{background:var(--color-background-info)}</style>
<h2 class="sr-only">Bar chart of Q1 revenue across three regions</h2>
<div style="position:relative;height:240px"><canvas id="c1"></canvas></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"></script>
<script>
new Chart(document.getElementById('c1'), { /* ... */ });
</script>
```
title — required; shown to the user and used as export filename stem
id — optional; if absent, host generates a UUID
mime — text/html (default) or image/svg+xml
theme — auto (default), light, or dark
- The content is a fragment. Do NOT write
<!DOCTYPE>, <html>, <head>,
<body> — the host wraps them.
- Explanatory prose goes OUTSIDE the fence, in your normal reply.
- Max 3 artifacts per reply.
- When you need to show the user the fence syntax itself (e.g., teaching this
feature), insert a zero-width space (U+200B) between the backticks in the
example: ```html-artifact. This prevents
your example from being captured as a real artifact.
Streaming Safety
Output streams token-by-token. Structure code so useful content appears early
and the script tag last:
- HTML:
<style> (short) → content HTML → <script> last. Scripts execute
after the fence closes, not during streaming.
- SVG:
<defs> (markers) → visual elements.
- Avoid gradients, shadows, blur — they flash during streaming DOM diffs. Use
solid flat fills.
- No
<!-- HTML comments --> or /* CSS comments */. They waste tokens and
may land mid-stream in ways that confuse rendering.
CDN allowlist (CSP-enforced)
External scripts, styles, fonts, images, and fetch / XMLHttpRequest / d3.json calls may reach ONLY these four hosts:
cdnjs.cloudflare.com
esm.sh
cdn.jsdelivr.net
unpkg.com
Any other origin is blocked by CSP and the request silently fails. You cannot
call arbitrary external APIs, your own backend, raw.githubusercontent.com,
or anything else — only static assets from these four CDNs. This applies to
both <script src>/<link href> loads and runtime fetch() calls (e.g. D3
topology JSON from jsdelivr is fine; fetching a weather API is not).
Design system
- Flat — no gradients, mesh backgrounds, noise textures, decorative
effects. Clean flat surfaces only.
- Dark mode is mandatory — every color must work in both light and dark.
Use the CSS variables below; they auto-adapt. Never hardcode
color: #333.
CSS variables provided by the host
Use these, not hardcoded hex:
- Backgrounds:
--color-background-primary (white/near-black),
--color-background-secondary (surfaces), --color-background-tertiary
(page bg), --color-background-info, --color-background-danger,
--color-background-success, --color-background-warning
- Text:
--color-text-primary, --color-text-secondary,
--color-text-tertiary, --color-text-info, --color-text-danger,
--color-text-success, --color-text-warning
- Borders:
--color-border-tertiary (0.08α, default),
--color-border-secondary (0.16α, hover), --color-border-primary (0.24α),
semantic -info/-danger/-success/-warning
- Typography:
--font-sans (SF Pro), --font-serif (New York, rare editorial
use), --font-mono (SF Mono)
- Layout:
--border-radius-md (8px), --border-radius-lg (12px, preferred),
--border-radius-xl (16px)
Typography
- Default font is
var(--font-sans). Headings: h1 22px, h2 18px, h3 16px —
all font-weight: 500. Body: 16px, weight 400, line-height 1.7.
- Two weights only: 400 regular, 500 bold. Never 600 or 700.
- Sentence case always. Never Title Case, never ALL CAPS. Applies to SVG text
labels and diagram headings too.
- No mid-sentence bolding. Bold is for headings and labels only. Entity names,
class names, function names go in
code style, not bold.
Borders, corners, form elements
- Borders:
0.5px solid var(--color-border-tertiary) (upgrade to -secondary
on hover).
- Corners:
var(--border-radius-md) for most elements, -lg for cards.
- No rounded corners on single-sided borders.
- Form elements (
input, select, textarea, button, range input) are
pre-styled — write bare tags, override only when necessary.
Widget container
- The container is
display: block; width: 100%. Start with your content
directly; no wrapper div needed. If you want vertical breathing room, add
padding: 1rem 0 on your first element.
- Never use
position: fixed — the host sizes the iframe to content height,
so fixed positioning collapses it. For modal mockups, wrap everything in a
normal-flow faux-viewport: <div style="min-height: 400px; background: rgba(0,0,0,0.45); display: flex; align-items: center; justify-content: center;"> and put the modal inside.
Color palette (9 ramps × 7 stops)
Classes: c-blue, c-teal, c-coral, c-pink, c-purple, c-green,
c-amber, c-red, c-gray. Each provides a light-mode and dark-mode
background + foreground + SVG fill/stroke. Apply to a <g> wrapping
shape+text, or to <rect>/<circle>/<ellipse> directly — never to <path>.
Assignment rules:
- Color encodes meaning, not sequence. Group nodes by category.
- Prefer
purple, teal, coral, pink for general diagram categories.
Reserve blue, green, amber, red for where the node genuinely
represents informational, success, warning, or error meaning.
- Use
gray for neutral/structural nodes.
- 2–3 colors per diagram, not 6+.
Text on colored backgrounds: use the 800 or 900 stop from the same ramp
for text — never plain black or generic gray. When both title and subtitle sit
on a colored fill, title must be darker (800 in light mode, 100 in dark) and
subtitle lighter (600 light, 200 dark).
Use case router
When the user asks for specific output types, read the relevant reference
file via the file_read tool:
- Charts (bar, line, pie, scatter, dashboards) →
references/charts.md —
Chart.js patterns, legends, number formatting
- Flowcharts / structural diagrams →
references/diagrams.md +
references/svg-setup.md
- Illustrative diagrams ("how does X work") →
references/diagrams.md
- UI mockups, cards, forms, comparisons →
references/ui-components.md
- Geographic maps (choropleths) →
references/maps.md
Scope
This skill is visualization-only. It does not search the web, call external
APIs, or retrieve live data. If the user's request requires fetching data from
the internet or an external source, complete that step first (using a search or
retrieval tool), then invoke this skill to visualize the results.
Forbidden
- Fetching live data or searching the web — data must already be in context
- Emoji (use CSS shapes or SVG paths)
- Gradients, drop shadows, blur, glow, neon
position: fixed
<!-- HTML comments --> / /* CSS comments */
- Font sizes below 11px
- Title Case / ALL CAPS (sentence case only)
- Mid-sentence bolding (use
code style for identifiers)
- Dark/colored backgrounds on the outermost container (host provides bg)
- Nested scrolling (auto-fit height)
display: none sections during streaming (hidden content streams
invisibly; show all stacked)
Accessibility
- HTML widgets: begin with a visually-hidden one-sentence summary:
<h2 class="sr-only">…</h2>.
- SVG widgets: root
<svg role="img"> with <title> and <desc> as the
first two children.
Output discipline
- Text goes in your response, visuals go in the artifact. Explanatory
paragraphs, intros, section headings — all in normal response prose, not
inside the fence.
- Tables go in response prose as markdown, not inside widgets.
- If you need multiple diagrams for a complex topic, stream them as separate
artifacts with prose between each.
Sharing externally (optional)
The inline html-artifact block is the primary output — it renders in
Kocoro Desktop with no public URL and no upload. Use it whenever the user's
goal is just "show me".
If the user also wants a sharable link (to send via Slack/Feishu/email, embed
in a doc, etc.), you may additionally:
- Use
file_write to save the same HTML body to a temp path
(e.g. /tmp/<short-id>.html).
- Use
publish_to_web with a specific purpose describing the recipient and
channel (e.g. "send revenue chart link to user via Slack").
Skip this entire block if the user did not ask for a shareable link — never
publish a copy "just in case." Public URLs cannot be deleted.
1---2name: kocoro-generative-ui3description: Generate interactive, inline HTML/SVG widgets (charts, diagrams, forms, dashboards, illustrations) that render in sandboxed iframes inside Kocoro Desktop chat. Use when the user asks to "visualize", "chart", "diagram", "explain visually", "show me", or when data is denser than a paragraph of prose.4---5
6# Kocoro Generative UI
7
8You produce rich visual content — SVG diagrams and HTML interactive widgets —
9that renders inline in the Kocoro Desktop conversation, token-by-token, in a
10WKWebView sandbox.
11
12> **Channel availability:** This skill is only exposed to the LLM on Desktop /
13> TUI / direct API paths. The Kocoro daemon suppresses it on cloud-distributed
14> channels (Feishu, Lark, WeCom, Slack, LINE, Telegram, webhook) because their
15> clients render markdown but not html-artifact fences — see
16> `internal/daemon/skill_filter.go` (`desktopOnlySkills`).
17
18## Output Contract
19
20Wrap every widget in a markdown fenced code block with info string
21`html-artifact`:
22
23 ```html-artifact title="Q1 revenue" id=art_a1 mime=text/html
24 <style>.bar{background:var(--color-background-info)}</style>
25 <h2 class="sr-only">Bar chart of Q1 revenue across three regions</h2>
26 <div style="position:relative;height:240px"><canvas id="c1"></canvas></div>
27 <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"></script>
28 <script>
29 new Chart(document.getElementById('c1'), { /* ... */ });
30 </script>
31 ```
32
33- `title` — required; shown to the user and used as export filename stem
34- `id` — optional; if absent, host generates a UUID
35- `mime` — `text/html` (default) or `image/svg+xml`
36- `theme` — `auto` (default), `light`, or `dark`
37- The content is a **fragment**. Do NOT write `<!DOCTYPE>`, `<html>`, `<head>`,
38 `<body>` — the host wraps them.
39- Explanatory prose goes OUTSIDE the fence, in your normal reply.
40- Max 3 artifacts per reply.
41- When you need to show the user the fence syntax itself (e.g., teaching this
42 feature), insert a zero-width space (U+200B) between the backticks in the
43 example: <code>``​`html-artifact</code>. This prevents
44 your example from being captured as a real artifact.
45
46## Streaming Safety
47
48Output streams token-by-token. Structure code so useful content appears early
49and the script tag last:
50
51- HTML: `<style>` (short) → content HTML → `<script>` last. Scripts execute
52 after the fence closes, not during streaming.
53- SVG: `<defs>` (markers) → visual elements.
54- Avoid gradients, shadows, blur — they flash during streaming DOM diffs. Use
55 solid flat fills.
56- No `<!-- HTML comments -->` or `/* CSS comments */`. They waste tokens and
57 may land mid-stream in ways that confuse rendering.
58
59## CDN allowlist (CSP-enforced)
60
61External scripts, styles, fonts, images, and `fetch` / `XMLHttpRequest` / `d3.json` calls may reach ONLY these four hosts:
62
63- `cdnjs.cloudflare.com`
64- `esm.sh`
65- `cdn.jsdelivr.net`
66- `unpkg.com`
67
68Any other origin is blocked by CSP and the request silently fails. You cannot
69call arbitrary external APIs, your own backend, `raw.githubusercontent.com`,
70or anything else — only static assets from these four CDNs. This applies to
71both `<script src>`/`<link href>` loads and runtime `fetch()` calls (e.g. D3
72topology JSON from jsdelivr is fine; fetching a weather API is not).
73
74## Design system
75
76- **Flat** — no gradients, mesh backgrounds, noise textures, decorative
77 effects. Clean flat surfaces only.
78- **Dark mode is mandatory** — every color must work in both light and dark.
79 Use the CSS variables below; they auto-adapt. Never hardcode `color: #333`.
80
81### CSS variables provided by the host
82
83Use these, not hardcoded hex:
84
85- Backgrounds: `--color-background-primary` (white/near-black),
86 `--color-background-secondary` (surfaces), `--color-background-tertiary`
87 (page bg), `--color-background-info`, `--color-background-danger`,
88 `--color-background-success`, `--color-background-warning`
89- Text: `--color-text-primary`, `--color-text-secondary`,
90 `--color-text-tertiary`, `--color-text-info`, `--color-text-danger`,
91 `--color-text-success`, `--color-text-warning`
92- Borders: `--color-border-tertiary` (0.08α, default),
93 `--color-border-secondary` (0.16α, hover), `--color-border-primary` (0.24α),
94 semantic `-info/-danger/-success/-warning`
95- Typography: `--font-sans` (SF Pro), `--font-serif` (New York, rare editorial
96 use), `--font-mono` (SF Mono)
97- Layout: `--border-radius-md` (8px), `--border-radius-lg` (12px, preferred),
98 `--border-radius-xl` (16px)
99
100### Typography
101
102- Default font is `var(--font-sans)`. Headings: h1 22px, h2 18px, h3 16px —
103 all `font-weight: 500`. Body: 16px, weight 400, line-height 1.7.
104- Two weights only: 400 regular, 500 bold. Never 600 or 700.
105- Sentence case always. Never Title Case, never ALL CAPS. Applies to SVG text
106 labels and diagram headings too.
107- No mid-sentence bolding. Bold is for headings and labels only. Entity names,
108 class names, function names go in `code style`, not **bold**.
109
110### Borders, corners, form elements
111
112- Borders: `0.5px solid var(--color-border-tertiary)` (upgrade to `-secondary`
113 on hover).
114- Corners: `var(--border-radius-md)` for most elements, `-lg` for cards.
115- No rounded corners on single-sided borders.
116- Form elements (`input`, `select`, `textarea`, `button`, range `input`) are
117 pre-styled — write bare tags, override only when necessary.
118
119### Widget container
120
121- The container is `display: block; width: 100%`. Start with your content
122 directly; no wrapper div needed. If you want vertical breathing room, add
123 `padding: 1rem 0` on your first element.
124- Never use `position: fixed` — the host sizes the iframe to content height,
125 so fixed positioning collapses it. For modal mockups, wrap everything in a
126 normal-flow faux-viewport: `<div style="min-height: 400px; background:
127 rgba(0,0,0,0.45); display: flex; align-items: center; justify-content:
128 center;">` and put the modal inside.
129
130## Color palette (9 ramps × 7 stops)
131
132Classes: `c-blue`, `c-teal`, `c-coral`, `c-pink`, `c-purple`, `c-green`,
133`c-amber`, `c-red`, `c-gray`. Each provides a light-mode and dark-mode
134background + foreground + SVG fill/stroke. Apply to a `<g>` wrapping
135shape+text, or to `<rect>`/`<circle>`/`<ellipse>` directly — never to `<path>`.
136
137**Assignment rules:**
138- Color encodes meaning, not sequence. Group nodes by category.
139- Prefer `purple`, `teal`, `coral`, `pink` for general diagram categories.
140 Reserve `blue`, `green`, `amber`, `red` for where the node genuinely
141 represents informational, success, warning, or error meaning.
142- Use `gray` for neutral/structural nodes.
143- 2–3 colors per diagram, not 6+.
144
145**Text on colored backgrounds:** use the 800 or 900 stop from the same ramp
146for text — never plain black or generic gray. When both title and subtitle sit
147on a colored fill, title must be darker (800 in light mode, 100 in dark) and
148subtitle lighter (600 light, 200 dark).
149
150## Use case router
151
152When the user asks for specific output types, read the relevant reference
153file via the `file_read` tool:
154
155- Charts (bar, line, pie, scatter, dashboards) → `references/charts.md` —
156 Chart.js patterns, legends, number formatting
157- Flowcharts / structural diagrams → `references/diagrams.md` +
158 `references/svg-setup.md`
159- Illustrative diagrams ("how does X work") → `references/diagrams.md`
160- UI mockups, cards, forms, comparisons → `references/ui-components.md`
161- Geographic maps (choropleths) → `references/maps.md`
162
163## Scope
164
165This skill is visualization-only. It does not search the web, call external
166APIs, or retrieve live data. If the user's request requires fetching data from
167the internet or an external source, complete that step first (using a search or
168retrieval tool), then invoke this skill to visualize the results.
169
170## Forbidden
171
172- Fetching live data or searching the web — data must already be in context
173- Emoji (use CSS shapes or SVG paths)
174- Gradients, drop shadows, blur, glow, neon
175- `position: fixed`
176- `<!-- HTML comments -->` / `/* CSS comments */`
177- Font sizes below 11px
178- Title Case / ALL CAPS (sentence case only)
179- Mid-sentence bolding (use `code style` for identifiers)
180- Dark/colored backgrounds on the outermost container (host provides bg)
181- Nested scrolling (auto-fit height)
182- `display: none` sections during streaming (hidden content streams
183 invisibly; show all stacked)
184
185## Accessibility
186
187- HTML widgets: begin with a visually-hidden one-sentence summary:
188 `<h2 class="sr-only">…</h2>`.
189- SVG widgets: root `<svg role="img">` with `<title>` and `<desc>` as the
190 first two children.
191
192## Output discipline
193
194- Text goes in your response, visuals go in the artifact. Explanatory
195 paragraphs, intros, section headings — all in normal response prose, not
196 inside the fence.
197- Tables go in response prose as markdown, not inside widgets.
198- If you need multiple diagrams for a complex topic, stream them as separate
199 artifacts with prose between each.
200
201## Sharing externally (optional)
202
203The inline `html-artifact` block is the **primary** output — it renders in
204Kocoro Desktop with no public URL and no upload. Use it whenever the user's
205goal is just "show me".
206
207If the user *also* wants a sharable link (to send via Slack/Feishu/email, embed
208in a doc, etc.), you may additionally:
209
2101. Use `file_write` to save the same HTML body to a temp path
211 (e.g. `/tmp/<short-id>.html`).
2122. Use `publish_to_web` with a specific `purpose` describing the recipient and
213 channel (e.g. `"send revenue chart link to user via Slack"`).
214
215Skip this entire block if the user did not ask for a shareable link — never
216publish a copy "just in case." Public URLs cannot be deleted.