en un clic
delivery-ascii-dashboard
Render data dashboards as pure ASCII art in monospace text -- the cheapest, most portable delivery method. No rendering engine, no SVG, no browser. LLM-native output with predictable character geometry.
Menu
Render data dashboards as pure ASCII art in monospace text -- the cheapest, most portable delivery method. No rendering engine, no SVG, no browser. LLM-native output with predictable character geometry.
Bundle plugin: installs the complete Visual Storytelling pipeline (brief, ingest, clean, select, deliver). See component SKILLs for detailed specs.
Data cleaning, profiling, transformation, and quality gates -- prepares raw data for visualization and analysis
Ingestion patterns for CSV, JSON, REST API, SQL, Excel, and Parquet -- guides an LLM through loading data from any common source
Render data dashboards as self-contained HTML files using Apache ECharts v6. Single file, zero build step, interactive charts with tooltips and data zoom. Declarative JSON option config optimized for AI generation.
Render data dashboards as static SVG panels embeddable in Markdown. Uses D3.js v7 mental model for scales, shapes, and axes. No runtime JS; output is pure SVG with inline styles for GitHub compatibility.
Guided requirements template for data storytelling projects -- walks users through audience, Big Idea, questions, data sources, and delivery target before any chart is created
| type | skill |
| lifecycle | stable |
| inheritance | inheritable |
| name | delivery-ascii-dashboard |
| description | Render data dashboards as pure ASCII art in monospace text -- the cheapest, most portable delivery method. No rendering engine, no SVG, no browser. LLM-native output with predictable character geometry. |
| tier | standard |
| applyTo | **/*ascii*,**/*text*dashboard*,**/*terminal*,**/*console*,**/*plain* |
| currency | "2026-05-02T00:00:00.000Z" |
| lastReviewed | "2026-05-02T00:00:00.000Z" |
Render dashboards as pure ASCII art. No emojis, no Unicode box-drawing beyond the basic set, no external renderer. The output is a monospace text block that looks correct in any terminal, any markdown code fence, any log file, any LLM context window.
This is the cheapest delivery method: zero dependencies, zero tokens spent on SVG coordinates, predictable character geometry. An LLM can produce and validate the output in the same context window.
delivery-svg-markdown or delivery-html-dashboard)ASCII dashboards are predictable because every character occupies exactly one cell in a monospace grid. No emoji, no CJK, no combining characters.
| Constant | Value | Rationale |
|---|---|---|
| Max width | 78 characters | Fits 80-column terminals with 1-char margin each side |
| Card padding | 1 character inside each border | Readable without waste |
| Column gap | 2 characters ( ) | Visually separates side-by-side cards |
| Row gap | 1 blank line | Separates card rows |
| Title centering | Centered within card width | Visual anchor |
| Number alignment | Right-aligned within column | Scannable |
Use only the basic ASCII set for maximum portability:
| Element | Characters | Example |
|---|---|---|
| Horizontal border | - | ------------------ |
| Vertical border | ` | ` |
| Corners | + | +--+ |
| Separator | = or - | +==================+ |
| Bar fill | # | ###### |
| Bar empty | . or space | ...... |
| Sparkline up | / | |
| Sparkline down | \ | |
| Sparkline flat | _ | |
| Bullet | * | * item |
Emojis render as 1 or 2 cells depending on the terminal, font, and OS. A green circle 🟢 might be 1 cell in VS Code and 2 cells in Windows Terminal. This breaks column alignment. ASCII characters are always 1 cell, always predictable.
Status indicators use letters instead:
| Status | ASCII | Meaning |
|---|---|---|
| Complete | [x] | Done |
| In progress | [-] | Active |
| Not started | [ ] | Pending |
| Pass | [OK] | Check passed |
| Fail | [!!] | Check failed |
| Warning | [??] | Needs attention |
+----------------+ +----------------+ +----------------+
| REVENUE | | USERS | | CHURN |
| $4.2M | | 12,847 | | 3.1% |
| +12% YoY | | +892 MoM | | -0.4pp |
+----------------+ +----------------+ +----------------+
Width per card = (78 - (N-1)*2) / N where N = number of cards. For 3 cards: 24 chars each.
Revenue by Region
==========================================
North America | #################### | 42%
Europe | ########### | 23%
Asia Pacific | ######### | 19%
Latin America | ##### | 11%
Other | ## | 5%
==========================================
Bar width = total width - label width - value width - borders. Fill character #, empty is space. Labels left-aligned, values right-aligned.
Trend (12 months): _/\__/\/\___/\ High: 4.2M Low: 2.1M
Characters: / = up, \ = down, _ = flat, ^ = peak. One character per data point. Keep to 20 characters max (readable at a glance).
+------------------------------------+ +------------------------------------+
| SALES PIPELINE | | SUPPORT TICKETS |
+------------------------------------+ +------------------------------------+
| | | |
| Q1 | ######## | $2.1M | | Open | ########### | 127 |
| Q2 | ########### | $2.8M | | Pending | ###### | 68 |
| Q3 | ############### | $3.7M | | Closed | ############## | 156 |
| Q4 | ################## | $4.2M | | Overdue | ## | 23 |
| | | |
| Trend: __/\/\__/\ YTD: $12.8M | | Avg resolution: 4.2 days |
+------------------------------------+ +------------------------------------+
Each column = (78 - 2) / 2 = 38 characters wide (including borders). Gap = 2 chars.
+==============================================================================+
| FLEET STATUS -- 2026-05-02 |
+==============================================================================+
+----------------+ +----------------+ +----------------+ +----------------+
| HEIRS | | UPGRADED | | PENDING | | PLUGINS |
| 41 | | 8 | | 33 | | 279 |
| total fleet | | [x] v0.9.9 | | [-] queued | | in Mall |
+----------------+ +----------------+ +----------------+ +----------------+
+------------------------------------+ +------------------------------------+
| VERSION DISTRIBUTION | | TOP PLUGINS |
+------------------------------------+ +------------------------------------+
| v0.9.9 | #### | 19% | | mermaid-mode | ######### | 7 |
| no-marker | ############## | 68% | | academic-paper | # | 1 |
| v0.6.2 | # | 5% | | data-story | # | 1 |
| v0.9.1 | # | 2% | | chart-interp | # | 1 |
| other | # | 5% | | exec-story | # | 1 |
+------------------------------------+ +------------------------------------+
+---------------------------------------------------------------------------+
| NEXT: node scripts/fleet-upgrade.cjs --apply 33 heirs ready |
+---------------------------------------------------------------------------+
total_width = 78
n_columns = 2
gap = 2
card_width = (total_width - (n_columns - 1) * gap) / n_columns
bar_area = card_width - label_width - value_width - 4 (borders + padding)
Never eyeball widths. Compute from the grid constants, then fill.
WRONG: North America | ############ | 42%
RIGHT: North America | ############ | 42%
Numbers scan faster when the ones digit is in a fixed column.
Largest bar on top. The eye scans top-down; put the story first.
+------------------------------------+
| VERSION DISTRIBUTION |
+------------------------------------+
Center the title within the card width. No bold, no underline (not portable). Caps or title case for visual weight.
The last row of the dashboard is the call to action. It spans the full width and contains the one thing the reader should do next.
After generating, count characters per line. Every line within a card must have the same length. If not, padding is wrong. This is the advantage of ASCII: you can validate by counting.
The dashboard takes a simple JSON or table structure:
{
"title": "Fleet Status",
"date": "2026-05-02",
"kpis": [
{ "label": "HEIRS", "value": "41", "detail": "total fleet" },
{ "label": "UPGRADED", "value": "8", "detail": "[x] v0.9.9" }
],
"charts": [
{
"title": "Version Distribution",
"type": "bar",
"items": [
{ "label": "v0.9.9", "value": 19 },
{ "label": "no-marker", "value": 68 }
]
}
],
"footer": "NEXT: node scripts/fleet-upgrade.cjs --apply"
}
After generating the dashboard, run a mechanical validation before writing the output file. This is mandatory. Do not skip it. Do not self-report "all lines OK" without actually measuring. "Looks correct" is not a measurement.
LLMs cannot reliably count characters in generated text. The model will produce lines it believes are 78 characters but are actually 77, 79, or 80. This is not a rare edge case; it happens on nearly every generation. The only reliable fix is to measure after generation and fix before delivery.
Use run_in_terminal to measure every line. This is the ONLY acceptable validation method. Mental counting or estimation is not acceptable.
PowerShell:
$lines = Get-Content "<file>"
$fails = $lines | Where-Object { $_.Length -gt 0 -and $_.Length -ne 78 }
if ($fails) { $fails | ForEach-Object { "$($_.Length): $_" } }
else { "ALL LINES OK (78 chars)" }
Do not freehand ASCII lines. Use a padding function to construct each line:
function Row(content): return "| " + content.padRight(74) + " |"
function Border(char): return "+" + (char * 76) + "+"
For side-by-side panels:
function DualRow(left, right):
L = "| " + left.padRight(34) + " |"
R = "| " + right.padRight(34) + " |"
return L + " " + R
Generate lines using these functions, then validate. This approach prevents most misalignment on first pass.
| Element | Formula | Result |
|---|---|---|
| Total line width | fixed | 78 |
| Full-width border | + + 76 dashes + + | 78 |
| Full-width inner | | + 74 content + | | 78 |
| Side-by-side border | + + 36 + + + + + + 36 + + | 78 |
| Side-by-side inner | | + 34 + | + + | + 34 + | | 78 |
The width is 78, NOT 80. Common mistake: using 80 as the target because "80-column terminal." The 1-char margin on each side means content is 78.
If any line fails:
|) or too short (add spaces before closing |)Do NOT write the output file until the measurement passes with zero failures. A dashboard with misaligned edges is a rendering bug, not a cosmetic issue.
| Anti-pattern | Fix |
|---|---|
| Using emojis for status indicators | Use [x], [!!], [OK] -- always 1 cell per character |
| Eyeballing column widths | Compute from grid constants. Count characters. |
Mixing Unicode box-drawing (┌─┐) with ASCII (+--+) | Pick one. ASCII `+- |
| Lines of different lengths within a card | Pad every line to card width. This is the #1 rendering bug |
| More than 78 characters wide | Wrapping breaks the layout. Redesign or split into rows |
| Putting detailed data in the dashboard | ASCII is for summaries. Link to detail elsewhere |
visual-vocabulary -- select chart types before rendering. ASCII supports: bar, KPI, sparkline, table.storytelling-requirements -- the brief determines whether ASCII is the right delivery target.delivery-svg-markdown -- upgrade path when ASCII isn't enough (richer visuals, color, branding).delivery-html-dashboard -- upgrade path when interactivity is needed.