Skip to main content
ClaudeWave
Skill1.4k repo starsupdated today

html-report

The html-report skill generates self-contained, styled HTML documents saved to the results folder that users can download, share, or export to PDF. Use this when delivering a polished, permanent research artifact such as an earnings summary, equity analysis, or screen writeup that combines narrative text, embedded data, interactive charts, and theme-aware styling designed to resemble professional research desk output.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/ginlix-ai/LangAlpha /tmp/html-report && cp -r /tmp/html-report/skills/html-report ~/.claude/skills/html-report
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# HTML Report

Author a styled, self-contained HTML **document** and write it to `results/` (e.g. `results/report.html`). The file panel renders it with full browser semantics — JavaScript runs, CDN libraries load, relative assets resolve, and the user can view it fullscreen, open it in a new tab, download it, or export it to PDF.

This is the right output when the user wants a **deliverable they can keep, share, or print** — an equity research note, an earnings recap, a screen writeup — not a throwaway answer.

> **Read `.agents/skills/ui-design/SKILL.md` before authoring.** It defines the typography, color, and composition standards that keep the report looking like a research desk artifact rather than a generic AI page. This skill covers the mechanics; that one covers the taste.

> **User preferences override these defaults.** Anything the user has told you — in this conversation, in your long-term memory, or in their saved preferences/memos — outranks every rule in this skill. If they want a different structure, no charts, a specific set of sections, or a particular file layout, do that. (Visual taste — fonts, color, accent, light/dark — is `.agents/skills/ui-design/SKILL.md`'s domain; that skill defers to the user's stated style.) Treat the rules here as sensible defaults for when the user hasn't specified.

## Decide: Which Output?

A report from this skill **can be interactive** (sortable tables, tab/filter controls, hover- and zoomable charts — see **Interactivity**, below). So interactivity is *not* what separates it from a dashboard. The real divide is **self-contained snapshot file vs. live served app**:

| Want | Use | Why |
|---|---|---|
| A document the user keeps, shares, or exports to PDF — even one that's interactive within itself | **html-report** (this skill) — `.html` in `results/` | One file on disk, served with real semantics, PDF-exportable. Interactivity runs client-side over an embedded data snapshot. |
| A quick visualization *inside the chat* (one chart, a metric row, a table) | **inline-widget** (`ShowWidget`) | Appears inline between text; no file, no panel |
| A **live served app** — refreshing data, server-side compute, multi-page routing, or a dataset too large to embed | **interactive-dashboard** (`GetPreviewUrl`) | A running app with a backend, not a static file. Needed when the data must be fetched live, not embedded. |
| A simple, short answer | **plain markdown** | A styled HTML document is overkill for a one-paragraph reply |

## Self-Contained by Default

Write **one** complete HTML file. Everything inline — no external CSS/JS files, no build step.

```python
import json

data = {"labels": ["Q1", "Q2", "Q3", "Q4"], "revenue": [2.1, 2.4, 2.6, 3.0]}

html = f"""<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Acme Q4 Revenue Review</title>
  <style>/* all CSS inline here */</style>
</head>
<body>
  <main>...</main>
  <script>const DATA = {json.dumps(data, ensure_ascii=False)};</script>
  <script>/* render charts from DATA */</script>
</body>
</html>"""

with open("results/report.html", "w", encoding="utf-8") as f:
    f.write(html)
```

Rules:
- Full `<!DOCTYPE html>` document with `<head>`/`<body>` (unlike inline-widget, which is a bare fragment).
- **All CSS in a `<style>` block, all JS in `<script>` blocks** — nothing external except allowlisted CDN libraries.
- **Embed data via `<script>const DATA = {json.dumps(data, ensure_ascii=False)};</script>`** — never inline raw Python dicts, never `fetch()` a local file. `ensure_ascii=False` keeps non-ASCII (names, currencies, CJK) readable and correctly encoded.
- **Sample or aggregate large datasets** before embedding. A report doesn't need every tick — downsample to a sensible resolution, aggregate to the reporting period. Keep the embedded payload lean (target well under ~1MB).

## Multi-File When Warranted

The viewer serves files with **real relative-path semantics**, so a report can reference sibling assets and they resolve correctly:

```
results/
  report.html              # references charts/revenue.png as a relative path
  charts/
    revenue.png
    margins.png
```

```html
<img src="charts/revenue.png" alt="Quarterly revenue" style="width:100%;max-width:720px;">
```

Use multi-file for **image-heavy reports** — e.g. when you've generated high-quality static charts with matplotlib/plotly `savefig` and want to embed them rather than redraw client-side.

Rules:
- Keep all asset paths **relative** (`charts/revenue.png`, not `/results/...` and not absolute filesystem paths).
- Keep every asset **inside the workspace** and under `results/` (or a subdir of it). Do not reference files outside the workspace.
- Prefer self-contained when the charts can reasonably be drawn client-side from embedded `DATA`; reach for multi-file when raster images give materially better output.

## CDN Allowlist

Only these origins are reachable from the rendered document. Anything else (including arbitrary `fetch()`) is blocked.

- `cdnjs.cloudflare.com`
- `cdn.jsdelivr.net`
- `unpkg.com`
- `esm.sh`
- Google Fonts: `fonts.googleapis.com` + `fonts.gstatic.com`

Load chart libraries, fonts, and helpers from these only. Do not call out to data APIs from the document — embed the data instead.

## Theme Variables (Defensive Fallback Form)

The viewer can inject app `--color-*` variables so the report themes with light/dark mode. **Always author colors in the fallback form** so the document also renders correctly standalone, in a downloaded file, and in print:

```css
color: var(--color-text-primary, #1a1a1a);
background: var(--color-bg-card, #ffffff);
border: 1px solid var(--color-border-muted, #e4e1dc);
```

The literal fallback is what shows when no app vars are injected (downloaded file, PDF, plain open). Never write a bare `var(--color-x)` without a fallback, and never hardcode a color with no variable — both break one of the