MIDNIGHT TONKOTSU

THE GUIDE

How this site was designed and built — the concept, the palette, the steam, the neon, and a recipe you can follow yourself.

1Concept & art direction

MIDNIGHT TONKOTSU is a fictional nine-stool ramen counter open 23:00–05:00, for night people. The page has two jobs: show the menu and help you find a door that has no sign — only a red lantern. The art direction is rain-slick asphalt with neon magenta and electric cyan glows, lantern red for the door, broth gold for the food. Every visual is drawn in code: no photographs, no stock, no generated images.

2Palette & type

#07080Dasphalt
#FF3DAEneon magenta
#28E0FFelectric cyan
#FF2B2Blantern red
#F0B64Abroth gold
#E9E6DCsteam white

Contrast discipline matters more than the neon: the base is near-black, body text is a warm off-white, and each neon color has exactly one meaning — magenta is signage, cyan is wayfinding and machine labels, red belongs only to the lantern (open/closed state), gold only to food and prices.

3Techniques

The steam simulation (signature)

The steam over the bowl is a canvas particle system. Each wisp is a pre-rendered soft radial-gradient sprite composited with lighter blending. Particles spawn on an ellipse matching the broth surface, rise with buoyancy, and carry their own sway phase so plumes braid instead of rising in parallel lines. The pointer applies a radial push plus a share of its own velocity, so you can stir the steam:

// pointer disturbance: radial push + inherited velocity
const dx = p.x - pointer.x, dy = p.y - pointer.y;
const d2 = dx*dx + dy*dy, R = 120;
if (d2 < R*R) {
  const d = Math.sqrt(d2) || 1;
  const f = (1 - d/R) * 0.9;
  p.vx += (dx/d) * f + pointer.vx * 0.05 * f;
  p.vy += (dy/d) * f * 0.5 + pointer.vy * 0.05 * f;
}

The loop is pre-warmed 180 steps so a full plume exists on first paint, pauses when scrolled offscreen, and under prefers-reduced-motion it draws one hand-placed static plume instead of animating.

The neon lighting model

Neon is not one glow — it's a stack: white-hot tube core, tight colored halo, wide bloom, then faint cast light. The flicker imitates a failing inverter: uneven timing, partial dips, a double-stutter — driven by steps(1, end) so it snaps rather than fades:

.neon {
  color: #fff0f7;
  text-shadow:
    0 0 4px  #fff,                        /* tube core   */
    0 0 11px var(--magenta),              /* halo        */
    0 0 24px var(--magenta),              /* bloom       */
    0 0 55px rgba(255,61,174,.65),        /* wide bloom  */
    0 0 110px rgba(255,61,174,.4);        /* cast light  */
}
@keyframes inverter-stutter {
  7%    { opacity: .35; text-shadow: 0 0 3px #fff; }
  7.6%  { opacity: 1; }
  54%   { opacity: .25; }
  54.3% { opacity: .9; }
  54.7% { opacity: .45; }  /* the double-stutter */
  55.2% { opacity: 1; }
}

The ticket machine

The menu is laid out as a real ticket machine: rows encode kitchen sequence (bowls → sides → drinks), buttons are actual <button> elements with aria-pressed state, and pressing one "prints" a paper stub into the tray — an off-white element whose perforated edge is cut with a CSS mask of repeating radial gradients. The stub is the one warm-paper surface on an otherwise wet-asphalt page, which is why it reads as an object.

4The three passes

  1. Pass 1 — correctness & composition. The steam was a blown-out white blob: halved sprite opacity, shrank particles, raised the emitter off the broth and sped the rise so it forms a plume. Also fixed a real bug — the paper stub's display: flex was overriding its hidden attribute, so it printed itself before anyone pressed a button.
  2. Pass 2 — elevate. Added a second sway harmonic and a slow ambient wind so the whole plume leans and twists; added the neon hover-buzz micro-interaction (get close and the tube stutters); redrew the bowl toppings — the two eggs plus naruto were reading as a cartoon face, a chashu slice broke it up.
  3. Pass 3 — taste. Chanel rule: removed the second (cyan) hero glow that competed with the steam's own cool tones; fixed the 390px topbar where the brand wrapped to two lines; rechecked keyboard focus rings and the reduced-motion static plume.

5Do this yourself

  1. Pick a place, not a topic — somewhere with hours, rules and a smell. Write its one-line job: "menu + find the door."
  2. Ask Claude for an art direction with a materials list (asphalt, neon, paper, steam), and assign each accent color exactly one meaning before any layout exists.
  3. Choose three typefaces that answer three different questions: signage, atmosphere, information. Reject any pairing you'd reuse on another project.
  4. Build the signature element first, alone in a blank page — here, the canvas steam — and iterate until it feels physical. Everything else stays quiet around it.
  5. Make structure carry meaning: menu rows in kitchen firing order, rule numbers that are real rules, steps that actually navigate somewhere.
  6. Write the copy like a person who works there. No lorem ipsum, no "delicious food, cozy atmosphere."
  7. Screenshot, critique, fix — three times, at 1440px and 390px. Each pass must remove something as well as add something.
  8. Last: reduced motion, keyboard focus, console clean. The invisible pass is the professional one.