DEV Community

Cover image for I built a Korean fire-noodle stall in pure CSS — and you can eat it
Alex Kolovskiy
Alex Kolovskiy

Posted on

I built a Korean fire-noodle stall in pure CSS — and you can eat it

Frontend Challenge CSS Art Submission 🍲🥧

This is a submission for Frontend Challenge - Comfort Food Edition, CSS Art.

Inspiration

Hello all, I want to share my favorite dish — Buldak (Korean fire noodles). I don't eat it that often lately since it's pretty spicy, but I recommend trying it if you've never had Korean food before. Cheers.

Instead of just drawing a bowl, I built a whole Korean street stall (포차 / pocha) where you assemble your own pot: toss in toppings from a side-dish tray, pick your heat level with chili peppers, and — when it's ready — eat it.

Demo

Things to try:

  • Tap the side dishes — each topping gets tossed into the pot with a little arc and a squash landing, and the dish gets a red 담김 ("added") stamp
  • Crank the heat to 핵불닭 (nuclear) — the sauce saturates, bubbles boil faster, flames erupt under the pot, the pot starts trembling, and the stall lights flicker
  • Hit 먹자 EAT! — the chopsticks dive in, the noodles disappear in bites, and you're left with a sauce-smeared pot and a "잘 먹었습니다" note
  • Watch the receipt — it counts your toppings and totals the price live ## Journey

The gimmick: the entire builder is a CSS state machine. Every topping is a checkbox, the heat level is a radio group, and even "eat" is just one more checkbox — the whole scene reacts through :has() selectors. The challenge allows a sprinkle of JavaScript, and I spent my entire JS budget on one thing: a ~6-line "chef's pick" randomizer button. Everything else — the toss animations, the heat states, the eating sequence — is pure CSS.

Favorite tricks in there:

  • Noodles from border arcs. Each strand is an ellipse with border: 7px solid transparent and only border-top-color set — you get a clean curved noodle for one element. A pile of them at different sizes and rotations, plus a red radial overlay with mix-blend-mode: multiply for the sauce coating.
  • The receipt is CSS counters. counter-reset: tops 0 price 350 on the root, then every checked dish does counter-increment: tops 1 price 50, and the bill renders counter(tops) " added · ₩" counter(price) "0". The base pot is ₩3500, each topping adds ₩500 — computed and displayed with zero JavaScript.
  • Eating in bites, not a wipe. The eat sequence animates clip-path: inset() through stepped keyframes — chomp to 31%, settle back to 28%, chomp to 64%, settle, gone — synced with the chopsticks' dive animation. The little settle-backs between bites sold the effect more than anything else.
  • Toss physics with one keyframe. Toppings fly in from the tray's direction, overshoot, squash on landing (scale: 1.08 .9), rebound, and settle. Each ingredient keeps its own final rotation because the keyframes end on rotate: var(--r).
  • Sesame is one element. A single 5px dot with a dozen box-shadow offsets, mixing golden and black toasted seeds. What I learned: :has() has quietly turned CSS into a real state-management tool. Once I stopped thinking "how do I fake interactivity" and started thinking "what is my state and what observes it," the whole thing became a set of declarative rules — honestly cleaner than some JS state code I've written.

I also learned to put transition delays in the checked-state rules, not the base rules. My first eat sequence took three seconds to reset because the delays applied in both directions.

Honest limitation: real drag-and-drop is impossible in pure CSS (nothing can track pointer position), so instead of faking it badly, I made the tap feel physical — the tray dish empties, gets stamped, and the ingredient arcs into the pot. There's a genuine pure-CSS drag primitive (resize handles + container queries) I considered for a "pull to pour sauce" mechanic, but it's clunky on touch, so it didn't make the cut.

Small things I'm proud of: the dented brass 양은냄비 pot (the pot every Korean instant noodle deserves) instead of a generic bowl, the celadon-glazed side dishes, and that prefers-reduced-motion users still get a fully working builder — the eat still works, just without the theatrics.

Next: maybe a slurp. If anyone knows how to make sound in pure CSS, my DMs are open.

Code is MIT — fork it, add your own toppings.

Top comments (0)