Word Cloud
render_wordcloud_chartVisualizes word frequency as a word cloud to identify dominant themes from survey responses, keywords, or topic frequency.
Instructions
Render a word cloud - 'What are the dominant themes?' Words sized by frequency or importance. Great for survey responses, keyword analysis, topic frequency.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Chart title | |
| data | Yes | Array of words with values | |
| options | No | ||
| theme | No | Theme preset: boardroom, corporate, sales-floor, golden-treasury, clinical, startup, ops-control, tokyo-midnight, zen-garden, consultant, black-tron, black-elegance, black-matrix, forest-amber, forest-earth, sky-light, sky-ocean, sky-twilight, gray-hf, gray-copilot | |
| palette | No | Override palette only (mix-and-match) | |
| typography | No | Override typography: professional, luxury, cyberpunk, editorial, mono, bold, system, techno | |
| effects | No | Override effects: none, subtle, shimmer, neon, energetic |
Implementation Reference
- src/charts/wordcloud.ts:29-99 (handler)The main handler function that renders a word cloud chart. It builds the HTML card layout, creates a Chart.js wordCloud instance (using chartjs-chart-wordcloud), scales font sizes linearly between 12-48px based on data values, and registers click/tooltip/export/refresh functionality.
export function renderWordCloudChart(container: HTMLElement, payload: WordCloudData): void { const { title, data, options } = payload; const theme = resolveTheme(payload.theme, { palette: payload.palette, typography: payload.typography, effects: payload.effects, }); if (theme) applyTheme(container, theme); container.innerHTML = ` <div class="chart-view"> <div class="card chart-card"> <div class="chart-card__header"> <div> <div class="chart-card__title${theme?.effects.shimmerTitle ? " shimmer-text" : ""}">${escapeHtml(title)}</div> <div class="chart-card__subtitle">${data.length} words</div> </div> </div> <div class="chart-card__body"> <canvas id="chart-canvas"></canvas> </div> </div> </div> `; const canvas = container.querySelector<HTMLCanvasElement>("#chart-canvas")!; const palette = resolveColors(options.colors, Math.min(data.length, 10)); // Scale font sizes: largest word = 48px, smallest = 12px const maxVal = Math.max(...data.map(d => d.value)); const minVal = Math.min(...data.map(d => d.value)); const range = maxVal - minVal || 1; const chartInstance = new Chart(canvas, { type: "wordCloud" as any, data: { labels: data.map(d => d.text), datasets: [{ data: data.map(d => 12 + ((d.value - minVal) / range) * 36), color: data.map((_, i) => palette[i % palette.length]), }], }, options: { responsive: true, maintainAspectRatio: false, onClick: (_event, elements) => { if (elements.length === 0) return; const idx = elements[0].index; const item = data[idx]; if (item) sendClickMessage(`"${item.text}": ${item.value} in "${title}"`); }, plugins: { legend: { display: false }, tooltip: { ...tooltipStyle(), callbacks: { label: (ctx: any) => { const item = data[ctx.dataIndex]; return item ? `${item.text}: ${item.value.toLocaleString()}` : ""; }, }, }, }, }, }); deferResize(chartInstance); addExportButton(container, chartInstance, title); addRefreshButton(container, () => (window as any).__mcpRefresh?.()); } - src/charts/wordcloud.ts:16-27 (schema)WordCloudData interface defining the input schema: type ('wordcloud'), title, data (array of WordItem with text/value), options (optional colors), theme, palette, typography, effects.
interface WordCloudData { type: "wordcloud"; title: string; data: WordItem[]; options: { colors?: string[]; }; theme?: string; palette?: string; typography?: string; effects?: string; } - src/charts/wordcloud.ts:101-101 (registration)Registers the wordcloud chart type under the tool name 'render_wordcloud_chart' via registerChart(). This maps the 'wordcloud' type from the server response to the render function.
registerChart("wordcloud", "render_wordcloud_chart", renderWordCloudChart); - src/charts/shared.ts:188-206 (helper)The registerChart function in shared.ts that manages the chart registry. When the server returns data with type 'wordcloud', the app dispatches to the registered handler via getChartEntry().
export function registerChart( type: string, toolName: string, render: (root: HTMLElement, data: any) => void, ): void { CHART_REGISTRY[type] = { toolName, render }; } export function getChartEntry(type: string): ChartEntry | undefined { return CHART_REGISTRY[type]; } export function getTypeToToolMap(): Record<string, string> { const map: Record<string, string> = {}; for (const [type, entry] of Object.entries(CHART_REGISTRY)) { map[type] = entry.toolName; } return map; } - src/app.ts:101-131 (helper)app.ts handles ontoolresult: parses the server response, looks up the 'wordcloud' type in the chart registry (via getTypeToToolMap/getChartEntry), and calls entry.render (which is renderWordCloudChart).
app.ontoolinput = (params) => { _pendingArgs = (params as any).arguments ?? null; }; app.ontoolresult = (result) => { // Try structuredContent first, fall back to parsing JSON from content let data = (result as any).structuredContent; if (!data?.type) { const texts = (result as any).content?.filter( (c: any) => c.type === "text" ) ?? []; for (const t of texts) { try { const parsed = JSON.parse(t.text); if (parsed?.type) { data = parsed; break; } } catch { /* not JSON, skip */ } } } // Store for refresh: resolve tool name from content type + pending args if (data?.type && _pendingArgs) { const toolMap = getTypeToToolMap(); const toolName = toolMap[data.type]; if (toolName) { storeLastToolCall(toolName, _pendingArgs); } } _pendingArgs = null; renderFromData(data); };