# Method · Malte Therkildsen

> Four disciplines, how a project runs and what it delivers, the tools and checks behind every app on this site, the work in numbers and the command that counted each one.

Source: https://therkildsen.dev/method

Method 4

# What I make and how I work

Four disciplines, each shown as a leaflet folded in three. Drag one open sideways or click it to see three live examples.

How a project runs

## Every project follows 4 steps

The quality bar is set before the first line of code and checked before anyone else sees the work.

What it leaves

## What a project delivers

The working product, the components it is built from and the measurements it was checked against, so the next change can be compared with the last.

Running workThe thing itself, in the browser, in light and dark, at phone and desktop widths

The partsThe tokens and components it is made of, each documented where it runs

The measuresSizes, colors and timings read in the browser, to check again after every change

A handoverThe order to build it in, and the numbers to compare against

How I build

## The tools and checks behind every app

If you have a technical team, the chapters from here show them the tools and checks behind every app on this site, the work in numbers, and the command that counted each one.

[Automated checks128can stop a build in RAMTT$ cd ~/Projects/RAMTT && node -e "const p=require('./package.json');console.log(Object.keys(p.scripts).filter(k=>/^(audit|lint|guard|check)[:-]/.test(k)).length)"](#m-guards)[Test files1,524in RAMTT and Zibaldone# It adds up the test files in RAMTT and in Zibaldone.](#m-tests)[Browser scripts168test pages in Chromium$ git -C ~/Projects/RAMTT ls-files | grep -E '(maal|measure)[^/]*\.(mjs|js|ts)$' | wc -l](#m-browser-scripts)[Components551specified in the design system$ git -C ~/Projects/ramtt-design-system fetch --quiet origin r25 && git -C ~/Projects/ramtt-design-system show origin/r25:spec/components.json | python3 -c "import json,sys;c=json.load(sys.stdin)['components'];print(len(c), sum(len(x.get('rules', [])) for x in c.values()))"](#m-components)

On the device

## Apps that work offline

The app saves each change on the device first and syncs it when a connection is available, so people can keep working without a network.

The databaseSQLite in the browser, stored in OPFS and synced to Postgres with PowerSync (ramtt.app).

The documentYjs documents in IndexedDB, merged character by character, with a server that stores the updates.

The app itselfA service worker that caches the app, so it opens without a network.

The stack

## The front end and the back end

The front end

ReactReact with TanStack Router for apps, built with Vite.

vinextvinext on Vite and Cloudflare Workers, prerendered, for a site in two languages.

JavaScriptPlain JavaScript and esbuild where a page needs no framework, as on this site.

CSSPlain CSS on design tokens, with a linter and a check that measures every component on a rendered page.

The back end

WorkersCloudflare Workers, Durable Objects with SQLite, and WebSockets.

PostgresSupabase with Postgres and row-level security, with [109](#m-migrations) migrations in RAMTT.

Sign inPasskeys verified on the server, and Web Crypto for encryption and signatures in the browser.

ServicesStripe with a verified webhook, Resend for email, and Claude through the Anthropic SDK.

Every change

## Automated checks

A quick set of checks runs at every commit, and the full set runs on a build server for every pull request. A change that fails either is not merged.

The prototypes and this site pass [566](#m-behavior-checks) browser tests in Chromium. A second check compares [48,250](#m-measured-checks) rendered values on [117](#m-measured-pages) of their pages with the design system’s specification.

AuditsThe JavaScript size of each route, secrets in a change, the colors of the design tokens and the text users see.

Browser scriptsScripts that click and type through a page and measure it.

WritingA writing check of every text in RAMTT at each commit, and of every page of this site at each build.

Working with Claude

## I write code with Claude, Anthropic’s SI model.

Its changes go through the same checks, browser tests and writing check as mine. [The commands](#sources) at the end of this page count every number on this site.

Numbers

## The work in numbers

From [25 Jan 2026](#m-first-commit) to [11 Oct 2026](#m-last-commit) I made [9,057](#m-commits) commits in [15](#m-repositories) repositories, on [214](#m-active-days) of [260](#m-span-days) days. The longest run of days with a commit is [67](#m-longest-streak) days, and it runs to the last commit. [988](#m-prs) pull requests were merged.

### The year, day by day

Drag along the days or throw them. The count is every commit up to the day under the needle. The busiest day was [5 Oct 2026](#m-busiest-day), with [524](#m-busiest-day) commits.

### Around the clock

[3,565](#m-night-commits) of the [9,057](#m-commits) commits were made between midnight and six in the morning, Copenhagen time.

Turn the hand, or use the arrow keys, to read any hour. Each bar is every commit made in that hour, on every day of the period.

### On one scale

The rest of the counts stand on one logarithmic tape. Pull it under the needle; it stops at each number.

- Shelves in the component library [12](#m-library-shelves)
- Components specified in the design system [551](#m-components)
- Prototypes [39](#m-prototypes)
- Database migrations [109](#m-migrations)
- Pages measured against the design system [117](#m-measured-pages)
- Guards and audits that fail a build [128](#m-guards)
- Browser scripts that drive a page [168](#m-browser-scripts)
- Unit tests [330](#m-unit-tests)
- Behavior checks in Chromium [566](#m-behavior-checks)
- Components in the component library [634](#m-library-components)
- Merged pull requests [988](#m-prs)
- Test files [1,524](#m-tests)
- Rules the design system measures its components by [4,111](#m-component-rules)
- Commits [9,057](#m-commits)
- Tracked files in the RAMTT monorepo [11,334](#m-tracked-files)
- Tests of the language’s official suite that Spark passes [38,639](#m-spark-pass)
- Measured checks on those pages [48,250](#m-measured-checks)
- TypeScript lines in the RAMTT monorepo [911,426](#m-ts-lines)

This site

## How this site is made

The face, the colors and the weight of this page. Every value is read from the page while you look at it, or from the file named beside it.

### One face, and its sizes

Inter Variable, served by the site and cut to the Latin letters and the weights the design draws. Each size is measured on this page, at this screen.

### Day and night, one set of names

The tokens are read from the design system’s stylesheet as you look. Drag the seam: day on one side, night on the other. Click a color to copy its name.

### An earlier front page, line by line

The markup of the site’s earlier front page, `web/home/markup.html`, with the commit that last changed each line. Loom, the Git I wrote from nothing, replays the same commits here and blames the file again.

The blame is drawn by the page’s script.

### What this page weighs

Measured by your browser while the page is open, with the interface that measured each value printed under it.

Sources

## The command behind each number

The site runs these commands when it is built. They last ran on [11 Oct 2026](#m-commits). Find one by what it counts or by what it runs, copy it, or replay what it printed.

### Commits

Each repository’s commits are read from every branch of its local copy, or from the GitHub API when it is only there. A commit is counted once, in the first repository that holds it, by its time and subject. Bots are left out, and the times are counted in Copenhagen time.

#### Commits in RAMTT monorepo

[4,875](#m-commits-RAMTT)

Read on [11 Oct 2026](#m-commits-RAMTT) in `~/Projects/RAMTT`.

The command read [6,343](#m-commits-RAMTT) commits without bots, and [1,468](#m-commits-RAMTT) of them are counted in another repository that holds the same commit.

The command for commits in RAMTT monorepo

```
git -C ~/Projects/RAMTT fetch --quiet origin && git -C ~/Projects/RAMTT log --all --format=%aI%x09%an%x09%s
```

#### Commits in Zibaldone

[1,565](#m-commits-zibaldone)

Read on [11 Oct 2026](#m-commits-zibaldone) in `~/Projects/zibaldone`.

The command read [1,570](#m-commits-zibaldone) commits without bots, and [5](#m-commits-zibaldone) of them are counted in another repository that holds the same commit.

The command for commits in Zibaldone

```
git -C ~/Projects/zibaldone fetch --quiet origin && git -C ~/Projects/zibaldone log --all --format=%aI%x09%an%x09%s
```

#### Commits in Design system

[1,092](#m-commits-ramtt-design-system)

Read on [11 Oct 2026](#m-commits-ramtt-design-system) in `~/Projects/ramtt-design-system`.

The command read [1,132](#m-commits-ramtt-design-system) commits without bots, and [40](#m-commits-ramtt-design-system) of them are counted in another repository that holds the same commit.

The command for commits in Design system

```
git -C ~/Projects/ramtt-design-system fetch --quiet origin && git -C ~/Projects/ramtt-design-system log --all --format=%aI%x09%an%x09%s
```

#### Commits in Context bundle

[76](#m-commits-ramtt-context)

Read on [11 Oct 2026](#m-commits-ramtt-context) in `~/Projects/ramtt-context`.

The command for commits in Context bundle

```
git -C ~/Projects/ramtt-context fetch --quiet origin && git -C ~/Projects/ramtt-context log --all --format=%aI%x09%an%x09%s
```

#### Commits in Portfolio

[418](#m-commits-portfolio)

Read on [11 Oct 2026](#m-commits-portfolio) in the portfolio folder.

The command for commits in Portfolio

```
git -C . fetch --quiet origin && git -C . log --all --format=%aI%x09%an%x09%s
```

#### Commits in Studio site

[5](#m-commits-cho52-studio)

Read on [11 Oct 2026](#m-commits-cho52-studio) in `~/Projects/cho52-studio`.

The command for commits in Studio site

```
git -C ~/Projects/cho52-studio fetch --quiet origin && git -C ~/Projects/cho52-studio log --all --format=%aI%x09%an%x09%s
```

#### Commits in RAMTT marketing

[27](#m-commits-ramtt-marketing)

Read on [11 Oct 2026](#m-commits-ramtt-marketing) in `~/Projects/ramtt-marketing`.

The command for commits in RAMTT marketing

```
git -C ~/Projects/ramtt-marketing fetch --quiet origin && git -C ~/Projects/ramtt-marketing log --all --format=%aI%x09%an%x09%s
```

#### Commits in Dotfiles

[9](#m-commits-dotfiles)

Read on [11 Oct 2026](#m-commits-dotfiles) in `~/Projects/dotfiles`.

The command for commits in Dotfiles

```
git -C ~/Projects/dotfiles fetch --quiet origin && git -C ~/Projects/dotfiles log --all --format=%aI%x09%an%x09%s
```

#### Commits in RAMTT before the rewrite

[115](#m-commits-ramtt-before-rewrite)

Read on [11 Oct 2026](#m-commits-ramtt-before-rewrite) in `~/ramtt_bank/ramtt-arkiv/2026-08-omlaegningen/_mirror-foer-rewrite.git`.

The command read [2,397](#m-commits-ramtt-before-rewrite) commits without bots, and [2,282](#m-commits-ramtt-before-rewrite) of them are counted in another repository that holds the same commit.

The command for commits in RAMTT before the rewrite

```
git -C ~/ramtt_bank/ramtt-arkiv/2026-08-omlaegningen/_mirror-foer-rewrite.git log --all --format=%aI%x09%an%x09%s
```

#### Commits in First platform

[824](#m-commits-ramtt-legacy-)

Read on [11 Oct 2026](#m-commits-ramtt-legacy-) in the GitHub API.

The command for commits in First platform

```
gh api --paginate "repos/RAMTT-HQ/ramtt-legacy-/commits?per_page=100" --jq '.[] | [.commit.author.date, .commit.author.name, (.commit.message | split("\n")[0])] | @tsv'
```

#### Commits in First website

[21](#m-commits-ramtt-website)

Read on [11 Oct 2026](#m-commits-ramtt-website) in the GitHub API.

The command for commits in First website

```
gh api --paginate "repos/RAMTT-HQ/ramtt-website/commits?per_page=100" --jq '.[] | [.commit.author.date, .commit.author.name, (.commit.message | split("\n")[0])] | @tsv'
```

#### Commits in Prototypes

[7](#m-commits-ramtt-build-prototypes-v2)

Read on [11 Oct 2026](#m-commits-ramtt-build-prototypes-v2) in the GitHub API.

The command for commits in Prototypes

```
gh api --paginate "repos/RAMTT-HQ/ramtt-build-prototypes-v2/commits?per_page=100" --jq '.[] | [.commit.author.date, .commit.author.name, (.commit.message | split("\n")[0])] | @tsv'
```

#### Commits in Second website

[18](#m-commits-ramtt-website-v2)

Read on [11 Oct 2026](#m-commits-ramtt-website-v2) in the GitHub API.

The command for commits in Second website

```
gh api --paginate "repos/maltetherkildsen-web/ramtt-website-v2/commits?per_page=100" --jq '.[] | [.commit.author.date, .commit.author.name, (.commit.message | split("\n")[0])] | @tsv'
```

#### Commits in RAMTT Cowork

[3](#m-commits-RAMTT-Cowork)

Read on [11 Oct 2026](#m-commits-RAMTT-Cowork) in the GitHub API.

The command for commits in RAMTT Cowork

```
gh api --paginate "repos/maltetherkildsen-web/RAMTT-Cowork/commits?per_page=100" --jq '.[] | [.commit.author.date, .commit.author.name, (.commit.message | split("\n")[0])] | @tsv'
```

#### Commits in Design Cowork

[2](#m-commits-ramtt_design_cowork)

Read on [11 Oct 2026](#m-commits-ramtt_design_cowork) in the GitHub API.

The command for commits in Design Cowork

```
gh api --paginate "repos/maltetherkildsen-web/ramtt_design_cowork/commits?per_page=100" --jq '.[] | [.commit.author.date, .commit.author.name, (.commit.message | split("\n")[0])] | @tsv'
```

#### Repositories

[15](#m-repositories)

It counts the repositories that hold at least one commit. It is calculated from [the commits of each repository](#g-commits).

#### Commits

[9,057](#m-commits)

It adds up the commits of every repository, each commit counted once. It is calculated from [the commits of each repository](#g-commits).

#### First commit

[25 Jan 2026](#m-first-commit)

It is the earliest commit date in Copenhagen time. It is calculated from [the commits of each repository](#g-commits).

#### Last commit

[11 Oct 2026](#m-last-commit)

It is the latest commit date in Copenhagen time. It is calculated from [the commits of each repository](#g-commits).

#### Active days

[214](#m-active-days)

It counts the dates in Copenhagen time that have at least one commit. It is calculated from [the commits of each repository](#g-commits).

#### Days in the period

[260](#m-span-days)

It counts the days from the first commit to the last, both included. It is calculated from [first commit](#m-first-commit) and [last commit](#m-last-commit).

#### Longest streak

[67](#m-longest-streak)days

It is the longest run of dates in a row that each have a commit. It is calculated from [the commits of each repository](#g-commits).

#### Busiest day

[524](#m-busiest-day)commits

It is the date with the most commits, and the date is kept with the number. It is calculated from [the commits of each repository](#g-commits).

#### Commits between midnight and six

[3,565](#m-night-commits)

It counts the commits made before six in the morning, Copenhagen time. It is calculated from [the commits of each repository](#g-commits).

### Pull requests

Merged pull requests are read with the GitHub CLI.

#### Merged pull requests in RAMTT monorepo

[497](#m-prs-RAMTT)

Read on [11 Oct 2026](#m-prs-RAMTT) in the GitHub API.

The command for merged pull requests in RAMTT monorepo

```
gh pr list -R RAMTT-HQ/RAMTT --state merged --limit 5000 --json number,createdAt,mergedAt --jq '.[] | [.number, .createdAt, .mergedAt] | @tsv'
```

#### Merged pull requests in Zibaldone

[317](#m-prs-zibaldone)

Read on [11 Oct 2026](#m-prs-zibaldone) in the GitHub API.

The command for merged pull requests in Zibaldone

```
gh pr list -R RAMTT-HQ/zibaldone --state merged --limit 5000 --json number,createdAt,mergedAt --jq '.[] | [.number, .createdAt, .mergedAt] | @tsv'
```

#### Merged pull requests in Design system

[13](#m-prs-ramtt-design-system)

Read on [11 Oct 2026](#m-prs-ramtt-design-system) in the GitHub API.

The command for merged pull requests in Design system

```
gh pr list -R RAMTT-HQ/ramtt-design-system --state merged --limit 5000 --json number,createdAt,mergedAt --jq '.[] | [.number, .createdAt, .mergedAt] | @tsv'
```

#### Merged pull requests in Context bundle

[13](#m-prs-ramtt-context)

Read on [11 Oct 2026](#m-prs-ramtt-context) in the GitHub API.

The command for merged pull requests in Context bundle

```
gh pr list -R RAMTT-HQ/ramtt-context --state merged --limit 5000 --json number,createdAt,mergedAt --jq '.[] | [.number, .createdAt, .mergedAt] | @tsv'
```

#### Merged pull requests in Portfolio

[147](#m-prs-portfolio)

Read on [11 Oct 2026](#m-prs-portfolio) in the GitHub API.

The command for merged pull requests in Portfolio

```
gh pr list -R maltetherkildsen-web/portfolio --state merged --limit 5000 --json number,createdAt,mergedAt --jq '.[] | [.number, .createdAt, .mergedAt] | @tsv'
```

#### Merged pull requests in Dotfiles

[1](#m-prs-dotfiles)

Read on [11 Oct 2026](#m-prs-dotfiles) in the GitHub API.

The command for merged pull requests in Dotfiles

```
gh pr list -R maltetherkildsen-web/dotfiles --state merged --limit 5000 --json number,createdAt,mergedAt --jq '.[] | [.number, .createdAt, .mergedAt] | @tsv'
```

#### Merged pull requests

[988](#m-prs)

It adds up the merged pull requests in RAMTT monorepo, Zibaldone, Design system, Context bundle, Portfolio and Dotfiles. It is calculated from [merged pull requests in RAMTT monorepo](#m-prs-RAMTT), [merged pull requests in Zibaldone](#m-prs-zibaldone), [merged pull requests in Design system](#m-prs-ramtt-design-system), [merged pull requests in Context bundle](#m-prs-ramtt-context), [merged pull requests in Portfolio](#m-prs-portfolio) and [merged pull requests in Dotfiles](#m-prs-dotfiles).

### Languages

GitHub counts the bytes of each language in each repository.

#### Bytes per language

[14 languages](#m-languages)

Read on [11 Oct 2026](#m-languages) in the GitHub API, once for each repository on GitHub.

The command for bytes per language

```
gh api repos///languages
```

### The codebase

These are counted with git in the local copies of the repositories.

#### Tracked files in the RAMTT monorepo

[11,334](#m-tracked-files)

Read on [11 Oct 2026](#m-tracked-files) in `~/Projects/RAMTT`.

The command for tracked files in the RAMTT monorepo

```
git -C ~/Projects/RAMTT ls-files | wc -l
```

#### TypeScript lines in the RAMTT monorepo

[911,426](#m-ts-lines)

Read on [11 Oct 2026](#m-ts-lines) in `~/Projects/RAMTT`.

The command for typeScript lines in the RAMTT monorepo

```
cd ~/Projects/RAMTT && git ls-files -z '*.ts' '*.tsx' | xargs -0 cat | wc -l
```

#### Test files in the RAMTT monorepo

[1,122](#m-tests-ramtt)

Read on [11 Oct 2026](#m-tests-ramtt) in `~/Projects/RAMTT`.

The command for test files in the RAMTT monorepo

```
git -C ~/Projects/RAMTT ls-files | grep -E '\.(test|spec)\.(ts|tsx|mjs|js)$' | wc -l
```

#### Test files in Zibaldone

[402](#m-tests-zibaldone)

Read on [11 Oct 2026](#m-tests-zibaldone) in `~/Projects/zibaldone`.

The command for test files in Zibaldone

```
git -C ~/Projects/zibaldone ls-files | grep -E '\.(test|spec)\.(ts|tsx|mjs|js)$' | wc -l
```

#### Test files

[1,524](#m-tests)

It adds up the test files in RAMTT and in Zibaldone. It is calculated from [test files in the RAMTT monorepo](#m-tests-ramtt) and [test files in Zibaldone](#m-tests-zibaldone).

#### Database migrations

[109](#m-migrations)

Read on [11 Oct 2026](#m-migrations) in `~/Projects/RAMTT`.

The command for database migrations

```
git -C ~/Projects/RAMTT ls-files | grep -i 'migrations/.*\.sql$' | wc -l
```

#### Guards and audits that fail a build

[128](#m-guards)

Read on [11 Oct 2026](#m-guards) in `~/Projects/RAMTT`.

The command for guards and audits that fail a build

```
cd ~/Projects/RAMTT && node -e "const p=require('./package.json');console.log(Object.keys(p.scripts).filter(k=>/^(audit|lint|guard|check)[:-]/.test(k)).length)"
```

#### Browser scripts that drive a page

[168](#m-browser-scripts)

Read on [11 Oct 2026](#m-browser-scripts) in `~/Projects/RAMTT`.

The command for browser scripts that drive a page

```
git -C ~/Projects/RAMTT ls-files | grep -E '(maal|measure)[^/]*\.(mjs|js|ts)$' | wc -l
```

#### Components specified in the design system

[551](#m-components)

Read on [11 Oct 2026](#m-components) in `~/Projects/ramtt-design-system`.

The command for components specified in the design system

```
git -C ~/Projects/ramtt-design-system fetch --quiet origin r25 && git -C ~/Projects/ramtt-design-system show origin/r25:spec/components.json | python3 -c "import json,sys;c=json.load(sys.stdin)['components'];print(len(c), sum(len(x.get('rules', [])) for x in c.values()))"
```

#### Rules the design system measures its components by

[4,111](#m-component-rules)

Read on [11 Oct 2026](#m-component-rules) in `~/Projects/ramtt-design-system`.

The command for rules the design system measures its components by

```
git -C ~/Projects/ramtt-design-system fetch --quiet origin r25 && git -C ~/Projects/ramtt-design-system show origin/r25:spec/components.json | python3 -c "import json,sys;c=json.load(sys.stdin)['components'];print(len(c), sum(len(x.get('rules', [])) for x in c.values()))"
```

### The prototypes

These are read from the prototypes’ own code, their component library, the files their checks wrote and the last green run of those checks.

#### Components in the component library

[634](#m-library-components)

Read on [11 Oct 2026](#m-library-components) in the portfolio folder.

The command for components in the component library

```
find prototypes/components -mindepth 2 -maxdepth 2 -name index.html | wc -l
```

#### Shelves in the component library

[12](#m-library-shelves)

Read on [11 Oct 2026](#m-library-shelves) in the portfolio folder.

The command for shelves in the component library

```
grep -o 'data-shelf="[^"]*"' prototypes/components/index.html | sort -u | grep -vc '"all"'
```

#### Prototypes

[39](#m-prototypes)

Read on [11 Oct 2026](#m-prototypes) in the portfolio folder.

The command for prototypes

```
node --input-type=module -e "import('./prototypes/source/kit.mjs').then((m) => console.log(m.PROTOTYPES.length))"
```

#### Behavior checks in Chromium

[566](#m-behavior-checks)

Read on [8 Oct 2026](#m-behavior-checks) in the portfolio folder, from `prototypes/source/test/last-check.json`.

The command for behavior checks in Chromium

```
sh ~/scripts/queue.sh sh ~/scripts/heavy.sh sh prototypes/source/test/check-all.sh
```

#### Pages measured against the design system

[117](#m-measured-pages)

Read on [8 Oct 2026](#m-measured-pages) in the portfolio folder, from `prototypes/source/test/last-check.json`.

The command for pages measured against the design system

```
sh ~/scripts/queue.sh sh ~/scripts/heavy.sh sh prototypes/source/test/check-all.sh
```

#### Measured checks on those pages

[48,250](#m-measured-checks)

Read on [8 Oct 2026](#m-measured-checks) in the portfolio folder, from `prototypes/source/test/last-check.json`.

The command for measured checks on those pages

```
sh ~/scripts/queue.sh sh ~/scripts/heavy.sh sh prototypes/source/test/check-all.sh
```

#### Unit tests

[330](#m-unit-tests)

Read on [8 Oct 2026](#m-unit-tests) in the portfolio folder, from `prototypes/source/test/last-check.json`.

The command for unit tests

```
sh ~/scripts/queue.sh sh ~/scripts/heavy.sh sh prototypes/source/test/check-all.sh
```

#### Tests of the language’s official suite that Spark passes

[38,639](#m-spark-pass)

Read on [11 Oct 2026](#m-spark-pass) in the portfolio folder.

The command for tests of the language’s official suite that Spark passes

```
python3 -c "import json;t=json.load(open('prototypes/p39-spark/test262/summary.json'))['totals'];print(sum(x['pass'] for x in t.values()), sum(x['fail'] for x in t.values()))"
```

#### Tests of the language’s official suite that Spark fails

[2](#m-spark-fail)

Read on [11 Oct 2026](#m-spark-fail) in the portfolio folder.

The command for tests of the language’s official suite that Spark fails

```
python3 -c "import json;t=json.load(open('prototypes/p39-spark/test262/summary.json'))['totals'];print(sum(x['pass'] for x in t.values()), sum(x['fail'] for x in t.values()))"
```

No command matches. Try a repository’s name, or a tool such as git or gh.

### How the totals add up

The totals are not counted by a command of their own. They are added up from the counts of each repository. Point at a number to see what it is made from; click it to read its source.

### Rebuilding the site

The first command runs every command above and writes the numbers. The second builds the pages from them.

The commands that build the site

```
node site/collect.mjs
cd web && npm run build
```

Colophon

## How the site is set and served

Set in Inter Variable, kept on the site’s own server and cut to the letters a Latin page uses and the weights from regular to bold, with the optical size kept. In the notes, Galley, the layout engine in the Lab, chooses the line breaks of each paragraph as TeX does and hyphenates with TeX’s patterns.

Built with vinext on Vite, rendered to HTML when the site is built, and served by a Cloudflare Worker at therkildsen.dev. The prototypes run on a second Worker at therkildsen.dev/lab, where a Durable Object with SQLite keeps their data and the contact form’s messages.

A service worker keeps every page on the device, so the site opens without a network, and a message written offline waits there until it can be sent.

The pages are drawn in the RAMTT design system: its tokens, its components and the site’s parts built from them.

Written and built by Malte Therkildsen.
