How La Centella was built
Fiesta maximalism with craft underneath. This page walks the whole system: the day to 2 AM atmosphere arc, papel picado rebuilt as honest SVG cutwork, one CSS variable that makes the entire page sweat, and night market photography staged like hand tickets. Every snippet below is from the live site.
Loud, but never accidental
La Centella is a family taqueria with a late night window. The brief called for papel picado banners, hand painted price tickets, a salsa heat meter that re themes the page, and real food photography carrying the menu. The hard constraint was tone: loud enough to feel like a street fiesta, disciplined enough that every choice reads decided.
The spineOne scroll, one night shift
The page is structured as a single day at the window. The hero is the noon table. The menu board fills at 4 PM. The salsa bar glows under string lights at 8 PM. The trompo turns in the dark kitchen at 11 PM. The story pauses under lamplight, and the page ends at the 2 AM window with a neon sign that actually knows whether the window is open right now. Every section carries a timestamp chip, so the scroll itself tells the story.
Four accents, taking turns
The palette is papel picado tissue paper: pink, orange, green, purple on warm cream and near black coffee. The discipline is that only one accent dominates any given viewport. The others appear as condiments: a chip here, a swatch there.
Shrikhand is the display voice: it reads like a hand painted stand sign, and it holds up at the hero's thirteen viewport width scale. Every big word on the page tilts one or two degrees, because a sign painter never quite levels the board.
Poppins carries paragraphs, buttons, and the small caps jewelry. The scale gap is deliberate: twelve rem display names against eleven pixel letter spaced labels is where the page gets its tension.
Noon to 2 AM in one scroll
Each section hands off to the next with a designed event, never a padding boundary: the tilted specials marquee bridges the hero into the menu, the menu's foot fades into the teal night, the banners go dark for the kitchen shift, and dawn never comes, the page just ends at the window.
Five moves, explained honestly
Hand written HTML, CSS, and vanilla JavaScript. No libraries, no build step. These are the five moves that carry the page.
No. 01Papel picado, cut with SVG masks
Each flag is one shared shape referenced by <use>. The cutout pattern is a mask with black shapes: black areas become holes, so whatever sits behind the banner genuinely shows through, like light through cut tissue. Four cut patterns cycle through a JS loop with staggered wave delays so the row moves like wind, not like a march. In the kitchen section the same flags return in near black shades: the motif survives the night shift.
<mask id="cutFlower"> <rect width="100" height="100" fill="#fff"/> <!-- black shapes punch real holes --> <circle cx="50" cy="30" r="9" fill="#000"/> </mask> <use href="#flagShape" mask="url(#cutFlower)" fill="var(--pink)"/>
No. 02The heat rig: one variable, the whole page sweats
The chili slider writes exactly one custom property, --heatF, between zero and one. Everything else is CSS reading that variable: page saturation, the flame fringe rising at the bottom of the screen, the footer flames, a heat vignette, the marquee borders, the level color. Tapping a molcajete bowl in the photo jumps the slider to that bowl's level, so the photograph is the interface.
/* JS writes one number */ root.style.setProperty('--heatF', value / 300); /* CSS does everything else */ body.heat-live #page{ filter: saturate(calc(1 + var(--heatF) * .5)); } .flame-viewport svg{ transform: scaleY(calc(var(--heatF) * var(--fs, 1))); }
One trap worth knowing: a filter on an ancestor becomes the containing block for any fixed positioned child inside it. The flames, the vignette, and the header live OUTSIDE the filtered wrapper as siblings, or they would stop sticking to the viewport the moment the heat turns on.
No. 03Photography staged as hand tickets
The dish photos ride inside the order tickets: washi tape corners overlap the print, a starburst price tag sits on the photo like a sticker, each card hangs at its own angle, and a warm multiply gradient grades every photo toward the palette. Responsive sources keep it honest: a webp around eight hundred pixels for phones, the full jpg for desktop, with width and height attributes so nothing shifts on load.
<img src="img/food/alpastor.jpg"
srcset="alpastor-sm.webp 800w, alpastor.jpg 1500w"
sizes="(max-width:700px) 92vw, 40vw"
width="1500" height="1120" loading="lazy">
No. 04The ambient loop that respects the room
The hero photo comes alive: a five second loop of the same table plays behind the headline. The video fades in only after the browser reports it is actually playing, so the photo is always the base experience. It pauses offscreen, never plays for people who prefer reduced motion or save data, and if a phone in low power mode refuses autoplay, nothing breaks, the photo simply stays.
<video muted playsinline loop preload="none" poster="img/poster.jpg"> // play() returns a promise: catch the refusal video.play().catch(() => heroStaysOnThePhoto());
No. 05A reveal gotcha: clip paths blind the observer
The trompo photo wipes in from a fully clipped state. The trap: Chromium computes IntersectionObserver visibility AFTER the element's own clip path, so an element clipped to nothing can never report itself visible, and the reveal never fires. The fix is to observe the parent and toggle the class on the child. If a reveal mysteriously never triggers, check whether the hidden state removes the element's visible area entirely.
/* hidden state: clip-path inset(100% 0 0 0) */ /* observe the PARENT, reveal the child */ io.observe(photo.parentElement); proxyMap.set(photo.parentElement, photo);
Build your own in six steps
Give the scroll a clock
Pick a narrative axis for the page, a day, a season, a temperature, and let every section's light and color obey it. Atmosphere that evolves beats atmosphere that repeats.
Lock the palette as tokens first
One background, one ink, a handful of accents, written as custom properties before any layout exists. Then spend the accents one viewport at a time.
Choose one variable for the signature
A slider, a toggle, a scroll position. Let it write a single number, and let a dozen unrelated things read it. The interaction feels alive because the whole page conspires.
Stage photos, never place them
Tape, tilt, grade, and mask every photograph into the design system. A photo in a bare rectangle is a screenshot, a photo under taped corners with a sticker price is a menu.
Make hover and press a family
Pick one grammar, here it is the sign painter press: hard offset shadow, and the element travels into its own shadow on press. Apply it to every button, never improvise per section.
Use the phone first
Drag the slider with a thumb, tap every bowl, read every label at 390 pixels wide. If the signature moment does not land on a phone, it does not land.