11 / 20
All 20 in 20 Tailwind Retro UI
- 01Tailwind CRT Scanlines and Screen Curvature
- 02Tailwind Pixel Art Scaling with Image Rendering
- 03Tailwind Dithering Patterns with Gradients
- 04Tailwind One Bit Bevel Borders with Box Shadow
- 05Tailwind Classic Mac System 7 Window Chrome
- 06Tailwind MS DOS Text Mode Interface Grid
- 07Tailwind Teletext and Ceefax Block Graphics
- 08Tailwind Amber and Green Phosphor Monitor
- 09Tailwind Windows 95 Desktop Interface
- 10Tailwind Retro Futuristic Terminal Interface
- 11Tailwind Eight Bit Pixel Art Buttons and HUD
- 12Tailwind Neo Brutalist Component Board
- 13Tailwind Skeuomorphic Cassette Player
- 14Tailwind Vaporwave Aesthetic Scene
- 15Tailwind Retro Arcade Game Interface
- 16Tailwind ASCII Art Terminal Interface
- 17Tailwind Nineties Web Guestbook Widget
- 18Tailwind Y2K Aqua Gloss Interface Kit
- 19Tailwind Vintage Storefront Layout
- 20Tailwind Retro Desktop Portfolio Template
Tailwind Eight Bit Pixel Art Buttons and HUD
A game HUD and control set built entirely from stepped box-shadow blocks: segmented health, score with tabular figures, a lives row, and buttons whose notched corners are shadow offsets rather than a border image. The palette is a fixed eight-colour NES subset, and the port makes the discipline enforceable — every colour in the markup is a palette utility, so a ninth colour would have to be typed as a raw hex and would stand out in review.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="twr-11 relative block w-full min-h-svh box-border bg-twr11-bg text-twr11-ink font-twr11-mono" aria-labelledby="twr-11-title">
<h2 class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap" id="twr-11-title">Eight-bit pixel art HUD and button set</h2>
<div class="absolute top-4 right-4 z-6">
<input class="peer absolute inset-0 size-11 m-0 opacity-0 cursor-pointer" type="checkbox" id="twr-11-theme">
<label class="grid place-items-center size-11 cursor-pointer bg-twr11-paper text-twr11-ink twr11-notch peer-focus-visible:outline-2 peer-focus-visible:outline-twr11-acc peer-focus-visible:outline-offset-[6px]" for="twr-11-theme">
<svg class="size-5" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 4a8 8 0 0 0 0 16Z" fill="currentColor"/></svg>
<span class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap">Toggle dark surround</span>
</label>
</div>
<div class="grid grid-cols-[minmax(0,1fr)] gap-6 max-w-[68rem] mx-auto px-[clamp(1rem,0.6rem+2vw,2.25rem)] pt-[clamp(3.75rem,3rem+3vw,5rem)] pb-16">
<p class="m-0 justify-self-start min-w-0 bg-twr11-ink text-twr11-paper px-2.5 py-1.5 text-[0.68rem] tracking-[0.12em] uppercase">NES-era palette subset · 8 colours, no anti-aliasing</p>
<div class="min-w-0 bg-twr11-surface p-[clamp(1rem,0.7rem+1.4vw,1.6rem)] twr11-notch">
<div class="grid gap-5 grid-cols-[repeat(auto-fit,minmax(min(100%,11rem),1fr))]">
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">HEALTH</span>
<div class="flex flex-wrap gap-[var(--twr-11-px)]" role="meter" aria-valuenow="7" aria-valuemin="0" aria-valuemax="10" aria-label="Health, 7 of 10">
<span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span>
</div>
<span class="text-[0.72rem] tabular-nums">7 / 10</span>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">SCORE</span>
<p class="m-0 text-[clamp(1.2rem,1rem+1.4vw,1.9rem)] font-bold tabular-nums tracking-[0.08em]">0128450</p>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">LIVES</span>
<ul class="list-none m-0 p-0 flex gap-2" aria-label="Three lives remaining">
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
</ul>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">STAGE</span>
<p class="m-0 text-[clamp(1.2rem,1rem+1.4vw,1.9rem)] font-bold tabular-nums">2–4</p>
</div>
</div>
</div>
<div class="min-w-0 grid gap-4 bg-twr11-surface p-[clamp(1rem,0.7rem+1.4vw,1.6rem)] twr11-notch">
<h3 class="m-0 text-[0.72rem] tracking-[0.16em] uppercase text-twr11-ink/70">Controls</h3>
<div class="flex flex-wrap gap-4">
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-red" type="button">START</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-blue" type="button">SELECT</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-green" type="button">CONTINUE</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-not-allowed font-inherit text-[0.8rem] font-bold tracking-[0.12em] bg-twr11-ink/25 text-twr11-ink twr11-notch" type="button" disabled>LOCKED</button>
</div>
<h3 class="m-0 text-[0.72rem] tracking-[0.16em] uppercase text-twr11-ink/70">Palette — eight entries, no ninth</h3>
<ul class="list-none m-0 p-0 grid gap-2.5 grid-cols-[repeat(auto-fit,minmax(min(100%,7rem),1fr))]">
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-ink [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>ink</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-paper [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>paper</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>red</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-orange [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>orange</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-yellow [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>yellow</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-green [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>green</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-blue [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>blue</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-sky [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>sky</li>
</ul>
</div>
</div>
</section><section class="twr-11 relative block w-full min-h-svh box-border bg-twr11-bg text-twr11-ink font-twr11-mono" aria-labelledby="twr-11-title">
<h2 class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap" id="twr-11-title">Eight-bit pixel art HUD and button set</h2>
<div class="absolute top-4 right-4 z-6">
<input class="peer absolute inset-0 size-11 m-0 opacity-0 cursor-pointer" type="checkbox" id="twr-11-theme">
<label class="grid place-items-center size-11 cursor-pointer bg-twr11-paper text-twr11-ink twr11-notch peer-focus-visible:outline-2 peer-focus-visible:outline-twr11-acc peer-focus-visible:outline-offset-[6px]" for="twr-11-theme">
<svg class="size-5" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 4a8 8 0 0 0 0 16Z" fill="currentColor"/></svg>
<span class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap">Toggle dark surround</span>
</label>
</div>
<div class="grid grid-cols-[minmax(0,1fr)] gap-6 max-w-[68rem] mx-auto px-[clamp(1rem,0.6rem+2vw,2.25rem)] pt-[clamp(3.75rem,3rem+3vw,5rem)] pb-16">
<p class="m-0 justify-self-start min-w-0 bg-twr11-ink text-twr11-paper px-2.5 py-1.5 text-[0.68rem] tracking-[0.12em] uppercase">NES-era palette subset · 8 colours, no anti-aliasing</p>
<div class="min-w-0 bg-twr11-surface p-[clamp(1rem,0.7rem+1.4vw,1.6rem)] twr11-notch">
<div class="grid gap-5 grid-cols-[repeat(auto-fit,minmax(min(100%,11rem),1fr))]">
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">HEALTH</span>
<div class="flex flex-wrap gap-[var(--twr-11-px)]" role="meter" aria-valuenow="7" aria-valuemin="0" aria-valuemax="10" aria-label="Health, 7 of 10">
<span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span>
</div>
<span class="text-[0.72rem] tabular-nums">7 / 10</span>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">SCORE</span>
<p class="m-0 text-[clamp(1.2rem,1rem+1.4vw,1.9rem)] font-bold tabular-nums tracking-[0.08em]">0128450</p>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">LIVES</span>
<ul class="list-none m-0 p-0 flex gap-2" aria-label="Three lives remaining">
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
</ul>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">STAGE</span>
<p class="m-0 text-[clamp(1.2rem,1rem+1.4vw,1.9rem)] font-bold tabular-nums">2–4</p>
</div>
</div>
</div>
<div class="min-w-0 grid gap-4 bg-twr11-surface p-[clamp(1rem,0.7rem+1.4vw,1.6rem)] twr11-notch">
<h3 class="m-0 text-[0.72rem] tracking-[0.16em] uppercase text-twr11-ink/70">Controls</h3>
<div class="flex flex-wrap gap-4">
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-red" type="button">START</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-blue" type="button">SELECT</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-green" type="button">CONTINUE</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-not-allowed font-inherit text-[0.8rem] font-bold tracking-[0.12em] bg-twr11-ink/25 text-twr11-ink twr11-notch" type="button" disabled>LOCKED</button>
</div>
<h3 class="m-0 text-[0.72rem] tracking-[0.16em] uppercase text-twr11-ink/70">Palette — eight entries, no ninth</h3>
<ul class="list-none m-0 p-0 grid gap-2.5 grid-cols-[repeat(auto-fit,minmax(min(100%,7rem),1fr))]">
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-ink [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>ink</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-paper [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>paper</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>red</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-orange [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>orange</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-yellow [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>yellow</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-green [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>green</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-blue [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>blue</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-sky [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>sky</li>
</ul>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-twr11-ink: #101820;
--color-twr11-paper: #f8f8f8;
--color-twr11-red: #d82800;
--color-twr11-orange: #fc9838;
--color-twr11-yellow: #fcfc54;
--color-twr11-green: #00a844;
--color-twr11-blue: #2038ec;
--color-twr11-sky: #9cd2f8;
--color-twr11-bg: #9cd2f8;
--color-twr11-surface: #f8f8f8;
--color-twr11-acc: #1a2ba8;
--color-twr11-acc: oklch(0.38 0.2 265);
--font-twr11-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;
}
.twr-11 {
--twr-11-px: 4px;
}
/* Four cardinal offsets whose union is a plus shape: the box's own corners are
left uncovered, which is the notch. Too long and too repeated to inline. */
@utility twr11-notch {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(255, 255, 255, 0.35), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(0, 0, 0, 0.3);
}
/* Pressed: the inner light and shadow swap sides. The face colour never changes,
because darkening it would introduce a colour outside the palette. */
@utility twr11-notch-in {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(0, 0, 0, 0.3), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(255, 255, 255, 0.35);
}
.twr-11:has(#twr-11-theme:checked) {
--color-twr11-bg: #14203a;
--color-twr11-bg: oklch(0.24 0.06 265);
--color-twr11-surface: #e4e6ec;
}@import "tailwindcss";
@theme {
--color-twr11-ink: #101820;
--color-twr11-paper: #f8f8f8;
--color-twr11-red: #d82800;
--color-twr11-orange: #fc9838;
--color-twr11-yellow: #fcfc54;
--color-twr11-green: #00a844;
--color-twr11-blue: #2038ec;
--color-twr11-sky: #9cd2f8;
--color-twr11-bg: #9cd2f8;
--color-twr11-surface: #f8f8f8;
--color-twr11-acc: #1a2ba8;
--color-twr11-acc: oklch(0.38 0.2 265);
--font-twr11-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;
}
.twr-11 {
--twr-11-px: 4px;
}
/* Four cardinal offsets whose union is a plus shape: the box's own corners are
left uncovered, which is the notch. Too long and too repeated to inline. */
@utility twr11-notch {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(255, 255, 255, 0.35), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(0, 0, 0, 0.3);
}
/* Pressed: the inner light and shadow swap sides. The face colour never changes,
because darkening it would introduce a colour outside the palette. */
@utility twr11-notch-in {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(0, 0, 0, 0.3), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(255, 255, 255, 0.35);
}
.twr-11:has(#twr-11-theme:checked) {
--color-twr11-bg: #14203a;
--color-twr11-bg: oklch(0.24 0.06 265);
--color-twr11-surface: #e4e6ec;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-twr11-ink: #101820;
--color-twr11-paper: #f8f8f8;
--color-twr11-red: #d82800;
--color-twr11-orange: #fc9838;
--color-twr11-yellow: #fcfc54;
--color-twr11-green: #00a844;
--color-twr11-blue: #2038ec;
--color-twr11-sky: #9cd2f8;
--color-twr11-bg: #9cd2f8;
--color-twr11-surface: #f8f8f8;
--color-twr11-acc: #1a2ba8;
--color-twr11-acc: oklch(0.38 0.2 265);
--font-twr11-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;
}
.twr-11 {
--twr-11-px: 4px;
}
/* Four cardinal offsets whose union is a plus shape: the box's own corners are
left uncovered, which is the notch. Too long and too repeated to inline. */
@utility twr11-notch {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(255, 255, 255, 0.35), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(0, 0, 0, 0.3);
}
/* Pressed: the inner light and shadow swap sides. The face colour never changes,
because darkening it would introduce a colour outside the palette. */
@utility twr11-notch-in {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(0, 0, 0, 0.3), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(255, 255, 255, 0.35);
}
.twr-11:has(#twr-11-theme:checked) {
--color-twr11-bg: #14203a;
--color-twr11-bg: oklch(0.24 0.06 265);
--color-twr11-surface: #e4e6ec;
}@import "tailwindcss";
@theme {
--color-twr11-ink: #101820;
--color-twr11-paper: #f8f8f8;
--color-twr11-red: #d82800;
--color-twr11-orange: #fc9838;
--color-twr11-yellow: #fcfc54;
--color-twr11-green: #00a844;
--color-twr11-blue: #2038ec;
--color-twr11-sky: #9cd2f8;
--color-twr11-bg: #9cd2f8;
--color-twr11-surface: #f8f8f8;
--color-twr11-acc: #1a2ba8;
--color-twr11-acc: oklch(0.38 0.2 265);
--font-twr11-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;
}
.twr-11 {
--twr-11-px: 4px;
}
/* Four cardinal offsets whose union is a plus shape: the box's own corners are
left uncovered, which is the notch. Too long and too repeated to inline. */
@utility twr11-notch {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(255, 255, 255, 0.35), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(0, 0, 0, 0.3);
}
/* Pressed: the inner light and shadow swap sides. The face colour never changes,
because darkening it would introduce a colour outside the palette. */
@utility twr11-notch-in {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(0, 0, 0, 0.3), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(255, 255, 255, 0.35);
}
.twr-11:has(#twr-11-theme:checked) {
--color-twr11-bg: #14203a;
--color-twr11-bg: oklch(0.24 0.06 265);
--color-twr11-surface: #e4e6ec;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The webfonts load as
<link>tags insetup, not as an@importin the stylesheet — Tailwind emits user@importrules after its own layers, where the browser drops them. - Palette-as-utilities is the real gain here: with
bg-twr11-redas the vocabulary, a ninth colour has to be typed as a raw hex and is obvious in review. Tokens enforce the constraint that makes pixel art read. - The notch is an
@utilitybecause it is six shadow layers on a dozen elements, and because the pressed variant needsactive:composition. - Sizes are arbitrary
calc()multiples of--twr-11-px, so the whole kit rescales from one integer and never lands on a half pixel. bg-twr11-ink/25appears exactly twice, over known flat grounds, and the write-up says why that is a compromise rather than a pattern to copy.- The health meter is a real
role="meter"with numeric attributes, so the segmented visual and the accessible value stay in agreement. - Every control is
min-h-11or larger with the notch drawn inside; scaling the pixel unit down to fit more buttons fails SC 2.5.8 immediately.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Eight Bit Pixel Art Buttons and HUD
Source: https://codefronts.com/design-styles/tailwind-retro-ui/tailwind-eight-bit-pixel-art-buttons-and-hud/
A game HUD and control set built entirely from stepped box-shadow blocks: segmented health, score with tabular figures, a lives row, and buttons whose notched corners are shadow offsets rather than a border image. The palette is a fixed eight-colour NES subset, and the port makes the discipline enforceable — every colour in the markup is a palette utility, so a ninth colour would have to be typed as a raw hex and would stand out in review.
## HTML
```html
<section class="twr-11 relative block w-full min-h-svh box-border bg-twr11-bg text-twr11-ink font-twr11-mono" aria-labelledby="twr-11-title">
<h2 class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap" id="twr-11-title">Eight-bit pixel art HUD and button set</h2>
<div class="absolute top-4 right-4 z-6">
<input class="peer absolute inset-0 size-11 m-0 opacity-0 cursor-pointer" type="checkbox" id="twr-11-theme">
<label class="grid place-items-center size-11 cursor-pointer bg-twr11-paper text-twr11-ink twr11-notch peer-focus-visible:outline-2 peer-focus-visible:outline-twr11-acc peer-focus-visible:outline-offset-[6px]" for="twr-11-theme">
<svg class="size-5" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 4a8 8 0 0 0 0 16Z" fill="currentColor"/></svg>
<span class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap">Toggle dark surround</span>
</label>
</div>
<div class="grid grid-cols-[minmax(0,1fr)] gap-6 max-w-[68rem] mx-auto px-[clamp(1rem,0.6rem+2vw,2.25rem)] pt-[clamp(3.75rem,3rem+3vw,5rem)] pb-16">
<p class="m-0 justify-self-start min-w-0 bg-twr11-ink text-twr11-paper px-2.5 py-1.5 text-[0.68rem] tracking-[0.12em] uppercase">NES-era palette subset · 8 colours, no anti-aliasing</p>
<div class="min-w-0 bg-twr11-surface p-[clamp(1rem,0.7rem+1.4vw,1.6rem)] twr11-notch">
<div class="grid gap-5 grid-cols-[repeat(auto-fit,minmax(min(100%,11rem),1fr))]">
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">HEALTH</span>
<div class="flex flex-wrap gap-[var(--twr-11-px)]" role="meter" aria-valuenow="7" aria-valuemin="0" aria-valuemax="10" aria-label="Health, 7 of 10">
<span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span>
</div>
<span class="text-[0.72rem] tabular-nums">7 / 10</span>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">SCORE</span>
<p class="m-0 text-[clamp(1.2rem,1rem+1.4vw,1.9rem)] font-bold tabular-nums tracking-[0.08em]">0128450</p>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">LIVES</span>
<ul class="list-none m-0 p-0 flex gap-2" aria-label="Three lives remaining">
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
</ul>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">STAGE</span>
<p class="m-0 text-[clamp(1.2rem,1rem+1.4vw,1.9rem)] font-bold tabular-nums">2–4</p>
</div>
</div>
</div>
<div class="min-w-0 grid gap-4 bg-twr11-surface p-[clamp(1rem,0.7rem+1.4vw,1.6rem)] twr11-notch">
<h3 class="m-0 text-[0.72rem] tracking-[0.16em] uppercase text-twr11-ink/70">Controls</h3>
<div class="flex flex-wrap gap-4">
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-red" type="button">START</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-blue" type="button">SELECT</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-green" type="button">CONTINUE</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-not-allowed font-inherit text-[0.8rem] font-bold tracking-[0.12em] bg-twr11-ink/25 text-twr11-ink twr11-notch" type="button" disabled>LOCKED</button>
</div>
<h3 class="m-0 text-[0.72rem] tracking-[0.16em] uppercase text-twr11-ink/70">Palette — eight entries, no ninth</h3>
<ul class="list-none m-0 p-0 grid gap-2.5 grid-cols-[repeat(auto-fit,minmax(min(100%,7rem),1fr))]">
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-ink [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>ink</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-paper [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>paper</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>red</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-orange [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>orange</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-yellow [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>yellow</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-green [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>green</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-blue [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>blue</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-sky [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>sky</li>
</ul>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-twr11-ink: #101820;
--color-twr11-paper: #f8f8f8;
--color-twr11-red: #d82800;
--color-twr11-orange: #fc9838;
--color-twr11-yellow: #fcfc54;
--color-twr11-green: #00a844;
--color-twr11-blue: #2038ec;
--color-twr11-sky: #9cd2f8;
--color-twr11-bg: #9cd2f8;
--color-twr11-surface: #f8f8f8;
--color-twr11-acc: #1a2ba8;
--color-twr11-acc: oklch(0.38 0.2 265);
--font-twr11-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;
}
.twr-11 {
--twr-11-px: 4px;
}
/* Four cardinal offsets whose union is a plus shape: the box's own corners are
left uncovered, which is the notch. Too long and too repeated to inline. */
@utility twr11-notch {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(255, 255, 255, 0.35), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(0, 0, 0, 0.3);
}
/* Pressed: the inner light and shadow swap sides. The face colour never changes,
because darkening it would introduce a colour outside the palette. */
@utility twr11-notch-in {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(0, 0, 0, 0.3), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(255, 255, 255, 0.35);
}
.twr-11:has(#twr-11-theme:checked) {
--color-twr11-bg: #14203a;
--color-twr11-bg: oklch(0.24 0.06 265);
--color-twr11-surface: #e4e6ec;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Eight Bit Pixel Art Buttons and HUD
Source: https://codefronts.com/design-styles/tailwind-retro-ui/tailwind-eight-bit-pixel-art-buttons-and-hud/
A game HUD and control set built entirely from stepped box-shadow blocks: segmented health, score with tabular figures, a lives row, and buttons whose notched corners are shadow offsets rather than a border image. The palette is a fixed eight-colour NES subset, and the port makes the discipline enforceable — every colour in the markup is a palette utility, so a ninth colour would have to be typed as a raw hex and would stand out in review.
## HTML
```html
<section class="twr-11 relative block w-full min-h-svh box-border bg-twr11-bg text-twr11-ink font-twr11-mono" aria-labelledby="twr-11-title">
<h2 class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap" id="twr-11-title">Eight-bit pixel art HUD and button set</h2>
<div class="absolute top-4 right-4 z-6">
<input class="peer absolute inset-0 size-11 m-0 opacity-0 cursor-pointer" type="checkbox" id="twr-11-theme">
<label class="grid place-items-center size-11 cursor-pointer bg-twr11-paper text-twr11-ink twr11-notch peer-focus-visible:outline-2 peer-focus-visible:outline-twr11-acc peer-focus-visible:outline-offset-[6px]" for="twr-11-theme">
<svg class="size-5" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 4a8 8 0 0 0 0 16Z" fill="currentColor"/></svg>
<span class="absolute size-px overflow-hidden [clip-path:inset(50%)] whitespace-nowrap">Toggle dark surround</span>
</label>
</div>
<div class="grid grid-cols-[minmax(0,1fr)] gap-6 max-w-[68rem] mx-auto px-[clamp(1rem,0.6rem+2vw,2.25rem)] pt-[clamp(3.75rem,3rem+3vw,5rem)] pb-16">
<p class="m-0 justify-self-start min-w-0 bg-twr11-ink text-twr11-paper px-2.5 py-1.5 text-[0.68rem] tracking-[0.12em] uppercase">NES-era palette subset · 8 colours, no anti-aliasing</p>
<div class="min-w-0 bg-twr11-surface p-[clamp(1rem,0.7rem+1.4vw,1.6rem)] twr11-notch">
<div class="grid gap-5 grid-cols-[repeat(auto-fit,minmax(min(100%,11rem),1fr))]">
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">HEALTH</span>
<div class="flex flex-wrap gap-[var(--twr-11-px)]" role="meter" aria-valuenow="7" aria-valuemin="0" aria-valuemax="10" aria-label="Health, 7 of 10">
<span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-red"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span><span class="w-[calc(var(--twr-11-px)*3)] h-[calc(var(--twr-11-px)*5)] bg-twr11-ink/25"></span>
</div>
<span class="text-[0.72rem] tabular-nums">7 / 10</span>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">SCORE</span>
<p class="m-0 text-[clamp(1.2rem,1rem+1.4vw,1.9rem)] font-bold tabular-nums tracking-[0.08em]">0128450</p>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">LIVES</span>
<ul class="list-none m-0 p-0 flex gap-2" aria-label="Three lives remaining">
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
<li><span class="block size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]" aria-hidden="true"></span></li>
</ul>
</div>
<div class="min-w-0 grid content-start gap-1.5">
<span class="text-[0.62rem] tracking-[0.18em] text-twr11-ink/70">STAGE</span>
<p class="m-0 text-[clamp(1.2rem,1rem+1.4vw,1.9rem)] font-bold tabular-nums">2–4</p>
</div>
</div>
</div>
<div class="min-w-0 grid gap-4 bg-twr11-surface p-[clamp(1rem,0.7rem+1.4vw,1.6rem)] twr11-notch">
<h3 class="m-0 text-[0.72rem] tracking-[0.16em] uppercase text-twr11-ink/70">Controls</h3>
<div class="flex flex-wrap gap-4">
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-red" type="button">START</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-blue" type="button">SELECT</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-pointer font-inherit text-[0.8rem] font-bold tracking-[0.12em] text-twr11-paper twr11-notch active:twr11-notch-in focus-visible:outline-2 focus-visible:outline-twr11-acc focus-visible:outline-offset-[6px] bg-twr11-green" type="button">CONTINUE</button>
<button class="min-h-11 min-w-11 px-4 py-2.5 border-0 cursor-not-allowed font-inherit text-[0.8rem] font-bold tracking-[0.12em] bg-twr11-ink/25 text-twr11-ink twr11-notch" type="button" disabled>LOCKED</button>
</div>
<h3 class="m-0 text-[0.72rem] tracking-[0.16em] uppercase text-twr11-ink/70">Palette — eight entries, no ninth</h3>
<ul class="list-none m-0 p-0 grid gap-2.5 grid-cols-[repeat(auto-fit,minmax(min(100%,7rem),1fr))]">
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-ink [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>ink</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-paper [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>paper</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-red [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>red</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-orange [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>orange</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-yellow [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>yellow</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-green [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>green</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-blue [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>blue</li>
<li class="flex items-center gap-2 min-w-0 text-[0.7rem]"><span class="flex-none size-4 bg-twr11-sky [box-shadow:0_0_0_var(--twr-11-px)_var(--color-twr11-ink)]"></span>sky</li>
</ul>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-twr11-ink: #101820;
--color-twr11-paper: #f8f8f8;
--color-twr11-red: #d82800;
--color-twr11-orange: #fc9838;
--color-twr11-yellow: #fcfc54;
--color-twr11-green: #00a844;
--color-twr11-blue: #2038ec;
--color-twr11-sky: #9cd2f8;
--color-twr11-bg: #9cd2f8;
--color-twr11-surface: #f8f8f8;
--color-twr11-acc: #1a2ba8;
--color-twr11-acc: oklch(0.38 0.2 265);
--font-twr11-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;
}
.twr-11 {
--twr-11-px: 4px;
}
/* Four cardinal offsets whose union is a plus shape: the box's own corners are
left uncovered, which is the notch. Too long and too repeated to inline. */
@utility twr11-notch {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(255, 255, 255, 0.35), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(0, 0, 0, 0.3);
}
/* Pressed: the inner light and shadow swap sides. The face colour never changes,
because darkening it would introduce a colour outside the palette. */
@utility twr11-notch-in {
box-shadow: calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink), var(--twr-11-px) 0 0 0 var(--color-twr11-ink), 0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink), 0 var(--twr-11-px) 0 0 var(--color-twr11-ink), inset 0 var(--twr-11-px) 0 0 rgba(0, 0, 0, 0.3), inset 0 calc(var(--twr-11-px) * -1) 0 0 rgba(255, 255, 255, 0.35);
}
.twr-11:has(#twr-11-theme:checked) {
--color-twr11-bg: #14203a;
--color-twr11-bg: oklch(0.24 0.06 265);
--color-twr11-surface: #e4e6ec;
}
```How this works
Stepped corners come from offset shadows, not from a border. Four solid shadow offsets — up, down, left, right, each one pixel unit — union into a plus shape, leaving the original box's corners uncovered, which reads as a notch. That is four long values repeated on every control, so it is an @utility, not an arbitrary class:
@utility twr11-notch {
box-shadow:
calc(var(--twr-11-px) * -1) 0 0 0 var(--color-twr11-ink),
var(--twr-11-px) 0 0 0 var(--color-twr11-ink),
0 calc(var(--twr-11-px) * -1) 0 0 var(--color-twr11-ink),
0 var(--twr-11-px) 0 0 var(--color-twr11-ink);
}Palette discipline is the actual craft, and utilities make it visible. Pixel art reads as pixel art because the same eight colours appear everywhere and nothing is anti-aliased into a ninth. With bg-twr11-red and text-twr11-paper as the only colour vocabulary, reaching for a slightly darker accent means typing bg-[#c02400] — which is immediately conspicuous in a diff. That is a better guarantee than a stylesheet convention, and it is the strongest argument for tokens-as-utilities in a constrained palette.
One caution about opacity modifiers. bg-twr11-ink/25 is legal Tailwind and technically produces a ninth colour. It is used exactly once, for empty health segments over a known flat ground, where the composited result lands on a palette-plausible value. Anywhere the ground varies, use a real palette entry instead — an alpha-blended token is not a palette colour.
Health is segmented because the hardware counted in units. A smooth percentage bar is a later idea and reads as modern instantly. A flex row of discrete blocks costs nothing, carries the period logic, and gives a natural accessible representation on role="meter" with real aria-valuenow and aria-valuemax.
Integer pixels or nothing. Nothing here is a bitmap, so image-rendering is irrelevant; the edges are crisp because every one is axis-aligned on a whole pixel. Set --twr-11-px to 3.5px, or derive it from a user-scalable rem, and the notches start landing between device pixels and soften.
Make it yours
- Change
--twr-11-pxon the section to rescale every notch, inset and gap; keep it a whole number of pixels. - Reskin the HUD by editing the eight
@themeentries — every element names a palette token, so nothing is missed. - Add health segments by copying one block and updating
aria-valuemax, since the meter reports real numbers. - Recolour a button with
[--twr-11-btn:var(--color-twr11-green)]on the element; the shadow geometry comes from the utility. - Make the corners single-step by removing the second ring inside the utility — it reads as an earlier, blockier machine.
- For a pressed state that keeps the palette honest, swap which entries the inner light and shadow use rather than lowering opacity.
Gotchas — read before shipping
- A fractional pixel unit softens every notch. Keep
--twr-11-pxan integer and never derive it from aremthe user can scale. - Opacity modifiers (
/25) silently create colours outside the palette. Legal in Tailwind, wrong for pixel art — use them only over a known flat ground, if at all. [image-rendering:pixelated]does nothing here. These are painted shapes, not sampled bitmaps.- Introducing a ninth colour to fix one contrast problem breaks the illusion for the whole interface. Change the shape or use an existing entry.
- Do not build the notch with
@apply; the pressed state needsactive:, which only an@utilitysupports. - Pixel chrome invites tiny targets. Every control here is at least
min-h-11with the notch drawn inside it.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Multi-layer box-shadow is the entire mechanism and has been Baseline since 2011, so the HUD renders on effectively anything. Tailwind v4's generated sheet and the @utility directive set the floor at Chrome 111+, Safari 16.4+, Firefox 128+. The NES palette subset is plain sRGB hex and is never colour-converted.