Lesson 2 of 3 · The funnel page
Anyone can build a page — that's the easy half now. The half that makes it a business is tiny and unglamorous: one promise, one form, one follow-up. This lesson builds all three.
A funnel isn't a stack of software. It's four decisions, and only one of them involves code.
One sentence that names the outcome for one kind of person. Not features. "Build a full funnel and a business for $0" — you can say what this training is in one line. Yours needs the same.
Reasons to believe: a demo, numbers, a screenshot of the real thing, your own build log. Proof is why strangers don't bounce.
One field. Email. That's the trade: their address for your thing. Every extra field you add costs you signups — measure it and you'll delete them.
The thank-you page delivers the first win immediately, and the emails after keep delivering. This is where "audience" is actually built.
The page you're reading this on follows the same skeleton as the training's own landing page. Top to bottom:
Name the outcome, the audience, and the constraint that makes it feel possible ("for $0", "tonight", "without a developer").
People who are already sold shouldn't have to scroll to act. Everyone else will scroll anyway.
"Who this isn't for" converts better than another benefit bullet — it signals you're not selling everyone.
If the page has two goals, it has none. Navigation off the page is a leak. The landing page of this training has no menu for a reason.
Here's the actual form on this training. One field, a hidden timestamp, a hidden honeypot to catch bots. It posts to a tiny service that stores the lead and sends you to the thank-you page:
<form action="/api/lead" method="post"> <input type="email" name="email" placeholder="you@email.com" required> <input type="hidden" name="source" value="my-landing-page"> <input type="hidden" name="ts" value=""> <!-- filled on load: bots submit in 0s --> <input class="hp" type="text" name="hp" tabindex="-1"> <!-- honeypot: humans never see it --> <button type="submit">Get the free training →</button> </form>
And the service behind it is smaller than this lesson. It receives the post, checks the honeypot and the timing, saves the lead, and redirects to the thank-you page:
def do_POST(self):
form = parse_form(self.rfile)
if form.get("hp"): return self.redirect("/free/start/") # bot
if too_fast(form.get("ts")): return self.redirect("/free/start/") # bot
if not EMAIL_RE.match(form["email"]): return self.fail("bad email")
db().execute("INSERT INTO leads (ts,email,source,ip) VALUES (?,?,?,?)", ...)
self.redirect("/free/start/") # the thank-you page does the selling
No $29/mo SaaS, no third-party script slowing the page, no tracking cookie you have to disclose. It runs on the same $0 server as the site, the data is yours in one file, and you can point the form at a real email platform later without touching the pages. The full source ships in the Starter Asset Kit.
Now the actual skill. OpenCode works best when you describe outcomes and constraints, check what it did, and steer. Not "write HTML" — tell it the job.
Build a single-page landing page that converts visitors into email signups for [OFFER] aimed at [AUDIENCE]. Above the fold: a benefit headline naming the outcome, a one-line subhead, and an email opt-in form (single field) posting to your capture endpoint with hidden fields source=[page-name] and ts. Then: problem/agitation, 3 benefit blocks, what-you-get in 3 steps, who-it's-for and who-it's-not, an FAQ, one guarantee line, one final CTA. No navigation. Dark modern design, inline CSS, one accent color, mobile-first, single index.html file. Everything points at one action: capture the email.
The loop that makes this a skill: describe the outcome → read the diff it shows you → say what's wrong in plain English → repeat until the page is right. Three rounds beats one perfect prompt. When it breaks something, say "undo that, keep everything else" — you are the editor-in-chief, it's the fastest typist you've ever had.
Honesty is part of the system. A funnel page with no traffic and no offer is a beautiful machine with no fuel and no engine:
[brackets]. Save it as index.html.lead_service.py needs a Python host — free tier: Render or PythonAnywhere. (Cloudflare Pages hosts the pages, not the backend — that's the one step Lesson 3's static deploy can't do for you.)Free hosting, free SSL, a real URL. Ten minutes, start to finish — and then it's a business with a front door.