- Astro 40.8%
- TypeScript 35.4%
- CSS 22.5%
- JavaScript 1.3%
|
|
||
|---|---|---|
| .claude | ||
| .forgejo/workflows | ||
| celilo-module | ||
| openspec | ||
| public | ||
| src | ||
| .gitignore | ||
| astro.config.mjs | ||
| bun.lock | ||
| mise.toml | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
peterbanka.org
Astro site for peterbanka.org — home, about, projects, blog, and résumé.
bun install
bun run dev # see the note below — it backgrounds itself
bun run build
bun run check # astro check (types)
bun run lint:css # lasertag — find dead CSS
The hero mark
@psbanka is generated by @celilo/visualizer:
a word rendered as the negative space in smooth flowing water.
The whole look lives in src/mark.json — nothing else needs editing. Tune
it in the visualizer's /flow route (cd ../celilo/packages/visualizer && bun run dev, then http://localhost:3000/flow), hit EXPORT JSON, and paste
the result over that file. It's a CeliloMarkOptions, which is exactly what
renderCeliloMark() takes — no conversion step.
buildTextMask sizes glyphs from the canvas HEIGHT (H * 0.74) and then
shrinks them until they fit WIDTH * 0.92. @psbanka is eight characters where
tango-nexus's NEXUS is five, so the board is 1400 wide rather than 1024 —
at 1024 the type shrinks hard and the strokes go too thin for the flow to read
inside them. HeroMark.astro's REF must stay in step with mark.json's
width, or the responsive scaling re-introduces the squeeze.
The canvas is decoration: the accessible name is a visually-hidden <span> in
the <h1>, and a render failure is caught so the heading still reads.
Fonts are copied into public/fonts/ and declared in BaseLayout.astro. A font
name alone is not enough — an undeclared family silently falls back to
sans-serif and the mask comes out the wrong shape.
Adding a blog post
Drop a markdown file in src/content/blog/. Nothing else to update — the slug
comes from the filename.
---
title: Something I think
date: 2026-08-04
description: Optional; shown on the index.
draft: false
---
Frontmatter is schema-validated, so a missing title or a malformed date
fails the build rather than quietly dropping the post.
The résumé
src/lib/resume.ts is the only source. Nothing fetches LinkedIn — there's no
public API for your own profile, scraping is blocked and against their terms,
and it would make the build depend on a third party being up. Paste from a
LinkedIn data export. Empty sections are omitted from the page.
Deployment
Published by celilo as the peterbanka-org module (celilo-module/), served by
Caddy at the apex of peterbanka.org.
The module requires both public_web and dns_registrar — but the hook
only ever calls public_web. Registering a route on a new hostname makes it
served and publicly resolvable in one deploy, because public_web reaches the
registrar itself (celilo #328), and it throws rather than report a success that
never reached clients. Declaring the registrar is how we guarantee one is on the
fleet for it to reach. Same shape as celilo's own celilo-website module.
Versioning is changeset-driven — see celilo-module/.changeset/README.md. The
site lives at the repo ROOT, outside celilo-module/, so module publish's
stale gate cannot see a content change; without a changeset, editing a post
republishes a frozen version number.
CI publishing
.forgejo/workflows/release.yml publishes on merge to main: pending
changesets open a "Version Packages" PR, and a run with none packages
celilo-module/ and PUTs the .netapp to celilo-registry. Publishing ends
there — rolling a published version out to peterbanka.org is module deploy.
The CELILO_PUBLISH_TOKEN that workflow uses is not hand-set. on_install
mints one scoped to the peterbanka-org package alone (registry_publish) and
writes it as the repo's Actions secret (source_forge), so every deploy rotates
it and a compromised runner can ship nothing else. Both capabilities are
optional: — with the forge down the site still publishes and CI keeps its old
token.
Gotchas
bun run devbackgrounds itself. Astro 7 keeps a dev-server registry, so the command returns immediately and the server usually lands on 4322 (4321 is often tango-nexus).bunx astro dev status/stop/logs.- Deleting a blog post needs a cache clear. The content layer store survives
a rebuild, so a removed markdown file keeps generating its route.
rm -rf .astro distfirst. - lasertag is pinned to
^0.5.2on purpose. 0.7 addedselector-crosses-ownership-boundary, but its Astro template parsing is still a design doc, so it cannot see.astrofiles and flags every nested selector in the house style — it reports 115 warnings against tango-nexus, which passes clean on 0.5. Revisit when lasertag ships a real Astro adapter. zfromastro:contentreports a deprecation hint. It resolves tozod/v4;astro checkis clean apart from those hints.