Palette
Four values, no gradients. The background is green-black rather than neutral black — it reads as chosen where #000 reads as default, and it stops photography on the slide from looking cut out.
--bg: #0F1410 /* green-black — the slide surface */
--surface: #18201A /* raised panels, code blocks, table headers */
--text: #E8E6DF /* warm off-white — never pure #FFF */
--muted: #8A9287 /* captions, labels, axis text */
--accent: #9BC53D /* moss — ONE accent, used sparingly */Warm text on a cool background is the whole trick: pure white on near-black buzzes at presentation scale, and the warmth is what makes it feel printed rather than emitted.
The accent is a scalpel. One accented thing per slide — a number, a single word, a rule under the active item. A slide with three accent colours has none.
Set the background on every slide, not on body — Renza renders slides full-bleed on their own surface, so a body background will not show through:
<meta name="color-scheme" content="dark">
section[data-renza-slide] { background: var(--bg); color: var(--text); }Type
One serif for display, one grotesque for everything else. The contrast does the work that a second colour would otherwise have to.
Display: "Instrument Serif", "Iowan Old Style", Georgia, serif
Body: "Inter", -apple-system, "Segoe UI", sans-serif
Mono: "JetBrains Mono", "SF Mono", ui-monospace, monospaceScale — deck type is read from across a room, so the steps are wide:
Slide title clamp(2.5rem, 5vw, 4rem) / 1.05 / -0.02em
Section label 0.8125rem / 1.2 / 0.08em UPPERCASE, --muted
Body clamp(1.125rem, 1.6vw, 1.5rem) / 1.5
Caption 0.9375rem / 1.4 / --mutedTitles are sentence case, never Title Case — Title Case reads as a slide template, sentence case reads as a sentence someone meant.
Body text tops out at ~60 characters per line. If a slide needs more than about 40 words, it is two slides.
Grid
A 12-column grid with generous, asymmetric margins. The asymmetry is what keeps it from looking like a corporate template.
padding: 8vh 10vw 8vh 12vw; /* heavier on the left — the text edge */
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 2rem;Three layouts cover almost every slide; resist inventing a fourth:
- Statement — title in columns 1–8, nothing else. Use for transitions.
- Split — text 1–6, visual 7–12, both aligned to the same baseline.
- Enumerated — a 2×2 or 3×1 of labelled blocks, each with a
--mutedlabel above a short line of--text.
Anchor content to the top-left, not the centre. Vertically centred text drifts between slides and makes a deck feel unmoored; a shared top edge makes consecutive slides feel like one document.
Motion
Restraint. The deck is read, not watched — motion marks a transition, it does not perform one.
- One entrance per slide, on the element that matters. Not a stagger down the whole slide.
- 200–300ms,
cubic-bezier(0.2, 0, 0, 1). Anything slower reads as waiting. - Opacity plus a ≤12px translate. No scale, no rotate, no blur.
- Nothing loops. A looping element steals attention for the whole slide.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation: none !important; transition: none !important; }
}That media query is not optional — a presenter cannot opt a room out of motion sickness, so the deck has to.
Do / Don't
Do
- Give every slide an explicit background (see Palette).
- Keep one idea per slide; split rather than shrink.
- Use
--mutedfor every label, unit, axis, and caption — it is what makes the--textweight feel deliberate. - Let a statement slide be almost empty. The space is the design.
- Use a 1px
--surfacerule to separate, instead of a box.
Don't
- No gradients, glass, glow, or blob shapes. They date instantly and read as generated.
- No pure
#000or#FFFanywhere. - No drop shadows on a dark surface — they are invisible and cost you nothing but bytes. Use
--surfaceelevation instead. - No icon next to every bullet. Icons that decorate rather than distinguish are noise.
- No more than one accent element per slide.
- Never ship your own nav, keyboard handler, or progress bar — Renza supplies all of it (see the slide contract).
Worked example
A complete statement slide, in the style, with nothing that needs stripping:
<section data-renza-slide id="thesis" data-renza-title="The thesis">
<p class="label">03 — Position</p>
<h2>Neutrality is the only moat that compounds.</h2>
<p class="lede">
Every feature here is copyable within a quarter. The graph is not.
</p>
</section><style>
#thesis {
background: #0F1410;
color: #E8E6DF;
padding: 8vh 10vw 8vh 12vw;
display: grid;
align-content: start;
gap: 1.5rem;
}
#thesis .label {
font: 500 0.8125rem/1.2 Inter, sans-serif;
letter-spacing: 0.08em;
text-transform: uppercase;
color: #8A9287;
}
#thesis h2 {
font: 400 clamp(2.5rem, 5vw, 4rem)/1.05 "Instrument Serif", Georgia, serif;
letter-spacing: -0.02em;
max-width: 18ch;
margin: 0;
}
#thesis .lede {
font: 400 clamp(1.125rem, 1.6vw, 1.5rem)/1.5 Inter, sans-serif;
max-width: 42ch;
color: #8A9287;
animation: rise 240ms cubic-bezier(0.2, 0, 0, 1) both;
}
#thesis .lede em { color: #9BC53D; font-style: normal; }
@keyframes rise { from { opacity: 0; transform: translateY(12px); } }
@media (prefers-reduced-motion: reduce) { #thesis .lede { animation: none; } }
</style>Note what is absent: no nav, no slide counter, no progress bar, no keyboard handler. Renza owns everything between slides; this owns everything inside one.