Loomwork

Loomwork: The Framework That Builds Everything

3 min read Updated July 23, 2026

Every site in this portfolio - including the one you’re reading - runs on Loomwork. I built it after scaffolding the same Astro project one too many times.

The Problem

I kept building sites. Johnny Solarseed, FlashMAWB, OpenBaseline, this portfolio - each one started the same way: scaffold Astro, set up content collections, configure Cloudflare, build a header and footer, write the same CSS reset, wire the same dark-mode toggle.

After the fourth time the pattern was obvious. What I wanted wasn’t an abstraction exercise, it was an extraction: take the pieces identical across every site and make them a living upstream I can pull from with git merge loomwork/main, not a starter template I copy once and forget.

What I Built

An open-source Astro publishing framework. Content collections with typed schemas, ten built-in themes with dark mode, five page templates, a mobile PWA editor, and zero-config Cloudflare deployment. Fork the repo, edit one config file, push to GitHub, and the site is live in about 30 seconds.

The core decision is a clean split between framework files and site files. Framework files (layouts, components, global CSS, content schemas) are maintained upstream and merge cleanly because you never edit them. Site files (config, site.css, homepage, header, footer, content) are yours, and upstream never touches them. Pulling a framework update into a running site is one command, not an afternoon of conflict resolution. That is the difference between a framework and a starter you forked once and can never update.

Ten themes, each a standalone CSS file that sets custom properties on :root, no PostCSS and no Sass and no compile step. Switch by changing one string in the config. Five templates (Default, Landing, Guide, Tool, Longform) selected from frontmatter. A floating reader-controls panel gives visitors dark mode, font size, content width, table-of-contents style, and zen mode, all persisted in localStorage. And a PWA editor at /mobile that reads and writes MDX through the GitHub REST API from your phone, with credentials encrypted at rest via AES-GCM.

Tech Stack

Languages
  • TypeScript
Runtime & frameworks
  • Astro 5
  • MDX
  • React
Data & storage
  • IndexedDB (offline drafts)
  • localStorage (reader preferences)
Infra & deploy
  • Cloudflare Pages
  • GitHub REST API
Notable libraries
  • Zod (schema validation)
  • DOMPurify (XSS)
  • Web Crypto API (PBKDF2 + AES-GCM)

How It Works

The CSS cascade is deliberate. global.css sets defaults at :where(:root) (zero specificity), theme CSS loads at normal :root, and site.css loads last and wins by source order, so a site author can override anything without fighting specificity.

Theme loading uses an inline document.write() in <head>: a script reads the saved theme from localStorage, resolves the file from a registry baked into the page, and emits the <link> synchronously. The browser treats that output as render-blocking, so the page never paints with the wrong theme, not even briefly, with a <noscript> fallback for JS-disabled users.

Content is Zod-validated. The build fails if frontmatter doesn’t match the schema, so broken metadata never ships to production.

Loomwork upstream merge model Framework files (layouts, components, global.css, content schemas) live upstream in loomwork/main and are merged into your fork with a single git merge. Because you never edit them, the merge is conflict-free. Site files (site.config.ts, site.css, the homepage, Header, Footer, and content) live only in your fork and upstream never touches them. loomwork/main upstream your site fork Framework files layouts/ components/ global.css content schemas git merge loomwork/main one command, no conflicts Framework files layouts/ components/ global.css content schemas you never edit these, so they merge clean Site files site.config.ts · site.css homepage · Header · Footer content/ yours; upstream never touches them
Loomwork's fork model: upstream owns the framework half, you own the site half.

What Made It Hard

Getting the framework/site split clean enough that upstream merges never conflict. Guaranteeing zero flash of the wrong theme without a build step. And passing a full security audit on a tool that stores GitHub credentials in the browser and loads user-supplied theme and font URLs - sixteen of eighteen findings resolved, zero critical or high remaining.

The Throughline

Loomwork is the layer underneath everything else here. Every site I build exercises it, and every pain point feeds back in - the theme-switching bug I hit on this very portfolio became a framework fix. It is the clearest example of a solo engineer shipping and maintaining a real open-source tool by building it for actual use, not hypothetical users.

Status

Active and in production. Loomwork 2.1 powers every site in this portfolio plus external sites on the framework. The mobile editor is temporarily disabled while security hardening wraps up; all code-level fixes are complete and re-enabling is the next step. Near-term roadmap: Playwright E2E tests, GitHub Actions CI, visual regression testing. The repo, a demo site, and a verification site are all live.

GitHub · Website · Demo