This is a submission for Frontend Challenge - Comfort Food Edition, Perfect Landing
What I Built
Pizza Mania — a landing page for a fictional Neapolitan pizzeria where the comfort food is pizza, and the comfort is aggressively defended by a chef named Giovanni.
The centerpiece is a build-your-own-pizza workshop: toppings composite as layered SVGs on a live pizza, the price ticks up in real time, and every ingredient lands with a little "thud" on the placemat. Add pineapple, and Giovanni scooters in to protest. Add it again in the same session and he comes back angrier. The third time he just… stops reacting. His disappointment is persisted in sessionStorage, because emotional continuity matters.
Around the workshop there's a full landing page: five house pizzas with a hand-drawn poster art direction, a cart with a real checkout flow (delivery to 11 countries, including Ukraine 🇺🇦), customer reviews — one of which honestly withholds a star — a love letter to Neapolitan dough, and the whole thing in three languages: English, Italian, and Ukrainian, with real pluralization rules for each.
Also: if your cart contains pineapple, the "Place order" button dodges your mouse. Twice. Then it gives up and mutters "va bene." It never dodges keyboard users — Giovanni has opinions, not accessibility violations.
Demo
🍕 Live: https://pizzamania.kolovsky.dev/
📦 Code: https://github.com/alexkolovsky/pizzamania
Try this path: hero → "Build your pizza" → add pineapple → apologize → remove pineapple (Giovanni visibly forgives you) → "Surprise me" → order. Then switch the language to Italian and do it again, because Giovanni is funnier in Italian.
Journey
The stack is deliberately boring in the right places. Astro 7 with fully static output, and exactly one Svelte 5 island for the builder + cart. Everything else ships zero JS. The nav's cart badge lives outside the island — a plain <script> and the island talk to the same nanostores atoms, which turned out to be a lovely way to prove state can cross the island boundary in both directions. GSAP only loads via dynamic import() at the moment a gag actually plays, so Giovanni never touches the initial bundle. No UI framework for styles — hand-written CSS with custom properties and clamp() type.
The real work was making the jokes accessible. Every gag has an accessibility-equivalent path, not just an escape hatch:
- One shared
aria-liveregion for the whole page. Toasts arearia-hidden; the same text goes through the live region exactly once, and same-tick announcements get queued and joined instead of overwriting each other (adding a 10th topping says both "topping added" and "maybe you want a lasagna?"). - Under
prefers-reduced-motion, Giovanni's scene doesn't even mount — his lines arrive as a static toast instead. Same joke, no motion. - The cart panel is a real dialog: focus trap,
inert+ scroll-lock on everything behind it, focus re-anchoring when the cart/checkout/success stages swap the DOM out from under you, and focus restore to the trigger on close. - The composite pizza is one
role="img"whose label reads the current recipe and price out loud.
The thing I'm most proud of is a color: #b07708. The mustard stars looked great and measured 2.05:1 against the cream cards — decorative to a contrast checker, meaningless to an actual human squinting at them. Finding a gold that still reads as gold but clears 3:1 on every background took longer than some features. That's frontend.
What I learned: hreflang links must be absolute URLs (Lighthouse will politely dock you until you believe it); Safari needs tabindex="-1" on the skip-link target; and a marquee needs a pause mechanism even when it already respects reduced motion — WCAG 2.2.2 doesn't care that it looks cool.
Final Lighthouse on the production build: 99 / 100 / 100 / 100 (perf / a11y / best practices / SEO).
Next: sound design (a faint wood-fire crackle on the hero is right there), more Giovanni lore, and possibly a prefers-reduced-judgment media query for pineapple lovers.
No pizzas were harmed. One chef was mildly inconvenienced.

Top comments (0)