Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tambour, a fictional team archive whose site is its own mid-90s desktop, rendered entirely from this theme's tokens, components and shell

The Windows 95 aesthetic, rebuilt as a working shell rather than as a set of widgets. Beveled window chrome with a real window manager under it, an icon grid, a taskbar that tracks what is open beside a plain text index of every window, a programs menu, a teal desktop with a wallpaper system, and a keyboard model that does not strand anyone. This is a shell archetype rather than a visual register: what the repo packages is the operating system, and the era is the costume it happens to be wearing. Search for a Windows 95 website and what you are usually picturing is this whole arrangement, a site that lives inside the metaphor, rather than a page with square buttons on it.

This is the shell, not the widget kit

The good work in this space is already done and it is worth naming precisely, because the difference is the reason this repo exists.

98.css and its family (XP.css, 7.css) are widget libraries: a beautifully faithful set of era controls, buttons, checkboxes, tabs, tree views, that you drop into your own page. They are excellent at that, they got the pixels right long before this repo existed, and if what you need is a period-correct checkbox you should use one of them instead of this.

What none of them ships is the shell. There is no window manager, no z-order, no taskbar that knows what is open, no icon navigation, no responsive behavior for the metaphor, and no answer for what happens when someone turns JavaScript off or arrives with a keyboard. Those are the hard parts, and they are what this repo is. The two compose fine: take this shell and put their controls inside the windows if you like their toggles better than the five in components/.

The demo

The screenshot above is demo/index.html, a fictional team archive called Tambour whose pages are windows: about, contents, pricing and the manual are programs on its desktop. That is the honesty test for a shell demo. A tambour is the slatted roll-top of a desk; the product is a place where finished documents are filed and kept, which is a filing cabinet with a lid, which is a thing this era's desktop was already a picture of. The metaphor is describing the product rather than dressing it.

Open it live, or clone the repo and open the file. There is no build step, no framework, no node_modules, and no server to start.

The demo declares no color of its own. It links tokens/tokens.css, components/components.css, shell/shell.css and shell/shell.js and reads every value from the first of those, so it stays honest about what the theme actually produces.

There is a second page worth opening: components/index.html renders the five in-window components with the markup to copy, on an ordinary page, which is its own point: the components do not need the shell.

Where the era ends and the trademark begins

This theme is built out of the era's generic vocabulary and nothing else. Gray bevels, square corners, a teal desktop, a navy title bar with a pair of rules across it, a taskbar with a menu button: all of that is the common design language of mid-90s graphical computing, shared across many systems and owned by none of them.

What is not generic is Microsoft's property, and none of it is here. There is no Windows logo and no flag motif anywhere in this repo. The launcher button is labeled Programs, not the word that operating system used. Every icon, glyph and control mark was drawn for this repo on a coordinate grid, in this session: the filing cabinet on the launcher, the document, the tag, the book, the diskette, the close and minimize marks. No Microsoft iconography is traced, adapted or approximated. No era typeface is embedded or shipped; the type is the ordinary system UI stack, which is the honest way to get a period-plausible grotesque without redistributing licensed software. The palette values that look familiar are familiar for a reason worth stating: teal, silver, gray, navy, maroon, black and white are seven of the sixteen HTML 4.01 named colors, standardized in a W3C specification in 1997 and about as generic as a color can be.

The nearest thing to a borrowing anywhere here is the four-line bevel itself, and that is a drawing technique documented in the era's own developer documentation, not an asset. tokens/tokens.css describes how it is constructed and why.

Position map

A visual style is a set of coordinates, not a mood. This theme sits at one point in the creative direction framework, which sets brand direction on four axes. Here is where it lands and what each choice pays for.

Axis Position What the position buys
Tone register Playful The shell is the joke: a site that answers "where is pricing" with a window called Pricing, and a close button that closes it. It lands in the first five seconds or not at all.
Aesthetic philosophy Polished Standard The chrome is the most-shipped interface pattern in the history of computing. Nobody needs a title bar explained to them, which is what frees the metaphor to be fun instead of homework.
Audience relationship Peer The desktop goes unexplained. Icons get names, not a tutorial; the reader has used a computer before and the interface assumes it.
Sensory ambition Resonant The teal, the silver and the bevels are doing feeling-work, and the feeling is recognition. This theme is engineering an atmosphere rather than demonstrating craft, and it should be booked as such.

Those four position names are the exact strings the framework uses. If you want the long version of any of them, the links go to the position page.

Where this parts company with its sibling. desktop-os-theme, the pilot for this archetype, ships the same shell in a modern-clean register and lands at Considered on the sensory axis. Its argument for staying there is that a device metaphor can be structure rather than atmosphere: no photograph behind it, no boot sequence, nothing staged. That argument is sound, and it does not survive the move to this era. A 1995 desktop is not a neutral structure a reader walks through; it is a specific year, and the specific feeling of that year is most of why anyone wants one. The same shell moves one position along the sensory axis when it changes clothes, and the other three hold. That is a good result for the collection's thesis rather than an awkward one: it is what "the register is separable" looks like when you actually measure both.

And the axis that strains here is a different one. Polished Standard means the conventional baseline, executed well. This chrome was the baseline, thirty years ago; shipping it in 2026 is unmistakably a stylistic gesture, and a fair reading pushes it toward Controlled Maximalist. It stays at Polished Standard because the strain is already paid for on the sensory axis, and booking the same nostalgia twice would be double counting. Under the finish, the aesthetic decisions are relentlessly conventional: nothing is invented, every control behaves exactly as its shape promises, a thing you press comes out and a thing you type into goes in, and the page is a masthead, a nav, six documents and a footer. What dates it is the paint.

Quick start

Clone once, then pick the path that matches what you came for. A shell theme has two different things worth taking, so the two grabs are stated separately.

git clone --depth 1 https://github.com/rampstackco/retro-desktop-theme

Grab the shell. Four files: the tokens, the in-window components, the chrome, the behavior. Your content goes in rd-window articles, your navigation in rd-icon anchors; the demo is the reference markup.

<link rel="stylesheet" href="/styles/tokens/tokens.css" />
<link rel="stylesheet" href="/styles/components/components.css" />
<link rel="stylesheet" href="/styles/shell/shell.css" />
<script src="/styles/shell/shell.js" defer></script>

Grab the register only. Skip the shell/ directory entirely and you have a beveled era register for ordinary pages: tokens plus five components, no windows anywhere. This is the grab where this repo behaves exactly like the register themes in the collection, and it is also the grab that overlaps most with 98.css, so compare the two and take whichever set of controls you like better.

<link rel="stylesheet" href="/styles/tokens/tokens.css" />
<link rel="stylesheet" href="/styles/components/components.css" />

Tailwind v4. One import. theme.css pulls in tokens.css and maps it onto Tailwind's theme namespaces, so you get bg-rd-face, shadow-rd-raise, text-rd-h1, h-rd-taskbar. The shell files are plain CSS and JS either way; the adapter covers the tokens.

@import "tailwindcss";
@import "./styles/tokens/theme.css";

Tailwind v3. Load the tokens in your stylesheet, then register the preset.

@import "./styles/tokens/tokens.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
// tailwind.config.js
module.exports = {
  presets: [require("./styles/tokens/preset.js")],
  content: ["./src/**/*.{html,js,jsx,ts,tsx}"],
};

The bevel is a token, which is the whole trick

A raised or sunken edge in this era is not one border. It is four one-pixel lines drawn in a fixed order, two light on the top and left and two dark on the bottom and right, and swapping the halves is the entire difference between a button and a text field.

CSS has border-style: outset and inset, and they draw a single flat edge that looks nothing like it. So this theme composes the bevel out of inset box-shadows and files it under --rd-raise and --rd-sink in tokens/tokens.css. That is what makes the era both accurate and adjustable: .rd-btn says box-shadow: var(--rd-raise) and .rd-btn:active says var(--rd-sink), and one edit to those two tokens re-draws every edge in the theme at once.

It also has a Tailwind consequence, and it was compiled rather than assumed: there is no --border-style-* namespace. An entry filed there produces no utility and no error, which tokens/theme.css demonstrates with a probe entry that generates nothing at all. The bevels ride the documented --shadow-* namespace instead, so shadow-rd-raise carries all four lines in one utility.

No JavaScript, no problem

The demo is a plain document that a script upgrades, not an app with a fallback. With JavaScript disabled it reads top to bottom: a masthead, the icon nav as a row of anchor links, every window as a beveled titled card in reading order, the taskbar's shortcut bar as a footer nav that jumps to each one. This is verified by loading the page with scripts off at both widths, not assumed. The mechanism is one class: shell.js puts rd-live on the root element as its first act, and every OS behavior in shell.css is scoped under it. The close and minimize buttons do not exist in the markup at all, and neither does the Programs button; the script injects all three, because a control that does nothing must not exist.

shell.js is one file of vanilla JavaScript with zero dependencies, annotated section by section, small enough to read over coffee. It is the whole shell.

Accessibility is the differentiator

A fake operating system that strands a keyboard user is a failed build, so the keyboard model is the part of this theme that got the most engineering:

  • The icons are not the only way through. The taskbar carries a shortcut bar: six plain text links, one per window, complete and identical whether or not the script runs. The desktop grid and the Programs menu are both icon surfaces, and an icon with a label under it is still an icon; a reader who does not read the desktop as navigation needs ordinary links, not a better-drawn folder. This is WCAG 2.4.5 Multiple Ways on purpose rather than by luck, and it is class decision 44. The bar is a fixed index; the list of open windows beside it is the part that tracks state, and the two are drawn differently, flat against raised, so nobody has to guess which is which.
  • Every icon, shortcut, control, taskbar entry, the launcher and the tray button is keyboard-reachable with a visible focus ring: the era's dotted rectangle, drawn inside the control, in two tones so it stays visible on the silver chrome and on the teal desktop alike.
  • The full Tab cycle was walked and recorded with the welcome window open: skip link, six icons, two window controls, the window's scroll region, two in-content links, launcher, six shortcuts, the open window's taskbar entry, wallpaper button, wrap. Twenty-one stops and then the cycle wraps, no element reached twice, no focus trap anywhere; closed windows leave the tab order by leaving the render tree.
  • Escape closes the topmost visible openable: the programs menu if it is open, otherwise the front window. One key, one rule. The word visible is load-bearing, and the regression test is in the verification: a minimized window can sit at the top of the stack, and a shell that forgets that turns Escape into a silent no-op.
  • Focus is managed at the three moments it can be lost. Opening a window moves focus into it. Closing one returns focus to the element that opened it. Minimizing one moves focus to the window's taskbar entry, because that is where the window went.
  • Close is never a dead end: behind the last window is always the desktop with its icons.
  • Windows carry role="dialog" with a real label, and no aria-modal, because nothing is modal and nothing traps. The scroll region is focusable so a keyboard user can scroll a long window. All of this ARIA is added by the script at enhance time, so the no-JS document never claims semantics it cannot honor.
  • Every text pairing that is not a disabled control clears WCAG AA, and the measurements are in the token comments. Two of them are era decisions that lost: the inactive title bar is a desaturated navy-gray rather than the era's mid gray, because white on that gray measures 3.95:1, and the chrome type is 14px rather than the 11px the era drew, because a floor is a floor. Both are named where they are made.
  • prefers-reduced-motion collapses the one animation to instant through the tokens, not through a bolted-on override. prefers-contrast: more forces the flat wallpaper regardless of what the picker says.

Where the reasoning lives

tokens/tokens.css is the single source of truth. Every literal value in the theme appears there exactly once; theme.css and preset.js hold no values of their own and point back at it with var(). The file is annotated by framework axis, contrast ratios in the comments are measured, and the shell geometry (title bar height, control size, taskbar height, cascade offset) is a token group like any other, which is what keeps a re-skin a one-file edit.

shell/shell.css and shell/shell.js draw the OS from those tokens. The window manager is deliberately small: multiple windows, cascade placement, raise on click, honest close and minimize, and nothing else. No drag, no resize, no maximize. One excellent window beats a buggy window manager, and drag in particular is where keyboard equivalence goes to die, so it is excluded on accessibility grounds and not only on scope.

The desktop ground is a wallpaper slot, not a color. Two variants ship: the flat teal field, which is the era's default and also what the no-JS document and prefers-contrast: more both get, and slats, a horizontal slat pattern in Tambour's own language, the roll-top rolled down over the whole screen. A taskbar button switches them; the switch is one data-wallpaper attribute on the body, all styling attribute-scoped in shell.css, and the script only toggles the attribute. Because the ground is dark and the only ink on it is white, the wallpaper is allowed to paint only at or below the teal, and all three of its tones are measured against white: 4.77:1, 5.75:1 and 7.18:1. The pattern is drawn as an inline SVG so it reads the tokens like everything else.

The slats wallpaper: the same desktop with a horizontal slat pattern under it, three tones all measured against the white icon labels

CUSTOMIZE.md documents retheming as axis moves rather than as a color picker. Its first worked move dials the era itself down: twelve token lines take this shell from full 1995 to a flat modern read with no change to any markup, stylesheet rule or line of script. That move is this repo's whole argument in diff form, and it names the two things that break if you make it carelessly.

Consuming this from a Claude skill. The design-standards skill asks for a project's design tokens as a required input and offers to define a working set when none exist. Point it at tokens/tokens.css instead. The file covers every category the skill asks for, in the order it asks, and the contrast ratios are already in the comments.

Adjacency: this and desktop-os-theme

desktop-os-theme is the same archetype at the other temperature: the same window mechanics, the same enhancement contract, the same wallpaper mechanism, wearing a modern-clean register with soft shadows and rounded corners. Neither repo is the other's fallback. Pick this one if the era is the point, pick that one if the desktop is the point, and if you are not sure, CUSTOMIZE.md's first move shows you the road between them so you can see what you would be trading.

If what you want is an ordinary page that looks like a terminal rather than a site that behaves like a computer, that is terminal-ui-theme, and it is a register rather than a shell.

The other shells

desktop-os-theme is the pilot of a four-repo class, and it and this repo are the era pair. The other two change the machine rather than the decade.

  • phone-launcher-theme is one app at a time. Its native state is 390 and the desktop is a presented device on a stage, so it carries no window stack at all: no minimize, no cascade, no z-order bookkeeping. If your content is a column somebody reads on a phone rather than a pile of windows, go there.
  • game-console-ui-theme is a board you drive from across the room. Rows of tiles as the whole navigation surface, arrow-key spatial navigation, type sized for ten feet, and a dark ground whose focus ring is the hero element.

The class-decision log for all four lives in the pilot: docs/class-decisions.md. This repo filed items 17 to 20 there, including the bevel rule that is the reason nothing here declares an era edge.

License and questions

MIT. See LICENSE. Use it commercially, fork it, rename the tokens, redraw the icons, ship it. No attribution required.

Every SVG in this repo was drawn for it. None of them is traced from, derived from, or fitted to any operating system's icon set, and no era typeface is embedded or redistributed here.

Issues and pull requests are welcome here. For questions, ideas, and anything conversational, use the discussions on the claude-skills repo, which is where all discussion for these repos lives.

About

A retro desktop shell theme in the windows 95 aesthetic: beveled chrome, taskbar, icon grid, era-true wallpapers, modern accessibility. Tailwind and shadcn tokens plus a live demo.

Topics

Resources

Security policy

Stars

1 star

Watchers

1 watching

Forks

Contributors

Languages