Technologies
- Astro 5 Static pages with built-in i18n (Spanish at the root, English under `/en/`) and a single server route, the contact endpoint.
- Tailwind CSS v4 Design tokens declared in `@theme` (near-black ink with a violet tint, one lilac accent, warm paper).
- Cloudflare Pages + @astrojs/cloudflare Adapter-based deployment with images optimized at build time and the secrets read at runtime.
- Lenis Smooth scroll, with the gallery carousel opted out so touch dragging keeps working.
- Resend Delivers contact form enquiries to the client's inbox from the `/api/contact` route.
- Fontsource (self-hosted) Oswald Variable for headlines and the wordmark, Inter Variable for body text, no third-party font CDN.
- @astrojs/sitemap Sitemap with Spanish and English alternates, leaving out the noindex privacy page.
- Playwright Script that captures each section on desktop and mobile.
Project Overview
Larry (larrymentalista.pages.dev) is a mentalist, speaker and creator from Buenos Aires who offers shows, conferences, workshops, coaching and his own products. The site is a single page that presents all of it in one place: the show video, his awards, what he offers, a gallery, the Lmental project, his bio and a way to contact him. The client asked to be presented as a mentalist, not as “the magician”, so the brand and titles follow that.
The foundation is the system from the Kovalink site, which I adapted instead of starting from scratch. I kept the stack and the main technical decisions, dropped the pinned-scroll proposals (there is only one video here) and the invitation section, and rebuilt the identity.
Objectives
- Mentalist, not magician - Brand, titles and copy position him as a mentalist, as the client requested.
- One video first - Lead with the vertical show video, muted on entering the screen, with a sound button.
- Everything he offers, in one place - Show, conferences, workshops, coaching and creations, using only the client’s own texts.
- Two languages - Rioplatense Spanish at
/and English at/en/, because his professional audience is international. - Client-editable content - Keep all copy in one data file.
Project Workflow
- Foundation and identity - Reused the Kovalink base (Astro 5, Tailwind v4, Lenis, Resend) and rebuilt the look: a near-black base with a violet tint, a single lilac accent (
#b9a2ff) taken from the violet of the client’s Lmental project and the labels in his video, and warm paper for text and the solid button. Oswald, a condensed face close to theatre posters, replaced Montserrat for headlines. - Provisional logo - Built an interim monogram as an Astro component (a block with a cut-out L and a dot) in two variants, full and compact, and a script that renders the favicons and the social card from it.
- Show video - A single vertical video with
preload="none"and a poster, muted when it enters the screen, plus a sound button that restarts it the first time it is used. - Range requests for video - Cloudflare Pages returns the whole static file even when a range is requested, and Safari on iPhone will not play video without a
206response. I added a/media/[name]route that reads the file from the assets store and returns the requested range, with the total size generated by a script before each build. - Sections - Hero with the client’s figures, career and awards, offers, a mosaic gallery on desktop that turns into a carousel with a lightbox on mobile, Lmental and a bio.
- Bilingual content - All copy lives in
content.esandcontent.enin a single typed file. The English object takes the Spanish type, so a missing key fails to compile. Spanish is the source and English is translated from it. - Contact - WhatsApp, email, Instagram and a form handled by a single SSR route. Anti-spam is a honeypot, a timestamp, a same-origin check and shared length limits. The form sends the visitor’s language, and the email to Larry says when someone wrote from
/en/. - Consent-gated analytics - A queue behind a consent banner, as in the Kovalink site.
- Cloudflare deployment - Moved the deploy to Cloudflare Pages with
nodejs_compat(the worker does not build without it because ofsharp) and documented it.
Results and Impact
- One source for copy - Spanish and English text, navigation and contact details live in
src/data/site.ts, shared by both language routes through a singleHomecomponent. - Only one dynamic route besides media - Everything is static except
/api/contactand the video range endpoint. - Video that plays on iPhone - The range endpoint makes the show video work on Safari for iOS despite the platform limitation.
- A guard against publishing internal files - A
check:rutasscript fails the check if anything internal reaches the build output, a lesson carried over from Kovalink. - Accessibility and layout - Viewport units use
svh, safe-area insets are respected and the hero stacks below 1024px. - No invented content - The “+25 years, +50 countries, +150 cities” figures and the awards come from the client’s own document. There are no testimonials or client logos because there was no material for them.
- Pending items documented - The final domain, a definitive logo, Resend and GA4 keys, photos of the creations and the legal review of the privacy page are listed as open items.