sowonpark.com
A WordPress site rebuilt as static files in one sitting
Static HTML · Python generators · Cloudflare Pages · Pages Functions · Resend
- ~2 hrsstart to live
- 248 MBof originals, to 13 MB
- 29tiles recovered exactly
- $0a year to host

The problem
A film portfolio sat on WordPress on shared hosting that was being cancelled. Three plugins deep, 248 MB of media, and a contact form on Contact Form 7 and Akismet.
The hard part was not the pages. It was the gallery: which still image linked to which Vimeo film existed only inside a plugin's own JSON. Lose that and 29 tiles become 29 guesses.
What I built
- Recovered the mapping first. Scraped the WordPress REST API and pulled the gallery block's JSON, so every image-to-film link came across exactly rather than by eye.
- Rebuilt the site with no framework, no build step and no dependencies. Two small Python generators: one produces responsive image derivatives, the other writes the HTML from a manifest.
- Replaced the contact form with a Pages Function, 57 lines using Resend, with a honeypot, Turnstile verification, length caps and HTML escaping. Two plugins and a subscription became one file.
- Preserved the SEO. Old WordPress media paths, wp-admin and wp-login all 301 to the right places, so nothing that was indexed broke.
- Handed the client their mail. Exported both mailboxes before the host went dark and moved ongoing delivery to free Cloudflare Email Routing, with a plain-English document explaining how to open the archive.
Architecture
- Runtime
- Static HTML, CSS and JavaScript. No framework, no build step, no npm dependencies at runtime.
- Generators
- Two Python scripts using only the standard library plus Pillow: one for image derivatives at three widths in WebP and JPEG, one for the page itself.
- Forms
- A Cloudflare Pages Function calling Resend, with honeypot, Turnstile, length caps and escaping.
- Delivery
- Cloudflare Pages, with a redirect map preserving every indexed WordPress URL.
Engineering discipline
The checks that make fast work safe. Every one of these is in the repo.
- Fidelity over speed on the one thing that mattered. The gallery mapping was recovered from data, not reconstructed from memory, because a wrong film under a still is worse than a missing one.
- The hosting bill went to zero and the attack surface went with it. No plugins, no admin login, nothing to patch.
- The client was left whole. Mail archived and forwarding moved before the old host was switched off, with written instructions rather than a verbal handover.
Built with AI, gated by tests
Two hours from first commit to a live site is what this method is for. Small, well-specified, fully verifiable work.
The verification here was not a test suite, it was the data: the recovered gallery JSON is the ground truth that says the 29 tiles are right.
What shipped
- Live at sowonpark.com, on Cloudflare Pages, at no hosting cost.
- 248 MB of WordPress originals became a 13 MB static site with responsive images at three widths.
- Built and shipped in a single session on 17 August 2026.
- Live
- sowonpark.com