[00]STYLEGUIDE> man design-systemnoindex
The parts WESLI.DEV is built from, with their states and real content. Page builders work from this page and COMPONENTS.md; nothing here is invented for the demo.
- evolution
- 0034
- last commit
- 05 OCT 2026 22:01 · #5f67501
- built
- 05 OCT 2026 22:01 (git)
- tokens
- 17 colours · 10 type sizes · 9 spaces
Near-black screen, off-white text, greys for hierarchy. Green means live or active, nothing else; amber is for alerts, red for errors. Contrast is measured against the background.
- --color-bg#060908the screen1.0:1
- --color-surface#0b0f0dpanels, inputs1.0:1
- --color-raised#111714hover planes1.1:1
- --color-fg-strong#f2f5f3emphasis, selection18.2:1
- --color-fg#d8dddabody text14.5:1
- --color-muted#8d9691secondary text6.6:1
- --color-subtle#7e8782metadata (min. text)5.4:1
- --color-dim#56605bdecoration only3.1:1
- --color-line-faint#121916grid guides1.1:1
- --color-line#1f2824hairlines1.3:1
- --color-line-strong#34403aframes, inputs1.8:1
- --color-accent#50d890live / active ONLY11.0:1
- --color-accent-dim#2b7a52live, quiet3.8:1
- --color-accent-ghostrgb(80 216 144 / 0.1)live wash—
- --color-alert#f0b44calerts10.8:1
- --color-error#ff8a7aerrors8.7:1
- --color-scrimrgb(6 9 8 / 0.86)dialog / nav scrim—
One mono voice, JetBrains Mono, with a real hierarchy: every size tracks the viewport's system scale and is clamped to stay legible.
EVOLUTION
I BUILD SYSTEMS
Built to learn
I build software that can think, act and improve.
A lot of my code is now written by coding agents that I direct and check. The work moved from typing every line to deciding what to build, setting the constraints and verifying what comes back.
Systems I designed, built and still run.
[02] WORK · RECENT ACTIVITY · SYSTEM STATUS
fig.02 · build #5f67501 · EVOLUTION 0034
| token | value |
|---|---|
| --text-micro | clamp(10px, calc(10px * var(--system-scale)), 13px) |
| --text-label | clamp(10px, calc(11.5px * var(--system-scale)), 15px) |
| --text-body | clamp(11px, calc(13.5px * var(--system-scale)), 18px) |
| --text-reading | clamp(15px, calc(16.5px * var(--system-scale)), 20px) |
| --text-lead | clamp(12.5px, calc(17px * var(--system-scale)), 23px) |
| --text-role | clamp(12px, calc(17px * var(--system-scale)), 24px) |
| --text-title | clamp(22px, calc(32px * var(--system-scale)), 52px) |
| --text-headline | clamp(32px, calc(60px * var(--system-scale)), 104px) |
| --text-display | clamp(40px, calc(var(--display-base) * var(--system-scale)), 176px) |
| --text-mega | clamp(46px, calc(9.2vw * var(--mega-factor)), 216px) |
Twelve columns inside the gutters, hairlines with + ticks where they meet. Spacing is a fluid scale; radii are zero.
.grid-12 + .grid-lines
Rule
.hairline · .frame
A hairline box with two + ticks: the light version of a Panel. Use it for figures, inputs and quotes.
spacing scale
- --space-3xsclamp(2px, calc(4px * var(--system-scale)), 6px)
- --space-2xsclamp(4px, calc(8px * var(--system-scale)), 12px)
- --space-xsclamp(6px, calc(12px * var(--system-scale)), 18px)
- --space-sclamp(10px, calc(16px * var(--system-scale)), 24px)
- --space-mclamp(14px, calc(24px * var(--system-scale)), 36px)
- --space-lclamp(20px, calc(36px * var(--system-scale)), 56px)
- --space-xlclamp(28px, calc(56px * var(--system-scale)), 88px)
- --space-2xlclamp(40px, calc(88px * var(--system-scale)), 136px)
- --space-3xlclamp(56px, calc(136px * var(--system-scale)), 208px)
SectionHeader introduces every section: index, command, title, intro. The title scrambles in the first time it scrolls into view.
From web design to agents, as a system log.
Buttons are commands: [ LABEL ] at rest, the shell command typed out on hover or focus, executing... when pressed (the one moment a button turns green). Hover and tab through these.
CommandLink
CommandButton · states
Disabled shows a dashed frame and never its command (the email channel is a placeholder, so the composer's send looks like this).
Tag
Hover only brightens a chip. Pressed is a state: green brackets, a ghost fill and an underline, so it never depends on colour alone. Filter chips need JS and are not rendered without it.
Kbd · Tooltip · Glyph
- arrow-right
- arrow-left
- arrow-up
- arrow-down
- arrow-up-right
- arrow-down-left
- plus
- close
- search
- command
- enter
- chevron-right
- expand
- copy
- check
Status dots say what is live. The clock, caffeinate level and weather are real and update in the browser; evolution comes from git at build time.
ProgressBar
Metric (real numbers only)
0034
evolutions
commits to this site
3
changes today
05 OCT 2026
03
case studies
07
routes
excluding shielded pages
Marquee
- directing coding agents (Claude Code, headless)
- LLM pipelines with structured output
- model routing + fallback
- MCP servers
- embeddings + retrieval (pgvector)
- prompt-injection guards
- TypeScript
- SvelteKit
- Astro + Sanity
- Expo / React Native
Panels frame live readouts. On content pages they construct when they scroll into view; their [data-seq] rows populate one by one.
RECENT ACTIVITY
- 0034launch SEO: let Google/Bing see the experience noindex, noindex pages.dev hostssite
- 0033FWRD case images recaptured in Englishsite
- 0032case covers from real product captures instead of the ASCII art inputssite
- v2.73.5FWRD Studio shipped v2.73.5fwrd
- 0031atlas: live-tested prompt fixes, intent protocol and consented handoff to Weslisite
SYSTEM SPEC
FWRD Studio- role
- founder / product & AI systems engineering
- year
- 2026 — now
- status
- live, in active development
- stack
- link
- fwrd.digital
- link
- FWRD Studio
PRINCIPLES
- Brief first, then code// three WebGL concepts for this site, dropped in one day: two for poor contrast and an invisible swarm, one for about 336 KB of JS against a 300 KB budget
- Verified, not claimed// Atlas reviews its own failures every night and adds guards
- Model output is data// Sponsorboard match pipeline, with a prompt-injection test
KeyValue
- species
- human (apparently)
- origin
- pencils and paint, then code
- uptime
- goes to the gym; Atlas watches the deploys
- languages
- Dutch, English, TypeScript
- coffee
- sufficient; see the home page
LogList renders evolution entries, activity and releases on a git-graph rail, grouped by day. Rows can be linked and filtered by area.
05 OCT 2026 · MON3 changes
- 0034launch SEO: let Google/Bing see the experience noindex, noindex pages.dev hostswork
- 0033FWRD case images recaptured in Englishwork
- 0032case covers from real product captures instead of the ASCII art inputswork
04 OCT 2026 · SUN6 changes
- 0031atlas: live-tested prompt fixes, intent protocol and consented handoff to Wesliwork
- 0030contact form sends through Resend via a Pages Functioncontact
- 0029v2 QA: shared fixes, audits, per-area fixes, final verificationbuild
- 0028v2 pages: home, work, cases, experience, about, contact, now, evolution, colophon, 404system
- 0027v2 foundation: design system, page shell, command palette, footer, live datasystem
- 0026v2 groundwork: BRIEF, QA tooling, media helperbuild
03 OCT 2026 · SAT17 changes
- 0025updated the experience pageswork
- 0024updated the experience pageswork
- 0023experience: uncropped screenshots, four projects marked as updateswork
- 0022home: drop the left rail and the boot log framehome
- 0021updated the experience pageswork
- 0020sticky nav with CTAs, announcement bar, comment-free build, Talk to Atlassystem
Subjects that name shielded work are replaced at build time ("updated the experience pages").
Figures are framed, numbered and zoomable: click or press enter for the lightbox, arrow keys to browse every image on the page, esc to close.



Long-form text for case bodies and the colophon: headings read as system labels, lists as terminal output, figures with fig.0N captions.
FWRD is my Dutch web company, and FWRD Studio is its product. It treats a website as something that keeps being worked on after launch.
How it works
A visitor describes their business in a chat box. An LLM pipeline turns that description into a structured site config, and the config renders into a client template that is then provisioned on Cloudflare. Building is free. You pay when the site goes live.
- The marketing site, fwrd.digital. Astro on Cloudflare Pages, with Sanity as a block-based page builder.
- The hub, app.fwrd.digital. A SvelteKit app plus a separate Cloudflare Worker for generation, chat, Stripe webhooks and crons.
- Client sites. Each site is built from one template, driven by tokens.
Every site has an MCP endpoint
Four tools: generate_page, edit_page, publish_site and run_report. The owner connects it to Claude and asks for changes in plain Dutch. Nothing goes live until it has been approved.
- Claude writes a schema-exact Sanity document.
- The server saves it as a draft.
- It scaffolds the Astro page.

Receipts over model claims.
// FWRD Studio, decisions worth explaining
$ npm run build
> astro build && node scripts/pagefind.mjs
[pagefind] indexed 11 pages| route | command | group |
|---|---|---|
| / | cd ~ | primary |
| /work/ | cd /work | primary |
| /about/ | cat about.md | primary |
| /contact/ | ping wesli | primary |
| /now/ | cat now.md | secondary |
| /evolution/ | git log --oneline | secondary |
| /colophon/ | man wesli.dev | secondary |
Press ctrl k anywhere to search.
Declarative reveals: add data-fx to an element and it plays once when it scrolls into view. Under reduced motion and in automated browsers everything renders in its final state.
SCRAMBLE
> typed in, left to right, one step per character
Blocks type in from top to bottom. Nothing reflows: the text is laid out before the clip opens, and screen readers always get the final content.
0034
timing tokens
| token | value |
|---|---|
| --dur-instant | 80ms |
| --dur-fast | 160ms |
| --dur-base | 240ms |
| --dur-slow | 480ms |
| --dur-slower | 800ms |
| --ease-system | cubic-bezier(0.22, 1, 0.36, 1) |
| --ease-out-expo | cubic-bezier(0.16, 1, 0.3, 1) |
| --ease-in-out | cubic-bezier(0.65, 0, 0.35, 1) |
| --ease-step | steps(6, end) |
AsciiWordmark