A Next.js (App Router) implementation of the Proof of Aussie beer CAPTCHA: a playful re-skin of Google reCAPTCHA where users must select all true blue Aussie beers before they can continue.
Requirements:
- Node.js 20+ (recommended)
Install dependencies and start the dev server:
npm install
npm run devOpen http://localhost:3000 in your browser.
Other scripts:
npm run lint # ESLint
npm run build # Production build
npm start # Start the production server (after build)The page renders only one element from the captcha by default — the inline "I'm a true blue Aussie" checkbox row, modeled after Google reCAPTCHA's "I'm not a robot" entry point. Clicking the checkbox triggers the actual image challenge in a floating popup.
[ I'm a true blue Aussie ] ──────── Proof of Aussie / Privacy · Terms
│
▼ click
┌──────────────────────────┐
│ Select all images of │ ← popup, blue header
│ a true blue Aussie beer │
│ ┌───┬───┬───┐ │
│ │ │ │ │ ← 3x3 grid │
│ ├───┼───┼───┤ │
│ │ │ │ │ │
│ ├───┼───┼───┤ │
│ │ │ │ │ │
│ └───┴───┴───┘ │
│ ↻ 🎧 ? [VERIFY] │
└──────────────────────────┘
The popup is rendered through a portal directly into document.body and is
displayed as a centered modal with a dim semi-transparent backdrop on every
screen size. The dialog is anchored to the visual center of the viewport
(both horizontally and vertically) using flexbox, so it stays centered when the
window is resized. On small screens (≤ 480px) the dialog grows up to a 360px
max width to remain readable down to ~320px wide phones.
The popup can be dismissed by:
- Pressing
Escape - Clicking the overlay (anywhere outside the popup)
poa-next/
├── public/ # beer photos used by tiles (with SVG fallbacks)
└── src/
├── app/
│ ├── globals.css # all styling (modal, checkbox row, popup, captcha)
│ ├── layout.tsx
│ └── page.tsx # renders <ProofOfAussieCaptcha /> in the modal body
├── components/
│ ├── Banner.tsx # success/error banner inside the popup
│ ├── BeerCaptcha.tsx # the 3x3 challenge (header + grid + footer)
│ ├── BeerTileButton.tsx # single tile (image only — no labels)
│ ├── CaptchaPopup.tsx # portal-based centered modal popup
│ ├── MiladycareHeader.tsx # outer modal header
│ ├── PoaCheckboxRow.tsx # in-page reCAPTCHA-style checkbox row
│ └── ProofOfAussieCaptcha.tsx # orchestrator (checkbox state + popup open/close)
└── lib/
└── beerCaptcha.ts # beer catalogue, SVG art, puzzle generator
ProofOfAussieCaptcha owns the verification state. It renders
PoaCheckboxRow inline (in the modal body) and, when the user clicks it,
mounts CaptchaPopup which portals a floating dialog into document.body.
The dialog hosts BeerCaptcha, which generates a fresh puzzle on every mount.
On a correct answer, BeerCaptcha calls onSuccess, the popup unmounts, and
the checkbox flips to its checked state.
- Audio challenge / Help buttons are intentionally stubbed (they show a banner message inside the popup).
- Beer tiles prefer image assets from
public/when available; otherwise they fall back to inline SVG art (src/lib/beerCaptcha.ts > ART). - Tile labels were intentionally removed to mirror the original Google reCAPTCHA UI — only images are shown.