KOPI SENJA ← back to the shop

Build guide · № 01

How the senja got built.

Every site in this collection documents itself: the brief it was handed, the one technique it had to push until it felt impossible, and what the critique passes caught. This is Kopi Senja's log.

The brief, as received

Site
KOPI SENJA — a third-generation kopitiam, corner lot, Jalan Sultan, KL, est. 1974. Fictional.
Concept
A website that lives at dusk. Visitors drag time itself and the shop answers — sky shifts, the neon sign wakes, steam keeps rising.
Signature
Interactive dusk: a draggable time arc morphs the scene day→night, with canvas steam that bends toward the cursor.
Palette
charcoal #120d0a · panel #1c1410 · ink #f2e6d0 · kopi #a4693a · neon jade #35d0a0
Type
DM Serif Display over Karla — the serif is the signage, the sans is the service.
Voice
The grandson who runs it now. Proud, plainspoken, a little funny.
Mandate
Wave 1 motion law: every screenful must move, react, or play. No images — the whole shop is drawn in code.

The signature technique

The hero is a single scene with one master input: T, time of day, 0 to 1. Dragging the sun along its arc recomputes everything downstream — the sky gradient interpolates through six keyframes, interior warmth fades up, stars gate in, the moon crossfades over the sun, and at T ≥ 0.66 the neon sign ignites. Not with a fade — with a real fluorescent-tube stutter, because the brief said the neon has flickered since 1989 and we take our fiction seriously:

/* the neon startup — a hand-timed ignition sequence, from index.html */
function neonOn(){
  if(neon.s!=='off')return;
  neon.s='igniting';
  if(reduced){setN(1);neon.s='on';return;}
  const seq=[[60,1],[70,0],[45,1],[130,0],[50,1],
             [70,0],[35,1],[240,.75],[60,0],[90,1]];
  let i=0;
  (function step(){
    if(neon.s!=='igniting')return;
    if(i>=seq.length){setN(1);neon.s='on';schedAmb();return;}
    setN(seq[i][1]);neon.t=setTimeout(step,seq[i][0]);i++;
  })();
}

Each pair is [milliseconds, tube opacity]. After ignition, an ambient timer dims the tube at random every 6–15 seconds. Reduced-motion visitors get the sign already lit — the page is complete without the theatre.

The steam is a 2D canvas layer: particles spawn at the two kopi cups' real screen positions, ride a slow sine wind, and bend toward the cursor like someone walked past. The system runs 260 warm-up steps before the first paint, so the first frame already has steam in the air. The whole scene — shophouse, skyline, marble table, cat — is inline SVG. Zero images.

What the critique passes caught

Each pass: screenshot the live page on desktop and mobile, read the shots like a hostile art director, fix everything, then add one deliberate upgrade.

Pass 1 — layout truths

  • Mobile hero was a collision — the headline sat directly on the shophouse and fought the neon sign. Shop rescaled and raised above the copy block; scrim deepened under the text.
  • The ceiling-fan drawing read as a sprout, not a fan. Redrawn with four proper blades and a hub.
  • Touch drag could strand the sun mid-sky if the gesture was interrupted — pointercancel now ends the drag cleanly.
  • Upgrade: the shop cat. Drag past senja and it takes its seat on the five-foot way — tail swish, jade eyes, occasional blink.

Pass 2 — texture and honesty

  • The hours panel's left column floated in dead space — the neon box now carries a hand-scrawled aside taped beneath it.
  • Footer claimed a guessed page weight; replaced with the measured number from the final build.
  • Marquee could drift under a paused animation frame on hidden tabs — verified it's pure CSS, no drift possible.
  • Upgrade: streetlamps. Two lamps flank the scene and warm up with the dusk — their glow pools on the pavement as the sky goes down.

Pass 3 — believability

  • The clock said 4.48 pm while the sky said full dusk. KL senja is around seven. The time mapping was rebuilt: the drag now runs 9 am to midnight, so the neon ignites at a truthful 7 pm.
  • On phones the "drag the sun" hint landed on the shop's rooftop neon and both lost. The hint now floats above the sun on small screens.
  • The live open/closed status was marked decorative and hidden from screen readers — it's real information, now exposed.