Overview
Marketing platform for a personal-training fitness club. The system has three faces — a public marketing site for prospects, a separate in-club touchscreen experience embedded via iframe for kiosks at the gym, and an admin CMS for the club's staff to update coaches, schedules, and packages without engineering help.
What I built
Public marketing site
- Coaches, classes, schedules, and personal-training package pages
- Sign-up / sign-in flow for prospect leads to register interest
- Heavy motion-driven hero sections with Lottie animations, Framer Motion reveals, and a stacked-center carousel for transformation stories
- Multiple carousel libraries chosen per use case — Embla for tight UI carousels, Swiper for hero galleries, Slick for content rows, react-stacked-center-carousel for the testimonial wall
In-club touchscreen mode
- A dedicated
/touchscreenroute designed for kiosk displays inside the club - Embeddable via iframe-resizer so the same Next.js app can be hosted inside a separate parent shell and resize itself dynamically
Admin CMS
- Companion admin app (separate repo) for managing coaches, schedules, packages, and content
- The marketing site reads from the same backend so changes go live immediately
Tech stack
- Frontend: Next.js 15, React 19, Tailwind CSS, Radix UI primitives
- Motion + media: Framer Motion + motion package, Lottie, react-text-loop for hero text
- Carousels: Embla, Swiper, Slick, react-multi-carousel, react-stacked-center-carousel
- Embedding: iframe-resizer for the touchscreen kiosk mode
- State: Zustand
- UX feedback: SweetAlert2 for confirmations and modals
My role
End-to-end ownership across both repos — public site and admin CMS. Designed the page architecture, the carousel and motion choices, and wired up the iframe-embedded touchscreen variant. The kiosk mode was the interesting constraint — same codebase, very different display assumptions (large screen, far-back viewing, no scroll).
What I learned
Most projects need one carousel library; this one needed five, because each section had different requirements — autoplay timing, peek of next slide, infinite loop, stacked-center perspective. I learned to pick the right tool per surface rather than forcing one library into every shape, and to keep the bundles in check by lazy-loading carousel code per route. The iframe-embedded touchscreen was also a useful exercise in making the same app behave differently by route: same components, very different shell, no fork.



