FrontendBeginneran afternoon

Ship a landing page fast

A landing page is the single URL you point people at to explain your product and capture intent — email signups, waitlist spots, or checkout. Shipping one fast lets you validate an idea, start a launch, or run ads before you've built the actual app, and momentum matters more than polish at this stage.

the approach

Don't build a design system or hand-roll UI — that's where afternoons die. Scaffold a real framework (Next.js + Tailwind, or Astro for a pure-static marketing page), pull prebuilt accessible components from shadcn/ui, and generate your first draft with an AI page builder from your actual copy. The page has exactly one job: one clear message and one action. Wire that action to do something real (capture an email), push to GitHub, and let Vercel deploy it. Content and clarity beat custom animations every time.

Step by step

  1. 1

    Scaffold a real stack, don't invent one

    Run `npx create-next-app@latest` (or an Astro starter if it's a pure static marketing page — Astro ships zero JS by default). Add Tailwind CSS v4 and initialize shadcn/ui so you have accessible buttons, inputs, and cards ready to drop in. Skip anything you'd have to configure yourself.

  2. 2

    Nail the message before you touch markup

    Write the headline, one-line subhead, and single call-to-action in a text file first. One page, one action. If you can't say what the product does in a sentence, no amount of gradient is going to save the page.

  3. 3

    Generate the first draft with an AI builder

    Feed v0.dev or Lovable your exact copy, your target audience, and a reference site you admire ('make it feel like Linear's landing page'). Generate the hero, then export the code straight into your repo instead of hand-typing sections.

  4. 4

    Assemble the standard sections

    Landing pages have a proven skeleton: hero, social proof (logos or a testimonial), three feature blocks, a short FAQ, and a closing CTA. Build each as its own reusable component so you can reorder and edit them without wading through one giant file.

  5. 5

    Wire the CTA to do something real

    Never ship a dead button. Point the form at a Resend audience for waitlist capture, or drop in a Stripe payment link if you're selling. Capturing emails from day one is the entire point of shipping early.

  6. 6

    Add analytics, SEO, and an OG image

    Turn on Vercel Analytics (or Plausible for privacy-friendly stats), set page metadata and a favicon, and generate an Open Graph image so the link doesn't look broken when someone shares it. Missing OG tags silently kill click-through.

  7. 7

    Deploy on git push

    Push to GitHub, import the repo into Vercel, and add your environment variables (like `RESEND_API_KEY`). Point a custom domain at it. Every future `git push` now redeploys automatically — no build servers to babysit.

  8. 8

    Check mobile and run Lighthouse

    Most of your traffic is on a phone. Open it at 375px wide, confirm nothing overflows and the CTA is tappable, then run a Lighthouse pass and fix anything below 90 — usually an oversized hero image or layout shift.

Starter snippet

tsx
// app/page.tsx — Next.js (App Router) + Tailwind. One file, real waitlist capture.
import { Resend } from "resend";

async function joinWaitlist(formData: FormData) {
  "use server";
  const email = String(formData.get("email"));
  const resend = new Resend(process.env.RESEND_API_KEY);
  await resend.contacts.create({ email, audienceId: process.env.RESEND_AUDIENCE_ID! });
}

export default function Home() {
  return (
    <main className="mx-auto flex min-h-dvh max-w-3xl flex-col items-center justify-center gap-6 px-6 text-center">
      <h1 className="text-balance text-5xl font-bold tracking-tight sm:text-6xl">
        Ship your idea before the coffee gets cold
      </h1>
      <p className="text-pretty text-lg text-neutral-500">
        Turn a prompt into a live product — no boilerplate, no config.
      </p>
      <form action={joinWaitlist} className="flex w-full max-w-sm gap-2">
        <input name="email" type="email" required placeholder="you@work.com"
          className="flex-1 rounded-md border px-3 py-2" />
        <button className="rounded-md bg-black px-4 py-2 font-medium text-white">
          Join waitlist
        </button>
      </form>
    </main>
  );
}

✕ Watch out for

  • Hand-building UI from scratch — you'll spend two hours perfecting a button instead of shipping. Pull components from shadcn/ui and move on.
  • Shipping a dead CTA that goes nowhere. Wire email capture on day one; a landing page that collects nothing is just a screenshot.
  • Never opening it on a phone. Desktop-perfect, mobile-broken is the default failure mode, and most of your visitors are on mobile.
  • Over-animating — autoplay hero videos and scroll effects tank your load time and Lighthouse score. Clarity beats motion.
  • Forgetting metadata and the OG image, so shared links render as a blank gray box and nobody clicks.

✓ Pro tips

  • Give your AI agent the raw material, not vague vibes: paste your exact copy, name the target audience, and link a reference site ('structure it like Linear's landing page'). Tell it to use Tailwind + shadcn/ui and build separate section components — not one 800-line file. Then verify every link and CTA actually points somewhere and it renders clean at 375px wide.
  • Ship the ugly-but-live version today and iterate copy tomorrow. A real URL collecting emails beats a beautiful draft sitting in a branch.
  • Steal structure, not pixels. Hero → proof → three features → FAQ → closing CTA is a proven skeleton; copying the layout of a page you admire is faster and better than a blank canvas.
  • Before you call it done, ask the agent to run an accessibility and Lighthouse pass and fix the results — contrast, alt text, and image sizing are the usual offenders and they're cheap to fix.