Doc to html
Skill giostriquer/agent-workshop/plugins/toolkit/skills/doc-to-html
Set of plugins of agents and skills for daily ai work
npx -y skills add giostriquer/agent-workshop --skill doc-to-htmlAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when turning a markdown report, audit, review, or research/findings document into a polished standalone dark-themed HTML page, or when revising such a page — content tweaks, inserting/moving/renumbering sections, ordering findings by severity, matching the repo's existing report style, or "this looks noisy / unreadable / ugly / off" feedback.
SKILL.md
20.2 KB, ~5.2k tokens by cl100k_base, as published. Nobody here has run it
Doc to HTML
Purpose
Render a markdown document (report, audit, review, research findings) as a single self-contained HTML page that reads calmly on a dark screen, navigates well, and prints clean — then govern how that page is edited afterward.
Two stances, deliberately different: the visual design is adaptable — first match whatever house style the repo already uses, and fall back to the defaults here only when there is none. The process rules are rigid — each exists because its absence failed in real use.
Step 0 — match the repo's house style first
Before applying any default in this skill, glob the repo (especially tmp/ and docs/) for an existing standalone .html report — excluding generated output (node_modules/, dist/, coverage/, playwright-report/, .next/, and similar build/test artifacts). A candidate counts only if it is hand-authored: an inline <style> block and prose content, not a minified or tool-emitted page. If one exists, it is the house style: read its <style> block and component vocabulary and match it — palette, type scale, class system, card/chip/table shapes. If several qualify, the most recently modified hand-authored report wins. Consistency with a sibling artifact beats this skill's defaults every time; a wrong-aesthetic first pass gets thrown away whole, so detect before you generate.
The design system below is the fallback for when no sibling report exists — not the first choice.
Page architecture
Every page gets:
- Single self-contained file. Inline CSS and JS, no external assets, no build step. The page must open from disk.
- Sticky TOC sidebar (~288px) with an active-item highlight (scroll-spy) and keyboard navigation (
j/kor arrow keys) driven by one explicit array of section ids in document order. A thin top progress bar is a nice touch. Below ~900px the sidebar collapses into static flow (reference CSS) — a fixed 288px rail otherwise eats a phone's whole viewport. - Surface picked by reader action. Choose how each section renders by what the reader does with it: facts sharing attributes → a table (explanation lives in the surrounding prose, not in the cells); an ordered process → the stepper; findings/claims → the finding card; nuance/caveat → the dashed caveat box; bulk raw output → terminal block or appendix. Consecutive sections carrying different kinds of content should not all render as the same shape — an unbroken run of identical cards is a flat hierarchy, however polished each card looks.
- Verified links only. Don't ship a link you didn't fetch; annotate the result inline (small green/red run next to the link). Enrichment links are optional — but whatever ships is verified. Note: some canonical-looking doc URLs are JS-rendered and 404 to a server-side fetch (e.g. client-side error-code decoders) — confirm a URL actually serves content before relying on it. Relative/companion links (a sibling file, the source md): verify the target file exists.
- Styled scrollbars. Every scroll container — the page, the sidebar, and especially overflowing
.term/code blocks and wide tables — gets themed scrollbars, never the raw OS default (CSS below). - Print media query. White background, dark text, hide the nav and keyboard hints (reference CSS below; it's on the checklist).
Evidence appendix — conditional, not standing. When the source carries bulk raw evidence (transcripts, terminal dumps, long excerpts), it moves to an appendix at the end and the body cites it with a small → A1 cite-chip — the body stays readable without dropping the proof. When the evidence is already compact (file:line refs, short quotes), it stays inline in the cards; an appendix of one-liners is empty ceremony. Either way, a footer listing the artifacts the work produced is high-value for audit/research output.
What yields to house style, what doesn't. Step 0's sibling governs visual treatment — link-annotation style, nav chrome, chip/card/table shapes all follow the house look, including where it disagrees with the defaults below. It never waives the architecture itself: single self-contained file, working TOC/scroll-spy/keyboard nav, print stylesheet, a readable narrow-screen collapse, and verified links ship on every page regardless of aesthetic.
Design system — defaults (fallback only)
Use these only when Step 0 finds no house style. They reproduce a rich, card-and-chip dark report; keep the readability floors even if you change the mood.
- Canvas + type. Dark blue-gray canvas (
--bg:#0e1117family); sans-serif body (serif reads muddy on dark) at ~16px with generous line-height. Body text must be bright (#d0d8e0+) — gray-on-dark is the #1 readability killer; when in doubt, brighten. Cap running prose at ~80ch (p,li{max-width:80ch}); tables, terminal blocks, and the stat grid may span the full column, but full-column paragraph lines (~120ch) are the quiet cousin of gray-on-dark. - Readable chips/code. Inline code and chips ~0.9em, near-white text on a clearly lighter chip.
- One accent family used sparingly (active TOC item, headline callout, section-number badge) plus semantic green/red/amber ONLY inside terminal blocks, link-result runs, and cost/severity pills.
- Component vocabulary (the look adopters actually expect):
.sec-num— mono section-number badge, aligned with its heading (see alignment rule)..hero+ a.stat-grid(up to 4-up) for the verdict / TL;DR — stat cells carry only numbers the document itself backs; three real stats beat four with one invented..card+.pid(mono id badge) + colored.chips (severity, evidence tier, disposition)..claim— a quote box (❝) carrying the one-line finding..term— terminal/code block withok/bad/dim/warnspans, horizontal scroll, styled scrollbar..why— dashed caveat box for "might not be a problem" / nuance..fix+ a.costpill for the action and its cost class.- cite-chips (
→ A1) linking body to appendix; a footer-of-artifacts.
- Differentiate caveat / "maybe" sections with a subtle background or dashed border — not louder colors.
Findings & audit reports
For reports that carry findings (audit, QA, review):
- Order by severity, descending. Most severe first, always (critical → high → medium → low). The ids are then reassigned top-down, so a deck whose findings arrive in mixed order (e.g. medium, high, low, critical) ships as
F-1critical,F-2high, …. After sorting, run the Renumbering procedure so ids, cross-refs, TOC, and the nav array all match. Exception: when the source already carries a stable, cross-referenced id scheme of its own (severity-coded ids tied to its priority matrix or roadmap), preserve those ids and skip reassignment — the Renumbering procedure governs ids this skill assigns, not ids the source owns. - Every finding card carries evidence and an action. Not just label → headline → body. Required shape: id + chip header (severity + evidence tier) → one-line claim (quote box) → an Evidence line that is concrete (a live result,
file:line, or an appendix cite) → a Fix line with a cost pill. The headline states the finding; the body proves it and says what to do. Concise beats extensive — but never a claim without its evidence. - Group when items partition. When findings naturally split (by product, area, severity, owner), group them into sub-sections with prefixed ids (
AUTH-1,API-1, …), each its own TOC group, then run the Renumbering procedure. A recognised variation, not an afterthought. - Optional Method section. For audit/QA/research output, a short "how this was produced" section — a few numbered practices + a one-line phase chain — helps the reader trust the claims.
Process rules (rigid)
- Default output path. Same directory as the source, same basename,
.htmlextension — unless the user or the document itself names a different target. - One pass. Generate the full HTML in one pass from the markdown.
- Derived numbers are recomputed. Totals and per-section counts come from the items actually rendered, not from the source's prose. When the source's stated numbers disagree — with the items, or with each other — render the recomputed values and flag the divergence to the user in the completion summary; never silently ship either side. The inverse is equally rigid: the layout never invents numbers — no stat cell, percentage, or count the source doesn't back, even when a grid slot looks empty without one.
- Targeted edit vs clean rewrite. Content tweaks are targeted edits. A change of design DIRECTION — including switching to match a house style found late — is always a full clean rewrite; incrementally restyling markup built for a different aesthetic compounds into a mess.
- One knob at a time. If the user dislikes the result, ask which specific element fails (contrast, density, hierarchy) and turn that one knob; don't swing the whole design.
- Renumbering procedure. When an insert, move, drop, sort, or re-group forces renumbering: renumber via descending replace-all or a temp placeholder (avoid collisions), then update every cross-reference, TOC entry, element id, and the keyboard-nav order array, and verify with a grep that ids are sequential and references resolve.
Pre-finish checklist
- Parse-check the HTML (balanced tags, sequential heading levels); no garbage/stray CSS tokens.
- Every TOC target id exists; the keyboard-nav order array matches document order.
- Findings are ordered most-severe-first; skill-assigned ids run top-down (source-owned id schemes are preserved as-is).
- Every scroll container has a styled scrollbar (no raw OS bars).
- Section-number badges align with their headings; cost pills sit in one consistent place across all cards.
- No markdown content dropped — spot-check section count and headline statements; derived totals/counts match the rendered items, any divergence from the source's stated numbers is flagged in the completion summary, and no number was invented to fill a layout slot.
- Every shipped external link was fetched and annotated; every relative link's target file exists.
- Print media query present: white background, dark text, nav and keyboard hints hidden, cards avoid page breaks.
- Narrow-screen check: at phone width the sidebar collapses to static flow and nothing overflows horizontally except intentional scroll containers.
Reference markup
Tokens and the cross-browser styled scrollbar (applies to the page and every scroll container):
:root{
--bg:#0e1117; --panel:#151b24; --line:#28313f;
--text:#dee4ec; --muted:#9ba6b4; --faint:#6b7585;
--accent:#5aa7ff; --green:#46c061; --amber:#e3a93c; --red:#f0635a;
--mono:'SFMono-Regular',Consolas,'Liberation Mono',Menlo,monospace;
}
*{scrollbar-width:thin;scrollbar-color:#33415c transparent} /* Firefox */
::-webkit-scrollbar{width:10px;height:10px} /* Chromium/WebKit */
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:#2c3a52;border-radius:6px;border:2px solid var(--bg)}
::-webkit-scrollbar-thumb:hover{background:#3a4d6b}
Layout shell — sticky nav, progress bar, hero + stat-grid, table wrap. This is the chrome the architecture section mandates; copy it on fallback runs instead of improvising:
body{margin:0;background:var(--bg);color:var(--text);font:16px/1.7 system-ui,'Segoe UI',sans-serif}
.layout{display:flex;max-width:1400px;margin:0 auto}
nav{position:sticky;top:0;flex:0 0 288px;height:100vh;overflow-y:auto;padding:28px 18px;border-right:1px solid var(--line)}
nav a{display:block;color:var(--muted);text-decoration:none;font-size:13.5px;line-height:1.45;padding:6px 10px;border-radius:6px;border-left:2px solid transparent}
nav a.active{color:var(--accent);background:#16202e;border-left-color:var(--accent)}
main{flex:1;min-width:0;padding:40px 48px 80px}
#bar{position:fixed;top:0;left:0;height:3px;width:0;background:var(--accent);z-index:10}
.hero{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:30px 34px;margin-bottom:36px}
.stat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:20px}
.stat{background:#101820;border:1px solid var(--line);border-radius:10px;padding:14px 16px}
.stat b{display:block;font-size:26px;color:var(--text)}
.stat span{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}
.tablewrap{overflow-x:auto}
table{width:100%;border-collapse:collapse;font-size:14px;margin:14px 0}
th,td{text-align:left;padding:9px 12px;border-bottom:1px solid var(--line)}
th{color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.07em}
p,li{max-width:80ch}
@media(max-width:900px){
.layout{display:block}
nav{position:static;height:auto;border-right:0;border-bottom:1px solid var(--line)}
main{padding:28px 20px 60px}
.stat-grid{grid-template-columns:repeat(2,1fr)}
}
Section / card header row — the number badge and its heading must share a centerline. Use align-items:center (NOT baseline) whenever the badge and heading font sizes differ, or the number floats high/low:
.sec-head{display:flex;align-items:center;gap:14px;margin-bottom:8px}
.sec-num{font:700 13px/1 var(--mono);color:var(--accent);background:#15233a;
border:1px solid #2c4366;border-radius:6px;padding:3px 9px;flex:0 0 auto}
.sec-head h2{font-size:24px;line-height:1.2;letter-spacing:-.01em}
Finding card — id/chip header → claim quote box → Evidence → Fix with a cost pill. The cost pill lives in the Fix header, the same place on every card (don't let it float at the end of whichever sentence happens to be last):
<section class="card" id="f01">
<div class="card-top">
<span class="pid">F-1</span>
<span class="chip critical">critical</span>
<span class="chip repro">reproduced</span>
<h3>Headline states the finding, not the topic</h3>
</div>
<div class="claim"><span class="tag">Claim</span>One-line statement of what was found.</div>
<div class="lbl">Evidence</div>
<p>Concrete proof: a live result, <code>path/to/file.ts:42</code>, or an appendix cite <a class="cite" href="#a1">→ A1</a>.</p>
<div class="lbl">Fix <span class="cost c-s">S</span></div>
<p>The action to take.</p>
</section>
.card{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:26px 30px;margin-bottom:30px;scroll-margin-top:24px}
.card.maybe{background:#171a26;border-style:dashed} /* caveat / "might not be a problem" */
.card-top{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin-bottom:14px}
.pid{font:700 13px/1 var(--mono);color:#fff;background:#293549;border-radius:6px;padding:3px 10px}
.card h3{font-size:19.5px;line-height:1.35;flex:1 1 100%;margin-top:2px} /* headline drops to its own line */
.chip{font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;border-radius:99px;padding:3px 11px;border:1px solid}
.chip.critical{color:#ff9d96;border-color:#6e3631;background:#2d1a18}
.chip.high{color:#ffce6e;border-color:#6e5520;background:#2b2210}
.chip.medium{color:#9ad97e;border-color:#3f5a2a;background:#1b2614}
.chip.low{color:#9aa6b6;border-color:#37425a;background:#1a2230}
.chip.repro{color:#7ee29a;border-color:#2c5e3b;background:#13261a} /* evidence tier */
.claim{background:#101820;border:1px solid #2a3c55;border-radius:10px;padding:17px 20px 17px 52px;margin:4px 0 20px;position:relative;font-size:16.5px;line-height:1.62;color:#e6edf6}
.claim::before{content:"❝";position:absolute;left:18px;top:13px;font-size:24px;color:var(--accent)}
.claim .tag{display:block;font-size:10.5px;font-weight:800;letter-spacing:.14em;color:var(--accent);text-transform:uppercase;margin-bottom:5px}
.lbl{font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase;color:#8e9aab;margin:20px 0 7px}
.cite{font:700 12px/1 var(--mono);color:var(--accent)}
.cost{font:700 11px/1 var(--mono);border-radius:5px;padding:2px 8px;vertical-align:1px}
.c-xs{color:#7ee29a;background:#13261a} .c-s{color:#9ad97e;background:#1b2614}
.c-m{color:#ecc06a;background:#272012} .c-l{color:#d4b3ff;background:#221a33}
Terminal / code block — semantic spans, horizontal scroll, themed scrollbar from the rule above:
.term{background:#0a0e14;border:1px solid #232c3a;border-radius:9px;font-family:var(--mono);
font-size:12.8px;line-height:1.75;padding:13px 17px;margin:10px 0;overflow-x:auto;color:#c1cddb;white-space:pre}
.term .ok{color:var(--green)} .term .bad{color:var(--red)} .term .dim{color:#5d6878} .term .warn{color:var(--amber)}
Vertical stepper (ordered process; connector line through the dots):
<ol class="stepper">
<li><span class="dot"></span><div><h3>Step title</h3><p>What happens.</p></div></li>
<li><span class="dot"></span><div><h3>Next step</h3><p>…</p></div></li>
</ol>
.stepper{list-style:none;margin:0;padding:0}
.stepper li{position:relative;display:flex;gap:16px;padding-bottom:24px}
.stepper li::before{content:"";position:absolute;left:7px;top:18px;bottom:0;width:2px;background:var(--line)}
.stepper li:last-child::before{display:none}
.dot{flex:none;width:16px;height:16px;margin-top:4px;border-radius:50%;border:2px solid var(--accent);background:#0f1520}
Interactive chrome — scroll-spy, keyboard nav, progress bar. The three classic bugs are pinned shut here: key handlers must not fire inside form fields, a short last section never enters a top-of-viewport observation band (the bottom-of-page fallback covers it), and the order array drifts from the DOM (keep the comment's warning; the renumbering procedure updates it):
<script>
const order=['hero','f01','f02','a1']; // section ids in document order — MUST match the DOM
const links=Object.fromEntries([...document.querySelectorAll('nav a')].map(a=>[a.hash.slice(1),a]));
let active=null; // null, not order[0] — the first observer callback must apply the initial highlight
const setActive=id=>{if(!links[id]||id===active)return;
links[active]?.classList.remove('active');links[id].classList.add('active');active=id;};
const spy=new IntersectionObserver(es=>{
const v=es.filter(e=>e.isIntersecting);if(v.length)setActive(v[0].target.id);},
{rootMargin:'0px 0px -60% 0px'}); // activate in the top 40% of the viewport
order.forEach(id=>{const el=document.getElementById(id);if(el)spy.observe(el);});
addEventListener('keydown',e=>{
if(e.target.closest('input,textarea,select')||e.metaKey||e.ctrlKey||e.altKey)return;
const d={j:1,ArrowDown:1,k:-1,ArrowUp:-1}[e.key];if(!d)return;e.preventDefault();
const next=order[Math.min(order.length-1,Math.max(0,order.indexOf(active)+d))];
document.getElementById(next)?.scrollIntoView({behavior:'smooth'});setActive(next);
});
addEventListener('scroll',()=>{
const h=document.documentElement,p=h.scrollTop/(h.scrollHeight-h.clientHeight)||0;
document.getElementById('bar').style.width=p*100+'%';
if(p>0.99)setActive(order[order.length-1]); // short last section: bottom of page wins
},{passive:true});
</script>
Print — mandatory architecture, checklist item 8:
@media print{
body{background:#fff;color:#111}
nav,#bar,.kbd-hint{display:none}
.layout{display:block} main{padding:0}
.hero,.card,.stat{background:#fff;border-color:#bbb;break-inside:avoid}
.term{background:#f4f4f4;color:#222;border-color:#ccc}
a{color:#134a9e}
}
Suggested invocation
- Turn
report.mdinto a standalone HTML page. (→ Step 0 first: match any sibling.htmlreport) - The page feels noisy / unreadable — fix it. (→ ask which knob fails: contrast, density, or hierarchy)
- Insert a new section between 4 and 5. (→ renumbering procedure, then the checklist)
- Order the findings by severity. (→ sort descending, then the renumbering procedure)
- Make it feel like a printed zine instead. (→ design-direction change: full clean rewrite)