| name | html-hermes-style |
| description | Hermes retro-TUI / mythological genre — character-driven dev storytelling. Use when: AI agent biography/profile, CLI tool story, fork-vs-upstream history, dev-blog mythology, character-driven postmortem. Trigger: agent introduction / agent profile / CLI tool story / fork vs upstream / dev-blog history / project mythology / 智能体传记 / CLI故事 / retro terminal. Inherits typography-system. NOT for: business reports or dashboards. |
name: html-hermes-style
description: "Use when generating retro-terminal / mythological / agent-self-portrait HTML documents: AI agent introductions, CLI tool stories, dev-blog-style postmortems, character-driven product histories, or any document where the artifact itself should feel like a TUI screen captured at twilight. Trigger: document subject is an AI agent or CLI tool with character/personality, OR retro-pixel + monospace + amber-on-dark aesthetic is desired. Routed by html-style-router — do not invoke directly unless router has selected this style."
HTML Document Style — Hermes Terminal (Retro TUI / Mythological)
Typography base (inherited): this skill composes ON TOP of the shared
typography-system foundation — link/inline
tokens/typography.css FIRST, then layer this skill for color + accent +
brand font-family ONLY. Never re-declare the type scale, vertical rhythm,
measure, page frame, or CJK rules; keep mixed CJK+Latin stacks Latin-first.
Verify: python3 scripts/audit-genre-typography.py.
The retro-terminal narrative style for AI agent biographies, CLI tool
postmortems, dev-blog histories, and any document where the artifact should
read like a Bloomberg-Terminal-meets-Egyptian-archaeology screen.
Apply this style when generating single-file HTML deliverables of type:
agent introduction, CLI tool story, fork-vs-upstream postmortem, technical
mythology piece, or any document whose subject has personality and whose
delivery surface should feel inhabited rather than corporate.
For data dashboards, use html-bloomberg-style (cool, sterile, financial).
For warm humanistic guides, use html-document-style (Claude).
For editorial reports, use html-economist-style.
For consulting strategy, use html-mckinsey-style.
Universal Layout Frame (MUST inject before any other CSS)
Non-negotiable. Hermes uses data-style-id="hermes-terminal" as provenance marker
(satisfies pre-tool-style-router-gate.py) since --hermes- is not in the canonical
token regex. Frame token still required to prevent hero/body misalignment bug.
:root{
--hermes-page-max:1040px;
--hermes-page-gutter-total:clamp(32px,6vw,96px);
}
.frame{
width:min(var(--hermes-page-max),calc(100% - var(--hermes-page-gutter-total)));
margin-inline:auto;
}
.tui-cover, .ascii-banner{padding-block:48px 32px;padding-inline:0;}
main.frame{padding-block:48px 80px;}
<body data-style-id="hermes-terminal">
<section class="tui-cover">
<div class="frame">
<pre class="ascii-banner">…</pre>
<h1>Agent Title</h1>
</div>
</section>
<main class="frame">…</main>
</body>
Anti-pattern: full-bleed ASCII banner with text-align: center and no .frame
wrapper drifts from body left-edge at wide viewports. Always wrap banner in
.frame so the visible ASCII content shares the same x=0 as body sections.
Design Philosophy
- Twilight desert canvas: blue-night-sky fading into sandy-desert haze evokes
archaeology + mythology + pre-dawn computing
- Pixel headlines: 8-bit display font with copper drop-shadow signals retro
agent identity — the document IS the agent's terminal
- Amber-on-dark: warm gold/amber palette differentiates from Bloomberg's
cool amber-on-blue-black; this is gold-on-warm-charcoal
- ASCII as illustration: monospace dot-art (caduceus, glyphs, dividers)
carries narrative weight — illustrations are made of characters
- Terminal chrome: corner ticks (
┌ ┐ └ ┘), section chevrons (>> §),
status-bar segments, blinking cursor — every container looks like a TUI panel
- Narrative density, not data density: unlike Bloomberg, the content is
prose with periodic stat panels; pacing is essayistic, not tabular
Color Palette (CSS Custom Properties)
:root {
--hermes-sky-deep: #1A2D4D;
--hermes-sky-mid: #2D4A6E;
--hermes-sand-mist: #6B5B47;
--hermes-bg-deep: #0F1419;
--hermes-bg-panel: #16191F;
--hermes-bg-card: rgba(15,20,25,0.78);
--hermes-bg-input: #0A0D12;
--hermes-border-faint: rgba(245,184,0,0.10);
--hermes-border: rgba(245,184,0,0.22);
--hermes-border-strong: rgba(245,184,0,0.45);
--hermes-gold: #F5B800;
--hermes-gold-bright: #FFC820;
--hermes-amber: #FFB800;
--hermes-copper: #C77A1F;
--hermes-bronze: #8B6F2D;
--hermes-text-bright: #F5DDA0;
--hermes-text-body: #C9A565;
--hermes-text-muted: #8B7656;
--hermes-text-faint: #5A4A30;
--hermes-green: #6FAF60;
--hermes-red: #C76060;
--hermes-cyan: #5AA0B8;
--hermes-pixel: 'Monocraft', 'Press Start 2P', 'VT323', 'Courier New', monospace;
--hermes-mono: 'JetBrains Mono', 'IBM Plex Mono', 'Menlo', monospace;
--hermes-ui: 'IBM Plex Sans', 'Inter', 'Noto Sans SC', 'PingFang SC', sans-serif;
--hermes-radius: 2px;
--hermes-pad: 20px;
}
Typography Rules
Font Loading
Monocraft (the Minecraft-aesthetic monospace by IdreesInc) is the canonical pixel
display face. Load via jsDelivr CDN; Google Fonts ships the rest.
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet">
<style>
@font-face {
font-family: 'Monocraft';
src: url('https://cdn.jsdelivr.net/gh/IdreesInc/Monocraft@main/dist/Monocraft.ttc') format('collection'),
url('https://cdn.jsdelivr.net/gh/IdreesInc/Monocraft@main/dist/Monocraft.ttc') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
</style>
If a local copy of Monocraft.ttc is installed in ~/Library/Fonts or
/Library/Fonts, the font-family: 'Monocraft' entry resolves locally first
(no CDN round-trip). Fallback chain: Monocraft → Press Start 2P → VT323 →
system monospace.
Hierarchy
| Element | Font | Weight | Size | Color | Usage |
|---|
| Pixel headline | --hermes-pixel | 400 | clamp(2.2rem, 7vw, 5rem) | --hermes-gold | Hero title only |
| Section title | --hermes-mono | 700 | 1.4rem | --hermes-gold | >> chevron + uppercase |
| Subsection | --hermes-mono | 600 | 1.05rem | --hermes-text-bright | §N. numbered |
| Body prose | --hermes-ui | 400 | 15px | --hermes-text-body | Narrative paragraphs |
| Body emphasis | --hermes-ui | 600 | 15px | --hermes-text-bright | In-prose emphasis |
| Label / caption | --hermes-mono | 500 | 11px | --hermes-text-muted | Uppercase, letter-spaced |
| Stat value | --hermes-pixel | 400 | 1.6rem | --hermes-gold | Big numbers in stat cards |
| Code / ASCII | --hermes-mono | 400 | 13px | --hermes-text-bright | Pre blocks, inline code |
| Status segment | --hermes-mono | 500 | 11px | --hermes-text-muted | Bottom status bar |
CJK Handling (Locked v3)
html, body { overflow-x: hidden; }
body {
word-break: keep-all;
overflow-wrap: break-word;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
}
.prose p { font-family: var(--hermes-ui); }
.prose strong { color: var(--hermes-text-bright); font-weight: 600; }
Critical (round-3 ratified): text-rendering: optimizeLegibility is required.
Without it, the gold-on-twilight palette renders measurably softer on retina,
which is the single largest "feels muddy" complaint when porting this style.
Structural Elements
Page Background — Desert Twilight
body {
background:
radial-gradient(ellipse 1400px 600px at 50% -200px, var(--hermes-sky-mid) 0%, transparent 60%),
radial-gradient(ellipse 1800px 800px at 50% 100%, var(--hermes-sand-mist) 0%, transparent 55%),
linear-gradient(180deg, var(--hermes-sky-deep) 0%, var(--hermes-bg-deep) 45%, var(--hermes-bg-deep) 100%);
background-attachment: fixed;
min-height: 100vh;
color: var(--hermes-text-body);
font-family: var(--hermes-ui);
}
Hero Layout (Locked v3 — grid + stretch + min-height)
The hero is a 2-column grid: ASCII glyph on the left, headline + meta + tagline +
status-bar on the right. Both columns stretch to the same height; the glyph is
vertically centered within its track.
.hero {
min-height: clamp(520px, 64vh, 680px);
display: grid;
grid-template-columns: minmax(260px, 320px) 1fr;
gap: 40px;
align-items: stretch;
padding: 16px 0 40px;
border-bottom: 1px solid var(--hermes-border);
}
Pixel Headline (Hero)
.hero-title {
font-family: var(--hermes-pixel);
font-size: clamp(2.2rem, 6vw, 4.6rem);
font-weight: 400;
color: var(--hermes-gold);
letter-spacing: 0;
line-height: 1.05;
text-transform: uppercase;
text-shadow:
3px 3px 0 var(--hermes-copper),
6px 6px 0 rgba(0,0,0,0.35);
margin: 0 0 0.6em 0;
}
Braille Caduceus Slot (Locked v6 — 2× scale + flush top-align + no halo + visible loop)
v6 supersedes v5 sizing: glyph font-size doubled, left column widened to minmax(420, 620),
hero min-height removed, animation amplitude widened to 0.30 ↔ 1.0 + parent breath layer.
The v5 spec block below is preserved for reference; the LIVE values are in the v6 hero rule.
The caduceus is rendered in Unicode Braille (U+2800–U+28FF), NOT block characters
or pixel-font glyphs. Each Braille code-point packs a 2×4 dot grid; concatenating them
produces dense pixel art that reads identically to the original Hermes CLI banner —
because it IS the original. Source: hermes_cli/banner.py:76–90 (Nous Research, MIT).
.hero {
min-height: clamp(520px, 64vh, 680px);
display: grid;
grid-template-columns: minmax(260px, 320px) 1fr;
gap: 40px;
align-items: start;
padding: 16px 0 40px;
border-bottom: 1px solid var(--hermes-border);
}
.ascii-glyph {
font-family: var(--hermes-mono);
font-size: clamp(14px, 1.85vw, 19px);
line-height: 1.05;
color: var(--hermes-gold);
white-space: pre;
user-select: none;
align-self: start;
width: max-content;
max-width: 100%;
margin: 0 auto;
padding-top: 0;
text-align: left;
position: relative;
}
.ascii-glyph.caduceus > span {
animation: caduceus-twinkle 3.2s ease-in-out infinite;
will-change: opacity;
}
.ascii-glyph.caduceus > span:nth-of-type(5),
.ascii-glyph.caduceus > span:nth-of-type(6) { animation-delay: 0s; }
.ascii-glyph.caduceus > span:nth-of-type(4),
.ascii-glyph.caduceus > span:nth-of-type(7) { animation-delay: 0.16s; }
.ascii-glyph.caduceus > span:nth-of-type(3),
.ascii-glyph.caduceus > span:nth-of-type(8) { animation-delay: 0.32s; }
.ascii-glyph.caduceus > span:nth-of-type(2),
.ascii-glyph.caduceus > span:nth-of-type(9) { animation-delay: 0.48s; }
.ascii-glyph.caduceus > span:nth-of-type(1),
.ascii-glyph.caduceus > span:nth-of-type(10) { animation-delay: 0.64s; }
.ascii-glyph.caduceus > span:nth-of-type(11) { animation-delay: 0.80s; }
.ascii-glyph.caduceus > span:nth-of-type(12) { animation-delay: 0.96s; }
.ascii-glyph.caduceus > span:nth-of-type(13) { animation-delay: 1.12s; }
.ascii-glyph.caduceus > span:nth-of-type(14) { animation-delay: 1.28s; }
.ascii-glyph.caduceus > span:nth-of-type(15) { animation-delay: 1.44s; }
@keyframes caduceus-twinkle {
0%, 100% { opacity: 0.45; }
35%, 65% { opacity: 1.0; }
}
.ascii-glyph .caduceus-bright {
text-shadow: 0 0 1px rgba(255, 215, 0, 0.4);
}
@media (prefers-reduced-motion: reduce) {
.ascii-glyph.caduceus > span { animation: none; opacity: 1; }
}
Critical (v3 invariants preserved): do NOT apply text-align: center to the
glyph. Lines have different rendered widths; per-line centering shifts them apart
and the art collapses. Use width: max-content + margin: 0 auto to center the
block as a single unit while preserving internal alignment.
v5 alignment: hero parent is now align-items: start (was stretch); glyph
itself uses align-self: start + margin: 0 auto + padding-top: 0. Glyph top
edge sits flush with the right column's headline top edge — verified vs Hermes
CLI banner's print order (caduceus first row, then metadata).
v5 motion: per-line nth-of-type(N) delays produce a center-out twinkle wave
across the 15 Braille rows. Period 3.2s, opacity range 0.45–1.0 (low contrast,
quiet). Brightest core (lines 5-6) leads; outer wings, then descending staff,
ripple in 0.16s steps. Reduced-motion → static at full opacity.
Canonical Braille Caduceus Pattern (verbatim from Hermes source)
15 lines × 30 Braille columns. Color tiers in order from hermes_cli/banner.py:
| Lines | Color (hex) | Role |
|---|
| 1–2 | #CD7F32 (bronze) | Outer wing tips |
| 3–4 | #FFBF00 (amber) | Wing inner curl |
| 5–6 | #FFD700 (gold) | Brightest core — wrap in .caduceus-bright |
| 7–8 | #FFBF00 (amber) | Center column connection |
| 9–10 | #CD7F32 (bronze) | Lower wing/staff |
| 11–15 | #B8860B (dark goldenrod) | Staff descending into base |
Embed via 15 <span> elements inside <div class="ascii-glyph caduceus">…</div>,
each <span> carrying its tier color via inline style="color:#…". Mark lines 5–6
with class="caduceus-bright" to receive the shimmer animation.
Other allowed glyphs (rare): lyre (Hermes' instrument), winged sandal, twin serpents.
Always use Braille block characters, never solid blocks (■) or pixel-font ASCII.
Panels with Corner Ticks (Locked v3 — zero-scrollbar policy)
.panel {
position: relative;
background: var(--hermes-bg-card);
border: 1px solid var(--hermes-border);
border-radius: var(--hermes-radius);
padding: 24px 28px;
backdrop-filter: blur(2px);
overflow: hidden;
min-width: 0;
}
.panel::before, .panel::after {
content: '';
position: absolute;
width: 14px; height: 14px;
border: 1px solid var(--hermes-gold);
}
.panel::before { top: -1px; left: -1px; border-right: none; border-bottom: none; }
.panel::after { bottom: -1px; right: -1px; border-left: none; border-top: none; }
.panel-title {
font-family: var(--hermes-mono);
font-size: 11px;
font-weight: 600;
color: var(--hermes-text-muted);
text-transform: uppercase;
letter-spacing: 2px;
margin: 0 0 14px 0;
padding-bottom: 8px;
border-bottom: 1px dashed var(--hermes-border);
}
Section Header
.section-title {
font-family: var(--hermes-mono);
font-size: 1.35rem;
font-weight: 700;
color: var(--hermes-gold);
text-transform: uppercase;
letter-spacing: 0.05em;
margin: 60px 0 20px 0;
padding-bottom: 10px;
border-bottom: 1px solid var(--hermes-border-strong);
}
.section-title::before {
content: '>> ';
color: var(--hermes-amber);
}
Stat Cards (Pixel Numbers)
.stat-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 14px;
margin: 28px 0;
}
.stat {
background: var(--hermes-bg-card);
border: 1px solid var(--hermes-border);
padding: 22px 20px;
border-radius: var(--hermes-radius);
text-align: left;
}
.stat .label {
font-family: var(--hermes-mono);
font-size: 10px;
color: var(--hermes-text-muted);
text-transform: uppercase;
letter-spacing: 1.5px;
margin-bottom: 12px;
}
.stat .value {
font-family: var(--hermes-pixel);
font-size: 1.5rem;
color: var(--hermes-gold);
text-shadow: 2px 2px 0 var(--hermes-copper);
line-height: 1.0;
}
.stat .unit {
font-family: var(--hermes-mono);
font-size: 11px;
color: var(--hermes-bronze);
margin-top: 8px;
}
Status Bar (Bottom Strip)
.status-bar {
background: var(--hermes-bg-panel);
border-top: 1px solid var(--hermes-border);
padding: 10px 28px;
font-family: var(--hermes-mono);
font-size: 11px;
color: var(--hermes-text-muted);
display: flex;
gap: 18px;
flex-wrap: wrap;
}
.status-bar .seg { display: inline-flex; gap: 6px; }
.status-bar .seg .key { color: var(--hermes-bronze); }
.status-bar .seg .val { color: var(--hermes-gold); }
.status-bar .sep { color: var(--hermes-text-faint); }
Timeline (Milestone Track)
.timeline { position: relative; padding-left: 28px; margin: 24px 0; }
.timeline::before {
content: '';
position: absolute;
left: 8px; top: 8px; bottom: 8px;
width: 1px;
background: var(--hermes-border-strong);
}
.tl-item { position: relative; padding: 6px 0 22px 0; }
.tl-item::before {
content: '◆';
position: absolute;
left: -28px;
top: 6px;
color: var(--hermes-gold);
font-size: 14px;
text-shadow: 0 0 8px var(--hermes-amber);
}
.tl-item .when {
font-family: var(--hermes-mono);
font-size: 11px;
color: var(--hermes-bronze);
text-transform: uppercase;
letter-spacing: 1.5px;
}
.tl-item .what {
font-family: var(--hermes-mono);
font-weight: 600;
color: var(--hermes-gold);
margin: 4px 0 6px 0;
}
.tl-item p { color: var(--hermes-text-body); margin: 0; }
Cursor Block (Blinking)
.cursor {
display: inline-block;
width: 0.55em;
height: 1em;
background: var(--hermes-gold);
vertical-align: text-bottom;
margin-left: 2px;
animation: hermes-blink 1.05s steps(2,start) infinite;
}
@keyframes hermes-blink { to { background: transparent; } }
Toolset / Skill Listing (Two-Tone)
.kv-list {
font-family: var(--hermes-mono);
font-size: 13px;
line-height: 2.1;
}
.kv-list .key {
color: var(--hermes-bronze);
display: inline-block;
min-width: 180px;
}
.kv-list .val {
color: var(--hermes-text-bright);
}
.kv-list .val .sep { color: var(--hermes-text-faint); margin: 0 4px; }
Quote / Callout — Inscription Style
.inscription {
border-left: 2px solid var(--hermes-gold);
background: linear-gradient(90deg, rgba(245,184,0,0.06) 0%, transparent 60%);
padding: 16px 22px;
margin: 24px 0;
font-family: var(--hermes-ui);
font-style: italic;
color: var(--hermes-text-bright);
}
.inscription cite {
display: block;
margin-top: 10px;
font-style: normal;
font-size: 12px;
color: var(--hermes-bronze);
font-family: var(--hermes-mono);
letter-spacing: 1px;
}
Layout Principles
- Container: max-width 1080px, 32px horizontal padding
- Section spacing: 60px between major sections (essayistic pacing)
- Border-radius: 2px (sharper than Bloomberg's 4px — more terminal-true)
- Density: medium-low (narrative, not data) — stat-grids cap at
repeat(4,1fr)
- Headings always uppercase + letter-spaced — terminal heritage
- One pixel-headline per page — reserve
--hermes-pixel for the hero ONLY;
using it elsewhere collapses the visual hierarchy
Grid Rules
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
@media (max-width: 900px) {
.stat-grid, .grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
.stat-grid, .grid-2, .grid-3 { grid-template-columns: 1fr; }
.hero-title { font-size: 2.2rem; }
}
Footer
<footer class="site-footer">
<p>[ProjectName] v[X.Y] — [Document Type]</p>
<p>Your Name | your@email.com</p>
<p class="attr">[Generation date + provenance]</p>
</footer>
.site-footer {
text-align: center;
padding: 60px 20px 40px;
color: #9B9B9D;
font-size: 13px;
line-height: 2.2;
border-top: 1px solid var(--hermes-border-faint);
margin-top: 80px;
}
Zero-Scrollbar Layout Policy (Locked v3 — non-negotiable)
The Hermes-Terminal style enforces a hard "no scrollbar anywhere" rule (mandated
by user preference, ratified in the round-3 polish on 2026-04-30). The policy
has four enforcement points; all are required together.
1. Page-level scrollbar suppression
html, body { overflow-x: hidden; }
Catches any horizontal-overflow leak that escapes the per-element guards below.
Vertical scroll on body remains, as expected for long documents.
2. All grids use minmax(0, 1fr) and zero-min children
Without min-width: 0, grid children default to auto minimum which is the
content's intrinsic width — long unbroken text or a wide table forces the track
wider than 1fr allows, and the parent grows to accommodate (showing scrollbar).
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; }
.stat-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 24px; }
.grid-2 > *, .grid-3 > *, .stat-grid > *, .split > .col { min-width: 0; }
.split > .col { overflow: hidden; }
3. Comparison tables MUST use table-layout: fixed + <colgroup>
table-layout: auto lets the table grow wider than its container when any cell
has long unbreakable content. fixed + explicit <colgroup> widths sums to 100%
and never overflows. Pair with word-break: break-word + overflow-wrap: anywhere
to allow CJK and URLs to wrap mid-content.
.compare-table {
width: 100%;
table-layout: fixed;
border-collapse: collapse;
word-break: break-word;
overflow-wrap: anywhere;
}
.compare-table td.axis {
font-family: var(--hermes-mono);
font-weight: 600;
font-size: 13px;
white-space: normal;
}
<table class="compare-table">
<colgroup>
<col style="width: 18%">
<col style="width: 41%">
<col style="width: 41%">
</colgroup>
...
</table>
For 4-column tables, use 12% / 29% / 29% / 30%. For 5-column, 10% / 22.5% × 4.
Always <colgroup>; never rely on cell style="width:N%" (browsers compute it
inconsistently with fixed layout).
4. ASCII pre-formatted blocks: overflow: hidden + responsive font-size
ASCII art (architecture diagrams, status panels) uses white-space: pre which
preserves long lines. On narrow viewports the right edge will clip — that's the
zero-scrollbar policy's price, and it's acceptable because ASCII degrades
gracefully (the box still reads as a terminal artifact).
.arch {
font-family: var(--hermes-mono);
font-size: clamp(10px, 1.05vw, 12px);
white-space: pre;
overflow: hidden;
}
@media (max-width: 600px) {
.arch { font-size: 9px; padding: 14px 16px; }
}
Why these four together
Removing any one re-introduces a scrollbar somewhere. Empirically validated on
2026-04-30 round 1 review: panel overflow: hidden alone wasn't enough — the
comparison table forced the panel wider via table-layout: auto. Fixed both
together → first scrollbar-free render.
Anti-Patterns (Never Do)
- No light/cream page background (twilight + desert is the identity)
- No serif fonts anywhere (pixel + mono + sans only)
- No
--hermes-pixel outside the hero title (reserve for one element to keep
hierarchy; using it on multiple H1s flattens the page)
- No emoji (per project rules; ASCII art is the substitute)
- No bright accent other than gold/amber (red/green/cyan exist only for
upstream-divergence-link semantics, not decoration)
- No box-shadow paper effects (this is a terminal, not paper —
text-shadow for pixel depth is the only allowed shadow)
- No
border-radius > 4px (sharp edges are part of the identity)
- No
flex: 1 on text-bearing cards (CJK text gets stretched into
unreadable wide lines; cap with explicit max-width)
- No
min(vw, px) to lock card upper bound (per project responsive rule;
use pure vw/% with max-width)
- No prose-heavy section without a stat-card or ASCII glyph break (the
identity collapses to plain dark mode if you write three paragraphs in a row
with no visual punctuation; insert a stat row, callout, or ASCII divider every
~400 words)
- No
table-layout: fixed as global default (cf. Bloomberg gotcha #4 —
short cells waste width; use auto + word-break: break-word universally,
opt into fixed only with <colgroup>)
- No CDN-loaded photographic image as background (the desert atmosphere is
pure CSS gradients; image backgrounds break offline rendering and bloat the
single-file deliverable)
Provenance Markers (Required)
Every Hermes-Terminal HTML deliverable MUST carry both:
- Identifier comment in
<head> (or top of body):
- Token signature — at least one CSS variable starting with
--hermes-
(the :root block above guarantees this)
Both are checked by pre-tool-style-router-gate.py (PreToolUse, hard block)
and post-tool-html-style-router-guard.py (PostToolUse, advisory). Bypass
marker html-style-router:bypass is allowed only for one-off tests.
Comparison with Other Styles
| Dimension | Claude | Economist | McKinsey | Bloomberg | Hermes |
|---|
| Page bg | Cream | White | White+gray | Dark cool | Twilight desert (warm dark) |
| Accent | Terracotta | Red | Deep Blue | Cool Amber | Warm Gold #F5B800 |
| Headlines | Serif | Sans | Sans heavy | Sans | Pixel display + copper shadow |
| Body | Sans | Serif | Sans | Sans | Sans + selective mono |
| Illustration | — | Charts | Pyramids | Tables | ASCII art |
| Corners | 10px | 0px | 0px | 4px | 2px |
| Shadows | Paper tiers | None | None | Glow | Pixel offset (text-shadow only) |
| Density | Spacious | Dense | Structured | Maximum | Medium narrative |
| Container | 1100px | 960px | 1040px | 1200px/full | 1080px |
| Feel | Academic book | Newspaper | Boardroom | Trading floor | Twilight CLI session |
| Best for | Guides, proposals | Reports, briefings | Strategy decks | Financial dashboards | Agent biographies, CLI postmortems, fork-vs-upstream stories |
Gotchas
-
Pixel font load is heavy and FOUT-prone. Press Start 2P is ~80KB and
often shows fallback first. Add font-display: swap (Google Fonts default)
AND set the hero container min-height so the pixel-shadow offset doesn't
reflow the page on font load. Validated: without min-height, the hero jumps
~40px when Press-Start-2P resolves.
-
Desert gradient must be background-attachment: fixed. Without fixed,
long pages reveal the gradient repeating per scroll-segment — looks like
stripes. With fixed, the twilight band stays anchored to the viewport,
reinforcing the "this is a terminal session" feeling.
-
Corner ticks via ::before/::after clash with overflow: hidden. If
the panel needs overflow: hidden (e.g., to clip a long table), the corner
ticks vanish because they sit at -1px outside the box. Workaround: wrap the
panel in an outer div that carries the ticks, with the inner content div
handling overflow. Or use border-image instead of pseudo-elements.
-
Two pixel headlines on one page collapse the hierarchy. Tempting to use
--hermes-pixel for major section breaks too. Don't. The hero pixel title
is the document's signature — second usage downgrades it to a styling tic.
Use uppercase mono --hermes-mono weight 700 for sections instead; the
contrast between pixel-once and mono-many is the actual hierarchy.
-
Gold-on-warm-dark is below WCAG AA without a guard. #F5B800 on
#0F1419 is ~9:1 (passes), BUT #C9A565 body on #0F1419 is ~5:1
(passes AA for normal text but fails AAA). Do not let body text drop below
--hermes-text-body (#C9A565). For long-reading prose, consider promoting
to --hermes-text-bright (#F5DDA0) — that hits ~10:1.
-
ASCII art at <10px font-size becomes unreadable noise. The pixel
density of monospace dot-art needs at least 10–12px to read as a glyph.
Below that it visually merges with neighboring borders. Validate by zooming
out to 75% — if the caduceus stops being legible, increase font-size.
-
CJK text in pixel font is broken. Press Start 2P does not include
CJK glyphs; if you put Chinese in the hero title it falls back to system
default and breaks the visual identity. Solution: hero title is English /
Latin only (e.g., "HERMES-AGENT", "FORK & FALLOUT"); Chinese subtitle uses
--hermes-mono (which falls back to a CJK-capable mono like Menlo + Noto
Sans SC).
-
Multi-row stat-grids look weak with gap: 14px. When stats wrap to a
second row on narrow viewports, the row-gap visually equals column-gap and
the rows feel un-grouped. Use row-gap: 24px separately so rows breathe
while columns stay tight.
-
Status bar segments need explicit flex-wrap: wrap + per-segment
flex-shrink: 0. On narrow viewports, a long segment value pushes the
following segments off-screen invisibly. With wrap + no-shrink, segments
wrap to a new line cleanly instead of clipping.
-
The aesthetic depends on the hero having both pixel title AND ASCII
glyph AND status bar visible above the fold. Cutting any one of the
three demotes the page to "yet another dark theme." When desktop hero
height drops below ~520px, the identity is gone. Set
.hero { min-height: clamp(520px, 64vh, 680px); } to enforce the
above-the-fold trinity (locked v3).
-
text-align: center on the ASCII glyph collapses the art (round-2 lesson).
Each line has a different rendered width because the leading-spaces position
is part of the composition. Centering each line independently shifts them
by different amounts and the caduceus reads as scattered noise. The correct
technique is to center the WHOLE pre block: width: max-content; margin: 0 auto; text-align: left; plus align-self: center for vertical placement.
-
The PreToolUse style-router gate reads new_string only, not the full
file (round-1 operational lesson). When patching an HTML deliverable's
middle, the gate may BLOCK because the diff doesn't carry the style-system:
or --hermes- marker even though the surrounding file does. Workaround:
embed a brief <!-- style-system: hermes-terminal --> or /* style-system: hermes-terminal */ comment inside every new_string that touches an HTML
file. Cosmetic noise, but it unblocks edits without weakening the gate.
-
Glyph column width must accommodate the post-clamp font-size at min
viewport (round-2 lesson). With font-size: clamp(14px, 1.85vw, 19px),
the glyph at desktop is ~19px × 14 chars wide ≈ 266px. The grid track
minmax(260px, 320px) is exactly sized to fit; reducing to minmax(200px, 260px) clips the glyph's right edge silently because parent has overflow: hidden (zero-scrollbar policy). Validated empirically: minmax 260-320 is
the safe lower bound at clamp(14px, 1.85vw, 19px). If you raise the glyph
font-size, raise the column min in lockstep.
Usage Checklist
When generating a Hermes-Terminal HTML:
- ☐ Hero contains: pixel headline + ASCII glyph + version/byline + tagline
- ☐ At least one stat-grid (4-card) showing key numbers
- ☐ At least one timeline OR comparison-table section
- ☐ Status bar at bottom of the hero OR sticky at page bottom
- ☐ All CSS variables prefixed
--hermes-* (token signature requirement)
- ☐ Identifier comment
<!-- style-system: hermes-terminal | html-style-router -->
- ☐ Pixel font: Monocraft via jsDelivr CDN @font-face declaration
- ☐ Zero-scrollbar policy: 4 enforcement points all present (page / grid / table / arch)
- ☐
text-rendering: optimizeLegibility on body (round-3 ratified)
- ☐ Footer in standard project format (Maurice signature, no "Author:" prefix)
- ☐ Auto-
open after write (per project rule)
Version Notes
-
v11 (FROZEN 2026-05-01) — fullPage-screenshot safe body background invariant
- dedicated CF subdomain naming convention.
(A) Screenshot-safe body background (the load-bearing fix). Chrome+Playwright
has a documented compositor bug where background-attachment: fixed only renders
for the initial viewport during a fullPage: true capture (Page.captureScreenshot { captureBeyondViewport: true }). For long-form posters this manifests as the
bottom 60–80% of the screenshot collapsing to the page's <html> default white
background, producing a "fog" effect over the lower content. Fix is invariant
per Inversion (cognitive model #001): instead of trying to make attachment: fixed
capture correctly, declare "every screenshot pixel must be --hermes-bg-deep" and
enforce it at the <html> element so any unpainted region inherits the dark
navy. Required pattern:
html { background-color: var(--hermes-bg-deep); }
body {
background-color: var(--hermes-bg-deep);
background-image:
radial-gradient(ellipse 1400px 600px at 50% -200px, var(--hermes-sky-mid) 0%, transparent 60%),
radial-gradient(ellipse 1800px 800px at 50% 100vh, var(--hermes-sand-mist) 0%, transparent 55%),
linear-gradient(180deg, var(--hermes-sky-deep) 0%, var(--hermes-bg-deep) 45%, var(--hermes-bg-deep) 100%);
background-repeat: no-repeat;
background-size: 100% 100vh, 100% 100vh, 100% 100vh;
min-height: 100vh;
}
Bottom radial anchor changed from at 50% 100% (unreliable under fullPage capture)
to at 50% 100vh (reliable per-viewport tile). background-attachment is forbidden
in any future variant; rely on <html> solid + per-viewport gradient tiling.
(B) Dual-resolution screenshot SOP (poster delivery convention). Posters now
ship in three sizes from a single Playwright session:
- 4K master —
viewport: 1440×900, deviceScaleFactor: 3, fullPage: true, type: png →
~4320 × N px (5–8 MB PNG). Archive master, GDrive, future re-render reference.
- Mobile master —
viewport: 430×932, deviceScaleFactor: 3, isMobile: true, hasTouch: true, fullPage: true, type: png → ~1290 × N px (4–6 MB PNG). Phone-native poster for
AirDrop / file delivery.
- WeChat-friendly delivery —
viewport: 1080×1920, deviceScaleFactor: 1, isMobile: true, fullPage: true, type: jpeg, quality: 92 → 1080 × N px (1–2 MB JPEG). The 1080-width
- JPEG combination guarantees WeChat parses as image (not file) and recipient
sees inline preview rather than download chip. Aspect ratio kept under 1:8 for
WeChat preview tolerance; if content exceeds, chunk into 2 stitched JPEGs of
≤1:5 each.
(C) CF subdomain naming convention. Each editorial article gets its OWN
CF Pages project; do NOT bundle multiple articles under one project's sub-paths
(the bundling pattern was rejected — URL slug must reflect content, not series host).
Pattern: <category-slug>-<NN>-<title-slug>.pages.dev where <category-slug> is
pinyin/English form (e.g. deeplearn), <NN> is the zero-padded episode number,
<title-slug> is a 1–4 token kebab-case content hint. Date is encoded in the
GDrive filename + article body, not the URL. Example: deeplearn-02-hermes-agent.pages.dev.
Legacy projects predating this convention (e.g. luofuli-interview-2026) are not
retroactively renamed.
(D) GDrive structured naming. Pattern: <YYYY-MM-DD>_<category>_第<NN>期_<title>.<ext>.
Both Chinese and ASCII permitted. Example:
2026-04-30_深度学习_第02期_Hermes-Agent_Nous-Research_OpenClaw对比_EvoMap抄袭争议.html.
Same prefix on accompanying screenshots so all artifacts of one article cluster
alphabetically in the folder.
-
v10 (FROZEN 2026-05-01) — final hero polish + skill solidification.
Single content fix: removed <p class="hero-questions-lead">本页要回答的问题</p>
from .hero-right so the 5-item <ol class="q-list"> lifts up one row, restoring
the visual center the v9 lead pulled down. Initial deploy was at
https://luofuli-interview-2026.pages.dev/hermes-agent/ (now superseded by v11
dedicated subdomain https://deeplearn-02-hermes-agent.pages.dev/).
-
v9 (2026-05-01 morning) — three layout/content patches after v8 review:
(1) Hero column rebalance: grid-template-columns: 1fr 1fr → 0.92fr 1.08fr
(right column ~8% wider, starts ~30px earlier at 1440 viewport); gap: 18px 40px
→ 18px 28px (col gap shrunk 12px, additional leftward pull). Combined effect:
right text region shifts ~60px leftward, closer to the glyph.
(2) Right column vertical centering: .hero-right { align-self: center }
added — top-anchored logo (~504px) leaves ~50px headroom above the right
content (~400px), creating a deliberate print-grade vertical anti-symmetry
(logo dominates row top, text floats in row middle). Reference: NYT/Economist
editorial layouts.
(3) Sub-line → 5-item numbered list: <p class="hero-sub">…/separator/…</p>
replaced with <div class="hero-questions"> containing <p class="hero-questions-lead">
<ol class="q-list"> × 5 items. CSS counter decimal-leading-zero produces
01–05 numerals in --hermes-bronze — pure CSS, zero JS, zero numeric markup.
Each question becomes a distinct line with its own numeral, matching the user's
intent of treating the 5 questions as the page's table of contents.
-
v8 (2026-05-01 early hours) — hero polish trio after v7 review:
(1) Title centered: text-align: center added to .hero-title so the
banner row 1 reads as a centered masthead (was implicitly left-aligned).
Margin-bottom tightened 0.6em → 0.5em. (2) Duplicate status-bar removed:
the <div class="status-bar"> inside .hero-right listed stars/forks/commits/ launched/license — exactly the numbers shown again as TL;DR cards two rows
below. Via Negativa: deleted to eliminate the double-coding maintenance burden.
(3) Right-column typography pass: meta 12px → 13px + line-height: 1.7
- faint underline border-bottom (group separator); tagline
1.1rem → 1.18rem
line-height: 1.75 + max-width: 600 → 620; sub 13px → 13.5px +
line-height: 1.85 + max-width: 600 → 620. Visual rhythm now favors
Gestalt-proximity grouping (meta block ↔ tagline ↔ sub) instead of uniform
spacing soup.
-
v7 (2026-04-30 late night) — major hero structural pivot + readability bump:
(1) Hero now 2 rows: <h1> promoted to direct child of .hero and given
grid-column: 1 / -1 so the title spans the full hero width as row 1; glyph
- new
.hero-right wrapper occupy row 2 in 1fr 1fr (50/50). DOM order
changed accordingly: header > h1 > glyph-div > hero-right-div. v6 wrapper
<div> renamed to <div class="hero-right">.
(2) Glyph back to mid scale: clamp(20, 2.8vw, 40) → clamp(18, 2.4vw, 32)
— v6's 2× was correct intent but with the 50/50 row 2 split, 32px max keeps
the 30-char Braille ~480px wide, fitting half-viewport at 1440 cleanly.
(3) Title bumped: clamp(2.2, 6vw, 4.6rem) → clamp(3, 9vw, 7.5rem) so
the title row 1 reads as a banner over the glyph + body region.
(4) Body text brightness: --hermes-text-body #C9A565 → #E8CB85
(HSL L 50% → 67%, H/S preserved so warm-tan identity stays); --hermes-text-muted
#8B7656 → #B89A6A to keep the 4-tier contrast hierarchy.
(5) Hero padding-top 16px → 8px to tighten the title's vertical anchor.
-
v6 (2026-04-30 night) — three sizing/motion fixes after v5 review:
(1) Glyph 2× scale: font-size clamp(14, 1.85vw, 19) → clamp(20, 2.8vw, 40),
left column track widened minmax(260, 320) → minmax(420, 620) so the 30-char
Braille pattern fits at full size. Glyph rendered height now ~600px, matching
right-column content height (title + meta + tagline + questions + status-bar).
(2) Hero min-height removed: was clamp(520, 64vh, 680), created ~200px
empty band below the right column with v5's align-items: start. Hero now
collapses to natural content height. Mobile rule (<900px) unchanged.
(3) Loop visibility boost: per-span wave amplitude widened 0.45 ↔ 1.0
→ 0.30 ↔ 1.0, period 3.2s → 2.4s, delay step 0.16s → 0.13s. Added a
parent .ascii-glyph.caduceus filter: brightness(0.92 ↔ 1.08) breath layer
(also 2.4s) for an unmissable global loop signal — prior wave was technically
looping but perceptually read as "flash once" because amplitude was too tight.
Bright core (lines 5-6) gets its own caduceus-twinkle-bright keyframe with
higher floor (0.55 ↔ 1.0) so the staff center never fully fades.
prefers-reduced-motion extended to disable both wave and breath layers.
-
v5 (2026-04-30 late evening) — editorial reversal of v4's halo direction.
User feedback: "logo 背后不要有光晕,点阵的 logo 变成闪动的效果" + reference
icons.icantcode.fyi (quiet-loaders library). Three changes: (1) ::before /
::after radial halos REMOVED — caduceus stands on body bg directly; (2) hero
parent forced align-items: start (was stretch) and glyph margin/padding
zeroed so glyph top sits flush with headline top; (3) v4 per-character
drop-shadow shimmer on .caduceus-bright REPLACED with center-out twinkle
wave: all 15 Braille <span> rows pulse opacity 0.45 ↔ 1.0 over 3.2s with
per-row nth-of-type delays rippling outward from the bright core (lines 5-6
lead, then ±1 ring 0.16s later, etc.). Low-contrast, non-flicker, quiet-loader
philosophy. prefers-reduced-motion honored: animation off, opacity 1.
-
v4 (2026-04-30 evening) — luxe upgrade pass after editorial review of v3 deliverable.
Three breaking changes: (1) glyph technique flipped from block-char ASCII to verbatim
Braille caduceus from hermes_cli/banner.py:76–90 (Nous Research, MIT) — the inaugural
deliverable was rendering a non-canonical interpretation; v4 ships pixel-identical to
the actual Hermes CLI startup banner. (2) align-self: center → start so glyph top-
aligns with headline (matches original banner print order). (3) Added radial gold halo
via ::before + inner ring ::after + per-character drop-shadow shimmer animation
on the brightest core lines (5–6, .caduceus-bright). prefers-reduced-motion honored.
-
v3 (frozen 2026-04-30) — Round 1+2+3 polish on the inaugural deliverable
consolidated. Locked: hero geometry (520-680px / 260-320px col), Monocraft
pixel font via jsDelivr, zero-scrollbar four-point policy, ASCII glyph block-
centered (NOT line-centered), text-rendering: optimizeLegibility, 13 gotchas.
-
v2 (2026-04-30 same-day) — pixel font switched Press Start 2P → Monocraft
per editorial direction. Local install + jsDelivr CDN both wired.
-
v1 (2026-04-30 inaugural) — initial draft based on Hermes-Agent CLI
screenshot abstraction. Added to html-style-router as 5th canonical style.
Your Name | your@email.com