
Release Notes One Pager
- 1.8k installs
- 82k repo stars
- Updated July 28, 2026
- nexu-io/open-design
A single-page, section-structured HTML document containing version, date, summary, Added items, Fixed bugs, Breaking changes, Known issues, and Upgrade instructions.
About
This skill produces a structured one-page HTML release notes document containing version info, Added/Fixed/Breaking changes, Known issues, and Upgrade notes. Developers use it to quickly create professional release announcements when shipping new versions. The workflow involves copying a seed template, mapping design system variables, populating six mandatory sections in order (Hero, Added, Fixed, Breaking changes, Known issues, Upgrade note), and applying honesty rules: explicit "None" or "No details provided" placeholders for missing information rather than invention. Self-check gates ensure P0 criteria are met before emission.
- Structured HTML template with pre-wired navigation anchors to Added, Fixed, Upgrade-note sections
- Honesty-first placeholders: writes explicit "None" and "No details provided" when user omits information
- Design system mapping via :root CSS variables from active DESIGN.md
- Six mandatory sections in fixed order: Hero, Added, Fixed, Breaking changes, Known issues, Upgrade note
- P0/P1/P2 self-check gates and layout reference skeletons included in resources
Release Notes One Pager by the numbers
- 1,759 all-time installs (skills.sh)
- +122 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #188 of 1,901 Documentation skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
release-notes-one-pager capabilities & compatibility
0
- Capabilities
- generate structured one page html release notes · map design system color, typography, layout, com · enforce section order and honest placeholders · pre wire navigation anchors · apply p0/p1/p2 self check gates
- Use cases
- documentation
- Platforms
- macOS · Windows · Linux
- Runs
- Runs locally
- Pricing
- Free
What release-notes-one-pager says it does
Release notes one-page HTML with highlights, Added, Fixed, Breaking changes, Known issues, and Upgrade note.
Do not write CSS from scratch unless the user explicitly asks for a bespoke structure.
npx skills add https://github.com/nexu-io/open-design --skill release-notes-one-pagerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.8k |
|---|---|
| repo stars | ★ 82k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 28, 2026 |
| Repository | nexu-io/open-design ↗ |
What it does
Generate a single-page HTML release notes document with highlights, changes, and upgrade instructions.
Who is it for?
Backend releases, SaaS updates, version bump announcements, shipping point releases (e.g., v2.3.1).
Skip if: Marketing landing pages, blog posts, internal changelogs that do not require a one-pager, real-time streaming updates.
When should I use this skill?
Ready to ship a new version and need to communicate changes to users and developers in a standard format.
What you get
A polished, accessible one-page release notes HTML that links to real destinations and honestly represents what changed.
- Single-page HTML file (index.html)
- Navigation menu with anchor links
- Six mandatory sections with real or honest placeholder content
By the numbers
- Six mandatory sections: Hero, Added, Fixed, Breaking changes, Known issues, Upgrade note
- Pre-wired topnav links target #added, #fixed, #upgrade-note anchors
- Layout 7 (log-list) used for Added, Fixed, Breaking changes sections
Files
Release Notes One-Pager Skill
Produce a single-page release notes document in HTML.
Resource map
release-notes-one-pager/
├── SKILL.md ← this file
├── example.html ← quality bar and style reference
├── assets/
│ └── template.html ← local seed file to copy to project index.html
└── references/
├── checklist.md ← P0 / P1 / P2 gates
└── layouts.md ← local section skeletonsDo not write CSS from scratch unless the user explicitly asks for a bespoke structure.
Workflow
Step 0 — Pre-flight
1. Read assets/template.html. 2. Read references/layouts.md. 3. Read active DESIGN.md and map it to the six :root variables.
Step 1 — Start from the shared seed
Copy assets/template.html to project index.html.
Update:
<title>- topnav logo text
- topnav link labels (destinations are pre-wired to
#added,#fixed,#upgrade-note) - topnav CTA label and
hrefdestination, or omit the topnav CTA entirely if no real destination exists - ensure the topnav link targets exist by adding matching section
idattributes
Step 2 — Build release-note structure
Inside <main id="content">, compose this section order:
1. Hero (Layout 1 or 2): version, date, one-sentence summary. 2. Added (use Layout 7 log-list; section root must include id="added"). 3. Fixed (use Layout 7 log-list; section root must include id="fixed"). 4. Breaking changes (use Layout 7 log-list, or one row explicitly saying "None"; section root must include id="breaking-changes"). 5. Known issues (Layout 7 or card list; section root must include id="known-issues"). 6. Upgrade note (short steps list or explicit no-action statement; section root must include id="upgrade-note"). 7. Closing CTA strip (Layout 6).
For every CTA in the emitted HTML (topnav, hero, closing strip), replace both the visible label and the href destination with real, safe values. If no real destination is available, omit the CTA entirely—do not use a placeholder such as href="#", a misleading page-anchor, or REPLACE_WITH_REAL_URL. Hero CTAs are optional; only add them when real destinations exist.
Step 3 — Honesty rules for missing details
If the user does not provide details, do not invent them. Write explicit placeholders:
- Summary:
No summary provided. - Added:
No additions provided - Fixed:
No fixes provided - Breaking changes:
None - Known issues:
None reported - Upgrade note:
No upgrade actions required based on provided information
If release version or date is missing, use — and label the field rather than guessing.
Step 4 — Self-check
Run references/checklist.md. Every P0 must pass.
Step 5 — Emit artifact
Wrap output as:
<artifact identifier="release-notes-one-pager" type="text/html" title="Release Notes">
<!doctype html>
<html>...</html>
</artifact>One sentence before the artifact. Nothing after </artifact>.
<!doctype html>
<!--
OD web-prototype seed.
Copy this file to <project>/index.html, then fill `<main id="content">` by
pasting blocks from `references/layouts.md`. Every class referenced in
layouts.md is defined here — DO NOT remove unused ones unless you also
remove their callers, and DO NOT invent new global classes (use inline
style="…" for one-off tweaks).
Theme tokens at the top of `<style>` are the *only* place to set palette
and type. They map cleanly onto a DESIGN.md — when an active design system
is injected, swap these six variables and everything reflows.
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>[REPLACE] Page title · brand</title>
<style>
/* ─── tokens ─────────────────────────────────────────────────────────
Six variables. Bind them to the active DESIGN.md and stop.
Do not introduce raw hex anywhere else in this file. */
:root {
--bg: #fafaf7; /* page background — never #fff */
--surface: #ffffff; /* cards, modals, raised areas */
--fg: #1a1916; /* primary text — never #000 */
--muted: #6b6964; /* secondary text, captions */
--border: #e8e5df; /* hairlines, dividers */
--accent: #c96442; /* one accent — used at most 2× per screen */
/* derived — do not change */
--accent-soft: color-mix(in oklch, var(--accent) 14%, transparent);
--fg-soft: color-mix(in oklch, var(--fg) 6%, transparent);
/* type — display = serif (default), body = sans, mono for numerics */
--font-display: 'Iowan Old Style', 'Charter', Georgia, 'Times New Roman', serif;
--font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
--font-mono: ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, monospace;
/* scale — clamp() so it works at 1280, 1440, 1920 without media queries */
--fs-h1: clamp(44px, 6vw, 76px);
--fs-h2: clamp(32px, 4vw, 48px);
--fs-h3: 22px;
--fs-lead: 19px;
--fs-body: 16px;
--fs-meta: 13px;
/* spacing — 8-point grid */
--gap-xs: 8px;
--gap-sm: 12px;
--gap-md: 20px;
--gap-lg: 32px;
--gap-xl: 56px;
--gap-2xl: 96px;
--container: 1120px;
--gutter: 32px;
--radius: 10px;
--radius-lg: 16px;
}
/* ─── reset & base ──────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
background: var(--bg);
color: var(--fg);
font-family: var(--font-body);
font-size: var(--fs-body);
line-height: 1.55;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }
p { text-wrap: pretty; }
h1, h2, h3, h4 { text-wrap: balance; }
/* ─── layout primitives ─────────────────────────────────────────── */
.container {
max-width: var(--container);
margin-inline: auto;
padding-inline: var(--gutter);
}
.section {
padding-block: clamp(48px, 8vw, var(--gap-2xl));
}
.section + .section { border-top: 1px solid var(--border); }
.stack { display: flex; flex-direction: column; }
.stack > * + * { margin-top: var(--gap-md); }
.row { display: flex; align-items: center; gap: var(--gap-md); }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--gap-md); }
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap-lg); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-lg); }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gap-md); }
.grid-2-1 { display: grid; grid-template-columns: 2fr 1fr; gap: var(--gap-xl); align-items: start; }
.grid-1-2 { display: grid; grid-template-columns: 1fr 2fr; gap: var(--gap-xl); align-items: start; }
@media (max-width: 920px) {
.grid-2, .grid-3, .grid-4, .grid-2-1, .grid-1-2 { grid-template-columns: 1fr; }
.topnav-inner { flex-wrap: wrap; }
.topnav nav { display: none; }
.log-row { grid-template-columns: 1fr; }
.log-row .pull { text-align: left; }
}
/* ─── type ──────────────────────────────────────────────────────── */
.h1, h1 { font-family: var(--font-display); font-size: var(--fs-h1); line-height: 1.04; letter-spacing: -0.02em; margin: 0; }
.h2, h2 { font-family: var(--font-display); font-size: var(--fs-h2); line-height: 1.1; letter-spacing: -0.015em; margin: 0; }
.h3, h3 { font-size: var(--fs-h3); font-weight: 600; line-height: 1.3; letter-spacing: -0.005em; margin: 0; }
.lead { font-size: var(--fs-lead); line-height: 1.55; color: var(--muted); max-width: 60ch; margin: 0; }
.eyebrow {
font-family: var(--font-mono);
font-size: 12px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--accent);
margin: 0 0 var(--gap-md);
}
.meta { font-family: var(--font-mono); font-size: var(--fs-meta); color: var(--muted); }
.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* ─── chrome: nav + footer ──────────────────────────────────────── */
.topnav {
position: sticky; top: 0; z-index: 10;
background: color-mix(in oklch, var(--bg) 92%, transparent);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
}
.topnav-inner { display: flex; align-items: center; justify-content: space-between; padding-block: 14px; }
.topnav .logo { font-family: var(--font-display); font-size: 19px; font-weight: 600; letter-spacing: -0.01em; }
.topnav nav { display: flex; gap: var(--gap-lg); }
.topnav nav a { font-size: 14px; color: var(--muted); }
.topnav nav a:hover { color: var(--fg); }
.pagefoot { padding-block: var(--gap-xl); color: var(--muted); font-size: 13px; border-top: 1px solid var(--border); }
.pagefoot .row-between { flex-wrap: wrap; gap: var(--gap-md); }
/* ─── buttons ───────────────────────────────────────────────────── */
.btn {
display: inline-flex; align-items: center; gap: 8px;
padding: 11px 20px;
border-radius: var(--radius);
border: 1px solid transparent;
font-size: 15px;
font-weight: 500;
letter-spacing: -0.005em;
transition: transform 0.05s ease, background 0.15s ease, border-color 0.15s ease;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); color: var(--surface); border-color: var(--accent); }
.btn-primary:hover { background: color-mix(in oklch, var(--accent) 88%, black); }
.btn-secondary { background: transparent; color: var(--fg); border-color: var(--border); }
.btn-secondary:hover { border-color: var(--fg); }
.btn-ghost { background: transparent; color: var(--fg); border-color: transparent; padding-inline: 8px; }
.btn-ghost:hover { color: var(--accent); }
.btn-arrow::after { content: '→'; transition: transform 0.15s ease; }
.btn-arrow:hover::after { transform: translateX(2px); }
/* ─── card / surface ────────────────────────────────────────────── */
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 28px;
}
.card-flat { background: transparent; border: 0; padding: 0; }
.card-rule { background: transparent; border: 0; border-top: 1px solid var(--fg); padding: 24px 0 0; border-radius: 0; }
/* ─── feature cell (icon + h3 + p) ──────────────────────────────── */
.feature .feature-mark {
width: 36px; height: 36px;
display: grid; place-items: center;
border: 1px solid var(--border);
border-radius: 10px;
color: var(--accent);
margin-bottom: var(--gap-md);
}
.feature .feature-mark svg { width: 18px; height: 18px; }
.feature h3 { margin-bottom: 6px; }
.feature p { margin: 0; color: var(--muted); font-size: 15px; }
/* ─── stat (big number + label) ─────────────────────────────────── */
.stat .stat-num {
font-family: var(--font-display);
font-size: clamp(56px, 8vw, 96px);
line-height: 0.95;
letter-spacing: -0.04em;
color: var(--accent);
font-weight: 600;
}
.stat .stat-label { color: var(--muted); font-size: 14px; margin-top: 8px; max-width: 24ch; }
.stat .stat-unit { font-size: 0.5em; opacity: 0.7; margin-left: 2px; }
/* ─── quote / testimonial ───────────────────────────────────────── */
.quote {
font-family: var(--font-display);
font-size: clamp(24px, 2.6vw, 32px);
line-height: 1.32;
letter-spacing: -0.01em;
max-width: 28ch;
}
.quote-author { color: var(--muted); font-size: 14px; margin-top: var(--gap-md); }
.quote-mark {
font-family: var(--font-display);
font-size: 140px; line-height: 0.7;
color: var(--accent); opacity: 0.18;
margin-bottom: -28px;
}
/* ─── pill / badge / tag ────────────────────────────────────────── */
.pill {
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 10px;
background: var(--accent-soft);
color: var(--accent);
border-radius: 999px;
font-family: var(--font-mono);
font-size: 11px;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.tag {
display: inline-flex; align-items: center;
padding: 4px 10px;
background: transparent;
color: var(--muted);
border: 1px solid var(--border);
border-radius: 999px;
font-size: 12px;
}
/* ─── form field ────────────────────────────────────────────────── */
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 13px; color: var(--muted); }
.input, .textarea {
width: 100%;
padding: 11px 14px;
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--surface);
color: var(--fg);
font: inherit;
font-size: 15px;
}
.input:focus, .textarea:focus {
outline: 2px solid var(--accent-soft);
border-color: var(--accent);
}
.textarea { min-height: 96px; resize: vertical; line-height: 1.55; }
/* ─── table (data-style, no chrome) ─────────────────────────────── */
.ds-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.ds-table th, .ds-table td { padding: 12px 14px; text-align: left; border-bottom: 1px solid var(--border); }
.ds-table th { color: var(--muted); font-weight: 500; font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.04em; text-transform: uppercase; }
.ds-table tbody tr:hover { background: var(--fg-soft); }
.ds-table .num-col { font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; }
/* ─── image placeholder (DS-tinted block, never broken <img>) ──── */
.ph-img {
background:
linear-gradient(135deg, var(--accent-soft), var(--fg-soft)),
var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
aspect-ratio: 16 / 10;
display: grid; place-items: center;
color: var(--muted);
font-family: var(--font-mono);
font-size: 12px;
letter-spacing: 0.04em;
}
.ph-img.square { aspect-ratio: 1 / 1; }
.ph-img.portrait { aspect-ratio: 3 / 4; }
.ph-img.wide { aspect-ratio: 16 / 9; }
/* ─── divider ───────────────────────────────────────────────────── */
.rule { border: 0; border-top: 1px solid var(--border); margin: 0; }
.rule-strong { border: 0; border-top: 1px solid var(--fg); margin: 0; }
/* ─── hero variants used by layouts.md ──────────────────────────── */
.hero { padding-block: clamp(80px, 12vw, 160px); }
.hero-center { text-align: center; max-width: 32ch; margin-inline: auto; }
.hero h1 { margin-bottom: var(--gap-md); }
.hero .lead { margin-bottom: var(--gap-lg); }
.hero-cta { display: inline-flex; gap: var(--gap-sm); flex-wrap: wrap; }
.hero-center .hero-cta { justify-content: center; }
.hero-split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-2xl); align-items: center; }
@media (max-width: 920px) { .hero-split { grid-template-columns: 1fr; } }
/* ─── log row (newsletter, blog list, changelog) ────────────────── */
.log-row { display: grid; grid-template-columns: 120px 1fr 100px; gap: var(--gap-lg); padding: 22px 0; border-top: 1px solid var(--border); align-items: baseline; }
.log-row .meta { color: var(--muted); }
.log-row h3 { font-size: 19px; }
.log-row .pull { text-align: right; }
/* ─── list (unordered/ordered list with consistent spacing) ─────── */
.list { margin: 16px 0 0; padding: 0 0 0 18px; }
.list li { margin: 8px 0; color: var(--fg); font-size: var(--fs-body); }
</style>
</head>
<body>
<header class="topnav" data-od-id="topnav">
<div class="container topnav-inner">
<span class="logo">[REPLACE] Brand</span>
<nav>
<a href="#added">[REPLACE] Added</a>
<a href="#fixed">[REPLACE] Fixed</a>
<a href="#upgrade-note">[REPLACE] Upgrade note</a>
</nav>
<a class="btn btn-primary" href="REPLACE_WITH_REAL_URL">[REPLACE] CTA</a>
</div>
</header>
<main id="content">
<!--
┌─────────────────────────────────────────────────────────────────┐
│ PASTE LAYOUTS FROM references/layouts.md HERE. │
│ ► Each layout block is a self-contained `<section>` — │
│ drop in 3–6 of them per page. │
│ ► Always lead with one hero (Layout 1 or 2). │
│ ► End with a CTA strip + footer (Layout 6 / footer below). │
└─────────────────────────────────────────────────────────────────┘
-->
<section class="section hero" data-od-id="hero">
<div class="container hero-center">
<p class="eyebrow">[REPLACE] Eyebrow</p>
<h1>[REPLACE] One sharp sentence about what this is.</h1>
<p class="lead">[REPLACE] One subhead sentence — concrete value, not a tagline.</p>
</div>
</section>
</main>
<footer class="pagefoot" data-od-id="footer">
<div class="container row-between">
<span>© [REPLACE] Brand · [REPLACE] Year</span>
<span class="meta">[REPLACE] tagline · contact@example.com</span>
</div>
</footer>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Release Notes v2.3.1</title>
<style>
:root {
--bg: #fafaf7;
--surface: #ffffff;
--fg: #1a1916;
--muted: #6b6964;
--border: #e8e5df;
--accent: #c96442;
--font-display: 'Iowan Old Style', 'Charter', Georgia, 'Times New Roman', serif;
--font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
--font-mono: ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, monospace;
}
* { box-sizing: border-box; }
body { margin: 0; font: 16px/1.55 var(--font-body); color: var(--fg); background: var(--bg); }
.container { max-width: 1120px; margin: 0 auto; padding: 0 32px; }
.section { padding: 72px 0; }
.section[data-od-id="hero"] { padding: 96px 0 84px; }
.section + .section { border-top: 1px solid var(--border); }
.topnav { position: sticky; top: 0; z-index: 10; background: color-mix(in oklch, var(--bg) 92%, transparent); border-bottom: 1px solid var(--border); backdrop-filter: blur(10px); }
.topnav-inner { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px 0; }
.logo { font: 600 19px/1.1 var(--font-display); letter-spacing: -0.01em; }
nav { display: flex; gap: 24px; }
nav a { text-decoration: none; color: var(--muted); font-size: 14px; }
nav a:hover { color: var(--fg); }
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 10px 18px; border: 1px solid transparent; border-radius: 10px; font: 500 15px/1 var(--font-body); cursor: pointer; }
.btn-primary { background: var(--accent); color: var(--surface); border-color: var(--accent); }
.hero { text-align: center; max-width: 80ch; margin: 0 auto; }
.eyebrow { margin: 0 0 14px; color: var(--accent); text-transform: uppercase; letter-spacing: 0.08em; font: 12px/1.2 var(--font-mono); }
h1 { margin: 0 auto 20px; max-width: 16ch; font: 600 clamp(40px, 6vw, 66px)/1.05 var(--font-display); letter-spacing: -0.02em; }
.lead { margin: 0 auto; color: var(--muted); font-size: 19px; max-width: 40ch; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
h2 { margin: 0; font: 600 clamp(30px, 4vw, 44px)/1.1 var(--font-display); letter-spacing: -0.015em; }
.meta { color: var(--muted); font: 13px/1.4 var(--font-mono); }
.log-row { display: grid; grid-template-columns: 120px 1fr 140px; gap: 24px; align-items: baseline; padding: 18px 0; border-top: 1px solid var(--border); }
.log-row h3 { margin: 0; font-size: 19px; letter-spacing: -0.005em; }
.log-row p { margin: 5px 0 0; color: var(--muted); font-size: 14px; }
.pull { text-align: right; }
.list { margin: 16px 0 0; padding: 0 0 0 18px; }
.list li { margin: 8px 0; }
.cta { text-align: center; max-width: 640px; margin: 0 auto; }
.cta p { color: var(--muted); margin: 14px 0 28px; }
.pagefoot { border-top: 1px solid var(--border); padding: 28px 0; font-size: 13px; color: var(--muted); }
.pagefoot .row-between { flex-wrap: wrap; }
.num { font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
@media (max-width: 920px) {
.log-row { grid-template-columns: 1fr; gap: 8px; }
.pull { text-align: left; }
nav { display: none; }
}
</style>
</head>
<body>
<header class="topnav" data-od-id="topnav">
<div class="container topnav-inner">
<span class="logo">Release notes</span>
<nav>
<a href="#added">Added</a>
<a href="#fixed">Fixed</a>
<a href="#upgrade-note">Upgrade note</a>
</nav>
</div>
</header>
<main id="content">
<section class="section" data-od-id="hero">
<div class="container hero">
<p class="eyebrow">Release notes · Version: v2.3.1 · Date: —</p>
<h1>v2.3.1</h1>
<p class="lead">No summary provided.</p>
</div>
</section>
<section class="section" id="added" data-od-id="added">
<div class="container">
<div class="row-between" style="margin-bottom: 24px;">
<h2>Added</h2>
<span class="meta">—</span>
</div>
<article class="log-row">
<span class="meta num">—</span>
<div>
<h3>No additions provided</h3>
</div>
<span class="pull meta">—</span>
</article>
</div>
</section>
<section class="section" id="fixed" data-od-id="fixed">
<div class="container">
<div class="row-between" style="margin-bottom: 24px;">
<h2>Fixed</h2>
<span class="meta">—</span>
</div>
<article class="log-row">
<span class="meta num">—</span>
<div>
<h3>No fixes provided</h3>
</div>
<span class="pull meta">—</span>
</article>
</div>
</section>
<section class="section" id="breaking-changes" data-od-id="breaking-changes">
<div class="container">
<div class="row-between" style="margin-bottom: 24px;">
<h2>Breaking changes</h2>
<span class="meta">—</span>
</div>
<article class="log-row">
<span class="meta num">—</span>
<div>
<h3>None</h3>
</div>
<span class="pull meta">—</span>
</article>
</div>
</section>
<section class="section" id="known-issues" data-od-id="known-issues">
<div class="container">
<div class="row-between" style="margin-bottom: 16px;">
<h2>Known issues</h2>
<span class="meta">—</span>
</div>
<p class="meta">None reported</p>
</div>
</section>
<section class="section" id="upgrade-note" data-od-id="upgrade-note">
<div class="container">
<div class="row-between" style="margin-bottom: 16px;">
<h2>Upgrade note</h2>
<span class="meta">—</span>
</div>
<p class="meta">No upgrade actions required based on provided information.</p>
</div>
</section>
</main>
<footer class="pagefoot" data-od-id="footer">
<div class="container row-between">
<span>© —</span>
<span class="meta">Release notes · v2.3.1</span>
</div>
</footer>
</body>
</html>
Release Notes One-Pager Checklist
Run this before emitting <artifact>. P0 = must pass; P1 = should pass; P2 = nice to have.
P0 — must pass
- [ ] Required sections exist and are visible: Added, Fixed, Breaking changes, Known issues, Upgrade note.
- [ ] Added section explicitly says
No additions providedwhen no additions are supplied. - [ ] Fixed section explicitly says
No fixes providedwhen no fixes are supplied. - [ ] Breaking changes section explicitly says
Nonewhen there are no breaking changes. - [ ] Known issues section explicitly says
None reportedwhen there are no known issues. - [ ] Upgrade note section explicitly says either concrete steps or
No upgrade actions required based on provided information. - [ ] No invented dates, versions, metrics, or claims. If missing, use labelled placeholders such as
Version: —. - [ ] No filler copy and no lorem ipsum.
- [ ] No raw hex colors outside the
:roottoken block. - [ ] No default AI-accent indigo or violet accents (
#6366f1,#4f46e5,#4338ca,#3730a3,#8b5cf6,#7c3aed,#a855f7). - [ ] No purple/blue trust gradient hero backgrounds.
- [ ] No emoji icons in headings, feature rows, buttons, or list rows.
- [ ] Display headings use
var(--font-display); no hardcoded sans display type. - [ ] No rounded card with a coloured left-border accent pattern.
- [ ] Every top-level
<section>has adata-od-id. - [ ] Every required release-note section root also includes the matching
idanchor:added,fixed,breaking-changes,known-issues,upgrade-note. - [ ] Every emitted CTA uses a real destination;
href="#"is not acceptable. If no destination exists, omit the closing CTA strip. - [ ] No placeholder tokens remain in href attributes:
[REPLACE],REPLACE_WITH_REAL_URL, orhttps://example.com. All hrefs must be valid URLs. - [ ] CTA copy must accurately describe an available destination; do not promise content that is not present.
- [ ] Mobile reflow works without horizontal scroll at narrow widths.
P1 — should pass
- [ ] Added and Fixed entries are concrete (what changed, not generic "improvements").
- [ ] Known issue rows include status or workaround when provided by the user.
- [ ] Upgrade note uses clear verbs (
Run,Update,Restart,Rebuild) for action steps. - [ ] Headlines stay concise (prefer under 14 words).
- [ ] CTA label is specific (
Read full changelog,Share release notes) and not generic (Learn more). - [ ] Accent usage stays restrained; avoid reusing accent treatment in every section.
P2 — nice to have
- [ ] One meaningful highlight in hero (single decisive sentence, not marketing fluff).
- [ ] Log rows are balanced in length and easy to scan.
- [ ] Numeric values use
.numstyle for legibility.
Web prototype layouts
8 paste-ready section skeletons. Drop into <main id="content"> of assets/template.html. Don't write sections from scratch — pick the closest layout, paste, swap copy.
Pre-flight (do this once before pasting anything)
1. Read `assets/template.html` through the end of the <style> block. Every class used below must exist there. If one is missing, add it to <style> rather than inlining it on each section. 2. Pick a section list before writing copy. Default rhythms:
- Landing: 1 hero → 2 features → 3 stat-row OR quote → 4 split → 6 cta-strip → footer
- Marketing / editorial: 1 hero-center → 7 log-list → 4 split → 6 cta-strip
- Pricing / docs: 1 hero-center → table-driven → 6 cta-strip
3. One accent per screen, used at most twice. The hero eyebrow and the primary button already use it; budget any third usage carefully.
Class inventory (must exist in template.html)
sectioncontainerherohero-centerhero-splithero-ctaeyebrowleadh1h2h3metanumbtnbtn-primarybtn-secondarybtn-ghostbtn-arrowcardcard-flatcard-rulefeaturefeature-markstatstat-numstat-labelstat-unitquotequote-markquote-authorpilltagfieldinputtextareads-tablenum-colph-imgsquareportraitwiderulerule-stronglistgrid-2grid-3grid-4grid-2-1grid-1-2rowrow-betweenstacklog-rowpulltopnavpagefoot
If you reach for a class not on this list, define it in <style> first or use style="…" inline. Never invent a global class on a <section> that isn't backed by CSS.
---
Layout 1 — Hero, centered
Use when the page leads with a thesis sentence (most landings, most marketing pages). One eyebrow, one h1 (≤14 words), one lead sentence, two CTAs.
<section class="section hero" data-od-id="hero">
<div class="container hero-center">
<p class="eyebrow">EYEBROW · CONTEXT</p>
<h1>One sharp sentence about what this is.</h1>
<p class="lead">One concrete-value subhead — what changes for the reader.</p>
<div class="hero-cta">
<a class="btn btn-primary" href="REPLACE_WITH_REAL_URL">Primary action</a>
<a class="btn btn-secondary" href="REPLACE_WITH_REAL_URL">Secondary</a>
</div>
</div>
</section>Layout 2 — Hero, split (text + visual)
Use when there is a real product visual (product UI, screenshot, photograph). Left half copy, right half a ph-img placeholder the user replaces.
<section class="section" data-od-id="hero-split">
<div class="container hero-split">
<div>
<p class="eyebrow">EYEBROW · ROLE</p>
<h1>Headline that names the change.</h1>
<p class="lead" style="margin-top: 20px;">A short subhead — concrete, not corporate. Two sentences max.</p>
<div class="hero-cta" style="margin-top: 28px;">
<a class="btn btn-primary" href="REPLACE_WITH_REAL_URL">Primary action</a>
<a class="btn btn-ghost btn-arrow" href="REPLACE_WITH_REAL_URL">Read the story</a>
</div>
</div>
<div class="ph-img wide" aria-label="Hero visual placeholder">[ Hero visual · 16:9 ]</div>
</div>
</section>Layout 3 — Feature triplet
Three feature cells. Lead with a small <h2> framing the row. Don't put an icon on every heading — one tasteful mark per cell, monoline.
<section class="section" data-od-id="features">
<div class="container stack" style="gap: 56px;">
<div style="max-width: 36ch;">
<p class="eyebrow">WHAT'S DIFFERENT</p>
<h2>Three things you'll notice in the first ten minutes.</h2>
</div>
<div class="grid-3">
<div class="feature card-flat">
<div class="feature-mark">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 3v18M3 12h18"/></svg>
</div>
<h3>Specific feature one</h3>
<p>Two-sentence description that names the user value, not the technology.</p>
</div>
<div class="feature card-flat">
<div class="feature-mark">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="8"/><path d="M12 8v4l3 2"/></svg>
</div>
<h3>Specific feature two</h3>
<p>Two-sentence description that names the user value, not the technology.</p>
</div>
<div class="feature card-flat">
<div class="feature-mark">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M4 7h16M4 12h10M4 17h16"/></svg>
</div>
<h3>Specific feature three</h3>
<p>Two-sentence description that names the user value, not the technology.</p>
</div>
</div>
</div>
</section>Layout 4 — Stat row (data billboard)
Use when there are real numbers. Three stats max — four feels like a brochure. Don't invent metrics. If you don't have a number, use a different layout.
<section class="section" data-od-id="stats">
<div class="container">
<p class="eyebrow" style="margin-bottom: 40px;">BY THE NUMBERS · 2026</p>
<div class="grid-3">
<div class="stat">
<div class="stat-num num">38<span class="stat-unit">×</span></div>
<p class="stat-label">less data moved over the wire vs. naive sync, on real customer workloads.</p>
</div>
<div class="stat">
<div class="stat-num num">3,184</div>
<p class="stat-label">paying teams, including 14 of the YC W26 batch.</p>
</div>
<div class="stat">
<div class="stat-num num">$0.04<span class="stat-unit">/GB</span></div>
<p class="stat-label">average egress saved — typical $1,800/mo bill drops to $200.</p>
</div>
</div>
</div>
</section>Layout 5 — Pull quote (testimonial)
A single decisive quote with attribution. Use sparingly — one per page, never two in a row.
<section class="section" data-od-id="quote">
<div class="container" style="max-width: 800px;">
<div class="quote-mark">"</div>
<blockquote class="quote">Filebase pays for itself in the first month. We were going to hire a dedicated DevOps person to babysit our sync — instead we just switched.</blockquote>
<p class="quote-author">— Mira Hassan, CTO at Northwind Studios</p>
</div>
</section>Layout 6 — CTA strip (closing)
End the page on one decisive ask. Centered, generous whitespace, one primary button. No secondary unless the page has zero other buttons.
<section class="section" data-od-id="cta-strip" style="text-align: center;">
<div class="container" style="max-width: 600px;">
<h2>Stop measuring meetings. Start measuring focus.</h2>
<p class="lead" style="margin: 16px auto 32px;">Free for solo. $4/mo per teammate after that.</p>
<a class="btn btn-primary" href="REPLACE_WITH_REAL_URL">Start free</a>
</div>
</section>Layout 7 — Log list (changelog / blog index / posts)
Editorial layout for a list of dated entries. Date in mono on the left, title + dek in the middle, optional pull stat on the right. Borders on top, never around — boxes feel like a brochure.
<section class="section" data-od-id="log">
<div class="container">
<div class="row-between" style="margin-bottom: 32px;">
<h2>Recent changes</h2>
<a class="btn btn-ghost btn-arrow" href="REPLACE_WITH_REAL_URL">View all</a>
</div>
<div>
<article class="log-row">
<span class="meta">Apr 27, 2026</span>
<div>
<h3>Sync engine v3 — half the wire bytes</h3>
<p style="margin: 4px 0 0; color: var(--muted); font-size: 14px;">A new content-defined chunker that produces 38× fewer post-edit changes on Final Cut projects.</p>
</div>
<span class="pull meta">Engineering</span>
</article>
<article class="log-row">
<span class="meta">Apr 19, 2026</span>
<div>
<h3>Per-folder bandwidth budgets</h3>
<p style="margin: 4px 0 0; color: var(--muted); font-size: 14px;">Cap how much a single project can pull each month — useful for archive folders.</p>
</div>
<span class="pull meta">Product</span>
</article>
<article class="log-row">
<span class="meta">Apr 04, 2026</span>
<div>
<h3>S3 + R2 dual-region replication</h3>
<p style="margin: 4px 0 0; color: var(--muted); font-size: 14px;">Two providers, automatic failover. Enterprise tier only for now.</p>
</div>
<span class="pull meta">Infra</span>
</article>
</div>
</div>
</section>Layout 7 note — Release-note sections (Added, Fixed, Breaking, Known issues)
When Layout 7 is used for release-note Added/Fixed/Breaking/Known issues sections, remove the header CTA row (the row-between div with "View all" button). Release-note sections typically have no per-section destination; leaving a placeholder violates SKILL.md Step 2. Replace the entire row:
<!-- REMOVE THIS from Layout 7 when used in release notes: -->
<div class="row-between" style="margin-bottom: 32px;">
<h2>Recent changes</h2>
<a class="btn btn-ghost btn-arrow" href="REPLACE_WITH_REAL_URL">View all</a>
</div>
<!-- WITH THIS: -->
<h2 style="margin-bottom: 32px;">Added</h2>
<!-- or Fixed, Breaking changes, Known issues -->---
List block — Known issues / Upgrade note
Use .list for itemized issue rows or step-by-step upgrade guidance. Keep the list clear, short, and factual; avoid long prose inside each bullet.
<section class="section" id="known-issues" data-od-id="known-issues">
<div class="container">
<div class="row-between" style="margin-bottom: 16px;">
<h2>Known issues</h2>
<span class="meta">—</span>
</div>
<ul class="list">
<li>Sync may lag by up to 30 seconds after a large file upload.</li>
<li>Drag-and-drop is disabled for archived projects in this release.</li>
<li>Mobile app notifications may arrive late on iOS 18.</li>
</ul>
</div>
</section>
<section class="section" id="upgrade-note" data-od-id="upgrade-note">
<div class="container">
<div class="row-between" style="margin-bottom: 16px;">
<h2>Upgrade note</h2>
<span class="meta">—</span>
</div>
<ol class="list">
<li>Update to v2.3.1 using your normal release process.</li>
<li>Restart the sync service after deployment.</li>
<li>Verify release notes in the internal changelog link.</li>
</ol>
</div>
</section>Layout 8 — Comparison table (pricing, plan matrix, before/after)
Hairline borders, mono numerics, one column highlighted via an accent border. Don't put the whole row in surface-color — that screams "table".
<section class="section" data-od-id="pricing">
<div class="container">
<div style="text-align: center; max-width: 36ch; margin: 0 auto 56px;">
<p class="eyebrow">PRICING</p>
<h2>One row of features. Three lines of pricing.</h2>
</div>
<table class="ds-table">
<thead>
<tr>
<th>Feature</th>
<th class="num-col">Solo</th>
<th class="num-col">Team</th>
<th class="num-col">Enterprise</th>
</tr>
</thead>
<tbody>
<tr><td>Sync engine v3</td><td class="num-col">✓</td><td class="num-col">✓</td><td class="num-col">✓</td></tr>
<tr><td>Per-folder budgets</td><td class="num-col">—</td><td class="num-col">✓</td><td class="num-col">✓</td></tr>
<tr><td>SAML / SCIM</td><td class="num-col">—</td><td class="num-col">—</td><td class="num-col">✓</td></tr>
<tr><td>Dedicated infra</td><td class="num-col">—</td><td class="num-col">—</td><td class="num-col">✓</td></tr>
<tr style="border-top: 1px solid var(--fg);">
<td><strong>Monthly</strong></td>
<td class="num-col"><strong>$0</strong></td>
<td class="num-col"><strong>$4 / seat</strong></td>
<td class="num-col"><strong>Talk to us</strong></td>
</tr>
</tbody>
</table>
</div>
</section>---
Section rhythm — when in doubt
For a 5-section landing: 1. Hero (Layout 1 or 2) 2. Features (Layout 3) 3. Stats or quote (Layout 4 or 5) 4. Split detail (custom, using grid-2-1 / grid-1-2) 5. CTA + footer (Layout 6)
For a 4-section docs/marketing index: 1. Hero center (Layout 1) 2. Log list (Layout 7) 3. CTA + footer (Layout 6)
Two stat rows in a row, two quote blocks in a row, two feature triplets in a row — all visual fatigue. Alternate.
Related skills
How it compares
Use release-notes-one-pager for styled HTML shipping pages; use a Markdown changelog skill when your repo only needs CHANGELOG.md.
FAQ
What if I don't have details for a section?
Write explicit placeholders like "None" or "No additions provided" instead of inventing content.
Do I need to write CSS?
No. Copy the seed template and map your design system variables to :root CSS; do not write CSS from scratch unless you explicitly ask.
Which sections are mandatory?
Hero, Added, Fixed, Breaking changes, Known issues, Upgrade note (in that order), plus optional Closing CTA strip.
Is Release Notes One Pager safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.