Fully migrated off Squarespace with the subscription cancelled. Grows with ordinary maintenance as new projects ship.
Portfolio Website
This site itself: a static, framework-free build with one shared design system across every page. Originally a Squarespace site with each page pasted in as a Code Block, now a plain git repo of HTML, CSS, and JavaScript served from GitHub Pages, with a shared nav, footer, and related-projects system that renders itself from a handful of JS registries instead of hand-edited markup repeated on every page.
Project Overview
One consistent design system and workflow for adding new project pages and content quickly, without fighting a page builder or carrying a recurring subscription.
Squarespace's workflow meant pasting HTML, CSS, and JS by hand into a Code Block on every page: no git history, no real diffs, and a monthly bill for hosting a site that doesn't need a page builder at all.
Move to GitHub Pages: every page becomes a real file in a git repo, deployed by a push, sharing one design system and a small set of registry-driven scripts instead of copy-pasted markup.
Where the Homepage's Personality Came From
The homepage's tile hero, hover-driven Kevin spritesheet, and KevinOS terminal trace back to a long-time favorite: Jesse Schell's personal site. Schell led the creation of Disney's Toontown Online, a childhood favorite, before founding Schell Games and writing The Art of Game Design. His homepage swaps a conventional nav bar for a single illustrated, sleeping version of himself; interacting with it wakes him up and reveals speech-bubble links out to his book, studio, and talks.
An Illustrated, Interactive Homepage
jesseschell.com replaces a standard nav with one character whose state changes on interaction, surfacing links as speech bubbles instead of a menu bar.
A Spritesheet Hero Instead of a Static Banner
kevinlewis.net's homepage borrows the same idea: a 9-frame Kevin spritesheet and KevinOS terminal that respond to hover instead of sitting still, turning the hero into something explorable rather than decorative.
How It Works
Clean URLs, No Build Step
Every route is a plain <slug>/index.html file (About, Projects, 404, and one folder per project), so URLs stay clean with no .html extension and no bundler sits between editing a file and it going live.
One Shared CSS + JS Pair
Every interior page pulls the same kl-design-system.css and site.js, wrapped in a .kl-page class. The homepage is the one deliberate exception, kept fully isolated with no .kl-page wrapper so interior changes can never touch it.
Nav, Footer, and Related Projects Render Themselves
The top nav, the footer, and each project page's "Keep Exploring" suggestions are all driven by small JS registries instead of markup repeated across 20-plus pages. Add one entry once and every page picks it up on load.
GitHub Pages + a Real Domain
Static files served straight from the main branch of a private repo, with a CNAME file and Pages' custom-domain setting pointing kevinlewis.net at GitHub's edge, HTTPS enforced.
Admin Hub
A separate subdomain hosts a private links hub to every project's live, admin, or status page, grouped Live, In Progress, and Planned. It's architecturally distinct from the main site: not GitHub Pages, but a small zero-framework Node server deployed to the same always-on EC2 box as Bob-a-Bot, behind a Caddy reverse proxy handling automatic HTTPS.
Node Server on Shared EC2
A zero-framework Node server built on the built-in http and crypto modules, deployed via scp and pm2 alongside Bob-a-Bot on the same EC2 box, with DNS pointed at it via an A record rather than a GitHub Pages CNAME.
AWS Cognito for User Management
Gated by an AWS Cognito Hosted UI user pool with self-registration off. The server runs the OAuth2 authorization-code exchange, verifies the returned ID token against the pool's JWKS, and sets an HMAC-signed session cookie, no passwords or session state handled by the server itself.
Tools + Build
Decisions Worth Calling Out
GitHub Pages Over Squarespace
Moved off a paid page-builder subscription onto free static hosting already used for other projects, trading a visual editor for git-based version control, real diffs, and a push-to-deploy workflow.
No Framework, No Build Step
Every page is plain HTML, CSS, and JS behind one shared stylesheet and script. For a mostly-static content site, a framework and bundler would add tooling without solving a real problem here.
Registry-Driven Nav, Footer, and Related Projects
Rather than hand-editing a nav block on every page, the nav, footer, and "Keep Exploring" suggestions render at runtime from three JS registries, so adding a link or a project happens in one place instead of 20-plus.
CSP Delivered as a Meta Tag
GitHub Pages serves static files with no way to set custom HTTP response headers, so the Content-Security-Policy ships as a meta tag in every page's head instead of a real header, the only mechanism available without adding a server or CDN layer.
Clean Slug URLs Over .html
Every route is <slug>/index.html rather than <slug>.html, so links read as /projects/pi-tether instead of carrying a file extension.
Self-Hosted Images, No Hotlinking
All images live in the repo's own assets folder rather than pointing at another repo or CDN, so the site never depends on an external source staying online or public.
Squarespace → GitHub Pages
The site ran on Squarespace for years with its built-in navigation disabled and every page rebuilt as a full-page Code Block. The migration replaced that entirely: no paste step, no subscription, no page builder standing between an edit and the live site.
22 Interior Pages, Rebuilt as Real Files
Every page converted from a pasted Code Block into its own <slug>/index.html, plus a from-scratch homepage rebuild since it was Squarespace's native block editor, not a Code Block, so nothing could be reused directly.
A Records Repointed at GitHub's Edge
Squarespace's own DNS Settings dropped the Squarespace Defaults A records and added GitHub Pages' four A records for the apex domain, leaving Google Workspace email untouched.
A Live Sweep Before Cancelling
Before cancelling Squarespace: every page checked for a 200 response, every referenced image checked for resolving, a console-error sweep, and a grep for any remaining Squarespace reference across every served file.
Subscription Cancelled
Domain registration and Google Workspace email were never billed through Squarespace, so cancelling it left both untouched. Only the recurring site-hosting subscription went away.
Notable Challenges
A few problems surfaced only because the migration forced a genuinely close look at what was actually deployed, not just what looked right locally.
Fixes That Never Left Scratch Work
Cancelling Squarespace forced a full recheck of the deployed files, which surfaced that a few features built earlier in the migration, including an image lightbox and a photo crossfade, had only ever existed in in-session scratch copies, never the actual committed files.
Rebuilt and Reverified Against the Live Site
All of them were rebuilt from scratch and confirmed live, not just locally, which is now the standing rule for this project: verify against what GitHub Pages is actually serving, not the local working copy.
A Dropdown That Closed Before the Mouse Arrived
The Interactive Projects nav dropdown closed before a real mouse path could reach an item inside it.
CSS Gap-Bridge, Then a JS Grace Timer
A CSS-only gap-bridge fix helped but wasn't reliable against real mouse movement, replaced with a JS grace-period timer keyed off the same class the mobile tap-toggle already used.
Stale DNS Cache Looked Like a Failed Cutover
After repointing DNS, the apex domain still resolved to the old Squarespace answer well after the change went through.
Checked a Public Resolver Instead
The local machine's DNS resolver was serving a stale cached answer; querying a public DNS resolver directly confirmed the change had actually propagated.
Cost
$0 a Month
GitHub Pages hosting is free, replacing a paid Squarespace plan.
Domain + Email, Unchanged
Domain registration and Google Workspace email were never billed through Squarespace, so cancelling it did not touch either.
Time, Not Money
The only ongoing cost is maintenance time, writing new project pages and keeping the design system consistent, the same as before, just without a recurring bill attached to it.
What's Next
Ongoing Content
New project pages and image updates as new projects ship, the same maintenance rhythm as before the migration.
Automated Checks
A lightweight check for broken links or malformed HTML before a push goes live, instead of relying on manual sweeps.