How the stdout showcase site was designed and built.

BUILD NOTES / NO SECRETS 3 PASSES / 2 PAGES / 1 FILE EACH BY CLAUDE FABLE 5

Everything on this page is how the stdout site actually got made: the concept, the load-bearing code, the asset pipeline (there isn't one, on purpose), and the honest three-pass fix log.

STACKhand-written HTML/CSS/JS, zero build PAYLOADone 43KB file per page + Google Fonts COLORS#FFFFFF, #000000, #C6FF00. no grays TYPEArchivo Black + JetBrains Mono
SEC.01 / CONCEPTTHE FICTION + THE LOOK

A LOG TOOL THAT READS LIKE A ZINE.

stdout is a fictional API logging product with one promise: your logs, readable. It takes the JSON your services spew and sets it in columns a human can scan. The product is about typography for machine output, so the site is typography, almost nothing else.

The art direction is brutalist print and xerox punk: photocopied poster energy, developer zine grid, three inks only. White is the paper, black is the toner, and acid green (#C6FF00) is the highlighter someone dragged across the important lines. There are no grays anywhere. Every "tone" you see is a halftone dot pattern, the way a photocopier would fake it.

Motion follows the print logic: nothing eases, everything cuts. Marquees tick like ticker tape (steps() easing, not linear), hover states slam between black and white with a two-frame acid flash, and the cursor is a blinking block caret because the whole site is one big terminal. The money shot is the hero: two display words stretched edge-to-edge at viewport scale, a marquee band slicing between them.

SEC.02 / TECHNIQUELOAD-BEARING CODE

FIVE TRICKS DOING THE HEAVY LIFTING.

Each one is copy-paste ready. No libraries, no shaders, no images.

EDGE-TO-EDGE DISPLAY TYPET.01

The hero words fill the viewport exactly, at any width, even before the webfont loads. SVG textLength forces the type to a fixed advance width and preserveAspectRatio="none" lets the band stretch vertically like a xeroxed poster. One catch found in pass 1: letter-spacing on the text element breaks the textLength math in Chromium and the last glyph clips. Leave it off.

<div class="band">
  <svg viewBox="0 0 1000 116" preserveAspectRatio="none">
    <text x="0" y="111" textLength="1000"
          lengthAdjust="spacingAndGlyphs">YOUR LOGS</text>
  </svg>
</div>
/* CSS: the band owns the color pair, the text inherits */
.band svg{width:100%;height:100%}
.band text{font-family:'Archivo Black';font-size:150px;fill:currentColor}
HARD CUTS: steps() EVERYWHERET.02

No linear, no ease. Marquees run on steps(240) so they shudder like machinery, and the hover inversion plays a two-frame acid flash before settling. Un-hovering cuts instantly, which is the joke.

.mq-track{display:flex;width:max-content;
  animation:mq 20s steps(240) infinite}
@keyframes mq{to{transform:translateX(-50%)}}

.band:hover{background:#000;color:#fff;
  animation:acid .18s steps(2,end)}
@keyframes acid{
  0%{background:#C6FF00;color:#000}   /* frame 1 */
  50%{background:#000;color:#C6FF00}  /* frame 2 */
}
THE REFORMAT LOOPT.03

The terminal demo is one DOM row per log line with two children: the raw JSON string and a CSS grid of columns. A setTimeout timeline appends raw rows, slams a stamp, then flips rows to column mode one by one with a green flash. Monospace plus fixed ch column widths is what makes the "snap" read.

var rows = LOGS.map(rowEl);
rows.forEach(function(r,i){ at(120 + i*105, function(){ tlines.appendChild(r); }); });
var t0 = 120 + LOGS.length*105 + 520;
at(t0, function(){ stamp.classList.add('on'); });   // REFORMAT slams in
rows.forEach(function(r,i){
  at(t0 + 620 + i*85, function(){
    r.classList.add('is-fmt','flash');              // raw -> columns, hard cut
    setTimeout(function(){ r.classList.remove('flash'); }, 130);
  });
});
at(t0 + 620 + rows.length*85 + 3620, cycle);        // hold, then loop
BLOCK CARET CURSORT.04

The pointer is replaced with a terminal caret: a green block that snaps to a 6px grid (quantized, never smooth) and blinks when you stop moving. Fine pointers only, and it turns itself off under prefers-reduced-motion.

if (matchMedia('(pointer:fine)').matches && !RM) {
  document.body.classList.add('cur-on');   /* body.cur-on * {cursor:none} */
  document.addEventListener('mousemove', function(e){
    tx = e.clientX; ty = e.clientY;
    cur.classList.add('moving');           /* pauses the blink */
    clearTimeout(idleT);
    idleT = setTimeout(function(){ cur.classList.remove('moving'); }, 260);
  }, {passive:true});
  (function loop(){
    var q = 6;  /* snap to grid = mechanical, not floaty */
    cur.style.transform = 'translate(' + Math.round(tx/q)*q + 'px,' + Math.round(ty/q)*q + 'px)';
    requestAnimationFrame(loop);
  })();
}
HALFTONE IN THREE INKST.05

The palette bans gray, so every mid-tone is a dot screen: four SVG patterns at different dot radii, stacked into ramps. The same four patterns build the hero ramp, the card corners, and the "photocopy fade" strips where white sections meet black ones.

<pattern id="ht4" width="9" height="9" patternUnits="userSpaceOnUse">
  <circle cx="4.5" cy="4.5" r="3.1" fill="#000"/>
</pattern>
<!-- ht3 r=2.2, ht2 r=1.4, ht1 r=.8 : one screen, four densities -->

<!-- a photocopy fade, white into black -->
<svg class="xfade">
  <rect y="0"  width="100%" height="9" fill="url(#ht1)"/>
  <rect y="9"  width="100%" height="9" fill="url(#ht2)"/>
  <rect y="18" width="100%" height="9" fill="url(#ht3)"/>
  <rect y="27" width="100%" height="9" fill="url(#ht4)"/>
</svg>
SEC.03 / ASSETSTHE PIPELINE THAT ISN'T

ZERO IMAGE FILES. ON PURPOSE.

There's no assets folder. Every visual on the site is procedural: the halftone screens and ramps are SVG patterns, the barcode is a run of rects, the registration mark is a circle and two lines, the annotation arrows are single paths, and the favicon is an inline SVG data URI (black square, green caret, white caret). The fake customer logos are set in the two house fonts with borders and stroke tricks, the way a zine would fake a logo wall with letraset.

That choice is the aesthetic. A photocopied zine can't embed a JPEG, it screens everything into dots, so the site does too. It also keeps each page to one hand-written file, around 43KB, fast enough that the first paint is the money shot. The log data in the terminal is a hardcoded array (real-looking routes, statuses, and durations) so the demo runs identically from file:// and production with no fetch calls.

SEC.04 / RECREATEPROMPT TO STEAL

WANT ONE LIKE THIS? SAY THIS.

Paste this into Claude and swap the bracketed bits. It's the same structure this site was built from.

COPY FROM HEREPROMPT
ROLE: You're an art director and creative developer who ships
hand-written HTML/CSS/JS. Brutalist print is a discipline, not
an excuse: razor grid, deliberate spacing, total color control.

TASK: Build a one-page marketing site for [PRODUCT], plus a
/guide page explaining how you built it. Then screenshot it,
critique it hard, and fix what you find. Three passes minimum.

CONTEXT: [PRODUCT] is [ONE-SENTENCE PITCH]. Audience:
[AUDIENCE]. Mood: brutalist print, xerox punk, developer zine.
Palette: white #FFFFFF, black #000000, one accent [HEX]. Nothing
else, no grays (fake tones with halftone dot patterns). Type:
[DISPLAY FONT] for display, [MONO FONT] for everything else.

FORMAT: Static files only. index.html and guide/index.html,
inline CSS/JS, no frameworks, no build step, no image files.
All decoration is inline SVG (patterns, barcodes, marks).

CONSTRAINTS:
- Hero words fill the viewport edge-to-edge (SVG textLength,
  preserveAspectRatio="none"). No letter-spacing on that text.
- Motion is hard cuts and steps() only. Marquee bands at
  different speeds. Hover blocks flip black/white with a
  two-frame accent flash.
- One live demo element that loops (mine: ugly JSON snapping
  into aligned columns in a fake terminal).
- Cursor is a blinking block caret, fine pointers only.
- Respect prefers-reduced-motion, keep the console clean,
  zero horizontal scroll at 390px.

EXAMPLES: Hero lines like "YOUR LOGS" / "READABLE." set
stacked with a ticker band between them. Section bars like
"SEC.02 / FEATURES" with page numbers, like a zine spread.
SEC.05 / ITERATION LOGWHAT ACTUALLY GOT FIXED

THREE PASSES, NO MERCY.

Every pass: screenshot at 1440px and 390px, read the images, list what's weak, fix all of it. This is the real list.

P.1STRUCTURE
  • All three hero bands clipped their last glyph: letter-spacing on SVG text breaks textLength math in Chromium. Removed it, type now lands flush on both edges.
  • Final CTA command box rendered white-on-white: it inherited the black section's white text color. Pinned .cmd to black-on-white.
  • Terminal had about 120px of dead white under the summary bar. Cut body height 430px to 302px and tightened the stream timing.
  • Hero bottom row was three floating islands. Rebuilt it as ruled columns (3px dividers) so it reads as a zine footer, and grew the halftone ramp into a full cell.
  • Feature numbers were too timid at 44px. Bumped to 64px with a hard acid-green offset shadow.
  • Mobile meta strip overflowed and clipped the FREE TIER tag mid-letter. Dropped two labels at 640px.
  • Pricing baselines misaligned ($0 vs "Let's talk"). Gave prices a shared min-height and a smaller size for the text price.
P.2DEPTH
  • Added a stepped scroll progress bar under the nav: green, quantized to 28 steps, snaps instead of glides.
  • Nav now tracks the active section and inverts that link to acid green (IntersectionObserver).
  • Added photocopy fade strips (stacked halftone rows) where white pages meet the black demo section and the footer.
  • Slapped a rotated LIVE LOOP sticker on the terminal and a blinking $ prompt after the stream, then moved the sticker off the mode chip it was covering.
  • Gave every feature card a corner dither that swaps black dots for green when the card inverts on hover.
  • Footer got print furniture: the three-ink spec swatches (#FFFFFF / #000000 / #C6FF00), a barcode, and a registration mark.
  • Equalized demo box heights across the feature grid and reversed the hero ramp so density grows toward the page edge.
P.3FINAL QA
  • 390px sweep: no horizontal scroll, tap targets at 44px+, hero bands hold their edge-to-edge fill at mobile ratios.
  • Built and shot this guide page, same furniture, same three inks, back-links in nav and footer.
  • Verified meta: title, description, og tags, SVG data-URI favicon on both pages.
  • Reduced-motion check: marquees freeze, carets stop blinking, the terminal renders the formatted columns statically, cursor hands back to the OS.
  • Console clean at both viewports (zero errors, zero failed requests), then deployed and re-shot the live URL to confirm parity with local.