← Learn · Prompt · 29 August 2026 · 15 min

The Prompt I Used to Build a Fake Old Computer on Replit (Beige Plastic, a CRT Screen, and Buttons That Actually Travel)

A copy-pasteable Replit Agent prompt for a skeuomorphic site where the whole page is one piece of 90s beige hardware — chunky bezel, green phosphor CRT with scanlines and bloom, a fake POST boot sequence, and knobs, switches and buttons that physically move.

Overview

The whole page is one piece of fake hardware. Yellowed beige ABS plastic, a chunky moulded bezel, visible screw wells, a parting line running down the case where the two halves of the injection mould met — and set into it, behind glass, a small green phosphor CRT with scanlines, bloom and a slow flicker. You do not scroll it. You operate it: press buttons that travel, drag a knob that snaps to detents, flip a switch with no easing on it at all, and the little screen changes.

It boots. That is the part that does the heavy lifting. A fake POST screen, a memory count that ticks up, a model number, and then the home screen — about two and a half seconds of the page pretending to be a machine warming up, and after that the viewer has already agreed to the premise.

What it produces: a fixed-aspect device filling the viewport with no browser scrollbar, a CSS-built case with real geometry, a phosphor screen with scanlines, a blurred bloom layer, curvature vignette and a rare horizontal roll, a boot sequence, a state machine behind the screen, physically travelling buttons, a drag-to-rotate knob with detents, a moulded slider, hard-switching toggles, and synthesized click and thunk sounds — muted by default.

Stack: React + Vite + TypeScript, plain CSS, the Web Audio API, and a handful of seamless texture images. No 3D, no canvas, no audio files.

I did not tell it what the thing does

This is the part worth copying more than the CSS. I opened Replit Agent with the aesthetic and nothing else:

I want to build a website that's one big piece of fake old hardware. Like a 90s handheld — beige plastic, chunky bezel, little CRT screen with scanlines. The whole page IS the device. You click real physical buttons, turn knobs, flip switches, and the little screen changes. I don't know what it should actually do yet. That's the part I want to figure out with you. Ask me whatever you need, go look at what people have already made in this space, and pitch me a few directions.

No spec, no feature list. The vagueness was real — I had the look and genuinely had not decided on the function. What came back was the reverse of the usual exchange: it interrogated me. Who is this for, a portfolio, a toy, or a tool? What is actually on the screen — content, or a mechanic? Does the hardware do one thing well or five things badly? Then it went and looked at what already exists in the skeuomorphic-device corner of the web, came back with what is overdone in it, and pitched three directions.

I rejected two of them out loud. The portfolio-in-a-device one is boring — every developer has built that, and the device becomes a frame around a list of links rather than a thing you use. The pivot to the third came out of the argument, not out of my spec. If you are going to run this yourself, have an opinion ready to push back with; the useful output is downstream of the disagreement.

Everything below is what I fed in after that, in pieces, once the concept was settled. Aesthetic direction from me, function from the conversation.

Why beige, and not the white neumorphic thing

The obvious alternative was soft white neumorphism — extruded pale plastic, dual shadows, the whole 2020 dribbble aesthetic. I have built that; it reads as modern design portfolio at a glance, which is the exact opposite of the read I wanted.

Yellowed beige with a green CRT reads as old instantly, at thumbnail size, before anyone has processed a single detail. It is also by some distance the cheapest convincing aesthetic to build: scanlines are one repeating gradient, bloom is a duplicated blurred text layer, and a boot sequence is a setTimeout chain. The three things that sell it hardest are all nearly free.

The prompt

Paste the whole thing at once, after the concept conversation — not instead of it.

Build **a website that is one single piece of fake 1990s hardware**. Yellowed beige plastic case, chunky moulded bezel, a small green-phosphor CRT screen behind glass, and physical controls — buttons, a knob, a slider, toggle switches. The *page* is the device: it fills the viewport, there is no scrollbar and no page content outside the case. Every control is real and dispatches into the screen's state machine. It boots before it does anything. **Stack — use exactly this, no substitutions:** - React + Vite + TypeScript - Plain CSS (or CSS modules). No Tailwind, no UI library, no icon library. - Web Audio API for the button click and power thunk — synthesized, **no audio files** - No 3D, no canvas, no WebGL. The case is CSS and SVG geometry. - No backend, no router. Fully static SPA. - Must pass `tsc` with no errors and run with a clean console. --- ## Step 1 — Textures, not a picture of a device **Do not render the device as one image.** The case geometry is built in CSS/SVG so it can move and respond. Images are used only as seamless surface textures blended over that geometry. Expect these in `attached_assets/`, imported as Vite modules: 1. `plastic.png` — seamless beige ABS plastic grain, subtly yellowed, tiles at 512px 2. `grain.png` — fine noise overlay for the whole case 3. `wear.png` — scuffs, edge wear, a scratch or two; one transparent overlay 4. `glass.png` — dust and fingerprints for the screen glass Apply as `background-image` over the CSS gradients with `background-blend-mode: multiply`, plastic at full strength, grain at ~0.35, wear at ~0.12, glass dust at ~0.06. If an asset is missing, fall back to the CSS gradient alone — never substitute a drawn SVG of a whole device. ## Step 2 — The case - Base plastic `#d8d0bc`; second panel (the bezel surround) `#c9c0a8`; recesses `#b8ae95`. - **All shadows warm.** `rgba(74, 62, 40, .35)` and similar. Never a grey or blue-grey shadow — cool shadows are what make CSS plastic look like CSS. - An injection-mould **parting line** running the full width of the case: a 1px dark line with a 1px light line under it, at about 62% height. - **Screw wells** in all four corners: a circular inset recess with a cross-slot head, darker at the top-left of the recess. - A **moulded speaker grille**: a dot grid of small inset circles, lower right. - **Silkscreen labels** beside every control, in tiny condensed uppercase (~9px, `letter-spacing: .12em`), colour `#6b6250`, `opacity: .75`, and each rotated a hair off-axis (±0.4deg) so the print looks slightly off-register. - The case fills the viewport: `body { overflow: hidden }`, no browser chrome, no scrollbar. ## Step 3 — The screen A rounded rectangle inset into the bezel, `#0a1a0a` base, phosphor `#33ff66`. Layers, bottom to top: 1. **Text layer** — the actual screen content, font `VT323` (Google Fonts) at ~22px. Never a modern sans on this screen. 2. **Bloom** — a duplicate of the text layer, `filter: blur(6px)`, `opacity: .65`, `mix-blend-mode: screen`, `pointer-events: none`. 3. **Scanlines** — `repeating-linear-gradient(transparent 0 2px, rgba(0,0,0,.35) 2px 4px)` across the whole screen. 4. **Curvature** — a radial vignette darkening the corners, generous `border-radius`, and an `inset` box-shadow. Do **not** use SVG `feDisplacementMap` barrel distortion; it costs more than it returns. 5. **Glass** — one soft diagonal specular highlight across the top-left, plus the dust texture at very low opacity. Motion: - **Flicker** — 3–5% opacity oscillation on the text layer at ~0.15s, via CSS keyframes. - **Roll** — every 20–40s (randomised), a horizontal band translates down the screen over ~350ms. Rare enough to be a glitch, not a loop. ## Step 4 — The controls The controls are where sites like this fail. Each one must move. - **Buttons** — on `:active`, `transform: translateY(2px)` **and** collapse the drop shadow. A button that only changes colour reads as fake immediately. Give them a moulded cap: light top edge, dark bottom edge, warm shadow beneath. - **Knob** — pointer-drag rotates it. Track the pointer with `setPointerCapture`, map vertical drag delta to degrees, clamp to a range, and **snap to detents** (e.g. 8 positions). A tick mark on the cap shows the position. Click a detent sound at each step. - **Slider** — a styled ``. The thumb looks like moulded plastic sitting in an inset channel; the track is a recess with an inner shadow. - **Toggles** — hard state change, **no transition, no easing**. Physical switches do not ease. The only animation permitted is the shadow swap. - Every control has a `:focus-visible` ring and works from the keyboard. ## Step 5 — Sound Synthesized with the Web Audio API, created inside the first user gesture (not at module load): - **Click** on button press — a short filtered noise burst, ~12ms, quiet. - **Thunk** on the power switch — a low sine drop, ~90ms. - **Detent tick** on knob steps — shorter and higher than the click. - **Muted by default**, with a physical mute toggle on the case. Master gain ~0.15. ## Step 6 — Boot sequence On load, the screen runs a fake POST before anything else is reachable: 1. A block cursor blinks alone for ~400ms 2. A model number and a fake ROM revision print 3. A memory count ticks up rapidly to a total, then `OK` 4. A short self-test list, each line resolving to `OK` on a delay 5. `READY.` — then the home screen Total ~2.5s. Add a `SKIP` affordance (any key or any button) — after the third visit nobody wants it, and a boot sequence you cannot skip is a bad website. ## Step 7 — Screen state The screen is a plain state machine — one `mode` value plus per-mode state, no router. Every hardware control dispatches into it; the screen never has its own buttons. Keyboard mirrors the hardware, and each mapped key is printed on the screen in the same style as the silkscreen (`OR HIT [P]`). ## Step 8 — Responsive The device has a fixed aspect ratio. Handle it deliberately, now, not at the end: - Wrap the device in a fixed-aspect container and `transform: scale()` it to fit the viewport, transform-origin centre, recalculated on resize. - Below ~600px wide, switch to a simplified portrait layout: the same case, controls stacked below the screen, no scaling gymnastics. - Never let the case overflow into a scrollbar at any viewport size. ## Step 9 — Pass/fail checks Before you tell me it is done, verify each: - [ ] No scrollbar at 1440x900, 1280x720, or 390x844 - [ ] A button pressed with the mouse visibly moves down and its shadow collapses - [ ] The knob follows the pointer past the edge of the knob itself, and snaps - [ ] Toggling a switch has **zero** transition time on the state change - [ ] The screen text has a visible halo around it that does not blur the scanlines - [ ] The boot sequence runs on load and can be skipped - [ ] With sound unmuted, a button press makes a sound; on first load, muted, it does not - [ ] Every control is reachable and operable by keyboard alone - [ ] `tsc` clean, console clean

Why each clause is in there

"Do not render the device as one image"

This is the single most important line in the prompt and it is the first thing an agent will do if you let it. If the case is one generated PNG, nothing moves, nothing is responsive, and every button is a dead hotspot on a picture. That is the failure mode of most "interactive hardware" sites — they are a photograph with an image map, and you can feel it within one click.

Generate seamless textures. Build the geometry in CSS. Then blend one over the other and the surface looks real while the object stays live.

"All shadows warm"

Beige plastic under a grey shadow reads as a grey rectangle someone tinted. Warm plastic needs warm shadow — the light bouncing off the case into its own recesses is beige light. This one substitution accounts for a startling amount of the difference between "old hardware" and "CSS div".

Parting line, screw wells, off-register silkscreen

These are manufacturing artefacts, and they are the tell that something was made in a factory rather than drawn. Nobody consciously notices a parting line; everybody notices its absence as "this looks CG". The silkscreen being fractionally rotated and slightly worn does the same job — perfectly aligned type is a vector file, imperfectly aligned type was printed on a physical object.

Bloom as a duplicated blurred layer

Phosphor glows because the light spreads on the glass. A text-shadow gets you a fuzzy edge; a duplicate layer at blur(6px) with mix-blend-mode: screen gets you a halo that reads as emitted light. It also has to sit under the scanlines — bloom over scanlines blurs the lines themselves and the screen instantly goes soft and modern.

"Buttons must travel"

Stated as its own clause because a colour change on :active is what you get by default and it feels wrong in a way people cannot name. Two pixels of translateY plus a collapsed shadow is the entire difference between a picture of a button and a button.

"No transition, no easing" on the toggles

Real switches snap — there is a spring, and it is over in a frame. An agent will add a 200ms ease to everything unless you forbid it on this one component. A toggle that glides is the most common single break in the illusion, precisely because it looks so good in isolation.

The boot sequence

Two and a half seconds of fake POST does more for the "old" feeling than any amount of texture work. It is also the best possible opening shot if you are filming the build — a beige CRT warming up on a full-screen website is surprising within two seconds, which is about how long you have.

Make it skippable anyway. It is charming once and an obstacle on the fourth visit.

Banning barrel distortion

A real CRT bulges, and you can fake it properly with an SVG feDisplacementMap. It also tanks the frame rate on anything animated behind it, on every machine. A radial vignette plus a big border-radius plus an inset shadow buys you 80% of the read for none of the cost. Say no to it explicitly or you will get it.

Knobs to turn first

  • Scanline opacity (0.35). The number that decides whether this is a CRT or a novelty filter. Below 0.2 it disappears; above 0.5 the screen is unreadable and looks like a jail cell.
  • Bloom blur (6px) and opacity (0.65). Raise the blur before the opacity, always. High-opacity tight bloom looks like a drop shadow; wide faint bloom looks like light.
  • Phosphor brightness. Green-on-black at low opacity looks incredible in a screenshot and is nearly unreadable in use. Keep body text brighter than instinct says — check it on a laptop at 40% screen brightness, which is where most people are.
  • Flicker range (3–5%) and period (0.15s). Past 8% it stops being a CRT and starts being a fault. If it feels weak, slow it down rather than deepen it.
  • Roll interval (20–40s). Rare is the whole point. A roll every 5 seconds is a broken television, not an old one.
  • Button travel (2px). 1px is invisible, 4px is a trampoline. The shadow collapsing matters as much as the movement.
  • Knob detent count (8). Fewer feels chunky and mechanical, more feels like a continuous dial with a stutter. Eight is the sweet spot and it also gives you eight readable screen states.
  • Grain opacity (~0.35) and wear (~0.12). The wear layer is the one that gets overcooked. It should be findable, not visible.
  • Master gain (0.15), muted by default. Sound doubles the realism for almost no build cost, and autoplaying it loses you the visitor. Both things are true.

If it comes out wrong

  • A grey rounded rectangle. The first pass always looks like this. It is the cool shadows and the missing texture blend, in that order. Fix the shadow colour before you touch anything else.
  • The case looks like a gradient, not plastic. The texture layer is missing or is being drawn with background-blend-mode: normal. It needs multiply over the gradient, not instead of it.
  • The screen looks soft and modern. Bloom is stacked above the scanlines and is blurring them. Bloom under, scanlines over.
  • The text is unreadable. Phosphor opacity tuned on a bright external monitor. Raise it and re-check the bloom, which will now be too strong.
  • Buttons feel dead. They are changing colour, not moving. This is the default output and it needs the translateY clause restated.
  • The knob jumps when you drag past its edge. No setPointerCapture. The pointer left the element and the handler stopped firing.
  • The knob rotates smoothly with no detents. The snap was applied to the visual rotation but not to the dispatched value, or vice versa. Both have to quantise, together.
  • The switch glides. A global transition: all .2s somewhere up the tree. Kill it on the toggle specifically.
  • A scrollbar appears at some window size. The scale wrapper is not recalculating on resize, or a shadow is spilling outside the container. Both are common; check the resize handler first.
  • On a phone it is a tiny unreadable device in the middle of a white page. The portrait branch was never built. transform: scale() alone does not survive a 390px viewport — this is why the prompt makes you decide in Step 8 rather than at the end.
  • No sound until you reload. The AudioContext was created at module load and is suspended. Create it inside the first click handler, or resume() from one.
  • The boot sequence replays on every state change. The timer chain is inside a component that remounts. Hoist it, and gate it on a boot-complete flag.

The part the prompt cannot do for you

Do not stop at the first result. The first pass will look like a grey rectangle with rounded corners — that is not a failed prompt, that is pass one. The version worth showing anyone is three or four rounds in, and each round is one specific complaint: the shadows are cool, the plastic has no grain, the buttons don't move, the screen is too dim.

The iteration is not overhead on the build. It is the build.

Recap

  • Bring the aesthetic, let the agent argue you into the function. The reversal — it interrogating you — produces a better concept than a spec written before the conversation.
  • Pick the aesthetic that reads at thumbnail size. Beige and green says "old" in one glance; soft white says "portfolio".
  • Generate textures, build geometry. One image of a whole device is a dead end with hotspots on it.
  • Warm shadows on warm plastic. Cool shadows are the single biggest tell.
  • Manufacturing artefacts sell the object — parting line, screw wells, slightly off-register silkscreen.
  • Controls must physically move, and the movement needs its own clause or you get a colour change.
  • Forbid easing where physics forbids it. Real switches snap.
  • Bloom under the scanlines, or the CRT goes soft.
  • A boot sequence buys more period feeling than any texture, and costs a setTimeout chain. Make it skippable.
  • Ban the expensive effect explicitly. feDisplacementMap is real barrel distortion and it is not worth the frames.
  • Decide the mobile strategy in the prompt, not at the end. A fixed-aspect device in a phone viewport is a genuine design problem.
  • Bright enough to read beats atmospheric. Always.
  • End with observable pass/fail checks — each one a bug you already know the prompt will otherwise produce.

If you want more prompts in this shape, there is a floor lamp hero with a brass switch that lights the whole page, an interactive light gallery with pull-chain physics, and a frosted glass refraction cube in WebGL.