Caimán
A bar's website: menu by category, offers and bookings.
- Astro 4
- Hand-written CSS
- Vanilla JS
- Canvas 2D
Caimán is the website of a bar and shisha lounge: the full menu split by category, offers, location and a booking form. Astro with static output, no UI framework, and no production dependency other than Astro itself. Today it runs in demo mode: a notice on the site explains that the contact, WhatsApp and booking features are switched off because the place changed hands.
Menu hub Shisha menu Booking form Location
What's inside
Thirteen pages plus a 404 of its own: home, menu hub, seven menus by category (shishas, cocktails, mixed drinks, beers, wines, soft drinks and milkshakes), offers, about, location and bookings. The menu hub is generated from two arrays declared in the file itself — two featured categories with description and price, five standard ones — and rendered with map(), so adding a category means adding a line. The menus for each category are written by hand, with Top, Recommended and New tags per item; the shisha one is the longest: twenty-four traditional blends, three premium, three vapes and one upgrade. Everything hangs off two layouts, and the whole navigation — nav bar, mobile dock, footer, every banner, the end of every menu — pushes you to the same place: bookings.
A design system by hand, with no framework
The main stylesheet is 1,065 lines of design system we wrote ourselves: tokens on :root (the three neons, the background, the typefaces, easing and radius), neon effects, nav bar, cards, forms and four breakpoints, including one for a phone held sideways. On top of that, a second sheet for the menu pages. No Tailwind, no Bootstrap: package.json declares a single dependency, astro. No icon library either: the seven category icons are inline SVG, and the logo is defined once per page as a sprite with a neon gradient and reused by reference. The only outside code loads from a CDN and only where it's needed: Swiper, on the offers page.
The booking, which is the point
The form asks for name, phone, email, date, time and number of people. The time is limited to the bar's real opening hours, and the party size is a range control from 1 to 12 with a label that updates live and gets the singular and the plural right. Native validation is off so it can be handled from JavaScript. The layout even hides the floating dock on that page, because there the whole page is the call to action. There's no backend behind it: the send button calls the validation function through onclick, and that opens the demo modal. And the page says so, with a notice above the form — not hidden away.
Animation that switches itself off
The script file is 327 lines of vanilla JavaScript in independent blocks, each with its own early exit if the element isn't on the page. The first thing it does, before any of those blocks, is read prefers-reduced-motion and pointer: fine, and from there everything showy is conditional: the particle canvas — on the home page and on the 404 too — paints a single still frame and never enters the animation loop if the user asks for less motion, the stats counter jumps straight to the final number, and the card tilt and the magnetic buttons don't even get registered if there's no mouse. The demo modal is a dialog with aria-modal, a tab trap in both directions, Escape to close and focus returned to whatever opened it. There's a skip link, visible focus with a cyan outline, and the expanded state announced in the menu and on every FAQ question.
Details
No UI dependencies at all
The only production dependency is astro; anything from outside comes in over a CDN, and only on the page that asks for it.
A design system of our own, over a thousand lines
Tokens on :root, neon effects, components and four breakpoints written by hand, with no Tailwind and no Bootstrap.
Every animation is conditional
prefers-reduced-motion and pointer: fine are read before anything else; the canvas paints one still frame instead of running a loop.
A modal that's genuinely accessible
A dialog with aria-modal, a tab trap in both directions, Escape to close and focus returned to the button that opened it.
A full booking form with no backend
A 1 to 12 range with a live label, times limited to the bar's opening hours, and a notice on screen saying real bookings are switched off.
Working on something similar?
If you need something like this — a landing page, a website, an ERP or a tool you can't find off the shelf — tell us about it and we'll come back with how we'd do it, how long it would take and what it would cost.
Tell us about your project