- HTML 89.1%
- JavaScript 5.9%
- CSS 4.9%
- Shell 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The header bar is back, now pointing at absolute URLs rather than relative folder paths: justcook.besthappypanda.com modeltrains.besthappypanda.com backpack.besthappypanda.com Since these are cross-origin, sync-from-dev.sh no longer strips the bar, and the service worker's same-origin check already keeps them out of the cache, so the sister-path guard in sw.js is gone as dead code. Cache bumped to v5 so installed copies pick up the new header. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
| public | ||
| tools | ||
| .gitignore | ||
| .pages | ||
| README.md | ||
The Knitting Studio
A free course in hand knitting: illustrated diagrams, stitch charts, a stitch library and a curated set of video tutorials. Static HTML — no build step, no framework, no dependencies.
Live at https://theknittingstudio.besthappypanda.com
Layout
.pages bovine-pages-server config (enables the site, sets the domain)
public/ everything that gets served
tools/ helper scripts, not published
Bovine serves the contents of public/ — nothing above it is web-visible.
Deployment
Hosting is bovine-pages-server
on bovine.squarecows.com. Pushing to main is the deploy: the plugin reads
the default branch directly, so there is no build or publish step.
The site is reachable two ways:
| URL | Notes |
|---|---|
https://theknittingstudio.besthappypanda.com |
The live site. |
https://adam.pages.sqcows.com/theknittingstudio.besthappypanda.com/index.html |
The pages URL. Visiting it is what registers the custom domain. |
Why the repository is named after the domain
Bovine verifies domain ownership by checking a DNS TXT record containing
sha256("owner/repository"). The TXT record on this domain was created for
adam/theknittingstudio.besthappypanda.com, so the repository has to carry that
exact name or verification fails and the custom domain silently 404s.
Gotcha: the pages URL needs an explicit filename
Because the repository name contains dots, bovine's directory-index logic reads
.com as a file extension and does not fall back to index.html:
adam.pages.sqcows.com/theknittingstudio.besthappypanda.com/ -> 404
adam.pages.sqcows.com/theknittingstudio.besthappypanda.com/index.html -> 200
This only affects the pages URL. The custom domain serves / correctly, because
there the repository name is not part of the path. If you ever need to
re-register the domain, hit the /index.html form.
Bringing the custom domain up
-
DNS — point the hostname at the Traefik server:
theknittingstudio.besthappypanda.com→ A record to the bovine server's IP, or a CNAME to its hostname. -
Register — visit
https://adam.pages.sqcows.com/theknittingstudio.besthappypanda.com/index.htmlonce. That read of.pagesis what writes the Traefik router into Redis and triggers the Let's Encrypt certificate. Until it happens the custom domain returns a bare404 page not found. -
DNS verification is enabled on this instance, so the domain also needs a TXT record proving ownership, or registration is refused (silently — the pages URL still returns 200, the custom domain just never comes up):
TXT theknittingstudio.besthappypanda.com bovine-pages-verification=6e2ded5ca8f03214570d54cdd899979db1ac49e5584aa2d15924e29ac12a431fThis record is already in place. The hash is
sha256("adam/theknittingstudio.besthappypanda.com"). If the repository is ever renamed or moved, recompute it and update DNS:printf '%s' "adam/theknittingstudio.besthappypanda.com" | shasum -a 256
Updating the site
The working copy lives in ~/Documents/knitting site, alongside three unrelated
sites. To pull the knitting site across and rebuild public/:
sh tools/sync-from-dev.sh
git add -A && git commit -m "Update site" && git push
Sister sites
The header bar links out to the other three sites, each on its own domain and its own repository:
| Site | Domain |
|---|---|
| Cook Without a Recipe | justcook.besthappypanda.com |
| The Model Railway Handbook | modeltrains.besthappypanda.com |
| Pack Bench | backpack.besthappypanda.com |
These are absolute cross-origin links, so they are copied through by the sync script untouched. Earlier they were relative paths to folders in the dev directory, which is why the script used to strip the bar out.
One gotcha: the service worker cache
public/sw.js serves assets cache-first, so an edited stylesheet or script
is invisible to anyone who has installed the app until the cache name changes.
After changing anything under public/assets/, bump it:
const CACHE = "knitting-studio-v5"; // was v4
Installing as an app
The site is a PWA: it installs to the home screen on iOS (Safari → Share → Add to Home Screen), Android (Chrome → ⋮ → Install app) and desktop Chrome/Edge, and works offline once installed. Instructions with diagrams are on the home page under "Put it on your phone or tablet".
Credits
Every diagram, swatch and chart is inline SVG drawn in the page. Videos are embedded from YouTube and belong to the teachers who made them; nothing is hosted here.