Beef & Buns
A cinematic site for a Sousse smash burger house, built around a scroll-scrubbed burger that assembles layer by layer, with an ordering menu, a WhatsApp order flow and a loyalty programme run from its own API and back office.
Visit live site
28
Menu items
26
API endpoints
04
Admin screens
Beef & Buns is a smash burger restaurant on Avenue les Orangers in Sousse, open every evening from 17:00 to 01:00. The brief was a site that carries the same weight as the food itself: a dark, grain-textured stage where the product is the interface rather than a photo dropped into a template. The result is a Next.js 16 application whose entire first act is a burger assembly clip scrubbed frame by frame from the scroll position behind the wordmark, so that scrolling down builds the burger layer by layer while ingredient callouts fade in around it.
The hero is not a video element. The clip is cut into 120 WebP frames at two widths, a 560px desktop set and a lighter 380px set used below a 768px breakpoint, and drawn to a fixed 2D canvas, because seeking an mp4 on every scroll tick stutters on Safari and iOS. A single GSAP ScrollTrigger spanning the hero and the Craft section maps its progress to a frame index held in a ref and drawn on the next animation frame, so scroll progress never triggers a React re-render. Around it, a preloader fills the bun logo with brand red from the bottom, then wipes upward, with a hard timeout so no visitor can ever be trapped behind it. Lenis provides smooth scrolling wired into the GSAP ticker, an animated SVG grain overlay sits above the page, and both the grain and the marquee stop under prefers-reduced-motion.
Around that centrepiece sits the commercial layer: a persistent cart, a slide-in order drawer with table booking that hands the order to WhatsApp, a searchable ordering menu on its own route, and a loyalty programme. Customers join with a phone number or an email, can start their card with welcome stamps won on a prize wheel at /jeu, and show a QR at the counter, where staff scan it in a separate back office that runs on an Express and MongoDB API. The original menu artwork ships as SVG badges and section headers, parallaxed outline numbers echo the printed layout, a twelve-tile Instagram wall drifts in two opposing rows on scroll, and the footer embeds a filtered Google map of the Avenue les Orangers address. The site runs in Docker on the agency's own VPS behind nginx, and the counter API and the back office are served from the same server.
The Challenge
An independent burger restaurant in Sousse with a strong printed identity and an active Instagram presence, but no digital home and no way to take an order outside a phone call. The commercial reality is WhatsApp: that is where customers already order, so any checkout that asked people to create an account or enter card details would simply be abandoned. At the same time the client wanted the site to feel like the brand, not like a menu PDF, which meant carrying a full-screen, scroll-scrubbed hero and heavy scroll choreography on mobile hardware without turning the first paint into a stall. The loyalty programme added a third constraint: customers had to join on iOS or Android with nothing more than a phone number or an email, with no account and no password, while the counter needed one place to scan a card, add stamps and hand out rewards.
What We Built
The public site is a Next.js 16 and React 19 application in TypeScript with Tailwind CSS v4, where the hero is a fixed 2D canvas that draws a 120-frame WebP sequence from the scroll position instead of seeking a video. GSAP ScrollTrigger maps scroll progress to a frame index, and Lenis drives smooth scrolling that respects prefers-reduced-motion. Ordering runs through a localStorage-backed cart context feeding a drawer that composes a formatted WhatsApp deep link, optionally carrying a table booking with day, time slot, guest count and notes. The /menu route is an ordering menu built from the same typed data, with search, a scroll-spy section rail, one-tap add with quantity steppers and an order total that stays in view. Loyalty identity is the contact itself: the card QR encodes beefnbuns: followed by the phone number or email, exactly what the counter scanner resolves, and the /jeu prize wheel seeds its draw with an HMAC of that contact. Pass issue is gated by a ten-minute HMAC download token and signs a .pkpass with passkit-generator or an RS256 save-to-wallet JWT for Google. Behind the card sits an Express and Mongoose counter API packaged for Docker, with 26 endpoints for admin auth, the programme, reward tiers, members, stats, public loyalty reads and wallet issue, and a separate Next.js back office where staff scan, stamp and redeem.
The Outcome
The site is live on beefandbuns.tn, running on Node 22 in Docker on the agency's own VPS behind nginx, with the counter API and the back office served from the same server. All 28 menu items can be added in one tap, from the burger rows, the tenders grid and the extras and drinks lists on the home page or from the /menu grid, and the composed order goes to the restaurant's WhatsApp, with a table reservation attached if wanted. Staff can stamp, correct and redeem from the back office, against reward tiers edited there without a redeploy. Apple Wallet and Google Wallet passes are built in both the site and the API but are not live yet: they wait on the restaurant's Apple Pass Type certificate and Google issuer account. The hero degrades cleanly: narrow screens load a lighter frame set, a slow connection falls back to the nearest loaded frame, the canvas fades out entirely once the menu takes the screen, reduced motion shows the finished burger without scrubbing, and marquee and grain animations stop under reduced-motion. The restaurant now has an address, hours, an embedded map, phone and Instagram in one place, and a menu it can extend by editing a single typed data file.
Scroll-scrubbed burger film
A burger assembly clip, cut into 120 WebP frames per set with a desktop set and a lighter mobile set chosen at 768px, is drawn to a fixed 2D canvas by one ScrollTrigger spanning the hero and the Craft section. Frames load first frame first, then eight spread keyframes, then batches of twelve, and each draw takes the nearest loaded frame. Edges dissolve through destination-out gradients, the canvas fades out as the menu arrives, and reduced motion shows the finished burger. site/src/components/ScrollBurger.tsx, site/public/burger-seq/
Ordering menu with search and section rail
The /menu route is an ordering grid rather than a printed book: a search field over names, ingredient lines and section titles, a sticky rail of five section chips kept in step by an IntersectionObserver, cards whose Add button turns into a quantity stepper, and the running order in a sticky panel on desktop or a bottom bar on phones. Burgers, tenders, fries, extras and drinks live in one typed data module alongside the brand block, so pricing and copy change in a single file, and the same module feeds the page's Menu JSON-LD with TND offers. site/src/components/OrderMenu.tsx, site/src/data/menu.ts, site/src/app/menu/page.tsx
Cart with WhatsApp order and table booking
A cart context persists lines to localStorage and survives reloads. The slide-in drawer handles quantities, removal and totals in Tunisian dinar, and folds in an optional reservation with fourteen day options, half-hour slots covering the 17:00 to 01:00 service, guest count and free-text notes, then composes the whole thing into a prefilled wa.me deep link. The cart is read through useSyncExternalStore, so the server and the first client render agree, and it stays in step across open tabs. site/src/components/CartContext.tsx, site/src/components/OrderDrawer.tsx
Loyalty card and wallet passes
A phone number or email is the member identity: the card QR encodes beefnbuns: plus the contact, the same string the counter scanner resolves. A ten-minute HMAC download token gates pass issue, passkit-generator signs a .pkpass and an RS256 save-to-wallet JWT covers Google, and /carte renders a noindex web card with the QR, stamp dots and a refreshable balance. No Apple or Google wallet credentials are configured yet, so no native pass is issued. site/src/lib/wallet.ts, site/src/components/LoyaltySection.tsx, site/src/app/carte/page.tsx, api/src/services/wallet.js
Spin-and-win prize wheel
The /jeu route has no losing wedge: six wedges of 3, 4, 5, 6, 8 and 10 welcome stamps are derived from the reward tiers and weighted towards the smaller grants, with the full card at 4 percent. The play route seeds the draw with an HMAC of the contact, so a replay lands on the same wedge and the card can recompute the grant without storing it. The SVG wheel spins while the request runs and lands on the server's wedge with a sprung pointer and a lamp chase. site/src/lib/game.ts, site/src/app/api/game/play/route.ts, site/src/components/PrizeWheel.tsx
Counter API and back office
An Express and Mongoose service packaged for Docker exposes 26 endpoints over five models (programme, reward tiers, members, an event log and wallet device registrations), with a 12-hour admin JWT, atomic stamp and redeem updates and a 14-day activity aggregation. The Next.js back office has a dashboard, a rewards builder with a live card preview, a member list and a rear-camera QR scanner using BarcodeDetector with a jsQR fallback and manual entry. Stamps and redemptions also trigger APNs pushes and Google object updates, which stay idle until wallet credentials are set. api/src/routes/, api/src/models/index.js, admin/src/app/
Live in production
Beef & Buns is running in production today. Open it, then tell us what you want built — BreakNRoot engineers systems like this one from first prototype to production.
BNR-CF-03Kinben Sushi
A Next.js 16 site for a Sousse sushi bar, built on two scroll-scrubbed 120-frame sequences, a 37-dish menu that orders over WhatsApp, and a QR loyalty passport stamped at the counter through its own Express and MongoDB API.
Open file
BNR-CF-02Babke Kebab & Plates
An Express and MongoDB build for a Levantine kebab house in Hammam Sousse: a trilingual storefront with WhatsApp ordering, a loyalty card and a 3D flip-book menu, run from a 17-panel staff dashboard.
Open file