[07]COLOPHON> man wesli.devbuild #5f67501
The stack, the ASCII pipeline, the swarm that carries page changes, where the live data comes from, and what the site promises about speed and access. The numbers on this page come from the repository or from your browser.
- evolution
- 0034
- last commit
- 05 OCT 2026 22:01
- built
- 05 OCT 2026 22:01
- output
- static HTML, one server function
Static HTML from Astro, no UI framework. The browser gets a handful of small TypeScript modules, and every page reads fine with JavaScript off.
| role | what | version | license |
|---|---|---|---|
| framework | AstroStatic HTML from .astro components. No UI framework. | 7.3.5 | MIT |
| styling | Tailwind CSSEvery colour, size and duration is a token in one @theme block. | 4.3.3 | MIT |
| motion | GSAPEntrances and the scramble. DrawSVG loads on the home page only. | 3.15.0 | GSAP standard (no charge) |
| scroll | LenisSmooth scrolling, loaded on your first scroll input. | 1.3.26 | MIT |
| rendering | Canvas 2DPortrait, network, swarm, globe and page transitions. | — | web platform |
| search | PagefindFull-text index behind Ctrl K, built after the site. | 1.5.2 | MIT |
| type | JetBrains MonoThe only typeface. See Type below. | 5.3.0 | OFL-1.1 |
| role | what | version | license |
|---|---|---|---|
| images | sharpTurns photos and renders into art maps; draws the social cards. | 0.35.5 | Apache-2.0 |
| sitemap | @astrojs/sitemapEvery indexed page, without the shielded ones. | 3.7.4 | MIT |
| language | TypeScriptClient modules, build scripts and the one server function. | 6.0.3 | Apache-2.0 |
| QA | PlaywrightScreenshots, overflow and smoke checks in headless Chrome. | 1.63.0 | Apache-2.0 |
| hosting | Cloudflare PagesStatic files, plus one Pages Function for Talk to Atlas. | — | service |
Nothing on this site is a picture of ASCII. Photos and renders become small data maps at build time; the browser turns those into glyphs on a canvas, cell by cell.
[01]source
scripts/input/A photo of me for the home portrait; renders and SVG drawings for the rest. None of them ship to the browser.
out .webp · .svg
[02]map
npm run portraitnpm run artsharp crops each source, tunes its contrast and packs it into a small PNG: red is tone, green is the subject mask, blue a palette index.
out 11 maps · 429 KB
[03]sample
lib/ascii/sample.tsPer cell: average tone and mask, then contrast, gamma, histogram equalisation and a little dither. Pure code, so it also renders the no-JS fallbacks.
out a 12-glyph ramp
[04]atlas
lib/swarm/atlas.tsEvery glyph is drawn once per colour and tone into a single sprite sheet, so nothing calls fillText while it animates.
out 13 colours × 8 tones
[05]canvas
Canvas 2DA frame is a run of drawImage() copies from the atlas. Settled art is a still canvas: no loop runs until something moves.
out zero work at rest
- R tone
- Brightness on its own. The black backdrop stays blank.
- G mask
- What counts as the object: # inside, · outside.
- B palette
- Where the art’s one hue lives; the dots stay neutral.
- = glyphs
- All three combined: 819 lit cells, one particle each.
# photo → map, then render the no-JS fallback from the same map
npm run portrait
# renders + SVG drawings → art maps + src/lib/swarm/art-meta.ts
npm run art
# 10 art maps, 394 KB together; the portrait map is 35.2 KB
Every lit cell of an art is one particle. When you follow a link, whatever ASCII is on screen breaks apart and flies to where the next page keeps its art.
- 0 mssampleWhatever ASCII is on screen is read back into particles: position, palette and tone per cell (at most 2,600 on desktop, so it reads as a swarm, not noise).
- 0 msfadeThe page content fades. The sticky nav stays: it is the one piece of chrome that never leaves.
- 0–700 msflightEach particle bursts outward, then follows a shared arc towards where the next page puts its art. The leading edge peels off first.
- 462 mshandoffThe cloud is written to sessionStorage and the next document is requested. Hover prefetch has usually fetched it already. A handoff older than 4 s is ignored.
- first paintredrawAn inline script on the new page draws the cloud before anything else paints, so the swarm never blinks out between documents.
- 0.9–1.5 sassembleThe page’s swarm takes the cloud and flies it into its own art, cell by cell. Surplus particles fade on landing, missing ones fade in.
| layout | viewport | glyph | max cols | particles | flight |
|---|---|---|---|---|---|
| desktop | ≥ 1600 × 860 | 7 px | 170 | 7,000 | 0.9–1.5 s |
| laptop | ≥ 1200 × 560 | 6.5 px | 130 | 5,500 | 0.9–1.5 s |
| tablet | ≥ 640 wide | 6 px | 110 | 4,000 | 0.9–1.5 s |
| mobile | < 640 wide | 5 px | 72 | 2,400 | 0.8–1.25 s |
the layout this browser is in now
Source and target cells are both sorted top to bottom and paired by rank, so a shape flows as a whole instead of dissolving into dust. Each particle follows a cubic curve: a burst outward, an arc it shares with the stream, a landing point that is re-read every frame, so scrolling mid-flight still lands. Reduced motion, a hidden tab or nothing ASCII on screen: the link just navigates.
Four readouts on this site change on their own: two in your browser, two at every build. None needs a key, and each has a plain fallback when its source is down.
WEATHER
, in your browser- source
- Open-Meteo forecast API
- place
- Utrecht, 52.09 / 5.12
- key
- none: a free, open endpoint
- cache
- 30 min in sessionStorage, 4 s timeout
- offline
- the line says “sky offline” and moves on
- now
- Utrecht--°Csky pendingasking the window
EVOLUTION
, at build time- source
- git log of this repository
- number
- the commit count, oldest = 0001
- shield
- subjects naming shielded work are rewritten (4 so far)
- fallback
- a committed snapshot, for shallow CI clones
FWRD RELEASE
, at build time- source
- fwrd.digital/changelog
- reads
- version and date of the newest release, nothing else
- timeout
- 5 s, then the last cached release
- now
- v2.73.5 · 05 OCT 2026 (fetched this build)
CAFFEINATE
, in your browser- source
- a model, not a sensor
- input
- my daily coffee rhythm and the clock in Amsterdam
- decay
- each cup absorbs over ~27 min, then halves every ~5 h
- clock
- NL
- now
- caffeinate: --
The only secrets belong to Talk to Atlas: the model key and its anti-abuse settings. They are Cloudflare secrets, read server-side by one Pages Function, and never part of anything your browser downloads.
The budget is what I hold every page to. The readout is what this page actually loaded in your browser, measured with the browser's own APIs and sent nowhere.
budget
- home
- JavaScript ≤ ~90 KB compressed
- other pages
- JavaScript ≤ ~60 KB compressed
- at rest
- no animation loops: canvases draw only while something moves
- layout shift
- ≈ 0: art boxes are sized up front, fallback fonts are metric-matched
- on demand
- smooth scroll on first scroll, the palette on first use
heaviest data, measured at build
- font
- 39.5 KB, one file for every weight
- art maps
- 394 KB for all 10; a page loads only its own
- portrait
- 35.2 KB, home only
measured in your browserneeds JavaScript
- JavaScriptcompressed, external files
- —
- CSScompressed
- —
- this documentcompressed HTML
- —
- requestsdocument included
- —
- largest paintLCP
- —
- layout shiftCLS, summed
- —
script budget— of 60 KB
The target is WCAG 2.2 AA. This is what that means on this site, criterion by criterion.
- 1.4.3Text contrast of at least 4.5:1. The dimmest text colour on the site measures 5.4:1 against the background.
- 2.4.7A visible focus ring on every control, in the green that otherwise only means “live”.
- 2.4.1A skip link first, then landmarks (header, main, footer) and one h1 per page.
- 2.1.1Everything works from the keyboard: the palette, the menu, dialogs, the image lightbox and the Atlas chat.
- 2.1.4Single-key shortcuts can be switched off, here or from the palette. Ctrl K always works.
- 2.5.5On touch screens every control is at least 44 px tall.
- 1.1.1ASCII art is decoration and hidden from screen readers; photos carry real alt text.
- 2.3.3With reduced motion on, entrances render in their final state and page changes are plain navigation.
- 2.2.2Anything that moves on its own can be paused. Status dots blink six times, then hold still.
- 1.4.13Tooltips stay while you hover them and close on Esc.
- no-jsWithout JavaScript every page is still readable. With it, no content waits on an animation.
your settings, as this page sees them
- motion
- everything renders in its final state without JavaScript
- pointer
- —
- shortcuts
- —
Something doesn't work for you, with a screen reader, a switch, a zoom level? Tell me and I'll fix it.
One monospace, the whole way down: it is the voice of a terminal, and it keeps every column of ASCII honest.
- family
- JetBrains Mono Variable, by JetBrains (OFL-1.1)
- axis
- weight 100–800, one file for every weight
- file
- latin subset, 39.5 KB woff2, preloaded on every page
- fallback
- Consolas at 109.1% · Menlo at 99.7%, metric-matched so the swap doesn’t move a line
- ligatures
- off: code reads as typed
- display
- none added: the page headers are the same mono, up to 216 px, tracked tight
The type scale, the colours and every shared component, with their states, are laid out on the styleguide.
Built on other people's good work.
- globe
- Land outlines from Natural Earth (public domain), via world-atlas
- portrait
- A photo of me, reduced to a 232 × 226 tone map and drawn as glyphs
- art
- The hourglass, the nautilus, this keyswitch and the 404 compass started as renders from FLUX1.1 [pro] via fal.ai. They only ever appear as glyphs. No people.
- code
- The open-source packages under Stack, with their licenses
- built by
- Me, Wesli Miggels, much of it through coding agents (Claude Code) that I direct and check
The site's version number is its commit count. It sits in the nav, the footer and here, and it changes with every commit.
0034
evolutions
built 05 OCT 2026
This page is part of evolution 0034. Every change before it is in the log, numbered, with the day it happened.
05 OCT 2026 · MON3 changes
04 OCT 2026 · SUN2 of 6 changes