Luma — Digital Marketing Agency Landing Page
A Vue 3 practice build: a neon landing page for a growth agency
Luma is a practice project I built to learn front-end work in Vue. It is a landing page for an imagined digital marketing agency, with a loud, high-contrast design: gradient lettering, hollow outline type and wireframe graphics. The aim was to learn Vue’s component model on a real layout, not to ship a finished product.
- Type
- Practice project · landing page
- Role
- Design & front-end build
- Core stack
- Vue 3 · TypeScript · Vite · Tailwind CSS v4 · Swiper
- Focus
- Vue components, SVG graphics, sliders

The problem
Most of my earlier work was in React. Moving to Vue meant learning a different way to write components: single-file components, <script setup>, props with defaults, and template refs.
A busy agency design was a good test. It has repeated parts like buttons and cards, decorative graphics, and two sliders, so it covers most of what a real Vue front end needs.
What I built
A Vue 3 single-page site in TypeScript, built with Vite, styled with Tailwind CSS v4 and deployed on Vercel.
Hero: a “Built for growth” headline in gradient letters cut by thin scan-lines, set against an angled neon panel, with a growth snapshot card showing a sparkline, services and key stats.
Brand banner: three rows of hollow “Shine. Grow. Scale.” text scrolling in opposite directions behind a black info band.
The Luma Way: a two-column grid of the agency’s service labs and values, with service buttons that link to the contact form.
Testimonials and featured work: two Swiper sliders with autoplay, looping, keyboard control and custom arrows and dots.
Contact and stats: a contact form with required fields and a thank-you message, a stats section, and a get-in-touch block.
The technical decisions, and why
One button component
Every button comes from a single BaseButton component with typed props for variant, size, icon and shape. It renders a link or a button depending on whether href is set, opens external links in a new tab, and exposes its DOM node so the sliders can use it for navigation.
Graphics drawn in code
The wireframe terrain dividers, the hero sparkline and the flowing testimonial lines are SVG paths built from small formulas in computed values, not image files. A prop like seed or lines gives each divider a different shape at no extra download.
Sliders tied to the component lifecycle
Each slider creates its Swiper instance in onMounted using template refs, and destroys it in onBeforeUnmount, so nothing is left running when the component goes away. The marquee animation also stops for visitors who prefer reduced motion.
Where it landed
The landing page is live and matches the design closely on desktop. It is a practice build: the agency, clients, testimonials and results are placeholder content, and the contact form does not send anywhere.
The main lesson was how close Vue and React are once components are small and typed. The same habits, one shared button and data-driven lists, carried straight across.
Built with
Related work
Learn by Build — Online Learning Landing Page
An early Next.js and Tailwind CSS practice project: a landing page for a hands-on learning platform, with colour-coded course cards and a searchable HTML reference.
Evro AI — B2B SaaS Landing Page
A React 19 and Vite landing page for an AI coaching startup: a header that follows the section colour, a pausable autoplay slider, and copy kept in typed data files.