# Prototemplate: the full text
Every docs page of https://www.prototemplate.com, the handbook's included, in reading order.
# What Prototemplate is
> Prototemplate is Kevin Liu's hub and working wiki for General Translation work: what it holds, who reads it and the order to read it in.
URL: https://www.prototemplate.com/docs
Prototemplate is Kevin Liu's hub and working wiki for his work at General Translation (GT), the localization platform for developers. It is a Next.js 16 site served at [www.prototemplate.com](https://www.prototemplate.com/), the canonical address, with prototemplate.vercel.app and prototemplate.kevinliu.studio as aliases. Two Vercel projects deploy the `main` branch of the public repository, [Kevin-Liu-01/Prototemplate](https://github.com/Kevin-Liu-01/Prototemplate): the General Translation team's project serves www, and Kevin's personal project serves the two aliases.
## The five tabs [#the-five-tabs]
The docs sit in five tabs, and the menu at the top of the sidebar switches between them. The Guide card opens the handbook, and every other card opens its tab's first page.
## The order to read it in [#the-order-to-read-it-in]
An agent reads three things before it works:
1. The [agent guide](https://www.prototemplate.com/docs/handbook/agents).
2. The [operating principles](https://www.prototemplate.com/docs/handbook/operating-principles).
3. The skill for its task at [/skills](https://www.prototemplate.com/skills). The skill's Review checklist is the bar for the work.
A person new to the hub reads in this order:
1. [Get started](https://www.prototemplate.com/docs/get-started), to run the site.
2. The [handbook](https://www.prototemplate.com/docs/handbook), for how the work is done.
3. The tab for the work at hand: [Components](https://www.prototemplate.com/docs/components) to build a surface, [Craft](https://www.prototemplate.com/docs/craft) for the design numbers, [Engineering](https://www.prototemplate.com/docs/engineering) for the browser and build traps, and [Internals](https://www.prototemplate.com/docs/internals) to change the hub itself.
## What it holds [#what-it-holds]
* **The design lab** at `/`: twenty-seven directions for the GT website, each a built page that runs live, with the anatomy wall and the capabilities ledger.
* **The brand book** at `/brand` and the **brand deck** at `/deck`, 93 slides in their own viewer.
* **The handbook** at [/docs/handbook](https://www.prototemplate.com/docs/handbook), a section of these docs: how Kevin runs GT work, and the canon: the agent guide, `BRAND.md`, `DESIGN.md`, `ARCHITECTURE.md`, the ship loop, the tools, the libraries, the graphics pipeline and the artifact pictures.
* **The skills** at [/skills](https://www.prototemplate.com/skills): the curated agent skills, each installable in any project.
* **The marks**, **the graphics** and **the films** at `/marks`, `/graphics` and `/motion`.
* **These docs** at `/docs`, in the layout generaltranslation.com/docs runs, in five tabs: the Guide with the handbook, the live component library at [/docs/components](https://www.prototemplate.com/docs/components) with the blog globe figure under Drawings, Craft, Engineering and Internals.
## Who reads it [#who-reads-it]
* **Kevin**, who reviews every change on localhost before it reaches `main`.
* **Agents** working in this repository, and agents in other repositories that installed its skills or copied its handbook.
* **The brand agency**, which reads the brand book, the deck and the design lab.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Get started
> Clone the repository, install it, check the machine with the doctor, run the dev server, and work beside other sessions in a worktree.
URL: https://www.prototemplate.com/docs/get-started
## Run the site [#run-the-site]
```bash
git clone --filter=blob:none https://github.com/Kevin-Liu-01/Prototemplate.git
cd Prototemplate
pnpm install
pnpm run doctor
git config core.hooksPath .githooks
pnpm dev
```
* `--filter=blob:none` makes a blobless clone. The history holds large reference captures, and a blobless clone downloads an old file's contents only when a command reads it.
* `pnpm install` also writes `.source/`, the compiled docs collection these pages are built from (`fumadocs-mdx`, run as the install's postinstall step).
* `pnpm run doctor` checks Node at the `.nvmrc` major, pnpm at `package.json`'s `packageManager`, the installed packages, the Chrome for Testing build the browser tools launch (`pnpm exec playwright-core install chromium`, or `CHROME_PATH`), and Python 3 with the packages in `requirements.txt`. ffmpeg and the HyperFrames CLI are optional; only the films need them. Each missing item prints the command that fixes it. Write `pnpm run doctor`: a bare `pnpm doctor` runs pnpm's own command.
* The pre-push hook in `.githooks/` runs `pnpm lint:public` and stops a push on any finding: a key shape, a machine path or, with `PT_DENYLIST` set, a term from the private denylist.
* `pnpm dev` serves the site at `http://localhost:3005`.
## Work beside other sessions [#work-beside-other-sessions]
Several agent sessions work in one checkout on Kevin's machine. A lane of work runs in its own git worktree, on its own branch and its own port, so no two sessions compile in the same `.next` folder:
```bash
git worktree add -b k/my-lane ../Prototemplate-wt-my-lane origin/main
cd ../Prototemplate-wt-my-lane
pnpm install --frozen-lockfile
pnpm exec next dev --turbopack --port 3022
```
* Stage explicit paths and commit with a pathspec. Never run `git add -A` or `git add .`: `motion/` belongs to the Videos session and stays untracked.
* Never stop the shared server on 3005, and never build in the shared `.next`.
* The [multi-session playbook](https://www.prototemplate.com/docs/handbook/multi-session-playbook) holds the rules for lanes, collisions and resuming.
## Rules for a shared machine [#rules-for-a-shared-machine]
Several sessions on one machine share its processes and its shell, so a command that is safe for a single user can stop another session's work.
1. Kill a process by its PID only. macOS ships BSD `pkill`, which stops reading options at the first pattern, so every option after it becomes another pattern. On 2026-10-01 `pkill -f "" -P 1` signalled every process whose command line contained "1": about 140 Chrome processes, other sessions' dev servers, a test run and the session's own renders. Record `$!` for each process you start, check it with `ps -o pid,ppid,command -p `, and stop it with `kill `.
2. Quote and brace every variable in zsh, the macOS default shell. A variable named `path` is zsh's array view of `PATH`, so assigning it makes every later command "not found". In `"$B:apps/web"` zsh reads `:a` as a modifier on `$B`, so write `"${B}:apps/web"`. An unquoted variable does not split into words, a glob with no match aborts the whole command line, and a word that starts with `=` is a command lookup, so `echo ====` fails and stops a `&&` chain.
3. Stop a server by the process that listens on its port: `kill $(lsof -ti tcp: -sTCP:LISTEN)`. Without `-sTCP:LISTEN`, `lsof` also returns the browser connected to the port, and the command kills it.
[Agents on one machine](https://www.prototemplate.com/docs/handbook/shared-machine) holds the full set, with memory, disk and long-running commands. [Dev servers and builds](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) covers the failures of `next dev` itself, such as the half-written `.next/dev/prerender-manifest.json` that turns every route into a 500 with "Unexpected non-whitespace character after JSON".
## The repository map [#the-repository-map]
| Folder | What it holds |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `src/app` | One folder per route: the gallery, `/brand`, `/docs`, `/skills`, `/motion`, `/d/` and the rest |
| `src/components` | `viewer` (the shell), `shared`, `shell`, `plate` (the sign-in port), `book` (the handbook's addresses and the Markdown renderer the skills pages use), `docs` (this site's parts, with `docs/demos`, the live plates) and `blog-globe` (the globe figures) |
| `src/lib` | Registries, generated data, the engines, and `seo/`, the SEO system |
| `scripts` | `lib`, `lint`, `check`, `build`, `skills` and `media`; [Scripts and generated files](https://www.prototemplate.com/docs/scripts) covers them |
| `content` | `docs/` (these pages), `blog/` and `authors/` |
| `deck` | The brand deck's slides and parts |
| `graphics` | The illustration toolchain |
| `skills` | The curated skills, one folder each |
| `docs` | The handbook, the ship loop, the libraries index, the graphics pipeline and the tools index |
| `public` | Captures, thumbnails, fonts, media and the built deck |
`AGENTS.md` at the root is the agent's entry point, and `README.md`, `ARCHITECTURE.md`, `DESIGN.md` and `BRAND.md` hold the routes, the code map, the visual laws and the identity.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Handbook
> What the handbook is, who reads it, the order to read it in, and how it relates to the skills.
URL: https://www.prototemplate.com/docs/handbook
This handbook records how Kevin Liu runs his work at General Translation (GT), a localization platform for developers. It is written for the agents and people who work with him: Claude Code and Codex sessions, teammates, and anyone who copies this repository into another project to work the same way. The [skills](https://www.prototemplate.com/skills) hold the procedures for each area of the work. The handbook holds what spans them: the standing principles, the bar for done, the rules for running many sessions and agents at once, pull requests and review, the product facts, the vocabulary and the dated rulings.
The handbook is a section of the docs site, served at /docs/handbook on each of the site's three addresses ([www.prototemplate.com](http://www.prototemplate.com), the canonical one, and the aliases prototemplate.vercel.app and prototemplate.kevinliu.studio). The files live in `docs/handbook/` of the public repository, and each page of the section includes its file, so the site always shows the file as it stands. The section opens with the [agent guide](https://www.prototemplate.com/docs/handbook/agents) and the operating principles. Its Process folder holds seven of the twelve documents below, its Reference folder holds the product map, the glossary, the numbers and the traps and fixes, and its Canon folder holds eight files from the repository's root and `docs/`: [BRAND.md](https://www.prototemplate.com/docs/handbook/brand), [DESIGN.md](https://www.prototemplate.com/docs/handbook/design), the [libraries](https://www.prototemplate.com/docs/handbook/libraries) with the build log, the [graphics pipeline](https://www.prototemplate.com/docs/handbook/graphics), the [artifact pictures](https://www.prototemplate.com/docs/handbook/artifact-pictures), [ARCHITECTURE.md](https://www.prototemplate.com/docs/handbook/architecture), the [ship loop](https://www.prototemplate.com/docs/handbook/ship-loop) and the [tools](https://www.prototemplate.com/docs/handbook/tools). Each page also answers as Markdown at its address plus `.md`. The rest of the docs site explains how the hub works.
## Guide and principles [#guide-and-principles]
## Process [#process]
## Reference [#reference]
## Canon [#canon]
The canon is the eight files at the repository's root and in `docs/` that hold the brand, the design system and the working procedures.
## The documents [#the-documents]
| Document | What it holds | Read it |
| ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| [Operating principles](https://www.prototemplate.com/docs/handbook/operating-principles) | The eighteen standing rules behind Kevin's corrections, each with how to apply it, the skill that holds its procedure and the dated directive it comes from | Before the first task of any GT work |
| [Quality bar](https://www.prototemplate.com/docs/handbook/quality-bar) | The measurable bar for each kind of artifact and for done, each row with the skill that owns it | Before showing Kevin work or shipping it |
| [Multi-session playbook](https://www.prototemplate.com/docs/handbook/multi-session-playbook) | Lanes, forked sessions, one instruction sent to several sessions, shared checkouts, collisions, Claude and Codex on one main, relay notes and shared resources | When another session works on the same machine or repository |
| [Decisions log](https://www.prototemplate.com/docs/handbook/decisions) | Kevin's dated rulings, what each replaced, his words and the lint, gate or skill that holds it | Before changing a standard, and when two sources disagree |
| [Agents on one machine](https://www.prototemplate.com/docs/handbook/shared-machine) | Stopping processes by their ids, zsh traps, exit-status gates, memory and disk, long commands and shared checkouts, each with the incident that set it | Before running agents, builds or servers on a machine other sessions use |
| [Agent workflows](https://www.prototemplate.com/docs/handbook/workflows) | Lane prompts that survive relayed messages, resuming a run, workflow shapes, refuters, kinds of check and paid model runs | Before launching subagents or a long autonomous run |
| [Pull requests and CI](https://www.prototemplate.com/docs/handbook/pull-requests) | CI signals that mislead, the review bots, pull request size and crops, parity for a redesigned flow, lints and ratchets, and git on shared trees | Before opening, updating or reporting a pull request |
| [Reviewing with Kevin](https://www.prototemplate.com/docs/handbook/review) | How his review words map to measures, one exemplar before a set, how a result reaches him, the ship states and the ask ledger | Before showing Kevin work and when reading his feedback |
| [GT product and architecture map](https://www.prototemplate.com/docs/handbook/gt-product-map) | What GT sells and to whom, how the products fit together, the copy that must be exact, the CLI and agent entry points, and the repositories | Before writing about, designing for or changing a GT product |
| [Glossary](https://www.prototemplate.com/docs/handbook/glossary) | The terms in Kevin's messages, the skills and the code, each with where it lives | When a word in a request or a skill is unfamiliar |
| [Numbers](https://www.prototemplate.com/docs/handbook/numbers) | Every load-bearing number by area, each with its reason, its token or constant, the lint that holds it and the page that explains it | Before changing a size, a duration or a limit, and when a review names one |
| [Traps and fixes](https://www.prototemplate.com/docs/handbook/traps) | One line per trap met in GT work: the symptom, the fix in a few words and the section that explains the cause | When something breaks, and before a round of work in an area |
## How the handbook relates to the skills [#how-the-handbook-relates-to-the-skills]
* A skill holds the procedure. The handbook states the rule and names the skill. When the two disagree, the skill is right, and the change that finds the difference corrects the handbook.
* `AGENTS.md` at the repository root is the entry point for an agent. It summarizes the principles, routes each kind of task to its skill, and points here for depth.
* The skills name handbook files by their paths (`docs/handbook/quality-bar.md`). A project that installs the skills copies this folder and `AGENTS.md` beside them, as README.md's "Import this into another project" section describes.
## Changing the handbook [#changing-the-handbook]
* A new ruling from Kevin goes into the decisions log as a dated row that names what it replaced, and the skill, lint or gate that holds it changes in the same commit.
* A document keeps the writing rules of `gt-voice`: plain declarative sentences, no em dashes, no metaphors, and no contrast pairs.
* The repository is public. No document carries keys, account ids, email addresses, personal details, customer names that generaltranslation.com does not show, unannounced plans or business figures (operating principle 18).
* On the site, a new document needs its page in the folder group of `content/docs/(guide)/handbook/` it belongs to (`(process)`, `(reference)` or `(canon)`), which includes the file with `docs/handbook/.md`, its row in that folder's `meta.json`, its entry in `src/app/handbook/registry.ts` in the same order, its card on the section's index page and its headings in `HANDBOOK_HEADINGS` (`src/lib/search-index.ts`). A page that sets live figures between sections includes the file one heading at a time, and the build fails when such a page leaves a heading of the file out. The `prototemplate` skill (section 6) lists every step, and `pnpm lint:registries` reports what a change missed.
## Sources [#sources]
* The first six documents were written on 2026-10-05 from Kevin's messages to Claude Code and Codex between 2026-07-20 and 2026-10-05, about 5,800 in all, and from the curated skills. The four Process documents on agents on one machine, agent workflows, pull requests and review were added on 2026-10-21 from the skills and the incident records behind them, and the numbers and the traps and fixes were added the same day as indexes of the docs pages and skills that hold each value and each failure. Each document's Sources section lists its own evidence.
* Kevin, 2026-10-05: "this prototemplate is supposed to be my hub for general translation work, but also i should be able to use it anywhere and build on top of it so it also acts as a wiki / repository of how i do work at GT".
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Agent guide
> The entry point for an agent: the read order, the principles in brief, the skill for each task, the house rules and using the hub elsewhere.
URL: https://www.prototemplate.com/docs/handbook/agents
General Translation (GT) builds localization tools for developers: open-source i18n libraries, a translation platform and the Locadex agent. Prototemplate is Kevin Liu's hub for his GT work and the wiki of how he does it. It holds the brand and design canon, the brand deck, the design lab, the curated skills and the handbook, and serves all of it at [www.prototemplate.com](http://www.prototemplate.com), the canonical address, and at the aliases prototemplate.vercel.app and prototemplate.kevinliu.studio. The General Translation team's Vercel project serves the first and Kevin's personal Vercel project serves the other two, and both projects deploy this repository's main branch. This file is the entry point for an agent working in this repository, or in another project that imported the hub. It is short on purpose: the skills hold the procedures and the handbook holds the depth.
Kevin's own words, 2026-10-05: "this prototemplate is supposed to be my hub for general translation work, but also i should be able to use it anywhere and build on top of it so it also acts as a wiki / repository of how i do work at GT".
## Read in this order [#read-in-this-order]
1. This file.
2. [Operating principles](https://www.prototemplate.com/docs/handbook/operating-principles), before the first task.
3. The skill for the task, from the routing table below. Its Review checklist is the bar for the work.
4. [Quality bar](https://www.prototemplate.com/docs/handbook/quality-bar), before showing Kevin anything or shipping it.
5. [Decisions log](https://www.prototemplate.com/docs/handbook/decisions), before changing a standard or when two sources disagree.
## The principles in brief [#the-principles-in-brief]
The [operating principles](https://www.prototemplate.com/docs/handbook/operating-principles) hold all eighteen with their sources.
1. Finish everything that was asked. "Continue" resumes every open item and every open lane.
2. Do every step an agent can do, and collect what only Kevin can do (a login, a payment, an approval) into one numbered list.
3. Change only what was asked, keep what he approved, and after a rejection restore the exact earlier state.
4. Fix the whole class of a defect, and add the lint or test that keeps it from coming back.
5. Measure the rendered result at the spot Kevin flagged. A page that loads is a proxy check and proves nothing about the look.
6. Show the result before he asks: before and after crops, a running URL, a gallery of takes.
7. Use real content and real assets, sourced and credited. Invent no quotes, numbers or logos.
8. Ship nothing unnecessary, and prefer the free and cheap design.
9. Keep secrets in protected files, and keep private facts off this public repository.
10. Codify what worked as a skill, a document or a lint that any agent can load.
## Which skill to load [#which-skill-to-load]
The skills live in `skills//SKILL.md`. In this repository they are already linked into `.claude/skills` and `.agents/skills`, so Claude Code, Codex and other Agent Skills loaders find them by name. [skills/README.md](https://www.prototemplate.com/skills) lists them by area. The Tools column names the pnpm commands for the task, run from this checkout; [docs/TOOLS.md](https://www.prototemplate.com/docs/handbook/tools), served at /docs/handbook/tools, lists every command and the scripts the skills bundle.
| Task | Skill | Tools |
| ------------------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------ |
| Writing any text: copy, docs, captions, PRs, posts, Slack | `gt-voice` | `pnpm lint:code` (em dashes, eyebrows and heading periods in code) |
| Ending a turn, reporting state, the PR slate, decision lists | `gt-reporting` | `pnpm check:pages --sheets` (contact sheets) |
| A page, doc, route or build of generaltranslation.com | `gt-website` (with gt-cloud's own `gt-landing`) | `pnpm check:pages --base --pages-module `, `pnpm lint:lines ` |
| A landing, pricing, enterprise or careers page | `gt-landing-pages` | `pnpm lint:lines ` |
| Anything in this repository | `prototemplate` | `pnpm lint:static`, `pnpm lint:registries`, `pnpm gen:all` |
| Running or debugging a local server, letting Kevin try a build | `gt-local-dev` | `pnpm dev`, `pnpm run doctor` |
| Lag, frame cost, Lighthouse, a heavy shader or canvas | `gt-performance` | `pnpm check:pages` (layout shift per cell) |
| Design taste, polish, a surface Kevin calls bad or busy | `gt-aesthetic` | `pnpm lint:lines:shell`, `pnpm lint:radius`, `pnpm lint:heads` |
| The brand, the one Inter, marks and third-party logos | `gt-brand` | `pnpm lint:type`, `pnpm build:marks` |
| A slide, the brand deck or any GT presentation | `gt-deck` | `pnpm build:deck` |
| Options, directions, variants, converging on a pick | `gt-explorations` | `pnpm capture:pages --direction ` |
| A lint, a gate, a new rule to enforce | `gt-lints` | `pnpm lint:static`, `pnpm lint:all`, `pnpm lint:public` |
| Proving a fix or feature is done | `gt-verify` | `pnpm check:pages`, `pnpm lint:lines ` |
| Commits, PRs, review bots, stacks, landing | `gt-ship` | `pnpm build`, `pnpm build:updated --staged`, `pnpm lint:public` |
| Workflows, subagents, briefs, handoffs, resuming after a stop | `gt-orchestration` | `pnpm skills:usage` |
| Animation of any kind | `gt-motion` | `pnpm check:pages` (interactions) |
| A blog or launch graphic | `gt-graphics` | none; the toolchain in `graphics/` (docs/GRAPHICS.md) |
| Dithered fields and artifact pictures | `gt-dither` | `pnpm mood-tone`, `pnpm lint:pictures` |
| A film, trailer, promo or demo GIF | `gt-films` | `pnpm build:motion` |
| A diagram or an isometric drawing | `gt-diagrams` | none |
| UI components and how product UI behaves | `gt-components` | `pnpm lint:code` |
| A product surface (sign-in, onboarding, the dashboard) and reviewing its states | `gt-product-surfaces` | none |
## The handbook [#the-handbook]
[docs/handbook/](https://www.prototemplate.com/docs/handbook), also served at /docs/handbook:
* [Operating principles](https://www.prototemplate.com/docs/handbook/operating-principles): the standing rules and where each procedure lives.
* [Quality bar](https://www.prototemplate.com/docs/handbook/quality-bar): the bar for each kind of artifact and for done.
* [Multi-session playbook](https://www.prototemplate.com/docs/handbook/multi-session-playbook): lanes, forks, shared checkouts, collisions, Claude and Codex on one main.
* [Decisions log](https://www.prototemplate.com/docs/handbook/decisions): Kevin's dated rulings and what each replaced.
* [Agents on one machine](https://www.prototemplate.com/docs/handbook/shared-machine): stopping processes by id, zsh traps, exit-status gates, memory and disk, long commands.
* [Agent workflows](https://www.prototemplate.com/docs/handbook/workflows): lane prompts, resuming a run, workflow shapes, refuters, kinds of check, paid model runs.
* [Pull requests and CI](https://www.prototemplate.com/docs/handbook/pull-requests): misleading CI signals, review bots, size and crops, parity, git on shared trees.
* [Reviewing with Kevin](https://www.prototemplate.com/docs/handbook/review): his review words as measures, one exemplar first, showing results, ship states, the ask ledger.
* [GT product and architecture map](https://www.prototemplate.com/docs/handbook/gt-product-map): what GT sells, the copy that must be exact, the repositories.
* [Glossary](https://www.prototemplate.com/docs/handbook/glossary): the working vocabulary and where each term lives.
* [Numbers](https://www.prototemplate.com/docs/handbook/numbers): every load-bearing number by area, with its token, its lint and the page that explains it.
* [Traps and fixes](https://www.prototemplate.com/docs/handbook/traps): one line per trap, the symptom first, then the fix and the section that explains it.
On the site the handbook is one section of the docs site. It opens with this guide and the operating principles, then three folders: Process (the quality bar, the playbook, the decisions log, and the documents on one machine, workflows, pull requests and review), Reference (the product map, the glossary, the numbers and the traps and fixes) and Canon (BRAND.md, DESIGN.md, the libraries with the build log, the graphics pipeline, the artifact pictures, ARCHITECTURE.md, the ship loop and the tools). Each file has a page under `content/docs/(guide)/handbook/` that shows it through fumadocs-mdx's include tag, so the Markdown file stays the one source. A document added to the handbook or the canon gets its page there, and a page that includes its file one heading at a time (to set a live plate between two sections) lists every heading of the file, or the build fails. The rest of the docs site at /docs explains how the hub works, holds the live component library under /docs/components and records the directions for the blog globe figure.
## House rules [#house-rules]
* **Writing.** Plain technical English: complete declarative sentences, no em dashes, no metaphors, no "X, not Y" pairs, no signposts and no eyebrows. Headings are plain nouns in sentence case with no trailing period (`gt-voice`).
* **Type.** Inter is the only typeface, the self-hosted rsms InterVariable, at weight 500 or less, read through the type tokens. `pnpm lint:type` holds it (`gt-brand`).
* **Lines.** Every line is drawn once by one owner, in one of three roles (DESIGN.md section 2). `pnpm lint:lines:shell` holds it.
* **Corners.** Rounded controls, square shells: controls and cards at 6px, chips at 4px, and only the shells square (DESIGN.md section 2, Corners). `pnpm lint:radius` holds it.
* **Pages.** Every page with a book head follows one structure (DESIGN.md section 4, The book page). `pnpm lint:heads` holds it.
* **Explorations stay local.** New directions and redesign rounds stay uncommitted or on a branch until Kevin reviews them on localhost and says to land them (`gt-explorations`, `gt-ship` section 8).
* **One session per lane.** Several sessions share this checkout. Work that belongs to another lane goes to that session by name, `motion/` belongs to the Videos session and stays untracked, and nobody runs `git add -A` or `git add .` (`docs/handbook/multi-session-playbook.md`, `prototemplate` section 8).
* **Commits.** Stage explicit paths and commit with a pathspec. Prototemplate commits author as Kevin with his GitHub noreply address and keep the session's `Co-Authored-By:` trailer (`docs/SHIP-LOOP.md` section 6). gt-cloud commits carry the repository's configured General Translation work identity, which its Vercel deploys require; never set that identity globally (`gt-ship` section 2).
* **Landing.** Kevin merges, or says to merge. In this repository nothing reaches main until he has reviewed it on localhost.
* **Privacy.** The repository and the site are public. No keys, tokens, account ids, email addresses, personal details, unannounced plans or business figures go into a file, a capture or a commit (operating principle 18).
## Working in this repository [#working-in-this-repository]
```bash
pnpm install
pnpm run doctor # what this machine is missing to run the tools
pnpm dev # http://localhost:3005
pnpm exec tsc --noEmit # 3 to 5 minutes
pnpm lint:static # every lint and test that needs no server (the lane and CI gate)
pnpm lint:all # lint:static, then the live audits against PT_BASE (default 3005)
pnpm check:pages --preset quick --pages # eight devices in dark and 1440x900 in light on the touched pages
```
* Reuse the dev server on 3005 when it is running, and never build in the shared `.next`. The build gate runs in a scratch worktree with `&&` (`gt-ship` section 8).
* The browser lints launch the Chrome for Testing build `playwright-core` installs (`pnpm exec playwright-core install chromium`); `CHROME_PATH` overrides it.
* Generated files change only through their scripts: `pnpm build:skills` (`src/lib/skills.ts`, `skills/README.md`), `pnpm build:updated` (`src/lib/updated.ts`), `pnpm build:deck`, `pnpm build:marks`, `pnpm build:tools` (`docs/TOOLS.md`); `pnpm gen:all` runs every one of them. `pnpm build:motion` runs only when the Videos session hands a film over (`gt-films` section 11).
* `README.md` maps the routes, `ARCHITECTURE.md` the code, `DESIGN.md` the visual laws and `BRAND.md` the identity.
## Using the hub in another project [#using-the-hub-in-another-project]
README.md's "Import this into another project" section gives the commands. In short:
1. Copy `skills/` and `scripts/skills/install.mjs` to the project's root, then run `node scripts/skills/install.mjs --project . --dry-run` there and again without `--dry-run`. The skills land as relative links in `.claude/skills` and `.agents/skills`, the layout this repository uses.
2. Copy `AGENTS.md`, `BRAND.md`, `DESIGN.md` and `docs/handbook/` beside them, so every link between the skills, the canon and the handbook keeps working, and add a `CLAUDE.md` that imports `AGENTS.md`.
3. Edit the copied `AGENTS.md`: the project's name and purpose, its own commands and ports, its lanes, and its own gates. Keep the principles, the routing table and the house rules that still apply.
4. Read the current canon by its address on the site ([www.prototemplate.com/docs/handbook/design](http://www.prototemplate.com/docs/handbook/design), `/docs/handbook`, `/skills/`), and copy the folders again to take later changes. The docs site's last page, [www.prototemplate.com/docs/template](http://www.prototemplate.com/docs/template), explains how to lift the docs site itself into the project.
## Ending a turn [#ending-a-turn]
A turn that changed something ends the way `gt-reporting` section 4 sets out: the answer to what Kevin asked in the first line, what shipped with its exact state, something he can see, a numbered list of what only he can do, and the risks, numbered so he can answer by number.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Operating principles
> The eighteen standing rules behind Kevin’s corrections, each with how to apply it, the skill that holds it and its dated directive.
URL: https://www.prototemplate.com/docs/handbook/operating-principles
General Translation (GT) is a localization platform for developers. Kevin Liu does design, website and product work at GT, and he runs it through several Claude Code and Codex sessions at once. The eighteen rules below come from his corrections to that work between 2026-07-20 and 2026-10-08. Read them before the first task of any GT work with him.
Each rule names the skill or document that holds its procedure. Where the two disagree, the skill is right and this page needs a fix. The [glossary](https://www.prototemplate.com/docs/handbook/glossary) defines working terms such as lane and feature flag. The [quality bar](https://www.prototemplate.com/docs/handbook/quality-bar) sets the bar for each kind of artifact, and the [product map](https://www.prototemplate.com/docs/handbook/gt-product-map) describes what GT sells and how its products fit together.
## 1. Keep going until everything is done [#1-keep-going-until-everything-is-done]
Run every wave of a plan to completion without stopping between waves to ask for permission. "Continue", "continue all" and "keep going" resume every open lane and every unfinished item. When an agent dies on a usage limit, an outage or a closed app, check the working tree, then resume the agent with its brief intact (`gt-orchestration` section 6). Do the hard items as well and report each one. Spend the time on the fixes, and write tests to prove them.
Kevin, 2026-09-09: "can we just do all of our updates? why are you holding back". He said the same on 2026-07-24 and 2026-09-12.
## 2. Do the work yourself and ask once for what only Kevin can do [#2-do-the-work-yourself-and-ask-once-for-what-only-kevin-can-do]
Do every step an agent can do, including console setup through a CLI (`vercel`, `gh`, `gcloud`) or the browser page Kevin already has open. Collect what only he can do (a login, a payment, a credential consent, an approval, a Linear issue id) into one numbered list with the exact file, line or URL for each item. A blanket approval covers the plan it answers. The safety lines still hold. Before a step that cannot be undone, such as a merge over recent work, check that nothing is lost. Wait for his word on a force push, a production deploy to GT's Vercel team, new spend, or landing an exploration round on Prototemplate main (`gt-ship` section 8).
Kevin, 2026-10-05: "anything approved is approved from me." Also 2026-07-20 and 2026-10-02.
## 3. Change only what was asked [#3-change-only-what-was-asked]
Make the smallest literal change that answers the request. "Move it down" means translate it and keep its angle and easing. When a request could mean a small or a large change, make the small one or ask. When a fix spreads into neighbouring behaviour, assets or metadata, revert the extra changes exactly and apply the narrow change. An image Kevin pastes is the whole spec.
Kevin, 2026-08-06: "why did so much change, i just wanted to alter the connectors and line coming up". On 2026-08-07 a landing update had also redone the OG image, the favicon and the metadata, and he said there was no need.
## 4. Keep approved work [#4-keep-approved-work]
Before changing a surface, list what Kevin praised on it and carry every item forward, because a rewrite that drops an approved element is a regression. When he rejects a direction, restore the files to exactly their state before the rejected change and rebuild from there, since the rejected version is never the base of the next attempt. Commit early in each round on a local branch so git holds the restore point, and archive each published version before overwriting it. The dated verdicts are in `gt-aesthetic` section 2, and the restore and archive steps are in `gt-explorations` section 6 (After a rejection) and section 7 (Archive before overwriting).
Kevin, 2026-08-07: "lets redo this to before i started asking for this change and rebuild". Also 2026-07-30 and 2026-10-03.
## 5. Fix the whole class [#5-fix-the-whole-class]
When Kevin flags one instance (an icon, a footer, a flag chip, a double border), enumerate the class programmatically with grep, a registry, a lint or a measurable check, fix every member, verify each one and report the count. The sweep repeats the requested change on each instance of the same defect, and rule 3 still holds for everything around them. When he likes a treatment in one place, apply it to the sibling components. The cross-app sweep is in `gt-components` (Standardization), and the fixes by failure class are in `gt-lints` section 6.
Kevin, 2026-09-28: "look for ANYWHERE ELSE icons nneed to be synced". Also 2026-08-03.
## 6. Find the root cause and guard it [#6-find-the-root-cause-and-guard-it]
Diagnose before editing: read the computed values of the element Kevin selected, read the full log, and reproduce with the deployed environment. Fix the cause, then add the regression test or lint that keeps the class from returning (`gt-lints` section 4). Error handling keeps the underlying error in its message and never substitutes a guessed cause.
Kevin, 2026-08-18: "right but why is the fetch failing". Also 2026-08-05.
## 7. Measure the rendered result [#7-measure-the-rendered-result]
A fix is reported only with visual or measured proof of the rendered result at the place Kevin flagged: computed styles on the live element, 2x crops of corners and junctions, and every animation state. A code change does not prove the render, and neither does a green proxy check (the page loads, the sizes match) or a settings panel that shows the right value. When a tool reads badly, switch to another one, such as a Playwright capture, and finish the verification yourself. The methods are in `gt-verify`, and the [quality bar](https://www.prototemplate.com/docs/handbook/quality-bar) (Done) states when work counts as finished.
Kevin, 2026-07-30: "no, the borders are still sstraight black, still padding, and borders wrong color". The fix before it had been reported as verified from a screenshot.
## 8. Show the result [#8-show-the-result]
Results reach Kevin as something he can see or hear: before and after crops at the same viewport, the localhost URL with its server running, a page open in his browser, or a small HTML page for a set of images or audio takes. Send them before he asks. The formats are in `gt-reporting` section 1, the review servers and the steps for letting him try a build are in `gt-local-dev` sections 1 and 5, and the crop and PR rules are in `gt-aesthetic` (Showing the work) and `gt-ship` section 4.
Kevin, 2026-10-05: "i cant listen to the voices, make it in html so i can go through and listen to em".
## 9. Real content and real assets [#9-real-content-and-real-assets]
Copy and numbers come from production, the benchmark and data files, or GT's published pages. Never invent testimonials, quotes, metrics, prices or feature promises, and mark placeholder content as placeholder. Marks, logos, flags and scans are the real files, sourced and credited: third-party logos from thesvg.org (`gt-brand` section 5), pictures with their source, license and credit (`gt-dither` section 5), and the search for an asset continues until the real one is found (`gt-brand` section 8, Third-party material).
Kevin, 2026-08-05: "like these arent real quotes", about a testimonial block an agent had written.
## 10. Ask only real decisions, with a recommendation [#10-ask-only-real-decisions-with-a-recommendation]
Ask Kevin only what is his to decide: spend, naming, licensing, scope, or an instruction that reads two ways. Ask each as a multiple-choice question with the recommended option first, and batch several into one numbered list with short ids so he can answer inline (`gt-reporting` section 6). When a new state resembles an existing one, reuse the existing behaviour and say so instead of asking. A gate that blocks a requested change is a question for him, and bypassing it silently is a defect.
Kevin, 2026-09-25: "no need to ask me anythiing just do this all for me please".
## 11. Correct from the first frame [#11-correct-from-the-first-frame]
Treat a gap at startup, a flash on reload and lag on the first interaction as defects, even when the page settles a moment later. Check the first frame and the first interaction after a cold load and after a reload, and reserve space so nothing shifts (`gt-verify`, `gt-performance`).
Kevin, 2026-08-08: "if i reload i briefly see 3 layers stacked on top of each other". Also 2026-08-04, on an animation that had to start "without a startup lag".
## 12. Nothing unnecessary ships [#12-nothing-unnecessary-ships]
A release carries no development code. Keep galleries, stand-ins, test-only hooks, dev routes, temporary tests, recorded fixtures and harnesses off the release branch (`gt-ship` section 3). Add no dependency that existing code can replace, keep comments to one or two lines, and keep an unready dashboard feature behind a feature flag.
Kevin, 2026-10-01: "we cant ship anythign unnnecessary". On 2026-08-28 he questioned three packages added for one feature, and since 2026-09-03 a dashboard page that is not ready ships behind a feature flag.
The same rule applies inside a change. Use the platform feature that removes code before adding code, such as a CSS grid row from 0fr to 1fr for an auto height in place of a measured one. When a review asks to test machinery that need not exist, remove the machinery. Kevin, 2026-10-06, on a caption card that measured its own height: "Beautiful but don't complicate. Always simplify."
## 13. Prefer free and cheap [#13-prefer-free-and-cheap]
Challenge any design that adds paid infrastructure, and lay out the free alternative with numbers first. Use the cheapest model that performs well enough, put spend caps on paid model runs (`gt-orchestration` section 7), and turn off git-triggered preview deploys where they only cost money: the landing builds main and staging only (`gt-website` section 8). Check which account a cost lands on before acting.
Kevin, 2026-09-15: "make a new pr to not allow preview deployments from git in landing, this is running up a lot of costs".
## 14. Secrets stay in protected files [#14-secrets-stay-in-protected-files]
Keys and tokens live in a protected config file or a gitignored env file. They never appear in chat, URLs, prompts, commits, docs or PR bodies, and briefs and docs name them by variable name only. When Kevin pastes a key into chat, move it into the env or config file, never echo it or commit it, and tell him it now sits in a transcript so he can rotate it. Never ask him to paste a key into chat.
Kevin's brief, 2026-08-03: "never print a key value".
## 15. "Fully" means complete [#15-fully-means-complete]
When Kevin asks to build out, enhance or update something fully, cover every section and capability with real diagrams, visuals and code, and state why the design works. A placeholder or a partial pass does not count.
Kevin, 2026-08-05: "show actual diagrams and visuialzations and code in these. enhance fully". Also 2026-08-04.
On a page that already exists, "enhance" keeps the page and adds to it: the copy, the sections and the pieces Kevin likes stay. Kevin, 2026-10-08, after a rebuild of the careers page dropped its hero and its copy: "keep the original write up".
## 16. Codify what worked [#16-codify-what-worked]
After something works once, turn it into a skill, a doc, a lint or saved parameters: the prompts that worked and how they were structured, a lint for each standard, and generation parameters saved next to each asset. Every tool and skill belongs to a workflow with a routing doc. A new skill follows the contract in `prototemplate` section 10, and a new lint follows `gt-lints` section 4.
Kevin, 2026-10-05: "create docs and skills for audio creation and generation, what prompts worked and how u structured it". Also 2026-07-24 and 2026-08-06.
## 17. Vendor-agnostic agent tooling [#17-vendor-agnostic-agent-tooling]
Agent tools, skills and scripts work with Codex, Claude Code and local models alike. Skills use the Agent Skills frontmatter fields only, so every loader accepts them (`prototemplate` section 10), and no script hard-wires one provider.
Kevin, 2026-09-10: "be vendor agnostic, dont just ennforce claude code".
## 18. Privacy on public surfaces [#18-privacy-on-public-surfaces]
Prototemplate is public at [www.prototemplate.com](http://www.prototemplate.com) and github.com/Kevin-Liu-01/Prototemplate. Nothing in it carries keys, account ids, email addresses, personal details, customer names that generaltranslation.com does not show, unannounced plans, or business numbers such as funding, revenue and headcount (`gt-brand` section 8, `gt-voice` "Facts and public surfaces"). Colleagues appear by role. `pnpm lint:public` scans every file for key shapes, machine paths and the terms on a private denylist, and the pre-push hook in `.githooks/` runs it.
The rule dates from the brand questionnaire round (2026-08-06 and 2026-08-11) and from 2026-10-05, when Kevin made Prototemplate his public hub for GT work.
## Where the procedures live [#where-the-procedures-live]
| Rules | Skill or document |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| 1, 13 | [`gt-orchestration`](https://www.prototemplate.com/skills/gt-orchestration): resuming agents, briefs, fan-out, spend caps |
| 1, 2 | [Multi-session playbook](https://www.prototemplate.com/docs/handbook/multi-session-playbook): lanes, broadcast messages, relays between Claude and Codex |
| 2, 4, 12 | [`gt-ship`](https://www.prototemplate.com/skills/gt-ship): PR shape, release hygiene, Prototemplate landing and deploys |
| 3, 4 | [`gt-aesthetic`](https://www.prototemplate.com/skills/gt-aesthetic): the reference, the dated verdicts, reading Kevin's asks |
| 4 | [`gt-explorations`](https://www.prototemplate.com/skills/gt-explorations): exploration rounds, archive and restore |
| 5, 6, 16 | [`gt-lints`](https://www.prototemplate.com/skills/gt-lints) and [`gt-components`](https://www.prototemplate.com/skills/gt-components): lints, sweeps, fixes by class |
| 6, 7, 11 | [`gt-verify`](https://www.prototemplate.com/skills/gt-verify): measurement, the viewport matrix, live checks |
| 7, 15 | [Quality bar](https://www.prototemplate.com/docs/handbook/quality-bar): the bar for each kind of artifact and for done |
| 8, 10 | [`gt-reporting`](https://www.prototemplate.com/skills/gt-reporting): crops, galleries, status lines, decision lists |
| 8 | [`gt-local-dev`](https://www.prototemplate.com/skills/gt-local-dev): review servers, letting Kevin try a build |
| 9 | [`gt-brand`](https://www.prototemplate.com/skills/gt-brand) (Third-party material) and [`gt-dither`](https://www.prototemplate.com/skills/gt-dither): real assets, provenance, credits, licences |
| 11, 13 | [`gt-performance`](https://www.prototemplate.com/skills/gt-performance): frame cost, first interaction, Lighthouse |
| 13 | [`gt-website`](https://www.prototemplate.com/skills/gt-website): landing deploys |
| 16, 17 | [`prototemplate`](https://www.prototemplate.com/skills/prototemplate): the skill contract and the hub |
| 18 | [`gt-brand`](https://www.prototemplate.com/skills/gt-brand), [`gt-voice`](https://www.prototemplate.com/skills/gt-voice) and [BRAND.md](https://www.prototemplate.com/docs/handbook/brand): public surfaces |
Kevin's wiki skill `agent-iteration-loop` holds the general loop of implementing, verifying, reviewing and shipping, and these rules apply inside it.
## Sources [#sources]
* Kevin's messages to Claude Code and Codex from 2026-07-20 to 2026-10-05, about 5,800 in all. Quotes keep his spelling. Rules 1, 4, 5 and 8 recur most: about 90 messages ask to continue or resume, 137 to revert or restore an earlier state, 177 for a change "everywhere" or "for all", and 86 to be shown the result. The counts include copies in forked sessions.
* Prototemplate: BRAND.md section 9; `skills/gt-aesthetic` sections 2 and 5; `skills/gt-ship` sections 3, 4 and 8; `skills/gt-lints` sections 1, 4 and 6; `skills/gt-components` (Standardization); `skills/gt-brand` sections 5 and 8; `skills/gt-dither` section 5; `skills/gt-voice` (Hard rules, Facts and public surfaces); `skills/gt-website` section 8; `skills/gt-local-dev` sections 1 and 5; `skills/prototemplate` sections 8 and 10; `docs/handbook/quality-bar.md` and `docs/handbook/glossary.md`.
* Kevin's private gt-cloud memory notes, which hold earlier statements of rules 2, 3, 4 and 12 and the writing rules this page follows, and two notes read on 2026-10-10 for the additions to rules 12 and 15.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Quality bar
> The measurable bar for each kind of artifact, from pages and motion to copy, pull requests and films, and for done, each row with its owner.
URL: https://www.prototemplate.com/docs/handbook/quality-bar
Kevin Liu reviews General Translation (GT) design and site work. Work is ready to show him or to ship when it clears the bars below for its kind of artifact. Each bar names the skill that owns it, and that skill holds the procedure for meeting the bar. When this page and a skill disagree, the skill wins, and the change that finds the difference corrects this page. A bar that no skill holds yet lives on this page, and its Owner column says so.
## The overall bar [#the-overall-bar]
* GT's own finished work is the reference. The brand deck governs product surfaces, and the shipped site, generaltranslation.com, governs landing and marketing pages ([gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 1). The deck is built from `deck/` and served at `/deck`, and the site is built from `apps/landing` on gt-cloud origin/main. From 2026-08-06 the Dossier (`/d/singularity-dossier`) governed the site (Kevin, 2026-08-06: "dossier is indeed our completed version and treat it as such"). On 2026-10-07 Kevin ruled "fix the dossier references", and the Dossier stays in the gallery as the direction the site grew from. Before the deck and the Dossier existed, the July rounds measured against generaltranslation.com and resend.com (Kevin, 2026-07-30).
* Clearing every row on this page is the minimum. The work must also hold up beside its reference at the same geometry, and the convergence loop below checks that.
* When tweaks will not reach the bar, restart from the reference. A version Kevin rejected is never the base of the next attempt ([gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 2). On 2026-08-11 he had the diagrams of the new site pages restarted outright.
* Every page gets a second pass against its reference before it is shown ([gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), verdict of 2026-08-17).
* A bar is met on the rendered result. A gate is a typecheck or a lint. A structural check confirms that a page loads with the right hierarchy and dimensions, and reports also call it a proxy check. A measured check reads computed values or pixels on the render, and a visual check is a person or a fresh critic comparing a crop with its reference. An item that passed only gates and structural checks is reported as unverified ([gt-verify](https://www.prototemplate.com/skills/gt-verify), The definition of done). Every report says which kind of check passed ([gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4; [gt-reporting](https://www.prototemplate.com/skills/gt-reporting), section 1).
## Reading the tables [#reading-the-tables]
Owner is the skill or document that holds the bar, with the section to read. Read is the day the owner was read for this page. Where the owner is this page, Read gives the day Kevin set the bar. Paths are relative to the Prototemplate root, and the [glossary](https://www.prototemplate.com/docs/handbook/glossary) defines terms such as plate, rail and the Dossier.
## Pages [#pages]
The rows apply to product surfaces, the site, Prototemplate's own pages and docs pages.
| Bar | Owner | Read |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| The page matches its reference measure for measure, and every value the reference lacks has a stated reason. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 1 | 2026-10-05 |
| Content comes from production or the prototype spec, and nothing is invented. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), review checklist | 2026-10-05 |
| A display head holds two lines at most at every width. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 4 | 2026-10-05 |
| A lead reads in two or three lines at 60 to 70 characters, and prose stays under 75. `node skills/gt-aesthetic/scripts/measure-type.mjs --strict` passes, or each flag has a reason. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), sections 1 and 4 | 2026-10-05 |
| Nothing overflows its column or the viewport, and no text is clipped. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), review checklist; [gt-lints](https://www.prototemplate.com/skills/gt-lints), check:pages | 2026-10-05 |
| Nothing shifts after first paint, and client-mounted rows reserve their height. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), review checklist; [gt-lints](https://www.prototemplate.com/skills/gt-lints), check:pages | 2026-10-05 |
| Tap targets on a phone are 44px. `check:pages` fails a target under 40px and notes one of 40 to 43px. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 3 (Rhythm); [gt-lints](https://www.prototemplate.com/skills/gt-lints), check:pages | 2026-10-05 |
| Text a reader needs clears 4.5:1 in both themes. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 3 (Hierarchy and contrast) | 2026-10-05 |
| Every line is drawn once by one owner, rules run edge to edge, and junctions pass at 2x crops. In Prototemplate's chrome each line takes the `hair`, `hair-soft` or `edge` role and `pnpm lint:lines:shell` is clean. Any other page passes `pnpm lint:lines ` in both themes. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 3; [DESIGN.md](https://www.prototemplate.com/docs/handbook/design), section 2; [gt-lints](https://www.prototemplate.com/skills/gt-lints), lint:lines | 2026-10-05 |
| The surface carries one dithered material, at the landing hero's strength or under it. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 3 (Material); [gt-dither](https://www.prototemplate.com/skills/gt-dither) | 2026-10-05 |
| The page uses one accent, GT blue, and semantic color sits only on icons. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 3 | 2026-10-05 |
| Each width shows one composition. Intermediate widths and zoomed windows fall to the mobile composition, with no hybrid of desktop logic and mobile layout. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), section 4 | 2026-10-05 |
| The longest translation of every string fits its reserved lines, and the layout holds in CJK, RTL and Indic text as well as Latin. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), section 5; [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 4 | 2026-10-05 |
| Both themes are shot at 1440 and 390 (plate pages also at 1527 by 814), and `pnpm check:pages --preset quick --pages ` shows zero defects on every touched page. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), section 5 (Local review); [gt-lints](https://www.prototemplate.com/skills/gt-lints), section 2 | 2026-10-05 |
| A Prototemplate page with a book head follows the book page standard (nothing drawn above the title, the panel with Updated first, one band ruled on both edges), and its corners follow the radius law. `pnpm lint:heads` and `pnpm lint:radius` pass, live modes included. | [prototemplate](https://www.prototemplate.com/skills/prototemplate), sections 3 and 5; [DESIGN.md](https://www.prototemplate.com/docs/handbook/design), sections 2 and 4 | 2026-10-06 |
| The lints pass: `pnpm lint:all` in Prototemplate and `pnpm lint` in gt-cloud. | [gt-lints](https://www.prototemplate.com/skills/gt-lints), review checklist | 2026-10-05 |
A landing or marketing page also clears the [gt-landing-pages](https://www.prototemplate.com/skills/gt-landing-pages) checklist (one rail, hatch spacers, heads, the shared `Cta`), checked at 390, 768, 1024, 1440 and 1920 in both themes.
## Motion [#motion]
| Bar | Owner | Read |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | ---------- |
| Dither loops draw at their 30 fps budget by design. Every other animation meets the 60 fps bar in the Performance table. | [gt-motion](https://www.prototemplate.com/skills/gt-motion), section 2 (Durations) | 2026-10-05 |
| A language morph lasts longer than 0.5 s, so the glyphs visibly regroup. It finishes inside the time its locale holds the screen, such as one stop of the hero's locale belt. Kevin, 2026-08-05: "the morphings are still way too fast theyre like \<0.5 sec". Later that day he called a slower morph "a lil too long". | This page | 2026-08-05 |
| A morph dissolves through glyphs at every width and never collapses into a fade. | [gt-motion](https://www.prototemplate.com/skills/gt-motion), section 5 | 2026-10-05 |
| A scroll story runs on one scrubbed dial. Each beat owns a scroll range with dwell, and scrolling back plays the story backward. | [gt-motion](https://www.prototemplate.com/skills/gt-motion), section 6 (Scroll stories); [gt-landing-pages](https://www.prototemplate.com/skills/gt-landing-pages), Scroll stories | 2026-10-05 |
| Product pages have no entrance animation. | [gt-motion](https://www.prototemplate.com/skills/gt-motion), section 1 | 2026-10-05 |
| Reduced motion renders a designed still, and the resting markup reads without JavaScript. | [gt-motion](https://www.prototemplate.com/skills/gt-motion), section 1 | 2026-10-05 |
| Scrolling is native (`gt-ui/no-smooth-scroll`). | [gt-motion](https://www.prototemplate.com/skills/gt-motion), section 1 | 2026-10-05 |
| Motion is verified with real pixels from an external browser, in both themes, under reduced motion, at 1440 and 390. | [gt-motion](https://www.prototemplate.com/skills/gt-motion), Verifying motion | 2026-10-05 |
## Graphics and diagrams [#graphics-and-diagrams]
| Bar | Owner | Read |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------- |
| Every crop comes from a registered capture of the real product. An illustrative mock in a set is described as a mock. | [gt-graphics](https://www.prototemplate.com/skills/gt-graphics), What a visual is | 2026-10-05 |
| Text in a blog visual measures 26px or more after the fit, and `pnpm graphics:audit` passes. | [gt-graphics](https://www.prototemplate.com/skills/gt-graphics), Sizing for the blog column | 2026-10-05 |
| Renders are supersampled (shot 7680 wide and halved to 3840). Every visual with lines or small type is read at 1:1 as well as on the contact sheet. | [gt-graphics](https://www.prototemplate.com/skills/gt-graphics), What a visual is and Procedure | 2026-10-05 |
| A diagram shows a relationship the text alone does not, drawn from the real artifact as one connected composition. | [gt-diagrams](https://www.prototemplate.com/skills/gt-diagrams), section 1 | 2026-10-05 |
| Numbers printed in a diagram match what the eye sees. Kevin, 2026-08-05: "yeah it just doesn tlook like +63%". | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), review checklist | 2026-10-05 |
| Junctions are read at 2x crops in both themes, because the line auditor skips SVG. | [gt-diagrams](https://www.prototemplate.com/skills/gt-diagrams), section 9 | 2026-10-05 |
| An OpenGraph card has a composition of its own, apart from the header cover, set in the house type with the house lines and centered on its canvas. It is rendered and looked at after every change, and its size and themes follow [gt-graphics](https://www.prototemplate.com/skills/gt-graphics) (Sizing for the blog column). Kevin, 2026-09-17: "the tweet/blog header cover is the angled one and the opengraph is the exploded components". | This page | 2026-09-17 |
## Copy [#copy]
| Bar | Owner | Read |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ---------- |
| The hard rules hold: no em dashes, metaphors, contrast pairs, fragment rhythm, exclamation marks, rhetorical questions, signposts, eyebrows, marketing vocabulary or emojis. | [gt-voice](https://www.prototemplate.com/skills/gt-voice), Hard rules | 2026-10-05 |
| Every line passes the copy test: it states a number or a mechanism, and a line a competitor could use unchanged is cut. | [gt-voice](https://www.prototemplate.com/skills/gt-voice), Facts and public surfaces | 2026-10-05 |
| The humanizer pass scores 35 of 50 or higher across directness, rhythm, trust, authenticity and density. | [gt-voice](https://www.prototemplate.com/skills/gt-voice), The humanizer pass | 2026-10-05 |
| Heads are plain nouns in sentence case with no trailing period, and Title Case is kept for buttons. | [gt-voice](https://www.prototemplate.com/skills/gt-voice), Headings and casing | 2026-10-05 |
| Every sentence has a subject and a verb, the subject is short, and no aside interrupts a clause. | [gt-voice](https://www.prototemplate.com/skills/gt-voice), Sentence shape | 2026-10-05 |
| Public writing stands alone for a developer who has never heard of Kevin or GT. It defines the product once, and each section opens with the point a stranger can reuse. | [gt-voice](https://www.prototemplate.com/skills/gt-voice), Writing for strangers | 2026-10-05 |
| Nothing sensitive appears on a public surface: funding, revenue, headcount, customer counts or unannounced launches. | [gt-voice](https://www.prototemplate.com/skills/gt-voice), Facts and public surfaces | 2026-10-05 |
## Pull requests [#pull-requests]
| Bar | Owner | Read |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------- |
| On a gt-cloud PR, Greptile reads 5/5 on the head commit. Kevin, 2026-09-13, after a merge at 4/5: "bruh u merged without addressingthis". | [gt-ship](https://www.prototemplate.com/skills/gt-ship), section 5 | 2026-10-05 |
| Every bot thread has a reply naming the fixing commit and is then resolved. | [gt-ship](https://www.prototemplate.com/skills/gt-ship), section 5 | 2026-10-05 |
| The three required checks on gt-cloud main are present and green, and `node skills/gt-ship/scripts/pr-bots.mjs ` exits 0. | [gt-ship](https://www.prototemplate.com/skills/gt-ship), section 5 | 2026-10-05 |
| `node skills/gt-ship/scripts/pr-size.mjs` was read and every large group is justified in the body. The diff holds no recorded fixtures, harnesses, review galleries or planning Markdown. | [gt-ship](https://www.prototemplate.com/skills/gt-ship), section 3 | 2026-10-05 |
| The PR carries one concern under a conventional title, and a `feat` PR links a Linear issue. | [gt-ship](https://www.prototemplate.com/skills/gt-ship), section 3 | 2026-10-05 |
| The body is a two-sentence summary and What to look at, with before and after crops refreshed after every visible change. It is written in Kevin's own register (lowercase, first person), and the crops carry most of the explanation (Kevin, 2026-10-05). | [gt-ship](https://www.prototemplate.com/skills/gt-ship), section 4; [gt-voice](https://www.prototemplate.com/skills/gt-voice), Two registers | 2026-10-05 |
| Kevin merges the PR or says to merge it. | [gt-ship](https://www.prototemplate.com/skills/gt-ship), section 5 | 2026-10-05 |
## Convergence loops [#convergence-loops]
A convergence loop iterates on quality until a bar holds: a page against its reference, a set of graphics against its best accepted item, a film cut against its brief. Kevin, 2026-07-30: "remember the bar is generaltranslation.com and resend.com. literally rereview and continuously score yourself until it look sright".
| Bar | Owner | Read |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | ---------- |
| The brief names the reference and the bar before the first round. For a set, the bar is the best item Kevin has accepted. | [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4 | 2026-10-05 |
| The work and the reference are captured at the same geometry (viewport, theme, camera, crop) and placed side by side. | [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4 | 2026-10-05 |
| A fresh critic that did not build the work scores each view blind against the reference. It is told to be harsh, and it names what the reference does that the work does not. | [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4 | 2026-10-05 |
| Each view has a numeric bar wherever it can be scored, stated in the brief. The bar ends the loop; a cap on rounds is a budget stop, and the report lists the gaps still open. | [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4 | 2026-10-05 |
| One strong view never averages away a weak one, and the builder never scores its own work. | [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4 | 2026-10-05 |
| Refiners fix only the gaps the critic named. | [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4 | 2026-10-05 |
| Kevin's note outranks a critic's pass. An item he called wrong stays open until he says otherwise. | [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4 | 2026-10-05 |
| When scores stop rising, the method changes: measure the reference and rebuild, or change the idea. | [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration), section 4; [gt-films](https://www.prototemplate.com/skills/gt-films), section 3 | 2026-10-05 |
## Performance [#performance]
| Bar | Owner | Read |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------- |
| Performance work leaves the look unchanged. An audit whose fix would change the design (contrast, tap target size, a dropped effect, a lower resolution) goes to Kevin with its measured gain. Kevin, 2026-08-05: "fix the lighthouse without changing anything aesthetically". | [gt-performance](https://www.prototemplate.com/skills/gt-performance), section 1 | 2026-10-05 |
| Animation and interaction run at 60 fps at full resolution. Loops start complete, and the first interaction never stalls. | [gt-performance](https://www.prototemplate.com/skills/gt-performance), section 1 | 2026-10-05 |
| Frame time is measured before and after the change (`node skills/gt-performance/scripts/frame-probe.mjs `) and reported in a table. | [gt-performance](https://www.prototemplate.com/skills/gt-performance), section 2 | 2026-10-05 |
| Every timing carries the machine's load average, and before and after runs go back to back under similar load, because parallel agents distort the numbers. | [gt-performance](https://www.prototemplate.com/skills/gt-performance), section 2 | 2026-10-05 |
| An engine with quality tiers picks its tier from measured frame cost. | [gt-performance](https://www.prototemplate.com/skills/gt-performance), section 3; [gt-motion](https://www.prototemplate.com/skills/gt-motion), section 6 | 2026-10-05 |
| Lighthouse is read from a production build in a clean profile, or from production after the merge, and the PR carries the real report. | [gt-performance](https://www.prototemplate.com/skills/gt-performance), section 6 | 2026-10-05 |
| A budget lives in the probe that measures it and fails like a lint, and a red budget blocks the change. | [gt-performance](https://www.prototemplate.com/skills/gt-performance), section 8 | 2026-10-05 |
## Films [#films]
| Bar | Owner | Read |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ---------- |
| Kevin reads the scripts before the build, which waits for his answer. He picks a new narrator from auditions. | [gt-films](https://www.prototemplate.com/skills/gt-films), sections 3 and 7 | 2026-10-05 |
| A critic watches each draft frame by frame (every 0.5 s, and every 0.25 s around each cut and major move) and reports every defect with its time and a fix. | [gt-films](https://www.prototemplate.com/skills/gt-films), section 9 | 2026-10-05 |
| `node skills/gt-films/scripts/measure-render.mjs` passes on the render (-17 to -15 LUFS, true peak under -1 dBTP, 1920 by 1080 at 60 fps), and `hyperframes check` ends with 0 errors. | [gt-films](https://www.prototemplate.com/skills/gt-films), review checklist | 2026-10-05 |
| A non-English take has a native listener's sign-off. | [gt-films](https://www.prototemplate.com/skills/gt-films), section 7 | 2026-10-05 |
## Charts [#charts]
Kevin set these bars for benchmark charts on 2026-07-30 and 2026-09-30. The wiki's `dataviz` skill holds the general method for form, color and marks.
| Bar | Owner | Read |
| --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ---------- |
| The win is obvious at a glance. | This page | 2026-07-30 |
| Compared series are stacked or overlaid so the margin reads exactly, and the bars in one set share one style. | This page | 2026-07-30 |
| The method is stated beside the chart: what was measured, how, and on what. | This page | 2026-07-30 |
| A metric that shows cost savings is prominent. | This page | 2026-07-30 |
| Benchmarks are run fresh for the chart that ships. | This page | 2026-09-30 |
| The chart leads with the most impressive true metric. Kevin, 2026-09-30: "why just tokens? show our speed diagram too thats more impressive". | This page | 2026-09-30 |
| Marks match their values, and every number agrees with each other place it appears. | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), review checklist | 2026-10-05 |
## Repositories [#repositories]
Kevin set these bars for a repository's own documents between 2026-08-02 and 2026-09-30.
| Bar | Owner | Read |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | ---------- |
| The README holds the shipped product's instructions and stats in a concise form, with the OpenGraph image and a demo GIF at the top and screenshots of what it does. Kevin, 2026-09-30: "youre treating the readme as like a log of work instead of a concise summary". | This page | 2026-09-30 |
| The repository's description and topics are set. | This page | 2026-08-04 |
| A `LICENSE` file states the terms. Prototemplate's license reserves all rights to General Translation, Inc., and third-party fonts, icons and adapted skills keep their own licenses. | [prototemplate](https://www.prototemplate.com/skills/prototemplate), section 10; [LICENSE](https://github.com/Kevin-Liu-01/Prototemplate/blob/main/LICENSE) | 2026-10-05 |
| `AGENTS.md` explains the repository's layout and philosophy, `SKILL.md` explains how to use the tool and everything it does, and both match the code. | This page | 2026-08-02 |
| Prose that has drifted from the code is corrected in the change that finds it. | [prototemplate](https://www.prototemplate.com/skills/prototemplate), section 1 | 2026-10-05 |
## Done [#done]
Work is ready to show when its artifact's table holds on localhost or in a file Kevin can open, and the report carries before and after crops of each changed region in both themes ([gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic), Showing the work). It is ready to ship when the pull request table holds as well. It is done when the rows below hold.
| Bar | Owner | Read |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ---------- |
| A visual fix is measured on the render at the spot Kevin flagged (computed values, 2x or 4x crops, pixel probes), in every state of a moving element. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), section 1 | 2026-10-05 |
| The real gesture and the real flow work in the running app, for every category of item the change covers. Any shortcut is named and then replaced by the real gesture. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), section 2 | 2026-10-05 |
| The stress matrix, viewports, themes, browsers and edge counts that apply were walked. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), sections 3 to 5 | 2026-10-05 |
| Items that were right before the change are still right. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), section 6 | 2026-10-05 |
| Every member of the defect's class was found, fixed and checked. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), section 8 | 2026-10-05 |
| Shipped work is live: every lane's commits are on main, production's commit contains them, the live page carries that deployment's stamp, and the OG card is read live. For Prototemplate, the `dpl` stamp on www equals the team deployment. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), section 7; [gt-ship](https://www.prototemplate.com/skills/gt-ship), section 8 | 2026-10-05 |
| The report says how each item was verified and names what was not, with the reason. | [gt-verify](https://www.prototemplate.com/skills/gt-verify), section 12 | 2026-10-05 |
## Sources [#sources]
* Skills read on 2026-10-05: `skills/gt-aesthetic/SKILL.md` and `references/verdicts.md`, `skills/gt-verify/SKILL.md`, `skills/gt-orchestration/SKILL.md`, `skills/gt-performance/SKILL.md`, `skills/gt-landing-pages/SKILL.md`, `skills/gt-lints/SKILL.md`, `skills/gt-motion/SKILL.md`, `skills/gt-graphics/SKILL.md`, `skills/gt-diagrams/SKILL.md`, `skills/gt-voice/SKILL.md`, `skills/gt-ship/SKILL.md`, `skills/gt-films/SKILL.md`, `skills/gt-dither/SKILL.md`, `skills/gt-reporting/SKILL.md`, `skills/prototemplate/SKILL.md`.
* Canon: `DESIGN.md` section 2, `deck/DECK-GRAMMAR.md`, `docs/SHIP-LOOP.md` section 2, `scripts/check/pagecheck/README.md`, `LICENSE`.
* Kevin's rulings, checked against his messages to Claude Code and Codex: 2026-07-30 (the reference sites, side-by-side scoring, chart margins, method and cost metric), 2026-08-01 and 2026-08-02 (the OpenGraph card's type and lines), 2026-08-02 (`AGENTS.md` and `SKILL.md`), 2026-08-04 (two-line heads, repository topics), 2026-08-05 (morph length, numbers in diagrams, Lighthouse with no visual change), 2026-08-06 (the Dossier), 2026-08-11 (the diagram restart), 2026-08-17 (the second pass), 2026-09-13 (Greptile 5/5), 2026-09-17 (the OpenGraph card's own composition), 2026-09-30 (chart metric, README), 2026-10-05 (the page heads, PR bodies that let the crops explain), 2026-10-07 (the shipped site as the site's reference).
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Multi-session playbook
> How many agent sessions share one machine: lanes, forked sessions, shared checkouts, collisions, Claude and Codex on one main, and resumption.
URL: https://www.prototemplate.com/docs/handbook/multi-session-playbook
Kevin Liu runs many agent sessions on one machine at the same time for his General Translation (GT) work: named Claude Code sessions, Codex sessions, and forks of both. Codex is OpenAI's coding agent, and Kevin runs it beside Claude Code. Inside Claude Code, the ListAgents tool lists the other Claude sessions on the machine by name, and the SendMessage tool delivers a message to one of them. This page holds the practices that let every session add to the others' work and undo none of it.
The single rules live in skills, and this page points to them. [`gt-ship`](https://www.prototemplate.com/skills/gt-ship) sections 1, 2 and 8 hold lanes, worktrees, staging and the shared Prototemplate checkout. [`gt-orchestration`](https://www.prototemplate.com/skills/gt-orchestration) holds a session's own subagents, resumption (section 6) and handoffs at a hard stop (section 8). The [`prototemplate`](https://www.prototemplate.com/skills/prototemplate) skill section 8 holds the lane map of the shared Prototemplate tree. The [glossary](https://www.prototemplate.com/docs/handbook/glossary) defines lane, session, forked session, handoff and relay note. When a skill and this page disagree, the skill wins.
## 1. Lanes [#1-lanes]
One session owns one lane. ListAgents prints the live list of sessions, and the table lists the GT lanes as of 2026-10-05.
| Session | Owns | Where it works |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Prototemplate | The site at prototemplate.com, its viewer shell, the deck build, the skills and the docs | The shared checkout (`$PROTOTEMPLATE`), with the dev server at `http://localhost:3005` |
| Videos | The films, their kit and `MOTION.md` | Prototemplate `motion/`, which stays untracked. Its Prototemplate commits carry only film and poster files in `public/media`. |
| Glyph Map | A page of generaltranslation.com that has not shipped | Its own gt-cloud worktree and dev port |
| New Onboarding and Dashboard | The dashboard sign-in and onboarding PRs, and in Prototemplate the mood slides in `deck/`, `src/components/plate`, `src/app/craft` and `public/brand/mood` | Its own gt-cloud worktrees. It pushes Prototemplate main from its own worktree. |
| Lottie | The blog's Lottie translation figure | Its own gt-cloud worktree and dev port |
| docs redesign | The docs site on generaltranslation.com | Its own gt-cloud worktrees |
Kevin's personal projects run in sessions and repositories of their own. They share the machine with the GT lanes (section 10) and nothing else.
* Work that belongs to another lane goes to that session. Find it with ListAgents and send the request with SendMessage, with Kevin's words for the request and the paths involved. Address the session by its name, because the bracketed id after the name changes when the session restarts.
* Codex sessions do not appear in ListAgents. Reach them through a relay note that Kevin pastes (section 7).
* Two lanes edit `deck/`. The session about to change a shared folder messages the other first (section 8).
* When Kevin narrows a session to one thing, the session drops everything else, including its own open items. While it waits, it starts no PR sweep and no work from another lane.
Kevin, 2026-10-03: "that videos one should be making them, and this one is just for prototemplate work".
* A session that gives up work to another lane sends the work's real state: the files, the commits, what passed and what is open. On 2026-10-03 the Prototemplate session handed two films to Videos with a message that understated how far they had come, and Videos learned the rest from the files. The receiving session reads the files and the git history before it acts on a handover message.
## 2. Forked sessions [#2-forked-sessions]
Kevin forks sessions often. Ten gt-cloud sessions active between August and October descend from one session started on 2026-07-30. Videos was forked from New Onboarding and Dashboard on 2026-10-01, Glyph Map from Videos on 2026-10-02, and the Prototemplate session from New Onboarding and Dashboard on 2026-10-03. A fork starts with its parent's whole message history, and every inherited message reads as if it were addressed to the fork.
* A fork acts on the newest instruction addressed to it and on its own lane. Inherited messages are history. Their asks belong to the parent, which is usually still running and still owns them.
* In a fork, "continue", "continue everything" and "keep going" cover the fork's own lane. Two forks got this wrong. The Glyph Map fork restarted its parent's film build before starting the map, and Kevin stopped it. The Prototemplate fork took "continue everything" as its parent's list and pushed review fixes to the parent's open PRs, one of them from the parent's scratch worktree. Kevin narrowed it twice that day, first to its own request and then to Prototemplate work alone, and the films it had started went to Videos.
Kevin, 2026-10-02: "wait another agent is workign on the motion and videos. just focus on the nnew page".
* Before acting, a fork learns what the parent already did and who holds the parent's lanes now. It reads `git status --short`, `git log --oneline -15` on its branch and on `origin/main`, `git worktree list`, the lane's notes (memory notes, `HANDOFF.md`, the round's spec) and ListAgents.
* A fork takes its own branch, worktree and dev port before it changes any file. Kevin's rule for any conversation, 2026-10-02: "the work in this convo should be on its own worktree branched off from main".
* In a Claude Code transcript (`~/.claude/projects//.jsonl`), an inherited message keeps the parent's `sessionId`. One message of 2026-07-31 sits in eleven gt-cloud transcripts with a single originating `sessionId`. A count of Kevin's messages across transcripts dedupes on `sessionId` and timestamp.
## 3. One instruction to several sessions [#3-one-instruction-to-several-sessions]
Kevin sometimes sends one instruction to several sessions within seconds. On 2026-08-06 "commit and push everything to prototemplate, our branches, and 4213" reached four gt-cloud sessions within 25 seconds. Two of them went after the same three targets. One of the two had its Prototemplate build collide with a concurrent build. The other later saw a worktree directory vanish between two commands, because a parallel session was porting into it.
* Each session does its own part: its own paths, its own branch, its own PR.
* The session whose lane owns a shared step does it, once. Shared steps include a push of Prototemplate main, a sync of files into another repository, and a commit on a PR branch that two sessions use. The other sessions commit their own paths and check whether the shared step already happened (`git fetch`, then `git log --oneline HEAD..origin/` or `gh pr view --json headRefOid`). They report the sha they found. When ownership is unclear, they ask the other session by SendMessage before pushing.
* A diverged branch is never force-pushed to make an instruction come true. On 2026-08-06 the branch of PR #4213 carried eight commits of the landing port that a force push would have erased. The session reported the divergence and offered to port the missing work onto that branch as new commits, which Kevin then asked for.
* When Kevin asks which session did something, answer from git and GitHub: the PR, the branch and commit, and the exact source text or file the work used. When Kevin asked "did we work on docs redesign in this convo?" on 2026-09-01, each session listed the PRs and files its conversation had touched, and the sessions that had not done the redesign said so.
* "Try again" after an API error or a spend limit re-runs the step that failed, starting from a fresh read of the state. On 2026-08-06 a session cut off by the spend limit re-read every target after "Try again" and reported each one clean.
## 4. Shared checkouts [#4-shared-checkouts]
`gt-ship` sections 1, 2 and 8 and `prototemplate` section 8 hold the rules for a shared checkout. They give `motion/` to Videos, require explicit paths and a pathspec commit, check the branch before every commit, keep the primary gt-cloud checkout on its old branch, and leave the Prototemplate dev server on 3005 and its `.next` alone.
* Re-read a shared file immediately before editing it, because another session may have saved it a minute ago.
* Keep scratch output in the session's scratchpad. Every session started in the main gt-cloud checkout reads its `.claude` folder, and on 2026-10-02 a preview written there had to be moved out.
## 5. Collisions [#5-collisions]
* Report another session's in-flight changes and leave them where they are. A lint or type failure in files the session does not own goes into its report and does not hold back its own clean diff (`docs/SHIP-LOOP.md` section 0). Kevin, 2026-07-31: "dont worry about the uncommited work. only worry about localhost3006/ page".
* Keep another session's uncommitted file out of your commit, even when your own tweak sits inside that file. Say in the report that the tweak will land with that session's commit.
* Rerun a failure once before diagnosing it when another session may be mid-save. Such failures include a 500 from hot reload, a page the line auditor refuses, and a type error in a file the other session is editing. On 2026-08-05 `tsc` failed on a parallel edit that used `Code2` before importing it. By the time the session looked, the other session had added the import, and the rerun passed.
* When the build stays broken on another session's change, make the smallest change that restores the build and tell the owner. On 2026-07-31 one session pushed a full sync to Prototemplate main while a second session was mid-push. The second session rebuilt on top of that push and landed one fix: `pnpm-workspace.yaml` held a placeholder line that made `pnpm install` fail.
* When another session's commit regresses your work, measure the regression and send the owner the exact fix. On 2026-09-29 a second session's commit on PR #5021 stopped a gallery state from playing when the console paged to it. The measurement and the fix went to that session, and it fixed the regression on the same PR.
* Fix another session's regression in the smallest unit that regressed (a token, a rule, a layer), and keep the rest of its file. On 2026-08-05 a parallel session had grayed a belt in `v0-pages.css` at higher specificity, and the fix changed that one rule to blue. On 2026-09-29 Kevin asked for the earlier glyphs back, and the fix restored only the rain layer from the earlier head and kept the other session's gallery console.
* Ask the owner before building a file another repository or session owns. `gt-ship` section 1 records the case of the CLI login callback page (2026-09-30).
* When two sessions find they are doing the same work, the one further along messages the other with its PRs, and the other stops. On 2026-09-30 the session that had opened the docs drift PRs told a second session, started from a task chip for the same fix, to stand down.
* When two sessions must change one feature, agree on a split by module and file. On 2026-09-29, in the sign-in gallery work, one session took the console requests in its own worktree, and the other kept the caption card's copy in a module of its own. When the first session shipped caption plates of its own, the second stopped its caption build before it wrote any files.
## 6. Claude and Codex together [#6-claude-and-codex-together]
Kevin, 2026-07-30: "let codex do its own thing, but branch off again".
* Each tool works on its own branch, in its own worktree, on its own dev port. A Codex branch named `codex/` is renamed `k/` before it becomes a gt-cloud PR (2026-08-27).
* Answer "are you on X's branch?" from git: `git -C branch --show-current` and `git -C log --oneline -1` for each worktree involved. The answer on 2026-07-30 named both worktrees, both branches, both ports and the commit both branches started from.
* Every landing starts from a fresh `origin/main` and adds to the other agent's work. Kevin ruled on 2026-09-23 for a main that both agents push. Each agent keeps absorbing the other's pushes by rebase, every push to main has run the core test suite, and the two agents share main without separate deploy windows ("WE MERGE").
* Before publishing to a shared main:
1. Record the starting base commit when the worktree is created.
2. Fetch and compare `git diff --stat origin/main` with your own change. For every file both agents touched, keep the incoming behaviour and re-apply yours on top. A merge without conflicts can still undo a feature through a whole-file replacement.
3. Read `git diff origin/main HEAD` in full, removals included, as the change about to be published.
4. Run the gates on the integrated commit. A green run on the branch before the merge says nothing about the merge.
5. Push without force. If the push is rejected, fetch, integrate and run the gates again.
In GT's repositories, gt-cloud main takes only squash merges through PRs with three required checks (`gt-ship` section 5), and Prototemplate's gates and deploy checks are in `gt-ship` section 8.
* Before a deploy that follows a stretch of both agents pushing, audit the last week of main for work one agent undid. Kevin, 2026-09-22: "MAKE SURE ALL CHANGES WITHIN LAST WEEK ARE PROPERLY SYNCED".
* In a fresh worktree from `origin/main`, list the week: `git log origin/main --since='7 days ago' --format='%h %ad %s'`, `git worktree list` and `git branch -r`.
* Check every branch that looks unmerged for patch equivalence with `git cherry -v origin/main ` and `git range-diff`. A squash or a rebase changes commit ids and keeps the work.
* Read each merge commit's conflict resolutions with `git show --remerge-diff `.
* For merged PRs, measure how many of their added lines survive on main and trace every removal to a stated follow-up. On 2026-09-08 Kevin thought the routing PR #4359 had been reverted. The gt-cloud audit found it open and unmerged with every commit intact, and it merged the next day.
* Leave the other agent's unfinished checkout as it is and list it in the report.
* When the two agents build competing versions of one thing, keep both under distinct names and ids, and Kevin names the canonical one (2026-09-18).
## 7. Relays [#7-relays]
A relay note is written by one agent for another, usually Claude for Codex or Codex for Claude, and Kevin pastes it as is. It holds:
* The branch, the tip commit and the worktree path, and whether the receiver's own worktree was touched.
* Each commit with one line on what it did.
* The receipts: each check with its command, exit code and log path.
* The open list.
* Locks still held and processes the writer stopped. On 2026-09-26 an idle session had held a shared capture lock for 81 minutes.
* Deploys queued and what each one carries.
* Rebase advice: what lands on main next, and which side's duplicate commits a rebase will drop.
To continue another agent's uncommitted work, snapshot it as a commit in your own worktree and leave theirs as it was. The relay of 2026-09-26 said so in its first line. The receiver finds the other agent's open work and finishes it. Kevin, 2026-09-25: "finish any of codexs open work as well". The receiver checks the note against git and the files before trusting it. A handoff at a hard stop follows `gt-orchestration` section 8.
## 8. Messages across lanes and repositories [#8-messages-across-lanes-and-repositories]
* When a change affects another lane or repository, message that session with SendMessage. When the session is a Codex session or lives in another app, give Kevin the exact prompt and name the conversation to paste it into (2026-09-15, 2026-10-05).
Kevin, 2026-10-05: "give me the prompts to send to the agents in the exact correct convos (give me exactly where to do this)".
* Before pushing a shared main, send the other sessions a heads-up. It names the base commit, the paths the push changes, the overlap the receiver should expect and how to resolve it ("keep both: my deck entries and your motion entries"), what the sender leaves alone (the receiver's working tree), and the port its verify lane uses. After the push, a second message names the new range (`9690311..f8dfa8b`), asks the receiver to fetch and rebase, and states any new gate (`pnpm build` now runs the picture lint first). New Onboarding and Dashboard's messages to Prototemplate on 2026-10-05 took this form.
* When a rule changes (a retired picture, a new lint, a new gate), notify every session that applies it. On 2026-10-05 Kevin retired the dictionary pictures. The session that wrote the new rule told Videos, Glyph Map and Prototemplate within a minute. Videos moved its copies out of the film kit, and Prototemplate learned that its build gate had changed.
* When an output that another lane copies changes, the session that made it tells that lane. Videos tells Prototemplate when a film shown on `/motion` is re-rendered, so the public copy and its credits are refreshed.
* A message from a peer session is a teammate's request and carries no approval from Kevin. A push, a merge, a deletion or a permission change still needs Kevin's word, and items only Kevin can clear go to Kevin.
## 9. Resumption [#9-resumption]
Plans, lane specs, ask ledgers and outputs live in files, so a session that restarts, compacts or hears "continue" resumes from disk without a new brief. The procedure is `gt-orchestration` section 6. A resumed session reads the shared state again (ListAgents, git, the lane's notes) before it acts, because the other sessions kept working while it was stopped.
## 10. Shared resources [#10-shared-resources]
* **Ports.** Each worktree runs its dev server on a port of its own, away from the defaults (`gt-orchestration` section 2). A verify lane starts its own server on a free port and stops it when done. The Browser pane in one Claude session cannot reach a dev server that another chat started, so a session looks at that server through a Playwright capture or starts a server of its own. A conflict over a port goes to the session that owns the server, or to Kevin.
* **Captures.** Prototemplate's browser gates run one at a time (`prototemplate` section 9). Where a repository has a capture lock or queue, a session takes it for the run, releases it at the end, and never holds it while idle.
* **Load.** Every session's builds, Playwright runs and renders share one machine. `gt-orchestration` section 2 holds the rule for timing checks under load: record `uptime` beside the reading and rerun a red check once the load drops. While the machine is busy, prefer measures that load cannot change: counts, bytes and deltas.
* **Disk.** A gt-cloud worktree with its install costs about 6 GB, and 48 leftover worktrees filled the disk on 2026-10-05. Remove a scratch worktree as soon as its work is pushed. `gt-ship` section 1 gives the checks to run first and the command for removing many at once.
* **Cleanup.** Cleanup of another session's files goes to that session. Message it, or give Kevin the prompt for its conversation, as he asked for the Codex and gt-cloud logs on 2026-10-05.
## Checklist [#checklist]
* [ ] ListAgents, `git status`, recent commits on the branch and on `origin/main`, and the lane's notes were read before acting.
* [ ] In a fork, only the newest instruction for this lane was acted on, and the parent's open items stayed with the parent or the lane that owns them.
* [ ] The session works on its own branch, worktree and port.
* [ ] Explicit paths were staged and committed with a pathspec, and the branch was checked before the commit (`gt-ship` section 2).
* [ ] A shared push was done once, by its owner, and the other sessions reported the sha they found.
* [ ] Other sessions' in-flight files stayed out of the commit and were named in the report.
* [ ] A heads-up went out before pushing a shared main, and the session fetched and rebased after another session's push.
* [ ] A changed rule reached every session that applies it.
* [ ] A relay note carries the branch, tip, worktree, commits, receipts with exit codes, open list, locks, queued deploys and rebase advice.
* [ ] Servers this session started are stopped, locks are released, `uptime` sits beside timings, and scratch worktrees are removed.
## Sources [#sources]
* Prototemplate: `skills/gt-ship/SKILL.md` sections 1, 2, 5 and 8; `skills/prototemplate/SKILL.md` sections 8 and 9; `skills/gt-orchestration/SKILL.md` sections 2, 6 and 8; `docs/SHIP-LOOP.md` section 0; `docs/handbook/glossary.md` (working terms).
* Kevin's private gt-cloud memory notes on lanes, ship gates, worktree disk use, the lost-work audit and four lanes' handoffs.
* Kevin's Claude Code and Codex session transcripts for the gt-cloud project, which stay private: the fork lineage read from each transcript's inherited `sessionId` and title records; the 2026-08-06 instruction and the four sessions' responses; the 2026-10-03 handover to Videos; the 2026-09-29 and 2026-09-30 messages between the sign-in sessions; the 2026-10-05 messages from New Onboarding and Dashboard and Videos; and the desktop app's notice that another chat's dev server is out of the Browser pane's reach (2026-09-29). The Codex sessions of September 2026 hold the shared-main audit of 2026-09-22 and the relay of 2026-09-26.
* Kevin's messages to Claude Code and Codex from 2026-07-30 to 2026-10-05, for the rulings quoted above. Quotes keep his spelling.
* Dates are in UTC, as the transcripts record them.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Decisions log
> Kevin’s dated rulings on process, product, design and the repositories, what each replaced, his words and the gate that holds it.
URL: https://www.prototemplate.com/docs/handbook/decisions
In his Claude Code and Codex sessions, Kevin Liu rules on how General Translation (GT) work is done, across process, product, design and the repositories. This log lists the rulings that set or replaced a standing practice from 2026-07-31 to 2026-10-20. Each row gives the date, the ruling, the practice it replaced, his words where the ruling needs a source, and the lint, gate or skill that holds it. Read it before you change a GT standard, and whenever an older note, transcript or skill gives conflicting guidance.
## Using the log [#using-the-log]
* The later ruling holds. Guidance with an earlier date in a memory note, a transcript or a skill gives way to a later row here, and the change that finds the conflict corrects the stale text. When a skill changed after a row and the two disagree, the skill holds and this log needs a fix.
* Design verdicts are recorded in full in [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md) in `gt-aesthetic`, with Kevin's words and what was wrong. Their rows here are one line and link there.
* The skills named in the last column hold the procedures. A row states the ruling and where it is enforced.
* Each path names its repository: gt-cloud, Prototemplate, or `content:` for generaltranslation/content, which holds the docs and blog source.
* A row quoting a transcript carries the day the transcript stamped on Kevin's message, which is UTC. A design verdict row carries its date in verdicts.md, and a row with no message behind it carries the date its skill or memory note gives. Those two use Kevin's local date in California, so they can sit one day before the UTC stamp of the same evening.
* Agents do not change a standard on their own. Bring Kevin the current row with a recommendation. When he rules, add a dated row that names what it replaced, and update the lint, gate or skill that holds it in the same change.
## July and August 2026 [#july-and-august-2026]
| Date | Ruling | Replaced | Kevin's words | Held by |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 2026-07-31 | Scrolling is native on every GT surface: no smooth scrolling, scroll hijacking or inertia library. A scroll story scrubs its timeline on the page's own scroll. | Lenis smooth scrolling, which Kevin asked for on 2026-07-22, 07-28 and 07-30 for the scroll stories and the presenter | "remove smooth scrolling from everything, i hate how it keeps going after i stop scrolling" | `no-smooth-scroll` in gt-cloud (landing, `packages/ui`) and Prototemplate `pnpm lint:code`, with `/present` exempt in Prototemplate's `.oxlintrc.json`; [gt-motion](https://www.prototemplate.com/skills/gt-motion) sections 1 and 6 |
| 2026-08-01 | Monospace is for numbers and code only. Headings, paragraphs, labels, pills and social cards are set in Inter. | Mono labels, pills and OG text in the July explorations | "mono should only be used for numbers." | `mono-is-not-voice`; `inter-only` allows Geist Mono for code only; [gt-brand](https://www.prototemplate.com/skills/gt-brand) section 4 |
| 2026-08-04 | Mock layouts and plan images are literal specs, and a display head holds two lines at most. Locadex appears as an isometric drawing that carries its mark, and a gif of it is refused. | Sections that kept the copy and drifted from the Figma layouts; three-line heads; a Figma note proposing a gif of Locadex | [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-08-04 | `no-gif-mark`; Prototemplate's `skills/gt-aesthetic/scripts/measure-type.mjs` flags a display head over two lines |
| 2026-08-06 | The Dossier (`/d/singularity-dossier`) is the completed reference for the site. Product surfaces follow the brand deck since 2026-09-25, for the brand the 2026-10-06 row below holds, and for the site the 2026-10-07 row below holds. | The July bar of generaltranslation.com and resend.com | [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-08-06 | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) section 1; [BRAND.md](https://www.prototemplate.com/docs/handbook/brand) section 8 |
| 2026-08-07 | Every crawler and agent may read the public site, and no rule blocks an AI crawler or a public page. Only the staging build disallows crawling. | None; a new standing rule | "make it so that all robots and agents can crawl us" | gt-cloud's `apps/landing/src/app/robots.ts`; [gt-website](https://www.prototemplate.com/skills/gt-website) section 7 and its review checklist |
| 2026-08-07 | A heading carries no trailing period. Body sentences keep theirs. The deck followed on 2026-09-08. | Landing section headings that ended in a period | "remove the periods from headers to standardize. our hero header has no periods"; on the deck: "i dont thinkn we need periods everywhere" | `no-heading-period` (gt-cloud #5007, Prototemplate `pnpm lint:code`); [gt-voice](https://www.prototemplate.com/skills/gt-voice), Headings and casing |
| 2026-08-08 | The staging build translates Spanish only. Production keeps the full locale roster. | Staging translating Japanese and Spanish | "only es for staging." | gt-cloud's `apps/landing/staging.gt.config.json` (`["es"]`) beside `gt.config.json`, run by `scripts/deploy-landing.sh --staging`; [gt-website](https://www.prototemplate.com/skills/gt-website) sections 3 and 8 |
| 2026-08-11 | For the gt-cloud redesign stack (landing, sign-in and dashboard), the production landing page is canonical. That page is gt-cloud #4213, built from the Dossier. Prototemplate and the toolchain lend isolated mechanics, assets and example copy, and the toolchain enterprise and pricing prototypes are the spec for those two pages. Product surfaces moved to the brand deck on 2026-09-25. | Copying the old toolchain page shell into new pages | "The production GT landing page is canonical." (a handoff brief he sent to the redesign sessions) | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) section 1; [gt-landing-pages](https://www.prototemplate.com/skills/gt-landing-pages), The reference |
| 2026-08-11 | GT surfaces avoid mono as the brand voice, smooth scrolling, robot or sparkle AI icons, flag soup, AI gradients and glass, eyebrows, and em dashes in rendered text. | The July explorations' eyebrows, gradients, glass and mono labels | "3 lines of text stacked to say the same thing" (on eyebrows). [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-08-11 | `no-eyebrow`, `no-em-dash`, `mono-is-not-voice`, `no-smooth-scroll`, `no-raw-locale-flags`, `icon-tiers`; AI icons, gradients and glass by review ([gt-brand](https://www.prototemplate.com/skills/gt-brand) section 7) |
| 2026-08-11 | No invented content. Copy, quotes, metrics, prices and product vignettes come from production, the benchmarks or GT's published pages. | Placeholder testimonials and invented enterprise vignettes | Kevin, 2026-08-05: "like these arent real quotes". [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-08-11 (round two) | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) review checklist; [operating-principles.md](https://www.prototemplate.com/docs/handbook/operating-principles) rule 9 |
| 2026-08-12 | Once Kevin picks a variant, the alternatives leave the code and stay in git history. | The variants program's switchers and dock, about 16,000 lines | "get rid of the variation system" | [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-08-12; [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) section 2 |
| 2026-08-14 | A landing button is the shared `Cta` component with a Title Case label, and its `tracked` value is one of the existing PostHog location slugs. A new slug needs Kevin's approval. | Buttons built by hand on each landing page | Decided in the landing button round (gt-cloud #4348) | `gt-ui/shared-cta` and `gt-ui/cta-title-case`; [gt-landing-pages](https://www.prototemplate.com/skills/gt-landing-pages), [gt-components](https://www.prototemplate.com/skills/gt-components) |
| 2026-08-14 | Flags render only through the shared `LocaleFlag` SVGs, on every surface including the dashboard. | Emoji flags | "NO EMOJIS!!! USE OUR FLAGF BLIB RARY!!!" | `no-raw-locale-flags` on gt-cloud's dashboard, landing and `packages/ui`; `packages/ui/src/components/ui/LocaleFlag.tsx`; [gt-components](https://www.prototemplate.com/skills/gt-components) |
| 2026-08-15 | PR titles and bodies are lowercase, plain technical English, with no em dashes and no mention of Claude. Kevin repeated it on 2026-09-08. | Generated PR prose | "write up the prs with no reference to claude code and no emdashes in lower case"; 2026-09-08: "make the pr language in my standard technical english lower case" | [gt-voice](https://www.prototemplate.com/skills/gt-voice), Code comments, commits and PR descriptions; [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 4 and `references/pr-body.md` |
| 2026-08-17 | Every page gets a second pass against its reference before it is shown. | Pages shipped on their first pass (contact, sign-in, legal) | [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-08-17 | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) section 2; [quality-bar.md](https://www.prototemplate.com/docs/handbook/quality-bar) |
| 2026-08-17 | A docs or blog URL never dead-ends. A near miss redirects to its page, a folder goes to its index, and an unmatched path lists the closest pages. | The plain 404 | "u should probably never hit a 404 on docs and blogs" | `resolveDocsPath` in gt-cloud's `apps/landing/src/lib/slug-suggest.ts`, and `apps/landing/src/lib/blog-near-miss.ts` (gt-cloud #4359, merged 2026-09-09); [gt-website](https://www.prototemplate.com/skills/gt-website) `references/docs.md` |
| 2026-08-26 | A docs page description opens with an action verb such as "Use" or "Install". Descriptions that open with "Learn how" or "Learn what" are rewritten. | Get Started captions that began "Learn how" | "learn is a terrible verb to start with, we like Use and install" | `content:DOCS-SKILL.md` (the rule for descriptions) |
| 2026-08-27 | Stacked PRs use GitHub's native stack, linked with `gh stack link`. Kevin reaffirmed it on 2026-10-05. | A `Stacked on #N` line in the body as the only link between PRs | "use the ACTUAL github stack feature"; 2026-10-05: "i meant use the actual pr stack feature" | [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 6 (`github/gh-stack`) |
| 2026-08-27 | gt-cloud commits carry Kevin's General Translation work identity. | Commits under his personal email, which gt-cloud's Vercel projects refuse to deploy | "gt-cloud deployments on vercel wiwll not accept my home email authored commits" | gt-cloud's repository `user.email`, which covers every worktree; [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 2 |
## September 2026 [#september-2026]
| Date | Ruling | Replaced | Kevin's words | Held by |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 2026-09-02 | Integration docs go under Integrations. A top-level docs section is reserved for a framework, plus the CLI and the Platform, and Integrations is the default when in doubt. | rrweb as a top-level docs section | "default to putting in the integrations section when in doubt" | `content:DOCS-SKILL.md`, "When something gets its own top-level section"; the top-level list is pinned in content CI by `content:scripts/validate-docs-structure.ts` (content #501) |
| 2026-09-03 | An unfinished dashboard feature ships behind a feature flag or does not ship. | Unfinished dashboard pages released without a gate | A team decision Kevin relayed with the fix request | The dashboard's feature flags, managed in the admin app (gt-cloud's `gt-dashboard` skill); [glossary.md](https://www.prototemplate.com/docs/handbook/glossary) |
| 2026-09-08 | Review requests go through GitHub reviewer requests, and Kevin chooses the reviewers. | Asking for reviews in a Slack channel | "keep this in mind for all our prs nnow, i connected everything in linear properly" | [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 5, Reviewers |
| 2026-09-08 | Writing is plain technical English: no em dashes, metaphors, contrast pairs, fragment rhythm or signposts. | Agent prose with metaphors and parallel constructions | "do it in stragiht standard technical english without any weird metaphoors" | [gt-voice](https://www.prototemplate.com/skills/gt-voice); `no-em-dash`; the humanizer skill in Kevin's wiki |
| 2026-09-09 | The brand review works from first principles. Only the company's legal name and the `gt-*` library names customers install are fixed. | None; the brief for the brand review | "just a few things that cant change (the legal name of the company, general translation, annd the nname of libraries our customers use" | No gate; the fixed names are defined in [BRAND.md](https://www.prototemplate.com/docs/handbook/brand) section 1 and [gt-brand](https://www.prototemplate.com/skills/gt-brand) section 1 |
| 2026-09-10 | Pricing shows whole-dollar amounts of $1 or more without cents. Cent prices and amounts under a dollar keep two decimals. | Two decimals on every price | "turn $2.00 and $1.00 and anything like this to $2 and $1" | gt-cloud's `packages/ui/src/components/pricing/dollar-format.ts` and `apps/landing/__tests__/usage-dollar-format.test.ts` (gt-cloud #4785) |
| 2026-09-10 | Public writing is written for a reader who knows nothing about Kevin, the team or the repository. It defines the product once, opens each section with the point that reader can reuse, and keeps PR numbers and internal names out of the prose. | Drafts that narrated process and cited internal names | "be so much more straightforward and clear to a user who has no idea who I am" | [gt-voice](https://www.prototemplate.com/skills/gt-voice); [quality-bar.md](https://www.prototemplate.com/docs/handbook/quality-bar), Copy |
| 2026-09-10 | The docs sidebar on a 404 page is the stock flat tree. | A client-side pathname override that kept the section tree and flashed the flat tree before hydration | "i cann see it flash. should we just have what it is before if its what fuma nama does?" | gt-cloud #4773 (the revert); [gt-website](https://www.prototemplate.com/skills/gt-website) section 4 |
| 2026-09-14 | Exploration rounds stay on a branch or uncommitted until Kevin reviews them on localhost and says to land them. The directions in a round differ in silhouette, material and action. | A ten-direction round pushed to Prototemplate main before he saw it | [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-09-14 | [prototemplate](https://www.prototemplate.com/skills/prototemplate) section 9; [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 8; [gt-explorations](https://www.prototemplate.com/skills/gt-explorations) |
| 2026-09-15 | Git pushes trigger no landing preview deploys. Main and staging deploy, and a preview is deployed by hand from the CLI. | A preview deploy on every push to a PR branch | "this is running up a lot of costs" | gt-cloud's `apps/landing/vercel.json` (`git.deploymentEnabled`), gt-cloud #4828; [gt-website](https://www.prototemplate.com/skills/gt-website) section 8 |
| 2026-09-15 | PostHog loading and analytics initialization stay as they are in any PR that is not about analytics. | A PR that deferred PostHog initialization in `packages/ui/src/components/analytics/PostHogProvider.tsx` | "dont touch posthog. evaluate your chnages for stuff that is high risk like posthog" | [gt-website](https://www.prototemplate.com/skills/gt-website) section 4; for onboarding, the parity gate in [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 7 |
| 2026-09-18 | Inter is the only typeface. [gt-brand](https://www.prototemplate.com/skills/gt-brand) section 4 names the few exceptions, such as the Prototemplate nameplate and the presenter. | Switzer as the display face beside Inter (the deck dropped it on 2026-09-08) | [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-09-18 | `inter-only`; gt-cloud #4887 deleted the Switzer files; [gt-brand](https://www.prototemplate.com/skills/gt-brand) section 4 |
| 2026-09-24 | Icons come in two tiers: Heroicons solid for marks that carry meaning, Lucide outline for controls. Brand marks stay as drawn. | Lucide outline glyphs everywhere | Kevin, 2026-09-28: "look for ANYWHERE ELSE icons nneed to be synced" | `icon-tiers` (the rule in gt-cloud #4909, the lint in #5007); [gt-components](https://www.prototemplate.com/skills/gt-components) `references/icons.md` |
| 2026-09-24 | The identity stays in the neutral, scalable territory: a grid, one type system, one accent blue, and parts that hold at 16px and in a terminal. | A more opinionated creative territory proposed in the brand review | "need to be scalable in future. not incredibly opinionated. feel like switzerland" | [BRAND.md](https://www.prototemplate.com/docs/handbook/brand); [gt-brand](https://www.prototemplate.com/skills/gt-brand) sections 2 and 3; no gate |
| 2026-09-25 | Prototemplate reserves all rights to General Translation, Inc. The repository is public to read, and third-party fonts, icons and adapted skills keep their own licenses. | The MIT license | "make prototemplate not mit licensed anymore." | [LICENSE](https://github.com/Kevin-Liu-01/Prototemplate/blob/main/LICENSE); README, License |
| 2026-09-25 | A coding agent runs the Setup for Agents prompt end to end on a fresh app before it ships, and again after any change to the prompt, the CLI or the quickstarts. | Shipping a generated prompt untested | "TRY IT OUT SEE IF IT WORKS AND YOU CAN GET TO CREATING A TRANSLATION". He asked again on 2026-09-30 and 2026-10-01. | [gt-website](https://www.prototemplate.com/skills/gt-website) section 6 and `references/pages.md` |
| 2026-09-25 | PR screenshots go into the body from the first push and are refreshed after every visible change. | Screenshots added at the end of review | "add the screenshots of this to the pr the whole time" | [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 4 |
| 2026-09-28 | Each column has one rail on each side, drawn once by the `.tc-rail` wrapper. | Doubled outer rails 10px outside each column | "make sure theres nno rules that leead to two side rails" | `single-rail` (gt-cloud #5007, Prototemplate `pnpm lint:code`); `retired-rail-vocabulary` in Prototemplate's `scripts/lint/practices.mjs`; [DESIGN.md](https://www.prototemplate.com/docs/handbook/design) section 3 |
| 2026-09-28 | The theme control draws the circle glyphs ◐ and ◑. | Sun and moon icons | [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-09-28 | The shared `ThemeToggle` in gt-cloud's `packages/ui/src/components/frame/ThemeToggle.tsx`; `no-theme-icons` on open gt-cloud #4977, which has not reached main |
| 2026-09-28 | PR screenshots are tight before and after crops of the changed elements, with the same clip on main and on the branch. | Full-page screenshots in two-column tables | "make this pr page much much easier to read and show the images" | [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 4 and `references/pr-body.md` |
| 2026-09-29 | No offer, credit or capability appears in the product before the backend delivers it. | An offer in the redesigned onboarding that the backend did not yet deliver | "we only show it if we actually do it" | The parity gate admits only stricter checks and recovery paths as additions ([gt-ship](https://www.prototemplate.com/skills/gt-ship) section 7); review |
| 2026-09-30 | The hero's second button is Setup for Agents, which copies the tested agent prompt. | A Docs button | "change docs into setup for agents with a copy icon and make that into its own pr" | `HeroSecondButton.tsx` and `CopyPromptButton.tsx` in gt-cloud's `apps/landing/src/components/landing/sections/agent/`; the prompt's one source in `content:docs/en-US/overview/for-coding-agents.mdx`, served at `/agent-prompt.md` (gt-cloud #5049); [gt-website](https://www.prototemplate.com/skills/gt-website) section 6 |
## October 2026 [#october-2026]
| Date | Ruling | Replaced | Kevin's words | Held by |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 2026-10-01 | GT's identity work takes dithered artifact pictures in black, white and blue as a reference. Kevin sent them to the brand agency with the race-type speed marks he chose on 2026-09-29, and he called the marks an experiment. The doubled-line monogram stays the current mark. | None; it builds on the 2026-09-24 territory | "artifacts, dithered, we like this aeshteitc of black white blue"; on the marks: "nothing but funnu experiementation" | [gt-dither](https://www.prototemplate.com/skills/gt-dither) (the pictures); `scripts/build/speed-marks.mjs` and `/marks` in Prototemplate; [gt-brand](https://www.prototemplate.com/skills/gt-brand) section 5 |
| 2026-10-01 | A release PR carries no development code. Galleries, stand-ins, test-only hooks, dev routes, recorded fixtures and harnesses stay on their own branch or in the scratchpad. | A release branch that carried the dev states gallery and a 24k-line parity suite | "please cleanup / remove all dev / temporary 'testing' code" | [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 3, Verification instruments stay out, and `skills/gt-ship/scripts/pr-size.mjs` |
| 2026-10-02 | An onboarding or auth redesign keeps every tracking call and backend side effect that production has. Parity is proven by recording production, replaying the release and diffing the two ledgers. | Judging parity from a reviewer's list of intended changes | "we need the new onboarding to keep all the tracking and backend stuff that the old onboarding did" | [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 7, The parity gate |
| 2026-10-02 | A PR's line count is part of its review. Before a push the diff is grouped into product, tests, fixtures, scripts and lockfile, and every large group has a reason. | A release PR of about 39,500 lines, most of them a recorded parity suite | "why is 5063 39.5k lines? fix this." | `skills/gt-ship/scripts/pr-size.mjs`; [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 3 |
| 2026-10-02 | A public repository with a third-party licensing problem stays public, and the third-party material is removed or replaced. Kevin ruled this in one of his own repositories, and it applies to Prototemplate. | Making a repository private to settle third-party terms | "never privatize the repo. simply remove third party models." | Review; each picture's source and license are confirmed when it is added ([gt-dither](https://www.prototemplate.com/skills/gt-dither) sections 5 and 7); [LICENSE](https://github.com/Kevin-Liu-01/Prototemplate/blob/main/LICENSE) lists Prototemplate's third-party material |
| 2026-10-02 | A PR is closed only when its change is already on main. The closing comment names the merged PR that carries the change, and the branch stays. Every other PR stays open for Kevin to decide. | Closing stale and superseded PRs in bulk | "only delete prs that are already in the codebase" | [gt-reporting](https://www.prototemplate.com/skills/gt-reporting) section 5 (close candidates in the PR slate); the closing comment is the check |
| 2026-10-03 | Each session owns one lane, and work for another lane goes to that session by name. | Sessions doing each other's work, such as a site session making films | "that videos one should be making them, and this one is just for prototemplate work" | [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 1; [prototemplate](https://www.prototemplate.com/skills/prototemplate) section 8; [multi-session-playbook.md](https://www.prototemplate.com/docs/handbook/multi-session-playbook) |
| 2026-10-03 | Content about places is organized by language. It names and outlines no country or territory, and its facts come from CLDR. | A brief for a map of countries drawn in their languages | "avoid political sensitivity without making it look forced" | [gt-website](https://www.prototemplate.com/skills/gt-website) section 6; [gt-product-map.md](https://www.prototemplate.com/docs/handbook/gt-product-map) section 6, Geography |
| 2026-10-05 | Prototemplate is the hub and wiki of how GT work is done, with a curated skill set in `skills//` that holds only the skills in real use. | A generated dump of 261 wiki skills on `/skills` | "this prototemplate is tupposed to be my hub for general trnalsation work"; on `/skills`: "we only need to show and store the ones weve actually been using" | [prototemplate](https://www.prototemplate.com/skills/prototemplate) section 10; `/skills` renders only the set |
| 2026-10-05 | Every element resolves through the type tokens to one face, the self-hosted rsms InterVariable 4.1. | Faces set differently from element to element, and Google's build of Inter | "esepcially encorce the CORRECT RASMUS INTER". [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-10-05 | `inter-only` in gt-cloud; `pnpm lint:type` in Prototemplate (`scripts/lint/type.mjs`, from the 2026-10-05 type round); [gt-brand](https://www.prototemplate.com/skills/gt-brand) section 4 |
| 2026-10-05 | Artifact pictures carry no readable English prose. | The dictionary, Johnson, OED and Oxford pictures | [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-10-05 | `pnpm lint:pictures` and [docs/ARTIFACT-PICTURES.md](https://www.prototemplate.com/docs/handbook/artifact-pictures) in Prototemplate; `check:artifact-pictures` on open gt-cloud #5133; [gt-dither](https://www.prototemplate.com/skills/gt-dither) |
| 2026-10-05 | A book head's title is the page's plain name (Brand, Documentation, Handbook), and the head's right side is a panel: the last update, then the page's own facts, each with an icon. | Titles that were phrases ("The brand", "Prototemplate docs") beside a plain meta table | "dont make it "the brand" "prototemplate docs" it should be Brand and Documentation and make the right side of those headers better, show last update, use icons" | `src/lib/page-names.ts`; `pnpm lint:heads` (S1, S5, H5) and `pnpm lint:updated`; [prototemplate](https://www.prototemplate.com/skills/prototemplate) section 3 |
| 2026-10-05 | Rounded controls, square shells: buttons, fields and segmented controls round at 6px, chips and key caps at 4px, cards and popovers at 6px, and only the UI shells are square. | Square boxes everywhere outside a short list of exceptions | "i want to enforce and keep this amount of border rounding instead of forcing Boxes. boxes only for ui shells" | `pnpm lint:radius` (`scripts/lint/radius.mjs`); [DESIGN.md](https://www.prototemplate.com/docs/handbook/design) section 2, Corners; [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) section 3 |
| 2026-10-06 | Every page with a book head renders one structure: nothing is drawn between the sheet's top border and the title, one hatch band carries a rule on both edges, and the mast, the panel and the section dividers are the same on every page. | Heads that differed from page to page, a guide line through the title, and a band without its top rule | "see how the brand is touching the up line and the spacer is missing a border above it? standardize our presentation more" | `pnpm lint:heads` and `pnpm lint:heads:live`; [DESIGN.md](https://www.prototemplate.com/docs/handbook/design) section 4, The book page; [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-10-06 |
| 2026-10-06 | The brand's head shows a reading time like the other pages and names no reference application. The brand has moved past the Dossier, and BRAND.md section 8 ("The completed reference") waits for Kevin's decision. | The Dossier as the brand's completed reference (the 2026-08-06 row) | "why is the dossier the reference for Brand? its evolved so much more since then", then "just give it a reading time like the other pages." | `/brand`'s panel; [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-10-06; no gate |
| 2026-10-06 | Simplify. The platform feature that removes code comes before new code, and machinery a review asks to test is removed when it need not exist. | A caption card that measured its own height with an observer and component state | "Beautiful but don't complicate. Always simplify." | [operating-principles.md](https://www.prototemplate.com/docs/handbook/operating-principles) rule 12; [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) |
| 2026-10-07 | The shipped site is the reference for landing and marketing pages: generaltranslation.com, built from `apps/landing` on gt-cloud origin/main. The Dossier stays in the gallery as the direction the site grew from. BRAND.md section 8 ("Where it ships") names where the identity ships: the site, the product surfaces that follow the brand deck, the films on `/motion` and the marks. | The Dossier as the completed reference for the site (the 2026-08-06 row), and the decision on BRAND.md section 8 that the 2026-10-06 row left open | "fix the dossier references." | [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) section 1; [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md), 2026-10-07; [BRAND.md](https://www.prototemplate.com/docs/handbook/brand) section 8; no gate |
| 2026-10-07 | A skill's title and a document's h1 name the thing with no leading "The": Brand and the correct Inter, Brand deck, Landing page grammar and GT website for the skills, and Graphics pipeline, Libraries and Ship loop for the documents. | Titles that opened with "The" ("The brand deck", "The Ship Loop") | "fix the The titles." | `scripts/build/skills.mjs` fails a skill title that opens with "The" and a skill whose h1 differs from its `metadata.title`; review holds the documents' h1s; the 2026-10-05 row on head titles |
| 2026-10-07 | Prototemplate is served at three addresses: [www.prototemplate.com](http://www.prototemplate.com) from the team's Vercel project, and prototemplate.vercel.app and prototemplate.kevinliu.studio from Kevin's personal project. On 2026-10-07 prototemplate.kevinliu.studio served the same deployment as prototemplate.vercel.app. | [www.prototemplate.com](http://www.prototemplate.com) as the one live domain, with prototemplate.vercel.app as the personal project's alias | "prototemplate.com and vercel.app are both ok, but prototemplate.kevinliu.studio shoul dbe a thing too." | [README.md](https://github.com/Kevin-Liu-01/Prototemplate/blob/main/README.md), What is here; [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 8 |
| 2026-10-07 | The film cuts in review are approved for the site. jihe-yuanben is published under CC BY-SA 4.0, and its credits file says so. Kevin signed off the last open items, the non-English takes that waited for a native listener, and expects those films to be updated. | Cuts held for Kevin's approval, the share-alike license of jihe-yuanben left to his decision, and non-English takes held for a native listener | "film cuts approved. jihe is yes. and the last ones are signed off, theyre going to be updated anyways" | [gt-films](https://www.prototemplate.com/skills/gt-films) sections 7, 8 and 11; `public/motion/published.json` |
| 2026-10-08 | On a page that already exists, "enhance" keeps the page and adds to it. Copy beside a team photo names nobody in it and states no headcount. | A careers rebuild that dropped the hero, the customer band and the original copy | "keep the original write up" | [operating-principles.md](https://www.prototemplate.com/docs/handbook/operating-principles) rule 15; [quality-bar.md](https://www.prototemplate.com/docs/handbook/quality-bar), Copy; [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) |
| 2026-10-10 | Prototemplate commits author as Kevin with his GitHub noreply address and keep the session's `Co-Authored-By:` trailer. | Commits under his personal or his work address | Answered in the review of the system v2 plan | [docs/SHIP-LOOP.md](https://www.prototemplate.com/docs/handbook/ship-loop) section 6; [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 2 |
| 2026-10-10 | [www.prototemplate.com](http://www.prototemplate.com) is the canonical address. prototemplate.vercel.app and prototemplate.kevinliu.studio stay as aliases. | prototemplate.vercel.app as the address in the site metadata and `llms.txt` | The recommended default, accepted in the same review | `SITE_URL` and `public/llms.txt`; [README.md](https://github.com/Kevin-Liu-01/Prototemplate/blob/main/README.md), What is here |
| 2026-10-10 | A customer or partner is named in this repository only where generaltranslation.com shows it. | A list in BRAND.md section 9 that named a customer the site no longer showed | The recommended default, accepted in the same review | [BRAND.md](https://www.prototemplate.com/docs/handbook/brand) section 9; `pnpm lint:public` and its private denylist |
| 2026-10-10 | gt-cloud's internal material stays out of the public skills: its dev-environment internals and the file maps of its private packages live in gt-cloud's own skills. PR numbers and branch names may appear. The copies of the gt-ui lint plugin and the plate stay at the copy taken, with no re-sync until gt-cloud's product and infrastructure owners agree. | Skill sections that described gt-cloud's dev infrastructure and package file maps | The recommended default, accepted in the same review | `pnpm lint:public`; `scripts/lint/copies.json`; [prototemplate](https://www.prototemplate.com/skills/prototemplate) |
| 2026-10-10 | The curated skills reach gt-cloud sessions as project links made by `pnpm skills:install --project` on a gt-cloud checkout and listed in that checkout's `.git/info/exclude`, so nothing gt-cloud tracks changes. | Skills that no gt-cloud session loaded | Answered in the same review | [README.md](https://github.com/Kevin-Liu-01/Prototemplate/blob/main/README.md), Skills |
| 2026-10-10 | The film sources in `motion/` are tracked through an allowlist: the kit code and one entry per published film. Unreleased films stay untracked, and Kevin reads the first staged diff. | `motion/` untracked as a whole | Answered in the same review | The motion block in `.gitignore`; [gt-films](https://www.prototemplate.com/skills/gt-films) |
| 2026-10-10 | Finished round specs move to `docs/archive/`, with machine paths replaced by placeholders. | Finished and abandoned specs kept beside the live sources | The recommended default, accepted in the same review | [docs/archive/README.md](https://github.com/Kevin-Liu-01/Prototemplate/blob/main/docs/archive/README.md); `pnpm lint:public` |
| 2026-10-14 | `/docs` is a docs site of ten pages on how Prototemplate works, built on fumadocs with the notebook layout generaltranslation.com/docs runs, outside the viewer shell, and written to serve as a template for another project. The canon documents (AGENTS.md, BRAND.md, DESIGN.md, ARCHITECTURE.md, the ship loop, the tools, the libraries with the build log, the graphics pipeline and the artifact pictures) joined the handbook at `/handbook/`, and their old `/docs/` addresses redirect there. | `/docs` as a book of the repository documents on the viewer shell, with the build log under the readme | "i want prototemplate to have its own proper seo system we can also make a very small like 10 page version of the docs site that just explains how it works and totally serves as a template" | `content/docs`, `src/app/docs`, `src/app/handbook/registry.ts`, the redirects in `next.config.ts`; `pnpm lint:registries`, `pnpm lint:seo` |
| 2026-10-20 | The handbook and the canon documents are a section of the docs site at `/docs/handbook/`. Each page includes its repository file, so `docs/handbook/` and the canon files stay the one source, and `/handbook` and `/handbook/` redirect to the new addresses. The libraries page carries the live build log, and pages set live figures beside the sections they illustrate. | The handbook as a book on the viewer shell at `/handbook/` (the 2026-10-14 row) | "put the handbook into prototennokate docs, with a ton more super cool componnents in there now" | `content/docs/handbook/`; the redirects in `next.config.ts`; `pnpm lint:registries`, `pnpm lint:seo` |
## Superseded July practices [#superseded-july-practices]
Notes, commits and transcripts from July 2026 still describe these practices, and no row above names them. The Replaced column of the tables above covers the other July practices: Lenis, headings with periods, Switzer and the July bar.
| July practice | Replaced by | Date | Held by |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Entrance animation, such as a fade-in on the landing hero | Kevin, 2026-08-06: "dont have a fade in animation in hero". Product pages have no entrance animation since 2026-09-28. The landing's sections keep one quiet reveal as they scroll into view, and other motion shows a real state change. | 2026-08-06; product pages 2026-09-28 | [gt-motion](https://www.prototemplate.com/skills/gt-motion) section 1 and section 6, The landing's quiet reveal |
| Liquid glass and glassmorphism. Kevin, 2026-07-30: "MAKE THIS HAVE A BACKGROUND WINDOW DISTORTION GLASSMORPHISM" | The avoid list refuses the AI gradient and glass look. | 2026-08-11 | Review ([gt-brand](https://www.prototemplate.com/skills/gt-brand) section 7) |
| DirectionDock, the control dock on every direction page. Kevin, 2026-07-30: "remove this thing on each page. this is a /present specific feature" | One pill took over the presenter's controls and DirectionDock was retired (Prototemplate 502dc0a). It returned the same night as a top-left back button on the standalone direction pages, hidden under `?chrome=0` (08b33c6). On 2026-09-08 `DirectionCorner` (`src/components/viewer/DirectionCorner.tsx`) replaced it on the viewer shell, and DirectionDock was deleted (c064945). | 2026-07-31; 2026-09-08 | [gt-components](https://www.prototemplate.com/skills/gt-components), Prototemplate's viewer shell; [prototemplate](https://www.prototemplate.com/skills/prototemplate) section 1 |
| gt-cloud's `apps/redesign` on port 3006 as the place where canon was edited | Prototemplate main is the only copy, and canon is edited there. `apps/redesign` stopped being a copy, nothing is copied in from another tree, and Prototemplate's dev server runs on 3005. | 2026-09-08 | [ARCHITECTURE.md](https://www.prototemplate.com/docs/handbook/architecture), The mirror; [docs/SHIP-LOOP.md](https://www.prototemplate.com/docs/handbook/ship-loop) section 7; [prototemplate](https://www.prototemplate.com/skills/prototemplate) section 1 |
## Recorded elsewhere [#recorded-elsewhere]
* Version pins, ports, open PR states and other temporary technical states describe the code on a date and change without a ruling. They live in [gt-website](https://www.prototemplate.com/skills/gt-website) section 8 and the Sources lines of the skills. The landing's Next.js pin is one of them.
* The full wording of each design verdict, with what was wrong and what Kevin approved, is in [verdicts.md](https://www.prototemplate.com/skills/gt-aesthetic/references/verdicts.md). The table in [gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) section 2 summarizes it.
* The Sources lines of `gt-voice`, `gt-website`, `gt-ship` and `gt-lints` list the directives each skill was written from. This log puts every ruling in one dated list with the practice it replaced.
## Sources [#sources]
* Kevin's messages to Claude Code and Codex from 2026-07-20 to 2026-10-05, about 5,800 in all; his rulings on the page heads, the corners and the brand's reference on 2026-10-05 and 2026-10-06, and on the Dossier references, the titles, the addresses and the films on 2026-10-07; and the session transcripts behind them for context. Quotes keep his spelling. Three quotes come from messages the corpus cut short or queued with an image, and were read in the transcripts: the 2026-08-11 eyebrow line, the 2026-09-25 screenshot line and the 2026-09-30 hero line.
* Prototemplate, read 2026-10-05: `skills/gt-aesthetic/references/verdicts.md` and `SKILL.md` sections 1 and 2; `skills/gt-ship` sections 1 to 8, `references/pr-body.md` and `scripts/pr-size.mjs`; `skills/gt-lints` and `references/gt-ui-rules.md`; `skills/gt-website` sections 3 to 8 and `references/docs.md` and `references/pages.md`; `skills/gt-voice`, Headings and casing; `skills/gt-brand` sections 1 to 5 and 7; `skills/gt-components`; `skills/gt-motion` sections 1 and 6; `skills/gt-dither` sections 5 and 7; `skills/gt-landing-pages`; `skills/gt-reporting` section 5; `skills/prototemplate` sections 1 and 8 to 10; `BRAND.md`; `DESIGN.md` section 3; `ARCHITECTURE.md`, The mirror; `LICENSE`; `README.md`; `docs/ARTIFACT-PICTURES.md`; `package.json`; `.oxlintrc.json`; `scripts/lint/practices.mjs`; `scripts/lint/type.mjs` in the working tree; commits 502dc0a and 08b33c6 (2026-07-31 Pacific), 229d413 and c064945 (2026-09-08).
* gt-cloud at origin/main e17fce499 (2026-10-05): `.oxlintrc.json` and `tooling/oxlint-plugins/gt-ui.ts`, `apps/landing/src/app/robots.ts`, `apps/landing/vercel.json`, `apps/landing/gt.config.json`, `apps/landing/staging.gt.config.json`, `scripts/deploy-landing.sh` and `packages/ui/src/components/pricing/dollar-format.ts`; merged PRs #4213, #4359, #4773, #4785, #4828, #4887, #4909, #5007 and #5049; open PRs #4977 and #5133.
* generaltranslation/content at main, read 2026-10-05: `DOCS-SKILL.md` ("When something gets its own top-level section" and the rule for descriptions); PR #501.
* Kevin's wiki: the humanizer skill.
* Kevin's Claude Code memory notes for gt-cloud, which stay private (25 notes; 5 added on 2026-10-10 from an allowlist of standing rulings, each row written fresh).
* The review of the system v2 plan on 2026-10-10: Kevin's answers and the recommended defaults he accepted, for the 2026-10-10 rows.
* Kevin's request of 2026-10-14 for the SEO system and the docs site, and his answers to the plan's open questions that day, for the 2026-10-14 row.
* Kevin's request of 2026-10-20 to move the handbook into the docs site with live components, for the 2026-10-20 row.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Agents on one machine
> Agent sessions on one workstation: stopping processes by id, zsh traps, exit-status gates, memory and disk, long commands and shared checkouts.
URL: https://www.prototemplate.com/docs/handbook/shared-machine
Kevin Liu runs many coding agent sessions on one Mac for his General Translation (GT) work: Claude Code sessions, Codex sessions, the subagents they launch, and his own apps beside them. The sessions share the machine's processes, its shell, its memory and its disk. Each trap below stopped other sessions' work at least once between August and October 2026, and each section gives the rule, the incident that set it, the fix and the skill that holds the procedure. The [multi-session playbook](https://www.prototemplate.com/docs/handbook/multi-session-playbook) holds the rules for lanes, branches and messages between sessions.
## Stopping a process [#stopping-a-process]
Stop a process by the process id recorded when it started. macOS ships the BSD `pkill`, which stops reading options at its first pattern, so every argument after the pattern becomes another pattern and matches far more than the command meant.
| Date | Command | What it matched | What it stopped |
| ---------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| 2026-10-01 | `pkill -f "" -P 1` | Every command line that contained "1" | About 140 Chrome processes, other sessions' dev servers, a test run and the session's own renders |
| 2026-10-13 | `pkill -f "next build --turbopack" -U $(id -u)` | Every command line that contained "501", the user id, which is part of the path of the agents' shared temp folder | Another session's deploy gate after hours of running, and several background waiters |
Record `$!` for every process you start, check it before you stop it, and stop it with `kill`. A dev server is found by the port it listens on. The `-sTCP:LISTEN` filter matters: without it, the kill also reaches a browser connected to that port.
```sh
pnpm dev --port 3011 > dev.log 2>&1 &
pid=$! # record the id at launch
ps -o pid,ppid,command -p "$pid" # the command is still yours
lsof -p "$pid" -d cwd # and it runs in your folder
kill "$pid"
kill $(lsof -ti tcp:3011 -sTCP:LISTEN) # a server, by the port it listens on
```
When matching by name cannot be avoided, put every option before the pattern and run `pgrep -fl` with the same arguments first, so the list of matches is read before anything is signalled. Every agent brief carries the rule, because a subagent knows only its brief. The procedure is in [harness-traps.md](https://www.prototemplate.com/skills/gt-orchestration/references/harness-traps.md) of `gt-orchestration` (Processes on a shared machine), and the port kill in [gt-local-dev](https://www.prototemplate.com/skills/gt-local-dev) section 2.
## Shell traps in zsh [#shell-traps-in-zsh]
Claude Code runs its shell commands in the user's shell, which is zsh on a Mac. Nine zsh behaviours differ from bash, and each one either fails silently or stops the rest of a command line.
| Trap | What happens | Fix |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| A variable named `path` | zsh ties the `path` array to `PATH`, so `path=apps/x` replaces the search path and every later command reports "command not found" | Name it `p`, `file` or `target` |
| `"$B:apps/landing"` | zsh reads `:a` as the absolute-path modifier and rewrites the string | Brace the name: `"${B}:apps/landing"` |
| `timeout 90 pnpm lint \|\| echo failed` | macOS has no GNU `timeout`, and the `\|\| echo` hides the "command not found" | `perl -e 'alarm 90; exec @ARGV' pnpm lint` |
| `for u in $urls` | An unquoted variable does not split on spaces, so the loop runs once over the whole string | An array, an explicit list, or `${=urls}` |
| Several heredocs on one `&&` chain | zsh feeds the bodies in operator order, and a Python body once became a pushed commit message | Write each message or script to a file first, then `git commit -F ` |
| `grep --include=*.tsx` | zsh expands the glob itself and fails with "no matches found" | Quote it: `--include='*.tsx'` |
| A glob with no match | The whole command line aborts with "no matches found", so `grep x a/*.md b/*.md` greps nothing when `b/` has no Markdown | `find ... -print0 \| xargs -0 grep`, or quote the pattern for a tool that globs itself |
| `echo ====` | A word that starts with `=` is a command lookup, so the line fails with "=== not found" and the rest of the chain stops | Quote it: `echo '----'` |
| `$TAIL[m]` in an ffmpeg filter graph | zsh reads `[m]` as an array subscript | `${TAIL}[m]` |
The heredoc trap is the costly one, because its result reaches the remote before anyone reads it. A commit message written to a file with `cat > msg.txt <<'EOF'`, as a command of its own, cannot pick up another heredoc's body. [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 2 holds the commit form, [gt-local-dev](https://www.prototemplate.com/skills/gt-local-dev) section 1 the quoting rules for port loops, and [sound.md](https://www.prototemplate.com/skills/gt-films/references/sound.md) of `gt-films` the ffmpeg case.
## Exit-status gates [#exit-status-gates]
A command that must stop on a failure chains to the next step with `&&` on the real exit status. A `;` ignores the status, and a pipe replaces it with the status of the last command in the pipe, because zsh runs without `pipefail` unless it is set.
| Date | Command | What happened |
| ---------- | -------------------------------------------------------- | ----------------------------------------------------------------- |
| 2026-08-07 | `pnpm build > log; git add -A && git commit && git push` | A broken build reached main: the `;` ignored the build's exit 1 |
| 2026-08-11 | `pnpm build 2>&1 \| tail -2 && git ...` | A failing build was pushed: the pipeline returned `tail`'s exit 0 |
| 2026-10-14 | `headroom can-start ... \| tail -1 && node check.mjs` | A browser started while the memory check said to wait |
Capture output to a file and gate on the command itself. When a report needs the number, capture the exit code on its own line.
```sh
pnpm build > build.log 2>&1 && git push origin HEAD:main || tail -40 build.log
pnpm build > build.log 2>&1; echo "build exit $?" # the real code, for a report
set -o pipefail # only where a pipe cannot be avoided
```
The rule is held by the [ship loop](https://www.prototemplate.com/docs/handbook/ship-loop) section 7, [gt-lints](https://www.prototemplate.com/skills/gt-lints) section 5 and the [Gates](https://www.prototemplate.com/docs/gates) page of the docs, which runs the build gate this way.
## Memory and disk [#memory-and-disk]
Gate each heavy job on its own memory estimate, and check free disk before a large batch. A runaway process on a shared workstation can take the whole machine faster than any alert reports it, and a crash restarts every session at once.
| What was measured | Value |
| -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| The workstation | A 128GB Mac that ran out of application memory twice on 2026-10-12 |
| One runaway node process | 457GB |
| All node processes at the crashes | 243 to 273 processes holding 91 to 555GB |
| The agent desktop app | 232GB with about 25 sessions open |
| `git grep -E` over 130 ORed ids without `-I`, 18 threads, in a repository with binary assets | Grew from 42.6 to 166GB in about 55 seconds |
| A local model trial on the GPU | Grew from 0 to 87GB in about 66 seconds |
| A gt-cloud worktree with its install | 4.3GB in `du`; removing one frees about 1.15GB, because pnpm clones files from its store |
| Leftover scratch worktrees on 2026-10-05 | 48 worktrees in 259GB of scratch space, with 27GB of the disk left free |
| The disk on 2026-10-14 | 100% full |
Headroom, Kevin's open-source menu bar app, reads the machine's memory, and its `can-start` command exits 0 when a job of the stated size fits and 1 when it should wait. A literal search runs with `-F` and a pattern file, and `git grep` gets `-I` to skip binaries and a thread count. A torch process gets a watermark ratio, so it fails with an out-of-memory error inside itself before it starves the machine. A scratch worktree is removed as soon as its branch is pushed.
```sh
headroom can-start --gb 6 --label build && pnpm build # 0 starts the job, 1 holds it
df -h /System/Volumes/Data # free disk, before a large batch
rg -F -l -f patterns.txt # many literal ids at once
git grep -I -F -f patterns.txt --threads 4
PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.35 python trial.py # caps the GPU allocator for this process
xargs -P 6 -n 1 git worktree remove --force --force < pushed-worktrees.txt
```
A worktree goes on the removal list only after `git -C status --short` prints nothing and `git -C branch -r --contains HEAD` names a remote branch. One removal job hit the two-hour background limit after removing 35 worktrees one at a time, and the parallel form above removed the rest in 12 minutes. A crash ends in a reboot, and a reboot empties the system temp folder that holds the sessions' scratchpads (helper scripts, ship records, scratch worktrees) and stops every process. The checkouts, files under `~/.config` and the agents' run journals survive, so a spec or a helper that must outlive the day goes into a repository or a durable folder. [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 1 holds the worktree checks, and [harness-traps.md](https://www.prototemplate.com/skills/gt-orchestration/references/harness-traps.md) of `gt-orchestration` holds what survives a reboot.
## Long commands [#long-commands]
An agent's background shell task is stopped at its timeout, which is at most two hours in Claude Code. A job that may run or wait past about 90 minutes starts detached from the session, writes its own process id, and is watched by a poll that ends on a milestone or on the job's exit.
```sh
(nohup sh -c 'echo $$ > job.pid; exec ./long-job.sh' >> job.log 2>&1 < /dev/null &) # parent PID reads 1
pid=$(cat job.pid)
until grep -q 'DONE' job.log || ! kill -0 "$pid" 2>/dev/null; do sleep 20; done # run as a background task, re-armed every two hours
```
On 2026-10-08 lane agents hung for two to five hours on shell calls that never started, which fits a confirmation prompt that a subagent cannot answer. Lane prompts now hold these rules:
* No `rm` of any kind in a lane's shell call. Deletions go to the lead or to a helper that refuses paths outside the scratchpad, and a symlink is replaced with `ln -sfn`.
* File edits and deletions go in separate calls.
* A git network call (`push`, `fetch`, `ls-remote`) runs alone under an alarm: `perl -e 'alarm 90; exec @ARGV' git push origin HEAD`.
* Every background worker is redirected (`> worker.log 2>&1 &`), and every long wait runs in the background and is polled.
* A long runner is resumable: it skips the passes it finished and reruns only its failures.
[harness-traps.md](https://www.prototemplate.com/skills/gt-orchestration/references/harness-traps.md) of `gt-orchestration` holds these rules under Long commands and Bash calls inside lanes.
## One checkout and several sessions [#one-checkout-and-several-sessions]
In a checkout that several sessions share, stage and commit only explicit paths. The index, the working tree and the branch are shared, so any command that takes "everything" takes the other sessions' work too. The [multi-session playbook](https://www.prototemplate.com/docs/handbook/multi-session-playbook) sections 4 and 5 hold the rules, and these are the incidents behind them.
| Date | What happened | The rule it set |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| 2026-08-07 | A bare `git commit` after `git add ` published another session's staged deletions inside a landing commit | Commit with a pathspec |
| 2026-08-07 | A desktop git client's revert, run mid-round, left conflict markers in four CSS files | Sweep for markers before every push or copy |
| 2026-08-07 | A co-editing session that commits with `git add -A` folded another session's uncommitted files into its own commit, and "nothing to commit" meant they were already in | Verify by content, and commit your own files promptly |
| 2026-08-26 | A copy into the tree with `rsync --delete`, run without a fetch, erased a 20-commit campaign another session had pushed | Fetch and read `HEAD..origin/main` before any copy or push |
| 2026-10-01 | `git add -A` swept 229 files (92MB) of another lane's folder onto main | Stage explicit paths |
```sh
git status --short # read paths you did not touch
git add src/app/page.tsx docs/handbook/review.md
git commit -F msg.txt -- src/app/page.tsx docs/handbook/review.md
git grep -n '^<<<<<<< ' -- src docs deck skills scripts # any hit stops the push
```
Rerun a failure once before diagnosing it when another session may be mid-save: a 500 from hot reload or a type error in a file another session is editing often clears on the second run. [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 2 holds the staging rules, and the [ship loop](https://www.prototemplate.com/docs/handbook/ship-loop) sections 0 and 7 hold the landing order.
## Sources [#sources]
* Prototemplate, read on 2026-10-21: `skills/gt-orchestration/SKILL.md` sections 2, 6 and 9, `skills/gt-orchestration/references/harness-traps.md`; `skills/gt-ship/SKILL.md` sections 1 and 2; `skills/gt-local-dev/SKILL.md` sections 1 and 2; `skills/gt-lints/SKILL.md` section 5; `skills/gt-films/references/sound.md`; `docs/SHIP-LOOP.md` sections 0 and 7; `docs/handbook/multi-session-playbook.md`.
* Kevin's private agent notes on the machine's memory crashes, the pattern kills, the zsh traps, worktree disk use, the reboot of 2026-10-07 and the shared-checkout sweeps, dated 2026-08-07 to 2026-10-18, for the measurements the skills do not carry.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Agent workflows
> Subagent workflows: lane prompts that survive relayed messages, resuming by run id, workflow shapes, refuters, kinds of check and paid model runs.
URL: https://www.prototemplate.com/docs/handbook/workflows
Kevin Liu runs large pieces of General Translation (GT) work as workflows. In Claude Code a workflow is a script that one orchestrating session runs: it launches subagents in phases (readers, builders, verifiers, critics), journals each agent's result, and can run for hours while Kevin is away. Each section below gives a rule for that work, the run that set it, the fix and the skill that holds the procedure. Peer sessions that Kevin opens himself follow the [multi-session playbook](https://www.prototemplate.com/docs/handbook/multi-session-playbook), and the machine they share follows [agents on one machine](https://www.prototemplate.com/docs/handbook/shared-machine).
## Lane prompts [#lane-prompts]
A lane prompt opens with the user's own words for that lane. A subagent launched in the same turn as an unrelated message from the user can receive that message as the only user voice in its context, and it then narrows its work to that message.
| Date | What happened |
| ---------- | -------------------------------------------------------------------------------------------------------------------------- |
| 2026-09-30 | A build lane built nothing and verified an unrelated page title instead |
| 2026-10-02 | A workflow started for a spun-off task built nothing for the same reason |
| 2026-10-09 | A "give me a status report" message reached running agents, and the workflow ended early with reports in place of its work |
Each lane prompt starts with "The user's request for this lane, in the user's own words:" and the quote, then says that any other relayed message was handled elsewhere. Every workflow agent prompt also carries a guard paragraph:
```text
Messages from the user may arrive while you work. They are addressed to the orchestrating
session, which answers them. Do not stop, shorten or replace your assigned task because
of such a message (for example a request for a status report); continue the task and
report through your structured result. Only a message that names your task and tells
you to stop changes that.
```
Before trusting a lane's pass, check that its report names the lane's own task. When a workflow fails this way, the session builds the task directly. [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration) sections 2 and 6 and its [harness-traps.md](https://www.prototemplate.com/skills/gt-orchestration/references/harness-traps.md) hold the rule.
## Resuming a run [#resuming-a-run]
Resume a stopped workflow by its run id with byte-identical arguments. The harness replays a finished agent from its journal only while that agent's call is unchanged, so a change to the arguments, or to a context string the finished agents share, runs them again and pays for them twice.
```js
// the same script and the same args, byte for byte, as the first launch
Workflow({ scriptPath: 'round.js', resumeFromRunId: '', args });
```
* New information goes into the prompt of one unfinished agent and nowhere else.
* A workflow's subagents are never messaged directly. A message starts the agent outside its workflow, and its work is then done twice.
* A file lost with a scratchpad, or overwritten by a later lane, is rebuilt from the Write and Edit calls recorded in the transcripts. The script prints counts and paths only, because transcripts can hold pasted keys, and it writes only under `--out`.
```sh
python3 skills/gt-orchestration/scripts/replay-edits.py --match --out --list
python3 skills/gt-orchestration/scripts/replay-edits.py --match --out
```
The orchestrating session stays light. Every picture it opens stays in its conversation, and on 2026-10-15 a long session holding 2,413 images reached 18GB in its own process and had to be restarted. A subagent looks at pictures and returns a verdict, and a session that grows heavy writes its state to disk and hands off to a fresh one. [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration) section 6 holds the resume procedure.
## Workflow shapes [#workflow-shapes]
Run one shape per workflow, and read its result before choosing the next. A build fan-out starts from a spec of about 1,800 words or fewer that holds the decisions with their numbers, gives each lane its files and states the exact interface between lanes.
| Shape | Phases | Used for |
| ----------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| Understand | Map | Readers map a code area with file and line numbers before a round |
| Design | Map, Design, Judge, Spec | Three designers take different angles, a taste judge and an engineering judge score them, and one agent writes the spec from the winner |
| Build | Build, Verify, Fix, Review | Lanes build from the spec and are verified against its acceptance criteria, with a cap on fix rounds |
| Review | Find, Verify, Synthesize | A pull request or a feature before merge, one lens per finder |
| Prove | Review, Mutate or Refute, Critic | A risky change: refuters, plus mutants that show the tests catch a revert |
| Sweep | Sweep, Audit or Verify | One mechanical change over many files, one agent per file group, then an adversarial re-read |
| Parity | Record, Synthesize, Fix, Verify | A redesign that must keep every tracking call and side effect of production |
| Probe | Probe, Verify | A hunt across the real inputs of a running server, one hunter per input class |
| Investigate | Investigate, Verify, Synthesize | A performance or behaviour question, one read-only agent per dimension with two skeptics each |
| Research | Research, Verify, Critique, Gap research, Synthesize | Facts a build will rest on, each note checked against primary sources |
| Package | Package, Check | Finished work cut into stacked branches from main, each gated in a clean checkout |
| Gauntlet | Build consumers, Matrix, Hostile inputs, Verify | A library change run on real consumer apps, the same request matrix on the change and on main, diffed |
A build lane reports in about 700 words or fewer: each file with one line, deviations from the spec with reasons, and the commands it ran with their results. A sweep or review lane returns a `checked` list (what it inspected and found clean) and an `uncertain` list, and leaves any value it cannot classify, because a missed change costs one more pass while a wrong one breaks the work. [workflow-shapes.md](https://www.prototemplate.com/skills/gt-orchestration/references/workflow-shapes.md) holds each shape with its schemas.
## Refuting findings [#refuting-findings]
Every critical and major finding goes to three refuters before anyone acts on it. Each refuter has its own lens and defaults to refuted when it cannot substantiate the claim, and a finding stands when at least two of the three fail to refute it.
| Lens | The question it answers |
| ------------ | --------------------------------------------------------------------------------------------- |
| Correctness | Is the claim true of the code on the pinned head commit? |
| Reproduction | Can the problem be observed in the code path, in the browser or by measurement? |
| Necessity | Would the fix change behaviour, bytes or a reader's understanding, and would it break a lint? |
* Refuted findings go to an appendix of the verdict and are never raised again.
* A probe carries an INTENDED list: one line per designed behaviour with an example input and its result, and every known issue marked "do not report again". Without it, hunters report the design as defects and the skeptics spend their runs refuting noise.
* A verifier pins the tree it read (the commit, or a hash of the uncommitted diff), and checks a regression claim against main before it blames the round.
* Packaging gates each branch in a clean checkout of that branch. Between 2026-10-03 and 2026-10-05 this caught CI failures that the working tree's gates had passed: the repository-wide formatter, and a generator that ran only with packages the first branch did not install.
[gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration) section 5 and [workflow-shapes.md](https://www.prototemplate.com/skills/gt-orchestration/references/workflow-shapes.md) (Review, Probe, Package) hold the rules.
## Kinds of check [#kinds-of-check]
Report gates, structural checks, measured checks and visual checks on separate lines. On 2026-07-30 a structural audit read 91 of 91 while 0 of 72 items passed a visual bar of 90 in every view, and a combined report would have read as a pass.
| Kind | What it proves |
| ---------- | ------------------------------------------------------------- |
| Gate | The typecheck or the lint passes |
| Structural | The page loads with the right hierarchy and dimensions |
| Measured | Computed values or pixels on the render match the numbers |
| Visual | A person or a fresh critic compared a crop with its reference |
Quality work converges through a separate critic scoring against a named reference, at bars of 8.5 of 10 per dimension and 90 of 100 overall and in every view. These rules close the ways to game the score:
* The critic is fresh, did not build the work, is told to be harsh, writes its mismatch notes before it scores and keeps the lower score when unsure.
* One strong view never averages away a weak one, and the builder never scores its own work.
* Work runs from the worst item upward over the whole set, because a sample proves nothing about the items it skipped.
* When a move fails twice, the idea changes: measure the reference and rebuild from the measurements.
* The cheapest phase the user most wants runs first. On 2026-07-29 a run of about 45 agents put its blind judge first, because the run before it had died on usage credits before its judge ran.
* The judge starts after the builders land, because a verdict on work still being rewritten goes stale within the hour.
[gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration) sections 4 and 5 and [convergence.md](https://www.prototemplate.com/skills/gt-orchestration/references/convergence.md) hold the loop, and the [quality bar](https://www.prototemplate.com/docs/handbook/quality-bar) holds its rows.
## Paid model runs [#paid-model-runs]
A run that pays per model call starts with a proposal and runs nothing until Kevin approves it. The proposal names the grid, a per-run cap and a total cap on estimated spend, a fixed trial count per cell and a no-retry rule, and it says that the cap can stop the study early.
| Part of the proposal | The comparison approved on 2026-10-05 |
| -------------------- | -------------------------------------- |
| Grid | Four models by six tasks by four modes |
| Fresh runs | 96 |
| Total cap | $25 of estimated spend |
| Retries | None |
1. Freeze the plan: the worker, its helpers and the grid file stay unedited after approval.
2. Run a pilot of a few cells and verify every record, costs and reservations included.
3. Launch the approved remainder once, under one worker that holds the run's lock file, so nothing starts a second collector.
4. At the end, run the verifier, which writes the verified summary and the accounting export.
A stop is diagnosed read-only, and its continuation is a new, separately labelled campaign that keeps every earlier record and cost reservation inside the original allowance. A timeout or a dropped connection is a defect in the harness, fixed before the continuation runs. A campaign of single attempts per cell names no winner. A heartbeat that checks a long run on a schedule stays read-only, never retries a cell or relaxes a limit, and speaks only on completion, on failure or when Kevin must decide. [gt-orchestration](https://www.prototemplate.com/skills/gt-orchestration) section 7 and [campaigns.md](https://www.prototemplate.com/skills/gt-orchestration/references/campaigns.md) hold the proposal, the stop question and the heartbeat prompt.
## Sources [#sources]
* Prototemplate, read on 2026-10-21: `skills/gt-orchestration/SKILL.md` sections 1 to 7; `skills/gt-orchestration/references/harness-traps.md`, `workflow-shapes.md`, `convergence.md` and `campaigns.md`; `skills/gt-orchestration/scripts/replay-edits.py`; `docs/handbook/quality-bar.md` (Convergence loops).
* Kevin's private agent notes on the relayed-message trap, workflow resumption after the reboot of 2026-10-07 and the session restarted at 18GB, dated 2026-09-30 to 2026-10-15.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Pull requests and CI
> Pull requests on gt-cloud: CI signals that mislead, review bots, size and shape, parity for redesigned flows, ratcheted lints and git on shared trees.
URL: https://www.prototemplate.com/docs/handbook/pull-requests
General Translation (GT) keeps its product and its website in gt-cloud, a private monorepo on GitHub. gt-cloud squash-merges pull requests, requires three checks on main (`Validate PR title and Linear issue`, `check-planning-files` and `run-tests`), and is reviewed by bots and by people. Kevin Liu's product and site work lands there as small pull requests, each from its own worktree. Each section below gives a rule for that work, the case that set it, the fix and the skill that holds the procedure. The facts are gt-cloud's as of October 2026, and the methods apply to any GitHub repository with CI and review bots.
## CI signals that mislead [#ci-signals-that-mislead]
Read a pull request's checks only after its merge conflicts are resolved, and list the branch's runs before blaming the latest push. GitHub runs no `pull_request` workflows while a pull request conflicts with its base, and each push cancels the run in flight, so the checks on the head can describe another commit or none.
| Signal | Cause | Fix |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| Checks are stale, cancelled or missing | The branch conflicts with its base (`mergeStateStatus: DIRTY`), so no `pull_request` workflow ran | Merge or rebase first, then read the checks |
| A red e2e on the latest push | The first run to finish reports every commit since the last green one; on 2026-09-29 a red e2e came from a commit five pushes earlier | List the runs and find the first red one |
| The build dies in "Running TypeScript" | The dashboard's type check outgrew Node's default 2GB heap | Raise `--max-old-space-size`; the build has run with 4096 since 2026-09-29 |
| A Playwright strict-mode violation | `getByText(..., { exact: true })` across the page also matches the label inside a closed `` | Scope text lookups inside a `getByTestId` locator |
| `mergeStateStatus: BLOCKED` with every check green | The code-owner review is missing | Request the code-owner review |
```sh
gh pr view --json mergeStateStatus,headRefOid
gh run list --branch --workflow "CI - Run Tests" # a trail of cancelled runs hides the first red
```
A required aggregate check fails when any job under it fails. `run-tests` aggregates lint, build, the unit test shards, validate, integration, e2e and db, so a red e2e blocks the merge although e2e is not a required check itself. [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 5 and [review-loop.md](https://www.prototemplate.com/skills/gt-ship/references/review-loop.md) hold the check list and what trips each job.
## Review bots [#review-bots]
Before acting on a bot's finding, compare the commit it reviewed with the pull request's head. Two review bots on gt-cloud write their summaries into the pull request body between HTML comment markers, and they rerun on different triggers.
| Bot | Reruns | Re-trigger | Reviewed commit |
| ------------- | ------------- | ------------------------------------------------------------------------------------------ | ------------------------------------- |
| Greptile | On open only | Comment `@greptile review again` (`@greptile review` the first time); about 4 to 5 minutes | `Last reviewed commit` in its summary |
| Cursor Bugbot | On every push | Comment `bugbot run` | Named in its summary |
Bots review a new pull request within about a minute. On 2026-09-24 a force push a minute after opening refreshed Bugbot and left Greptile's summary describing a diff that no longer existed. An edit to the body right after a force push can also restore Bugbot's stale summary. The bar on gt-cloud is Greptile at 5/5 on the head commit with every bot thread answered and resolved.
* Rewrite only the part of the body above the first bot marker, and keep every bot block byte for byte.
* Classify each finding before acting on it: mine and real (fix, push, reply with the sha, resolve), stale (reply with the commit that removed the code, resolve), not mine (say so and leave it to its owner), or an owner's decision (ask).
* A risk label from an approval bot is a label and needs no reply.
* Reply on each thread with the fixing commit, then resolve it. A thread resolved without a reply still reads as unanswered to a human reviewer.
```sh
gh api graphql \
-f query='mutation($id:ID!,$body:String!){addPullRequestReviewThreadReply(input:{pullRequestReviewThreadId:$id,body:$body}){comment{url}}}' \
-F id=PRRT_xxx -f body='Fixed in abc1234: the query is bounded to 100 rows.'
gh api graphql \
-f query='mutation($id:ID!){resolveReviewThread(input:{threadId:$id}){thread{isResolved}}}' \
-F id=PRRT_xxx
node skills/gt-ship/scripts/pr-bots.mjs # exits 0 at 5/5 on the head, no open thread, no conflict, checks green
```
[gt-ship](https://www.prototemplate.com/skills/gt-ship) sections 4 and 5 and [review-loop.md](https://www.prototemplate.com/skills/gt-ship/references/review-loop.md) hold the loop, and the [quality bar](https://www.prototemplate.com/docs/handbook/quality-bar) holds its rows for pull requests.
## Size and shape [#size-and-shape]
A reviewer reads a pull request's line count first. Group the diff by kind before pushing, and justify each large group in the body or cut it. On 2026-10-02 Kevin sent back a release pull request for a redesigned onboarding flow because of its size.
| Part of the release pull request | Size |
| ---------------------------------------------- | ------------------------------- |
| The whole pull request | 39.5k lines |
| A record-and-replay parity suite | 24k lines |
| Pretty-printed recorded JSON inside that suite | 18k lines |
| Comments | 20% of the added product lines |
| Tests | 1.2 test lines per product line |
* Verification instruments (recorded fixtures, record-and-replay suites, harnesses, capture scripts, review galleries) live on their own branch or in the scratchpad.
* Each behaviour is tested once, with targeted assertions added to the existing test file.
* A comment says why in one or two lines.
* A pull request carries one concern, and an unrelated repair gets its own.
* Planning Markdown stays out: `check-planning-files` fails on an added Markdown file that reads as a plan.
```sh
node skills/gt-ship/scripts/pr-size.mjs # origin/main...HEAD, grouped by kind
node skills/gt-ship/scripts/pr-size.mjs --base origin/ # in a stack
node scripts/check-plan-files.mjs --base origin/main # in gt-cloud, before pushing
```
Screenshots go in with the first push and are refreshed after every visible change, as before and after crops. Full-page captures in a two-column table render as strips that nobody can read.
| Crop rule | Value |
| --------- | ----------------------------------------------------------------------------------------------------- |
| Clip | The changed elements' bounding boxes plus 24px of padding |
| Width | 420 to 900 CSS px |
| Height | 620 CSS px at most |
| Pairing | The same clip on main and on the branch |
| Layout | `\| Before (main) \| After (this branch) \|` for crops up to 640px wide; wider crops stack full width |
| Themes | Both, where the change has a theme |
[gt-ship](https://www.prototemplate.com/skills/gt-ship) sections 3 and 4 and [pr-body.md](https://www.prototemplate.com/skills/gt-ship/references/pr-body.md) hold the size audit and the body's shape.
## Parity for a redesigned flow [#parity-for-a-redesigned-flow]
A redesign of a sign-in or onboarding flow keeps every tracking call and backend side effect that production has, and the proof is a diff of recorded side effects. A reviewer's list of intended changes proves nothing: one audit called an organization audit event preserved while a later fix had already dropped a field from the event's scope.
1. Record production at the module boundaries for each scenario, in a detached worktree of main.
2. Replay the same scenarios on the release and record the same boundaries.
3. Diff the two ledgers, and run the diff again after every fix.
```sh
git fetch origin
git worktree add --detach ../parity-main origin/main # production's code, for the recording
```
Additions are allowed only for stricter authorization checks and new recovery paths, and the body lists each one. When parity would mean reporting a step the redesign removed, ask the owner of the flow and fake no event. The record-and-replay suite, the 24k lines above, stays on its own branch. [gt-ship](https://www.prototemplate.com/skills/gt-ship) section 7 holds the gate, and the [decisions log](https://www.prototemplate.com/docs/handbook/decisions) holds the ruling of 2026-10-02.
## Lints and ratchets [#lints-and-ratchets]
A rule that matters gets a lint that fails on drift, and the lint's design follows from how many sessions edit the code at once.
* A ratchet counts violations per file. Parallel sessions move lines all the time, and a per-file count stays the same when a line moves.
* A baseline above the real count lets a new violation into that file without a failure, so the baseline is lowered after every cleanup.
* A clean exit under `--report` proves nothing, because `--report` drops the failing exit codes.
* A gate never passes when it could not judge: it exits 2 on an HTTP error, a missing file or a state that did not open.
* Every exemption carries its reason in config.
Every Prototemplate lint prints `file:line rule message` and exits 0, 1 or 2, and the [Gates](https://www.prototemplate.com/docs/gates) page of the docs lists them. [gt-lints](https://www.prototemplate.com/skills/gt-lints) sections 1, 4 and 5 and [prototemplate-gates.md](https://www.prototemplate.com/skills/gt-lints/references/prototemplate-gates.md) hold the contract.
## Git on shared trees [#git-on-shared-trees]
Before reporting a push, prove it from the remote. When several sessions share a worktree, its branch, its files and its tracking refs can change between two commands.
| Trap | What happened | Fix |
| ------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| A fast-forward across a `.gitignore` change | It overwrote ignored files at newly tracked paths with no warning (2026-10-10) | Copy the ignored originals aside before the fast-forward |
| A rebuild of history | 32 shell scripts were committed at mode 100644, and lanes that ran them directly failed (2026-10-10) | `git update-index --chmod=+x `, then commit |
| A lease against a stale tracking ref | A force push erased a collaborator's five commits (2026-08-26) | Fetch first, then lease against the sha you expect |
| GitHub's update-branch button | It creates a merge commit on the remote and turns auto-merge off; a force push turns it off too | `git pull --rebase` before the next push, then `gh pr merge --auto` again |
| Two sessions in one worktree | One switched the branch, and two commits meant for a pull request never reached it (2026-09-28) | Check the branch before each commit, and compare the pull request's head with `HEAD` before reporting |
| A listing cut with `head -8` | It hid an existing test file, and a write meant for a new file replaced seven tests | Prove a file is new with `git ls-tree` and `test -f`, and never cut an existence check |
```sh
git fetch origin && git log --oneline HEAD..origin/ # a collaborator's commits
git push --force-with-lease=: origin HEAD:
git branch --show-current # before every commit
gh pr view --json headRefName,headRefOid && git rev-parse HEAD # before saying "pushed"
git ls-tree origin/main -- ; test -f && echo exists # before writing a "new" file
```
[gt-ship](https://www.prototemplate.com/skills/gt-ship) sections 1 and 2 hold the commit and push rules, and the [multi-session playbook](https://www.prototemplate.com/docs/handbook/multi-session-playbook) holds the rules for branches that two agents push.
## Sources [#sources]
* Prototemplate, read on 2026-10-21: `skills/gt-ship/SKILL.md` sections 1 to 7, `skills/gt-ship/references/review-loop.md` and `pr-body.md`, `skills/gt-ship/scripts/pr-size.mjs` and `pr-bots.mjs`; `skills/gt-lints/SKILL.md` sections 1, 4 and 5 and `references/prototemplate-gates.md`; `docs/handbook/quality-bar.md` (Pull requests); `docs/handbook/decisions.md` (2026-10-02).
* gt-cloud's CI workflows, rulesets and review bot behaviour, as `review-loop.md` records them from origin/main on 2026-10-05.
* Kevin's private agent notes on the review bots, pull request size, crops in pull request bodies, the parity gate and the history rebuild of 2026-10-10, dated 2026-08-26 to 2026-10-10.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Reviewing with Kevin
> How Kevin’s review words map to measures, one exemplar before a set, how a result reaches him, the five ship states and the ask ledger.
URL: https://www.prototemplate.com/docs/handbook/review
Kevin Liu does design, website and product work at General Translation (GT), and he reviews the work his agent sessions do: on localhost, in pull requests and in the desktop app where the sessions run. His review words have fixed readings, his rounds start from one exemplar, and every result reaches him as something to see with its state named. Each section below gives the rule, the review that set it and the skill that holds the procedure. The [quality bar](https://www.prototemplate.com/docs/handbook/quality-bar) holds the bar the work is measured against, and the [operating principles](https://www.prototemplate.com/docs/handbook/operating-principles) hold the standing rules behind his corrections.
## Words read as measures [#words-read-as-measures]
Each word Kevin uses in a review has one reading, and each reading was set by a correction. Apply the reading on the render and report the measured values.
| Word | Reading | The case that set it |
| --------------------------------------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| "Equivalent", "equal" | Both measures take the larger value | 2026-09-30: two gaps evened at 10px in an 814px-tall window were rejected; the accepted pair reads 16 and 16 there and 26 and 26 at 900px |
| "Smaller", "larger" | The next rung of the existing ladder | 2026-09-28: 13px card facts went to the 12px rung |
| "Fix this", on one instance | The whole class: find every member, fix it, report the count | [Operating principle 5](https://www.prototemplate.com/docs/handbook/operating-principles) |
| "Remove this" | The smallest reading, then a check of the neighbours | Standing rule |
| "Add it to the left of X" | X alone; the rest of X's column stays | 2026-08-13 |
| "Standardize" | One structure on every page of the kind, with a lint or the page check to catch a page that drifts | 2026-10-06, the book page |
| "Enhance", on an existing page | Keep the page, its sections and its copy word for word, and add to it | 2026-10-08: a rebuild that dropped a page's hero, logo band and copy was rejected |
| "Redesign" | Visibly new; a change that keeps the old shape comes back as not done | 2026-09-30 |
| "Keep its aesthetic" | The geometry and the material stay, and only the named thing changes | Standing rule |
| "Make it look better", with a reference | Measure the reference and match it | Standing rule; without a reference, the brand deck for a product surface and the shipped site for a landing page |
Kevin, 2026-08-13: "incorrect. i only want you to add it to left of ...".
Once a rule matters to him, Kevin asks for a lint, so a new rule ships with its lint or names the lint that should hold it. [process.md](https://www.prototemplate.com/skills/gt-aesthetic/references/process.md) of `gt-aesthetic` (Reading Kevin's asks) holds the readings.
## One exemplar first [#one-exemplar-first]
Build one section, one page or one state, get Kevin's sign-off on its grammar, then replicate it across the set. A full set built on a reading he had not confirmed costs the whole round. A version he rejected is never the base of the next attempt, which restarts from the reference.
| Date | What happened | The rule it set |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| 2026-08-04 | Seven landing sections fanned out on an unconfirmed reading of the mock images, and one element survived review: an isometric drawing | One exemplar first; mock images and prototype pages are literal specs, and their notes are change orders |
| 2026-08-12 | After Kevin picked one variant per page, a variants system of about 16,000 lines left the code, and the sign-in route was checked byte-identical to the committed page | The alternatives leave the code after a pick and stay in git history |
| 2026-09-04 | Nine of ten shader frames sent for a pick looked the same | Check that a set differs before sending it |
| 2026-09-14 | A round rebuilt ten directions as forks of one earlier direction, and seven of the ten heroes had the same layout, headline and hero visual | Directions differ in silhouette, material and action |
Kevin, 2026-09-04: "they all looks the same bro 9 / 10 are the same".
The set check flags a pair of pictures under 2% mean difference as the same picture, and a pair whose tone grids correlate at 0.9 or above as the same composition. A clean report means only that no two options are near copies, so the silhouette, material and action table is still read by eye.
```sh
node skills/gt-explorations/scripts/distinct-set.mjs public/shots/light/.jpg public/shots/light/.jpg
node skills/gt-explorations/scripts/distinct-set.mjs --strict
```
* A direction lives in its own route with its CSS scoped under its own root class, so it never restyles another direction. Keyframe names are global, so a direction prefixes its own with its slug.
* Explorations stay on a branch or uncommitted until Kevin has reviewed them on localhost, because Prototemplate's main branch deploys the public site.
[gt-aesthetic](https://www.prototemplate.com/skills/gt-aesthetic) section 5 holds the loop, and [gt-explorations](https://www.prototemplate.com/skills/gt-explorations) section 2, [rounds.md](https://www.prototemplate.com/skills/gt-explorations/references/rounds.md) and [charter.md](https://www.prototemplate.com/skills/gt-explorations/references/charter.md) hold the rules for a round.
## Showing the result [#showing-the-result]
Every visual or audible result reaches Kevin as something he can see or hear, in the turn it is made and before he asks for it.
| What changed | What Kevin gets |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
| An area of a page or a component | Before and after crops of every changed area at the same viewport and clip, 420 to 900 CSS px wide, in both themes |
| A set of marks, covers or directions | One contact sheet with every item numbered, plus the files |
| A page, a flow or an app | The URL of a running server, with its port, branch and commit |
| Audio takes or voices | Each option numbered on screen, as a video or on a small listening page |
| Scripts, voiceover lines, deck text | The text, for review before the final render |
Images go into the reply as attached files, so he can forward them. A claim about size or spacing carries the value measured in the browser, such as "both buttons read 9.5px from label to glyph". Crops are shot with an external browser harness, because the desktop app's browser pane pauses `requestAnimationFrame` and canvases come out blank there.
The desktop app's file card plays video files and does not play audio-only files, so on 2026-10-16 a pronunciation sample sent as `.mp3` could not be heard. A listening sample goes out as `.mp4`: one 1280 by 720 card per option with its number large, drawn with Pillow where the installed ffmpeg has no `drawtext` filter, cut to the audio and joined with ffmpeg's concat demuxer. The question then names the numbers on screen.
```sh
ffmpeg -loop 1 -i card-1.png -i take-1.wav -c:v libx264 -tune stillimage -pix_fmt yuv420p -c:a aac -shortest option-1.mp4
printf "file '%s'\n" option-*.mp4 > options.txt
ffmpeg -f concat -safe 0 -i options.txt -c copy options.mp4
```
[gt-reporting](https://www.prototemplate.com/skills/gt-reporting) section 1 holds the table, and [process.md](https://www.prototemplate.com/skills/gt-aesthetic/references/process.md) of `gt-aesthetic` holds the local review recipe.
## Ship states [#ship-states]
Each item in a report ends in one state, and each state carries its proof.
| State | Words | Proof in the line |
| ---------- | --------------------------------------------------------------------- | --------------------------------------------------- |
| Local only | "local only, uncommitted" or "committed locally at ``, unpushed" | The sha |
| Pushed | "pushed to `` at ``" | The branch and the sha |
| PR open | "PR open, checks green, needs one approval" | The full link and its checks |
| Merged | "merged to main as ``" or "merged into the PR branch ``" | The merge sha and the branch it went into |
| Live | "deployed and verified live at ``, serving ``" | The URL and how the build was matched to the commit |
Kevin, 2026-10-03: "when u say "merge" u mean into ur pr right".
A merged change is live only once a production build of its commit has succeeded and serves the page. While production builds fail, the site keeps serving the last good deployment, so the newest production build is read before a report says "live". A clean local type check does not prove the hosted build either. On 2026-10-16 a push that compiled cleanly with `tsc -b` failed its hosted build three times: TanStack Start's import protection refuses a server-only import that stays in a page's module graph, and a helper in a module the page imported called `setResponseStatus` from a default parameter. In a module a page imports, every request-scoped server call stays inside the server function's handler or behind an awaited import.
[gt-reporting](https://www.prototemplate.com/skills/gt-reporting) section 2 holds the states, and [gt-verify](https://www.prototemplate.com/skills/gt-verify) section 7 holds the checks that prove a deploy.
## The ask ledger [#the-ask-ledger]
Kevin sends long messages with several asks and adds more while work runs, so every ask is numbered in the order received and tracked until it is reported.
```text
N. [done | in progress | blocked: reason] the ask in Kevin's terms. Where: file, route or URL. Proof: commit, PR or URL. Verified: how.
```
* A report on multi-ask work closes with the full ledger, done items included. When he re-sends a compiled list, it is matched line by line and every item is reported.
* "Did we do this" gets a yes or a no first, then the item's ledger line.
* A turn opens with the answer to what he asked, about the exact pull request, page or file he named, then what shipped, something to see, and a numbered list of what only he can do (an approval, a login, a payment, a credential, a choice).
* A short summary holds what shipped and what only he can do, in under fifteen lines.
* Workflow internals stay out: lane and agent names, bot rounds, lint runs, rebases and follow-up pull requests opened along the way.
When a run will outlast a compaction of the session, the ledger lives in a file named in each report, so a bare "continue" resumes from it. [gt-reporting](https://www.prototemplate.com/skills/gt-reporting) sections 3 and 4 hold the ledger and the order of a turn's close.
## Sources [#sources]
* Prototemplate, read on 2026-10-21: `skills/gt-aesthetic/SKILL.md` section 5 and `references/process.md`; `skills/gt-explorations/SKILL.md` section 2, `references/rounds.md` and `references/charter.md`, `scripts/distinct-set.mjs`; `skills/gt-reporting/SKILL.md` sections 1 to 4; `skills/gt-orchestration/SKILL.md` section 1; `docs/handbook/decisions.md` (2026-08-12); `docs/handbook/operating-principles.md`.
* Kevin's messages to Claude Code and Codex for the quoted rulings. Quotes keep his spelling.
* Kevin's private agent notes on the sign-in gap review, the first landing build, the variants program, sending audio samples and a hosted build failure, dated 2026-08-04 to 2026-10-16.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# GT product and architecture map
> What General Translation sells and to whom, how the products fit together, the copy that must be exact, and where each part lives.
URL: https://www.prototemplate.com/docs/handbook/gt-product-map
This page is for agents and people who write about General Translation (GT), design for it or change its products. It states what GT sells and to whom, how the products fit together, the facts copy must get right, and where each part lives in the repositories. Each fact carries the date it was read or ruled. Everything on the page is safe to publish: it names no customer, states no business figures and leaves internal data-model details to gt-cloud's own documents.
Detail stays with the documents that own it:
* [BRAND.md](https://www.prototemplate.com/docs/handbook/brand) and [gt-brand](https://www.prototemplate.com/skills/gt-brand) hold the name, the idea, the positioning line and the marks.
* [gt-website](https://www.prototemplate.com/skills/gt-website) holds the landing app map, docs routing, the blog and deploys.
* [gt-landing-pages](https://www.prototemplate.com/skills/gt-landing-pages) holds the page grammar for the home, pricing, enterprise and careers pages.
* [gt-voice](https://www.prototemplate.com/skills/gt-voice) holds the writing rules, and [gt-components](https://www.prototemplate.com/skills/gt-components) holds the translation component rules.
* gt-cloud's `AGENTS.md` (which `CLAUDE.md` links to) and its `.agents/skills` hold the monorepo file map and the engineering rules, such as `audit-events` and `server-security`.
`$GT_CLOUD` is a gt-cloud checkout at origin/main. gt-cloud facts below were read at e17fce499 on 2026-10-05.
## 1. Positioning [#1-positioning]
The home page hero says GT "builds full-stack localization for apps, docs, and websites" (read 2026-10-05). GT builds every layer of that stack itself:
1. open-source i18n libraries and SDKs for every major framework;
2. context-aware translation APIs;
3. the platform for versioning, editing, review and delivery;
4. Locadex, the agent that internationalizes a codebase and keeps it localized.
Kevin, 2026-07-30: "the whole point is that were a full stack localization, end to end".
* The positioning is the Vercel model applied to localization. GT pairs open-source developer tools with the hosted infrastructure that runs them best (BRAND.md section 2). This is the one comparison GT copy makes (gt-voice, hard rule 2).
* The thesis is "Every product in every language" (BRAND.md section 2). Copy quotes it as written.
* Pricing is usage-based. Legacy translation management systems (TMS) charge per seat and cover part of the stack. Because GT owns the whole stack, it can own the whole customer experience (BRAND.md section 9).
* Copy states the mission only as the live careers page states it.
## 2. Audience and the sale [#2-audience-and-the-sale]
* The audience has two ends, which Kevin calls a barbell (2026-07-30). Developers and small teams start self-serve at one end. Enterprises buy through sales at the other. A page carries enterprise presence and developer comfort together.
* BRAND.md section 9 names the buyer: technical and product executives at growth-stage startups, whose engineering and growth teams use the product. The open source carries a community register and the platform an enterprise register (BRAND.md section 2).
* Many buyers cannot yet tell localization, translation and internationalization (i18n) apart, so pages show what localization does: translated copy, changed code, converted currency, reformatted dates and numbers, and layout rearranged for a script. The terms themselves stay on the page for evaluators who check for them. The docs define them on [Key concepts](https://generaltranslation.com/docs/overview/key-concepts).
* Heroes and demos show the product working. Kevin, 2026-08-11, on the enterprise page: "far less telling, more showing, so same content but less text and more better diagrams".
## 3. Products [#3-products]
| Product | What it does | Where it lives |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The `gt` libraries | `gt-next`, `gt-react`, `gt-tanstack-start` and `gt-react-native` (each 11.4.9 on npm, 2026-10-05), `gt-vue` and `gt-node` render translations and format locale-sensitive values in the app. `gt-next` also detects the locale and routes by it. | `generaltranslation/gt`, `packages/` |
| The Python SDKs | `gt-flask` and `gt-fastapi` on PyPI, built on the `generaltranslation` core package. BRAND.md's naming table writes the family as `gt-python`, which is the repository name; no package of that name exists (PyPI, 2026-10-05). | `generaltranslation/gt-python` |
| The `gt` CLI | Sets up a project, signs in, translates files and calls the API (`gt` 2.25.1 on npm, 2026-10-05). Section 7 has the commands. | `generaltranslation/gt`, `packages/cli` |
| The platform and dashboard | Projects, Context Groups, the translation editor, review and approval, version branching, annotations and audit logs at dash.generaltranslation.com. Review works over the web workspace, the API and the CLI. | `$GT_CLOUD/apps/dashboard`, `apps/api` |
| The translation API | Context-aware translation of text, files and components, published as `/openapi.yaml`. | `$GT_CLOUD/apps/api` |
| The translation CDN | Serves pre-generated translations from a global, low-latency CDN, and pushes over-the-air updates without a redeploy of the app. | `$GT_CLOUD/apps/edge` (Cloudflare Workers) |
| Runtime translation | Translates user-generated content on demand with the project's context. In Next.js it is `` and `tx()` from `gt-next/server`, built on `GTRuntime` in the core library. | `generaltranslation/gt`, `packages/core` and `packages/next` |
| Locadex | A hosted agent. It connects to GitHub and to content sources (Google Drive, Figma, a CMS), scans the repository, internationalizes the code, generates translations and opens pull requests. Its automations keep the app localized after the first pass. | `$GT_CLOUD/apps/locadex`, `packages/locadex-core` |
| Integrations | Mintlify, Sanity (`gt-sanity`), Storyblok, Google Drive and rrweb (`gt-rrweb`), the GitHub Action, and the MCP server (`@generaltranslation/mcp`). | `generaltranslation/gt` (Sanity, rrweb, MCP), `$GT_CLOUD/packages/integrations` (hosted connectors such as Google Drive and Storyblok), `generaltranslation/translate` (the Action) |
The React libraries share one API. `` wraps a block of static JSX, and ``, ``, `` and `` mark its dynamic parts. `gt()` translates a string, `msg()` marks strings in a data array, and `` and `tx()` translate content at runtime in server code. The usage rules, including `const gt = useGT();` and `await getGT()` in async server code, are in [gt-components](https://www.prototemplate.com/skills/gt-components) and gt-cloud's `AGENTS.md`.
This plate runs `EdgeGlobe`, the drawing of the translation CDN that the home page of generaltranslation.com uses. A request travels to the closest point of presence, where the translation already sits, and the payload returns along the same route.
## 4. Context [#4-context]
Context reaches a translation through three layers: the Organization, then the Project, then the Component (Kevin's outline of 2026-07-30; the dashboard guide [Defining context for translations](https://generaltranslation.com/docs/platform/dashboard/guides/defining-context-for-translations), read 2026-10-05). Each layer is inherited by the one below it.
| Layer | What sets context there |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Organization | Context Groups live at the Organization level. A Context Group pairs a Glossary with Custom Prompts. |
| Project | A project applies one or more Context Groups in priority order. The top group wins where two groups overlap, and newly generated terms are saved to it. |
| Component | `` sets context for one block. `gt()` and `getGT()` take a `$context` option. `$context` on `` is a deprecated alias. |
* The Glossary holds terminology: product names, brand names, feature names, technical terms and phrases that stay untranslated. Its standing example is that Locadex is never translated in any locale.
* Custom Prompts hold style: tone, audience, formality, conventions and formatting. A prompt applies to every locale or to one. Kevin's July outline called this half Directives, and the importer still accepts exports that use that label. The dashboard, the API and the pricing page call it Custom Prompts (2026-10-05), and copy uses that name.
* Kevin's component example, from the 2026-07-30 outline: `Click the toast to dismiss`.
* An edit to a Context Group applies to new translations. The Apply button on a project's Context page updates existing translations with chosen Glossary terms.
* The Context Management API (`org:context:read` and `org:context:write`) and its MCP tools automate groups, terms and prompts.
## 5. Enterprise and plans [#5-enterprise-and-plans]
Plan facts come only from the public pricing page, [https://generaltranslation.com/pricing](https://generaltranslation.com/pricing), quoted as it read on 2026-10-10. Plan rules the page does not state, such as what a new account receives, are internal and stay in gt-cloud's `gt-dashboard` skill.
* The lead: "Start for free with usage-based billing. Unlimited projects and users on every plan."
* Starter: "$0", "For individuals and small teams". It lists unlimited projects, users and languages, the Translation Editor, the GitHub Integration, the Locadex AI Agent and usage-based pricing, with a Get Started button.
* Enterprise: marked Recommended, "For large teams with complex localization needs". It lists unlimited projects, users and languages; "Dedicated FDE hours to build any workflow for your use case."; "Custom integrations, webhooks, and tailored automation."; and "SSO, RBAC with custom permissions, SOC 2 and ISO 27001 certificates", with a Contact Us button.
* The comparison table: a Platform Fee of $0 on Starter and Custom on Enterprise, and Usage Rates that link to [https://generaltranslation.com/pricing/usage](https://generaltranslation.com/pricing/usage) on Starter and read Custom on Enterprise. Its rows name the core products (Locadex AI Agent, Custom Workflows, Translation CLI, Context Platform, Translation CDN, Version Branching), the platform (languages, projects and users unlimited on both plans, Context Groups, Keyword Glossary, Custom Prompts, Translation Editor, Custom Roles, Webhooks, SOC 2 Type II and ISO 27001 certification, SSO over SAML and OIDC) and support (GitHub, email, Discord, Slack and phone). The table marks which plan has each row with icons, so copy that says which plan includes a row reads the live page first.
The comparison table follows the cards directly (Kevin, 2026-08-15), and the page's diagram sits below the plans. The money format on pricing pages is gt-landing-pages' whole-dollar rule.
Kevin set the four enterprise pillars on 2026-08-15, and the enterprise page carries them (read 2026-10-05). His list named the third pillar Forward-deployed engineers, and the live page heads it Forward-Deployed Support, the name copy uses.
| Pillar | Copy |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| Security and governance | SSO, SOC 2, ISO 27001, audit logs, and custom roles. The pricing table adds SSO over SAML and OIDC, SOC 2 Type II and RBAC with custom permissions. |
| Enterprise platform | Share translation context, glossaries, and custom prompts across every project and content source in your company. |
| Forward-deployed support | Dedicated FDE hours with localization engineers to set up your system and bring localization to production. |
| Custom workflows | Reliable, scalable translation workflows across any file format or framework. Custom integrations, webhooks, and tailored automation. |
* The enterprise page's section order is governance and SSO, translation review, shared context across teams, forward-deployed support, then the contact form (Kevin, 2026-08-16). A change to the page's sections follows that order.
* Features grouped under one heading share one purpose (Kevin, 2026-08-15).
* The enterprise hero has one button. Kevin cut its second button, Talk to an Engineer, on 2026-08-15.
## 6. Copy that must be exact [#6-copy-that-must-be-exact]
| Topic | What copy says | Source |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Layout per language | "Dynamic layout for each language". GT rearranges components for a language, such as right-to-left order for Arabic. The components themselves stay unchanged. | Kevin, 2026-08-06: "technically we dont alter components, but can rearrange them dynamically like for arabic" |
| Review surfaces | "Review and approve with your team, over web, API, or CLI." Copy names all three surfaces, because enterprises judge vendors on agent readiness. | Kevin, 2026-08-06: "from one surface implies that we're forcing you to use our dashboard" |
| Formatting | "Numbers, currencies, dates, plurals, and more", with no "edge cases handled" lead. | Kevin, 2026-08-06 |
| Delivery | "Served using a global, low-latency translation CDN." and "Push over-the-air updates without redeploying your app." Translations can also ship with the code, so the home page's delivery band reads "Served from local files or the edge" (read 2026-10-05). Copy that describes delivery in general names both paths. | Kevin, 2026-08-15, for the enterprise page's delivery panel |
| Enterprise voice | "Every company's localization needs are different. General Translation adapts to your existing stack, workflows, and review process." The customer uses the platform with its own team or alongside GT's forward-deployed engineers. A line that implies GT's team is better than the customer's is cut, and gt-voice holds the register. | Kevin, 2026-08-15 |
| Localized heroes | Each locale's hero line is idiomatic and carries the exact meaning in that language and culture. A locale route such as `/ja` opens with its hero sentence and diagram in that locale. | Kevin, 2026-08-08 |
| Geography | Content about places is organized by language. It names no country or territory, draws no borders, takes its facts from CLDR, and treats disputed areas through one policy. | Kevin, 2026-10-03: "avoid political sensitivity without making it look forced" |
| Infrastructure diagrams | Edge nodes carry real cloud region names such as `us-east-1`, shortened where a label would clip. | Kevin, 2026-08-06 |
| Names | Product tokens keep their exact form (`gt`, `gt-next`, `gt login`), Locadex is never translated, and the naming table is BRAND.md section 1. | BRAND.md, gt-voice |
| Public facts | A customer or partner is named only where generaltranslation.com shows it, and BRAND.md section 9 follows the site. No surface states funding, revenue, headcount or the timing of an unannounced launch. | gt-brand section 8; the decisions log, 2026-10-10 |
## 7. CLI and agent entry points [#7-cli-and-agent-entry-points]
The CLI facts below come from the start prompt served at `/agent-prompt.md` (read 2026-10-05) and from the CLI source on `generaltranslation/gt` origin/main. A coding agent ran the prompt end to end on a fresh Next.js app on 2026-09-25 with gt 2.22.3 and again on 2026-09-30 with gt 2.23.1. The published CLI was 2.25.1 on 2026-10-05.
* `gt login` signs the CLI in with the person's GT account. It opens GT's sign-in page in the browser and shows a confirmation page when sign-in completes. `gt login --no-browser` prints a sign-in URL and a code to use on any device, and an SSH session takes that path by default. `gt whoami` reports the signed-in account.
* Public writing explains how to sign in and use the product. It leaves out how the CLI obtains, stores or refreshes its tokens, which is the public authentication boundary in the `AGENTS.md` of `generaltranslation/content`.
* `gt translate --dry-run` shows the scope, and `gt translate` translates it. With translations stored in the repository, the run writes `public/_gt/.json`, `gt-lock.json` and a `_versionId` in `gt.config.json`.
* `gt init` and `gt configure` ask any unanswered question through an interactive prompt and wait with no timeout. An agent passes `--no-interactive` (or `--json`, which implies it) and a flag for every question. A missing answer then exits 1, lists the flags still needed and changes no file. Kevin asked on 2026-10-01 that agents always run the CLI this way.
* The CLI has no `--version` flag. `npm view gt version` gives the published version, and the `translate` banner prints the installed one. `gt auth` is not a command in current releases.
* A development key belongs in `.env.development.local`, which `next dev` loads and `next build` does not. A production `next build` refuses to run with a development key present.
The docs serve agents directly (gt-cloud #4499, merged 2026-09-10). gt-website's `references/docs.md` holds the routes behind them.
* `/llms.txt` is the curated entry point, `/llms-index.txt` lists every page, and `/openapi.yaml` is the API specification. `/llms-full.txt`, scoped `/docs//llms.txt` files, `/AGENTS.md` and `/sitemap.md` sit beside them.
* Appending `.mdx` or `.md` to a docs page URL returns the page's raw Markdown twin.
* Every docs page's Copy page menu carries the llms.txt entries (Kevin, 2026-09-11).
* The hero's second button is Setup for Agents (gt-cloud #5049, merged 2026-10-01). It copies the start prompt, whose one source is `docs/en-US/overview/for-coding-agents.mdx` in the content repository. The same text is served raw at `/agent-prompt.md`. After any change to the prompt, the CLI or the quickstarts, the prompt is run end to end by a coding agent on a fresh app. Kevin, 2026-09-30: "Agent experience (AX) is a huge deal for us".
The start prompt sets these onboarding rules for an agent (read 2026-10-05):
1. Inspect the repository before asking anything: framework, router, app directory, existing i18n library, GT configuration, source language and build scripts.
2. In a monorepo, choose the app or content directory and run setup there. Setup never runs at the workspace root.
3. Ask for missing decisions one at a time: the source language, the target languages, then the first page or workflow. When the project itself is unclear, ask one question ("What would you like to translate?") with concrete choices.
4. Preserve existing locale choices and reuse an existing i18n setup. The source language is never assumed to be English.
5. Sign in with `gt login`. The agent never asks for a pasted API key, a password or OAuth tokens, and it writes new keys to ignored files without printing them.
6. Carry the work through setup, translation and verification, then hand off what changed, the project and locales, what was verified and what the person still has to do. Auto-merge and paid plan changes wait for the person's direction.
## 8. Repositories [#8-repositories]
| Repository | Visibility | What it holds |
| ------------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `generaltranslation/gt-cloud` | private | The turbo and pnpm monorepo: the dashboard, landing, API, workers, AI proxy, edge, Locadex and admin apps, and the shared packages (`packages/ui`, `db`, `node`, `settings` and others). |
| `generaltranslation/content` | public | Docs, blog posts and devlogs, mounted at `apps/landing/content` as a submodule. Every landing deploy checks out the tip of content main (`$GT_CLOUD/scripts/deploy-landing.sh`), and a merge to content main triggers a deploy. |
| `generaltranslation/legal` | public | The legal pages, a pinned shallow submodule at `apps/landing/legal`. |
| `generaltranslation/gt` | public | The CLI, the JavaScript libraries, the core library, the compiler, the MCP server and the Sanity and rrweb plugins. |
| `generaltranslation/gt-python` | public | The Python SDKs. |
| `generaltranslation/translate` | public | The GitHub Action. |
| `Kevin-Liu-01/Prototemplate` | public | The design hub and public reference behind prototemplate.com: BRAND.md, DESIGN.md, the deck, the skills and this handbook. |
File-level maps stay with their owners: gt-cloud's `AGENTS.md` and `.agents/skills` (`gt-landing`, `gt-dashboard`, `gt-api`, `gt-admin`), [gt-website](https://www.prototemplate.com/skills/gt-website) for the landing and [gt-brand](https://www.prototemplate.com/skills/gt-brand) for the identity files.
## 9. Site behaviour [#9-site-behaviour]
[gt-website](https://www.prototemplate.com/skills/gt-website) owns the site's routing. Its `references/docs.md` holds the unsupported-locale redirects, the docs near-miss ladder and suggestion page (gt-cloud #4359), the markdown twins and the step order in `src/proxy.ts`. The rules below are not in that reference. Each was read on gt-cloud's origin/main and checked on production on 2026-10-05.
* Staging builds translate one locale. `apps/landing/staging.gt.config.json` lists `es` only, and `gt.config.json` keeps the production roster (`es`, `fr`, `zh`, `ja`, `it`, `ru` and `en-GB` beside `en-US`). Kevin, 2026-08-08: "only es for staging".
* Missing localized content falls back to en-US. A legal page renders the en-US copy in place, an untranslated docs page serves the default language, and a blog slug absent in a locale redirects to the en-US post. Kevin, 2026-08-17: "fix pages that are breaking from like en-GB".
* The docs suggestion page answers HTTP 200 with `noindex, nofollow` by design (gt-cloud #4359). A real 404 needs the not-found boundary, and under the force-static root layout that boundary never sees the requested slug. The blog checks frontmatter aliases and close matches before it renders its own suggestion page.
This plate sets the production roster of the landing app in `LocaleTag` pills: en-US as the source and seven target locales. The staging build translates `es` alone.
## 10. Public surfaces [#10-public-surfaces]
Every address below answered HTTP 200 on 2026-10-10. [BRAND.md](https://www.prototemplate.com/docs/handbook/brand) section 8 says how the identity applies to each kind of surface.
| Surface | Address |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Home page | [https://generaltranslation.com](https://generaltranslation.com) |
| Pricing and usage rates | [https://generaltranslation.com/pricing](https://generaltranslation.com/pricing), [https://generaltranslation.com/pricing/usage](https://generaltranslation.com/pricing/usage) |
| Enterprise and its contact form | [https://generaltranslation.com/enterprise](https://generaltranslation.com/enterprise), [https://generaltranslation.com/enterprise/contact](https://generaltranslation.com/enterprise/contact) |
| Careers and contact | [https://generaltranslation.com/careers](https://generaltranslation.com/careers), [https://generaltranslation.com/contact](https://generaltranslation.com/contact) |
| Documentation | [https://generaltranslation.com/docs](https://generaltranslation.com/docs), with [https://generaltranslation.com/llms.txt](https://generaltranslation.com/llms.txt) and [https://generaltranslation.com/agent-prompt.md](https://generaltranslation.com/agent-prompt.md) for agents (section 7) |
| Knowledge base | [https://generaltranslation.com/kb](https://generaltranslation.com/kb) |
| Blog and changelog | [https://generaltranslation.com/blog](https://generaltranslation.com/blog) |
| Supported locales | [https://generaltranslation.com/supported-locales](https://generaltranslation.com/supported-locales) |
| Localization report card | [https://generaltranslation.com/report-card](https://generaltranslation.com/report-card) |
| Legal pages | [https://generaltranslation.com/legal](https://generaltranslation.com/legal) |
| Dashboard sign-in | [https://dash.generaltranslation.com](https://dash.generaltranslation.com) |
| Social | [https://x.com/generaltxn](https://x.com/generaltxn), [https://www.linkedin.com/company/generaltranslation/](https://www.linkedin.com/company/generaltranslation/) |
| Open source | [https://github.com/generaltranslation](https://github.com/generaltranslation) |
| Design hub (this repository) | [https://www.prototemplate.com](https://www.prototemplate.com/), with /brand, /docs (this handbook is /docs/handbook), /skills, /deck, /motion, /graphics, /marks, /blog and /d/production |
| Companion tooling | [https://glyphfield.com](https://glyphfield.com), the shader and animation studio behind several graphics and films |
## Sources [#sources]
* Prototemplate: [BRAND.md](https://www.prototemplate.com/docs/handbook/brand) sections 1, 2 and 9; [gt-brand](https://www.prototemplate.com/skills/gt-brand) sections 1, 2 and 8; [gt-website](https://www.prototemplate.com/skills/gt-website) with `references/docs.md` and `references/pages.md`; [gt-voice](https://www.prototemplate.com/skills/gt-voice); [gt-landing-pages](https://www.prototemplate.com/skills/gt-landing-pages); [gt-components](https://www.prototemplate.com/skills/gt-components).
* gt-cloud at origin/main e17fce499 (2026-10-05): `AGENTS.md`, `.gitmodules`, `apps/landing/gt.config.json`, `apps/landing/staging.gt.config.json`, `apps/landing/src/app/[locale]/docs/[variant]/[...slug]/page.tsx`, `apps/landing/src/app/[locale]/blog/[slug]/page.tsx`, `apps/landing/src/lib/legal.ts`, `apps/landing/src/components/landing/sections/global/Global.tsx`, `apps/landing/src/components/pages/enterprise/services-landing/GovernedExplorer.tsx`, `scripts/deploy-landing.sh`, `.agents/skills/gt-landing/SKILL.md`; pull requests #4359, #4499 and #5049.
* `generaltranslation/gt` at origin/main a16ae03c6 (2026-10-05): `packages/`, `packages/cli/src/cli/base.ts`, `packages/cli/src/auth/__tests__/oauth.test.ts`, `packages/cli/src/cli/__tests__/initOnboarding.test.ts`, `packages/core/src/runtime.ts`, `packages/next/src/server.ts`, `packages/next/src/index.types.ts`.
* `generaltranslation/content` at origin/main (2026-10-05): `AGENTS.md`, Public authentication boundary.
* generaltranslation.com, read 2026-10-10: `/pricing` (section 5) and the addresses in section 10, each fetched with curl. Read 2026-10-05: the home page, `/en-US/pricing`, `/en-US/enterprise`, `/en-US/careers`, `/ja`, `/llms.txt`, `/llms-index.txt`, `/agent-prompt.md`, `/openapi.yaml` and the docs guide Defining context for translations.
* npm and PyPI package pages, and the public repository list of the `generaltranslation` GitHub organization, read 2026-10-05.
* Kevin's rulings: the full stack, the barbell, the buyers who cannot yet name localization, and the context layers (2026-07-30); layout, review surfaces, formatting and region names (2026-08-06); locale heroes and staging (2026-08-08); showing over telling (2026-08-11); the enterprise pillars and CDN copy (2026-08-15); the enterprise order and the pricing cards (2026-08-15 and 2026-08-16); en-GB routing (2026-08-17); the copy page menu (2026-09-11); the agent button and AX (2026-09-30); the interactive CLI (2026-10-01); geography by language (2026-10-03).
* The list of brand surfaces sent to the brand agency on 2026-09-04, from which section 10 is rebuilt and checked against the live addresses.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Glossary
> The terms in Kevin’s messages, the skills and the code, each defined in a sentence or two with where it lives.
URL: https://www.prototemplate.com/docs/handbook/glossary
This glossary defines the terms that appear in Kevin Liu's messages, in the General Translation (GT) skills and in the code of gt-cloud and Prototemplate. Each entry defines its term in one to three sentences and names the file, skill or document that owns it. The owner holds the full rule, so where the two disagree the owner is right and this page needs a fix. The vocabulary covers 2026-07-20 to 2026-10-05, and the retired terms in the last section point to [decisions.md](https://www.prototemplate.com/docs/handbook/decisions).
Paths without a prefix are in a Prototemplate checkout. A path marked `gt-cloud:` is in gt-cloud, `gt:` marks one in the open-source gt repository and `content:` one in the content repository.
## Company and products [#company-and-products]
| Term | Meaning | Where it lives |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| General Translation (GT) | General Translation, Inc. builds the full stack for localization: open-source i18n libraries, context-aware translation APIs, a platform for review and delivery, and the Locadex agent. GT is the short form and the mark. | [BRAND.md](https://www.prototemplate.com/docs/handbook/brand) sections 1 and 2; [gt-product-map.md](https://www.prototemplate.com/docs/handbook/gt-product-map) section 1 |
| gt (the libraries) | GT publishes its open-source i18n libraries from one public monorepo. On npm the package named `gt` is the CLI, and `generaltranslation` is the core library the others build on. | `gt:packages/`; BRAND.md section 1 |
| gt-next and its siblings | These framework packages render translations and format locale-sensitive values in an app: `gt-next`, `gt-react`, `gt-tanstack-start`, `gt-react-native`, `gt-vue` and `gt-node`, with `gt-flask` and `gt-fastapi` for Python. gt-cloud's own apps translate their UI with `gt-next`. | `gt:packages/next` and its neighbours; the Python SDKs in `generaltranslation/gt-python`; gt-product-map.md section 3 |
| `` | The `` component marks a block of JSX for translation. Wrap the largest static block once, never nest it, pass dynamic parts through `Var`, `Num`, `Currency`, `DateTime`, `Plural` and `Branch`, and guide one block with its `context` prop. | [`gt-components`](https://www.prototemplate.com/skills/gt-components) `references/react.md`; gt-cloud `CLAUDE.md` |
| `gt()` | The `gt()` function translates a string. It covers the user-facing props that `` does not reach, such as a placeholder, a title or an `aria-label`. | gt-components `references/react.md` |
| `msg()` | The `msg()` function marks the strings of a data array where the array is declared. The component that renders the array reads them through `useMessages()` or `getMessages()`. | gt-components `references/react.md` |
| `useGT` | The client hook returns the `gt` function itself, so the line is always `const gt = useGT();` and never `const { gt } = useGT()`. | gt-cloud `CLAUDE.md` |
| `getGT` | Async server components and `generateMetadata` get the function with `const gt = await getGT();`, imported from `gt-next/server`. | gt-cloud `CLAUDE.md` |
| The gt CLI | The CLI signs in with `gt login` through GT's sign-in page in the browser, and `gt translate` translates a project after a `--dry-run`. Because `gt init` and `gt configure` wait on interactive prompts with no timeout, an agent passes `--no-interactive` and a flag for every question. | `gt:packages/cli`; gt-product-map.md section 7 |
| Locadex | Locadex is GT's hosted AI agent. It internationalizes a codebase, generates translations, opens pull requests and keeps the app localized afterwards. Its name is never translated, and drawings seat its real mark as an alpha mask (the gt-ui rule `no-gif-mark` refuses a gif). | `gt-cloud:apps/locadex`, `public/brand/locadex-mark.svg`; [`gt-brand`](https://www.prototemplate.com/skills/gt-brand); gt-product-map.md section 3 |
| Context Group | A Context Group is a reusable collection of translation context kept at the organization level: a Glossary and the style prompts. A project applies groups in priority order, and context then narrows from the organization to the project to the component (``). | `gt-cloud:apps/dashboard`, route `org/[orgId]/context/[groupId]`; gt-product-map.md section 4 |
| Glossary | The Glossary is the terminology half of a Context Group. It lists product and brand names, feature names, technical terms and phrases that stay untranslated, and its standing example is that Locadex is never translated. | the group's `glossary` route; gt-product-map.md section 4 |
| Directives | Directives was Kevin's July name for the style half of a Context Group: tone, audience, formality, conventions and formatting. The dashboard, the API and the pricing page call it Custom Prompts, copy uses that name, and the code keeps `directives` (`DirectivesEditor`). | the group's `custom-prompts` route; gt-product-map.md section 4 |
| The dashboard | The dashboard is GT's product app at dash.generaltranslation.com. It holds projects, Context Groups, the translation editor, review, billing, and the sign-in and onboarding pages on the plate frame, and its product surfaces are judged against the brand deck. | `gt-cloud:apps/dashboard`; gt-cloud `.agents/skills/gt-dashboard`; [`gt-aesthetic`](https://www.prototemplate.com/skills/gt-aesthetic) section 1 |
| The translation CDN | The translation CDN is an edge service on Cloudflare Workers that serves translations. Through it a team pushes translation updates over the air without redeploying its app. | `gt-cloud:apps/edge`; gt-product-map.md section 3 |
| Setup for Agents | Setup for Agents is the second button in the landing hero (gt-cloud #5049). It copies the start prompt that takes a coding agent from an empty project to a first translation, and every change to the prompt, the CLI or the quickstarts is proven by handing the prompt unchanged to a fresh agent on a fresh app. | `content:docs/en-US/overview/for-coding-agents.mdx`, served at `/agent-prompt.md`; [`gt-website`](https://www.prototemplate.com/skills/gt-website) section 6 |
| The report card | The report card is a public page that grades how localized any site is on six checks: hreflang, language declaration, routing, metadata, content and charset. Prototemplate's copy is the `/report-card` page of the shipped site. | generaltranslation.com/report-card (`gt-cloud:apps/landing/src/app/[locale]/(home)/report-card`, `apps/landing/src/lib/report-card/`); `/d/production/report-card`, `src/components/try/`, `src/lib/try/` |
## Repositories and places [#repositories-and-places]
| Term | Meaning | Where it lives |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| gt-cloud | The gt-cloud repository is GT's private product monorepo on turbo and pnpm. It holds the dashboard, the landing site with the docs and blog, the API, workers, the AI proxy, the edge CDN, Locadex, the admin app and the shared packages, and it squash-merges small PRs from `k/` branches once three required checks pass and the review bots are answered. | github.com/generaltranslation/gt-cloud; gt-cloud `AGENTS.md`; [`gt-ship`](https://www.prototemplate.com/skills/gt-ship) section 5 |
| The gt repository | The public monorepo `generaltranslation/gt` holds the CLI, the JavaScript libraries, the core library, the compiler and the MCP server. CLI changes such as the login callback page land there. | github.com/generaltranslation/gt; gt-product-map.md section 8 |
| The content repo | The public `generaltranslation/content` repository holds the docs, blog posts and authors, and gt-cloud mounts it as the `apps/landing/content` submodule. Every landing deploy checks out the tip of content main, so merging a content PR publishes it, and when a post needs new components, images or redirects the gt-cloud side merges first. | gt-website sections 4 and 5; gt-product-map.md section 8 |
| Prototemplate | Prototemplate is Kevin's public hub and wiki for GT work. Its Next.js site, served at [www.prototemplate.com](http://www.prototemplate.com), prototemplate.vercel.app and prototemplate.kevinliu.studio, holds the brand book, the design canon, the deck, the design lab, the marks, the films, the graphics, the skills and this handbook. Its `main` holds the primary copy of the canon, all rights are reserved to General Translation, and its dev server runs on localhost:3005. | github.com/Kevin-Liu-01/Prototemplate; [`prototemplate`](https://www.prototemplate.com/skills/prototemplate) section 1 |
| The deck | The deck is the GT brand deck: 93 slides built from `deck/` into one self-contained viewer that `/deck` frames. It is the reference for every product surface, and the Prototemplate viewer shell was modeled on its viewer (2026-09-08). | `deck/`, `deck/DECK-GRAMMAR.md`, `pnpm build:deck`; [`gt-deck`](https://www.prototemplate.com/skills/gt-deck) |
| The Dossier | The Dossier (`singularity-dossier`) is the direction the shipped GT site grew from, and it stays in the gallery. Kevin called it complete on 2026-08-06 ("dossier is indeed our completed version and treat it as such"), and it was the reference for every marketing page until 2026-10-07, when he ruled "fix the dossier references". Since then the shipped generaltranslation.com has been the site's reference ([decisions.md](https://www.prototemplate.com/docs/handbook/decisions)). | `/d/singularity-dossier` and its `/enterprise`; BRAND.md section 8; gt-aesthetic section 1 |
| Toolchain | Toolchain is the direction that served as the single source of truth for the forks from July. It set one ruled column, bento rows, isometric line diagrams and the `tc-*` vocabulary that the gt-cloud landing engine still uses, and its enterprise and pricing pages are literal specs, copy included. | `src/app/d/toolchain/`, `/d/toolchain`; [ARCHITECTURE.md](https://www.prototemplate.com/docs/handbook/architecture) "The SSOT rule" |
| A direction | A direction is one exploration of the GT site's design, served at `/d/` and registered in `DIRECTIONS`, where four entries are full sites (the Dossier, Orbit, Signal and production). In July and August Kevin named directions by their label numbers, and the labels were renumbered more than once (Toolchain was 10 then and is 01 now). | `src/lib/directions.ts`; `/directions/`; retired ones at `/archive/`; [`gt-explorations`](https://www.prototemplate.com/skills/gt-explorations) section 3 |
| A fork | A fork is a direction built on Toolchain's sections and diagrams, imported directly and re-skinned through its own root class (`.lensgate-root`, `.terminusboard-root`). Fork work never edits Toolchain's files, and a forked session is a different thing, defined under Working terms. | ARCHITECTURE.md "The SSOT rule" |
| The presenter | The presenter at `/present` is a full-screen tool built on 2026-07-30 to review the directions. It runs an intro, the case for the redesign, a craft gallery, a live viewer of the first 16 prototypes and a scoreboard. | `src/app/present/` |
| /d/production | This route rebuilds the shipped generaltranslation.com page for page in Prototemplate, with the dashboard's sign-in, onboarding, consent, device and CLI pages and their draggable state console (`?state=` opens a state). Review galleries that Kevin asks for live here, outside gt-cloud PRs. | `src/app/d/production/`, `src/components/plate/`; gt-ship section 3 |
| /dev/states | The dashboard's `/dev/states` route is a development-only gallery of every sign-in and onboarding state. It stays on its own gt-cloud branch and never ships in a PR (2026-10-01). | gt-cloud's own `gt-dashboard` skill |
| The review server | The review server is the running dev server Kevin reviews a branch on. The landing's `pnpm dev` serves localhost:3001 and Prototemplate serves localhost:3005, each extra worktree takes a port of its own, and the session keeps the server up and says which branch and commit it serves. | gt-local-dev section 1; gt-website section 2; prototemplate section 7 |
| motion/ | The `motion/` folder in Kevin's Prototemplate checkout is untracked, and the Videos session builds the films there with HyperFrames from the brief `motion/MOTION.md`. Other sessions read it and never stage, edit or delete it, and the published copies live in `public/media/` and on `/motion`. | [`gt-films`](https://www.prototemplate.com/skills/gt-films) section 1 |
| The scratchpad | The scratchpad is the temporary folder Claude Code gives each session for specs, context files, harnesses and recorded fixtures. Nothing in it reaches a PR, and its files can vanish at the desktop app's date change, so durable work goes into a repository. | gt-ship section 3; gt-local-dev section 6 |
## Design vocabulary [#design-vocabulary]
| Term | Meaning | Where it lives |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Rail | A rail is the single hairline on each side of the page column, drawn once by the column wrapper (`.tc-rail` with `border-inline: 1px solid var(--tc-hair)`). Since 2026-09-28 a column has one rail on each side, and the `single-rail` lint holds it. | [DESIGN.md](https://www.prototemplate.com/docs/handbook/design) section 3; [`gt-landing-pages`](https://www.prototemplate.com/skills/gt-landing-pages) "Rail and bands" |
| Band | A band is a horizontal section of a landing page. A band inside the column (`.tc-sec`) draws only its bottom rule, and a full-bleed band (`.tc-band.tcb`, `.v0-dep`) spans the viewport and draws its own rail pair once, at the column edges. | gt-landing-pages "Rail and bands" |
| Hatch spacer | A hatch spacer is a strip 28 to 40px tall with a hairline on each edge over a 45 degree hatch. It separates home bands (`.v0-hatch`) and rows inside a section (`.tc-hatch`), and it owns both of its edges, so the section before it drops its bottom rule. | gt-landing-pages "Hatch spacers"; DESIGN.md section 2 "Sanctioned devices" gives the shell's version, the book page's band (`.pt-book-band`), which also draws its own rule on both edges (2026-10-06) |
| Seam | A seam is the 1px line where two rows, cells or sections meet, formed by the row's hairline ground showing through a 1px gap. DESIGN.md section 10 also calls the slide-to-reveal handle the seam (`RevealSeam`, `--seam-cut`). | DESIGN.md sections 2 and 10 |
| The row owns every seam | This ownership rule for grids says that the row draws every structural line between its cells, cells draw no borders, and a framed cell shows the row's ground through a 1px padding reveal. Where a row meets a line that already exists, the cell sits flush and drops that side's reveal. | DESIGN.md section 2 "Ownership"; gt-landing-pages "The row owns every seam" |
| BentoRow and BentoCell | These two grid primitives implement that rule. The row is a grid with `gap-px` over the `--tc-hair` ground (props `cols`, `eqHeads` and `headH`), and the cell has no border props (`framed` adds the reveal). | `gt-cloud:apps/landing/src/components/landing/shell/Bento.tsx`, `src/components/shell/Bento.tsx`; gt-components |
| Registration cross | A registration cross is a small 1px plus seated exactly where two real hairlines cross. Kevin calls them corner crosses and DESIGN.md calls them border crosses, each landing section seam paints one at both rail corners, and a cross floating in app UI is ornament (2026-09-25). | DESIGN.md section 2 "Sanctioned devices"; gt-landing-pages "Registration crosses"; gt-aesthetic section 3 |
| The doubled line | The doubled line is GT's connector. One SVG path is stroked twice, a full ink stroke under a narrower stroke in the surface color, which leaves two parallel hairlines at a constant gap. It is the one sanctioned double line, also called the thread, and the GT mark draws every stroke in this grammar. | DESIGN.md section 5; `src/components/shared/diagrams/DoubledLine.tsx`; [`gt-diagrams`](https://www.prototemplate.com/skills/gt-diagrams) |
| The plate | The plate is the dashboard's auth frame for the sign-in, consent, device, CLI and onboarding pages, with the form column on the left up to `--plate-edge` and the dithered field on the right. Elsewhere a plate is the one second surface under diagrams (`--pt-plate`), a layer of an isometric stack, or one of the speed marks. | `gt-cloud:apps/dashboard/src/components/frame/PlateFrame.tsx`, `src/components/brand/FieldStack.tsx` and `src/app/brand-tokens.css` there; the port in `src/components/plate/` |
| Hairline roles | The three line weights each have one job. The `hair` weight (ink at 18% in light) draws large surfaces and the lines that divide a page, `hair-soft` (ink at 9%) draws list rows, and `edge` (ink at 62%) frames a picture or a capture, so a large surface drawn in the edge weight reads as a boxed image. | DESIGN.md section 2 "Line law for chrome"; `src/components/viewer/tokens.css` |
| The book page | Every Prototemplate page with a book head renders one structure: the page's plain name as the title with nothing drawn above it, a lead of one to three lines, the panel (Updated, then the page's facts), one rule, an optional note and contents, one hatch band, then sections opened by a `Section n` divider. A page differs from another only in its words and its facts. | DESIGN.md section 4, The book page; `BookHead` in `src/components/viewer/BookView.tsx`; `pnpm lint:heads` |
| Rounded controls, square shells | Prototemplate's corner law: the shells that hold the interface (the frame, the sidebar, the toolbar bar, the sheet, rules and bands) are square, and everything a reader presses, types into or picks up is rounded: controls at 6px, a part inside one at 5px, chips at 4px, cards and popovers at 6px. | DESIGN.md section 2, Corners; the radius tokens in `src/components/viewer/tokens.css`; `pnpm lint:radius` |
| Ink | Ink is `#070707`, the darkest of the four absolute colors, used for content text on paper and as the ground of the dark theme. Raised ink (`#101010`) is the one dark artifact surface for code, config and diffs. | DESIGN.md section 1; `src/app/globals.css` |
| Ink-2 | Ink-2 is the second text step, for secondary text and leads (`--pt-ink-2`, `#3a3d44` in light). On a light surface, text a reader needs is set in ink-2 wherever titanium would fail contrast. | gt-aesthetic section 3; `src/components/viewer/tokens.css` |
| Titanium | Titanium is `#8a8f98`, the third and last text step, for captions, counters and keys. It measures 3.25:1 on white, so the dashboard plate darkens it to `#6e737c` for its 13px captions. | DESIGN.md section 1; gt-aesthetic section 3 |
| Paper | Paper is `#ffffff`, the light ground. Dark mode is a token remap in which paper collapses onto ink, so each theme has one surface. | DESIGN.md section 1 |
| GT blue | GT blue is the one accent, `#2f5ce0`, lifted to `#86a8ff` on dark bands. It marks actions, hover, highlights and icons while text and underlines stay ink, and a drawing gives it to one element. | DESIGN.md section 1; BRAND.md section 5; gt-aesthetic section 3 |
| The mobile type ladder | The mobile type ladder is the set of `--tcm-*` tokens that set type and spacing under 720px, declared in the engine's last 720px block and read as `var(--tcm-X, )`. The mobile cut in `v0-pages.css` outranks the engine on the `sgdh-root` pages, so a change to the ladder is made in both places. | DESIGN.md section 12 |
| The svh and dvh law | On a mobile stage, whatever must reach the true screen bottom sizes from `100dvh`, and every height that takes part in layout uses `100svh`. A layout height in dvh grows the document each time the URL bar shows or hides. | DESIGN.md section 13 |
| Read lines | The read lines are the two scroll anchors of a scroll story. A beat locks in when its copy block's center crosses the read line at 55% of the viewport, and its copy lights as it rises through the highlight line at 80%. | DESIGN.md section 14; `src/app/d/_v0/sections/FullStack.tsx` |
| The moving type law | The moving type law governs a word that morphs between languages. The word is one shaped text node with `lang` and `dir`, its width is measured from a hidden probe and is the only layout property that animates, and the host drives one clock per page. | DESIGN.md section 8; `src/components/shared/EverySentence.tsx`; [`gt-motion`](https://www.prototemplate.com/skills/gt-motion) section 5 |
| Box-air | Box-air is the mobile standard for boxed cells: block padding of 36 and 38px (`--tcm-box-pt`, `--tcm-box-pb`), 28px (`--tcm-box-gap`) between a box's head and its artifact, and no copy within 20px of a hairline. | DESIGN.md section 12 "The box-air standard" |
## Material and motion [#material-and-motion]
| Term | Meaning | Where it lives |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Bayer dither | Bayer dither is ordered dither through a 4x4 or 8x8 Bayer threshold matrix, and it is the brand's only texture. A tone ramp prints as whole square cells in one ink, and alpha veils, smooth gradients and error diffusion are refused. | DESIGN.md section 7; `src/lib/dither.ts`; [`gt-dither`](https://www.prototemplate.com/skills/gt-dither) section 1 |
| The studio field | The studio field is the GPU engine for the animated Bayer materials: `createStudioField` with ten `BAYER_PRESETS` sharing one WebGL context. Preset 02, bayer-8x8 (`bayer8`), is the default, the landing hero's field and the reference for material on product surfaces. | `src/lib/studio-field.ts`, `gt-cloud:apps/landing/src/lib/studio-field.ts`; gt-dither sections 2 and 3 |
| Glyph field | The glyph field is the canvas engine (`createGlyphField`) that rains glyphs from eight writing systems and condenses them into words, conserving matter between morphs. Its glyphs stay solid anti-aliased type, because dither on moving glyphs flickers (2026-08-06, 2026-09-28). | `src/lib/glyph-field.ts`, `gt-cloud:packages/ui/src/lib/glyph-field.ts`; BRAND.md section 7; gt-dither section 3 |
| Glyph rain | Glyph Rain is a direction, and the landing component of the same name mounts the glyph field rising (`GlyphRain.tsx`, `drift: 'rise'`). Kevin uses the name for the effect wherever it appears, such as the careers page and the pricing close. | `src/app/d/glyph-rain/`, `gt-cloud:apps/landing/src/components/landing/shared/GlyphRain.tsx`; gt-landing-pages |
| Ink field | The ink field is the closing band's material (`createInkField`). The glyph field's eight-script glyphs rise off the ink in the band's margins, stay clear of the content box measured from the live DOM, and answer the pointer. | `src/app/d/glyph-rain/sections/band/inkField.ts`, `gt-cloud:apps/landing/src/components/landing/shared/InkField.tsx`; gt-components `references/instruments.md` |
| Event horizon | Event Horizon is the direction where component walls dive into a black-hole gate, and the name also covers its WebGL lensing engine. The landing's careers and 404 heroes stand on that field, and as page-scale material in the app it was judged too heavy and deleted (2026-09-25). | `src/app/d/event-horizon/`, `src/lib/horizon-field.ts`, `gt-cloud:apps/landing/src/lib/horizon-field.ts` |
| The terminus board | Terminus Board is the direction with a split-flap headline over a flip-wave grid of languages, styled on an airport departures board. The landing's blog header is a split-flap board built from it, and its face settle is the one overshoot easing the landing allows. | `src/app/d/terminus-board/`; `gt-cloud:apps/landing/src/components/blog/BlogHeroBoard.tsx` and `flap.ts`; gt-motion section 2 |
| Gem smoke | Gem smoke is Paper Shaders' Gem Smoke material (Apache-2.0) as Glyphfield renders it, in blue, fire and ink palettes. It is the films' palette, it fills two deck section openers and the designed blog covers, and it can wrap a mark such as the bar monogram as a glass shape. | `motion/kit/gemsmoke.js`; gt-films sections 5 and 6; gt-deck `references/full-picture-slides.md` |
| Glyphfield | Glyphfield is Kevin's open-source shader and animation studio at glyphfield.com/studio, where new GT material starts before it ships as engine code or an export. Agents drive it through `window.glyphfield.studio`, and its name refers to the studio while "glyph field" names the engine above. | github.com/Kevin-Liu-01/Glyphfield; gt-dither section 4; gt-cloud `.agents/skills/glyphfield` |
| Artifact pictures | Artifact pictures are photographs and scans of objects, artworks and places, screened through the house 8x8 dither at 1 CSS px cells. They appear on the dashboard's sign-in and onboarding field, the plate port, the deck's mood slides and the transition demo in the build log on /docs/handbook/libraries, and each one shows writing, language or the earth, carries no readable English prose and credits its source. | [docs/ARTIFACT-PICTURES.md](https://www.prototemplate.com/docs/handbook/artifact-pictures); gt-dither section 5 |
| The Blue Marble standard | The Blue Marble standard is the tone and screen standard every artifact picture is cut to, taken from the Blue Marble picture of the earth on the onboarding field. A scene lands on mean tone 0.361 and standard deviation 0.342, the cutter is `pnpm mood-tone`, and the picture lint pins the standard file by sha256. | `scripts/media/mood-tone/standard.json`; docs/ARTIFACT-PICTURES.md, "The rules" items 3 and 4 |
| Speed marks | The speed marks are the seven race-type GT marks Kevin chose on 2026-09-29 to show beside the current doubled-line mark: the bar monogram, its lockup, the plate, double cut, the livery stack, the dithered monogram and the ASCII monogram. They are generated from geometry and font outlines and never redrawn by hand. | `scripts/build/speed-marks.mjs` (`pnpm build:marks`), `public/marks/`, `/marks`, deck slides 17 to 23; gt-brand `references/marks.md` |
| The bar monogram | The bar monogram is the speed mark that builds G and T from rectangles on a 120-unit cap, slanted forward 12 degrees, with one cut at mid cap height and three speed bars leading into the G. It holds at 16px and has lockup, dithered and ASCII versions. | `public/marks/bar-monogram.svg`; gt-brand `references/marks.md` |
This plate mounts the studio field. Each numbered chip remounts it with one of the ten `BAYER_PRESETS`, and chip 02 is bayer-8x8, the field of the landing hero.
This plate runs the glyph field. Glyphs from eight writing systems fall and condense into the word for language in one script after another, and the glyphs of each word become the next word.
This plate runs the ink field in its interactive mode. Glyphs rise off the ink, the glyphs near the pointer shiver, and a click bursts the nearest one.
This plate runs the event horizon field: a photon ring around a dark core, with ruled lines bending into it.
## Gates and tools [#gates-and-tools]
| Term | Meaning | Where it lives |
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| The line auditor | The line auditor (`scripts/lint/lines.mjs`) reads computed CSS in Chrome and fails on doubled lines, two owners on one seam, self-stacks, invisible seams and chrome borders outside the three hairline roles. The shell audit `pnpm lint:lines:shell` walks the shell routes against the dev server on 3005, `pnpm lint:lines ` audits any page, and SVG strokes still need 2x crops checked by eye. | DESIGN.md section 2; [`gt-lints`](https://www.prototemplate.com/skills/gt-lints) section 2, `references/line-auditor.md` |
| The page check | The page check (`pnpm check:pages`) loads every page on a table of phones, tablets and desktops in both themes, reading phones and tablets as touch devices. It reports overflow, clipping, console errors, tap targets under 40px, layout shift and failed interactions in `.pagecheck/REPORT.md`, and it runs on the touched pages each round and on the whole site before a release. | `scripts/check/pagecheck/` and its README; gt-lints section 2 |
| The practices ratchet | The practices ratchet (`pnpm lint:practices`) counts nine code checks per file against a baseline, among them bare `useEffect`, `any`, `!important`, raw hex in TypeScript and the retired rail vocabulary. It fails when a file's count rises, so recorded debt is paid down in its own changes. | `scripts/lint/practices.mjs`, `scripts/lint/practices.baseline.json`; gt-lints section 2 |
| The gt-ui oxlint plugin | The gt-ui plugin holds gt-cloud's design and copy laws as oxlint rules, among them `single-rail`, `inter-only`, `icon-tiers`, `no-em-dash`, `no-eyebrow`, `no-smooth-scroll`, `mono-is-not-voice` and `shared-cta`. Prototemplate runs a whole-file copy through `pnpm lint:code` and recopies it whenever gt-cloud's version changes. | `gt-cloud:tooling/oxlint-plugins/gt-ui.ts`, `scripts/lint/oxlint-plugins/gt-ui.ts`; gt-lints `references/gt-ui-rules.md` |
| The picture lint | The picture lint (`pnpm lint:pictures`) holds every artifact picture to the Blue Marble standard by hash, size, tone and credit. It runs before `next build`, so a picture defect stops the build, and `pnpm test:pictures` breaks one thing per test to prove the lint catches it. | `scripts/lint/pictures.mjs`; gt-lints section 2; gt-dither section 8 |
| The type lint | The type lint (`scripts/lint/type.mjs`, started 2026-10-05) holds Prototemplate's type to the rsms InterVariable through the type tokens. It allows no other family, no weight above 500 and no positive tracking, and it keeps mono to code and to named entries such as numbers, paths and hex values. | gt-lints "The type lint"; gt-brand `references/type.md` |
| `lint:all` | Prototemplate's `pnpm lint:all` chains the static lints, the browser audits against the dev server on 3005 and the lint tests with `&&`. Run the browser gates one at a time, and read `package.json` for the exact chain. | `package.json`; prototemplate section 9 |
| The parity gate and ledgers | The parity gate is the release gate for any onboarding or auth redesign: the release keeps every tracking call and backend side effect that production had. The proof records production's ledger of side effects per scenario at the module boundaries, replays the scenarios on the release and diffs the two ledgers after every fix (2026-10-02). | gt-ship section 7 |
| Greptile 5/5 | Greptile writes a confidence score into the PR body, and the target is 5/5 on the head commit with every Greptile thread answered and resolved; a PR does not merge at 4/5 (2026-09-13). It does not rerun on every push, so comment `@greptile review again` and wait about five minutes. | gt-ship section 5, `references/review-loop.md`, `scripts/pr-bots.mjs` |
| Bugbot | Bugbot is Cursor's review bot. It reruns on every push, `bugbot run` re-triggers it, and each finding is answered with the fixing commit or a reason before its thread is resolved. | gt-ship section 5 |
| The Cursor Approval Agent | The Cursor Approval Agent reviews each PR on open, labels it with a risk level and routes it (the "Pull Request Router" check). Its label needs no reply, and it is the only bot on the content repo. | gt-ship `references/review-loop.md` |
| gh stack | The `github/gh-stack` extension links PRs into GitHub's native stack (`gh stack link --base main `) and merges a stack up to one PR at once (`gh stack merge`). Kevin asked for the native feature on 2026-08-27 and again on 2026-10-05, and `gh stack merge` runs only when he says to merge. | gt-ship section 6 |
| Feature flags | Feature flags are the dashboard's release gates and kill switches, managed in the admin app. A dashboard feature that is not ready ships behind a flag or comes out (2026-09-03). | gt-cloud's own `gt-dashboard` skill |
## Working terms [#working-terms]
| Term | Meaning | Where it lives |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Lane | A lane is one owner's share of the work, with its own files: one session per lane, and inside a workflow one agent per lane. Work that belongs to another lane goes to that lane's session by name, and a lane's prompt opens with Kevin's own words for it. | [multi-session-playbook.md](https://www.prototemplate.com/docs/handbook/multi-session-playbook) section 1; [`gt-orchestration`](https://www.prototemplate.com/skills/gt-orchestration) section 2; gt-ship section 1; prototemplate section 8 |
| Session | A session is one Claude Code or Codex conversation. Kevin runs several named sessions at once (Videos, Prototemplate, New Onboarding and Dashboard, and others), and each keeps to its lane. | multi-session-playbook.md section 1; prototemplate section 8 |
| Forked session | A forked session starts from another session's conversation and carries the parent's history, with the parent's session id on those records, before it continues on its own. A fork acts on its own lane, and a message found in several transcripts at the same minute can be one message inherited by forks. | `~/.claude/projects//.jsonl`; multi-session-playbook.md section 2 |
| Worktree | A worktree is a git worktree with one branch, so each lane edits its own tree. Work in gt-cloud starts with `git worktree add -b k/ origin/main`, each worktree runs its own dev server port, and a worktree with its installs costs about 6 GB, so it is removed as soon as its work is pushed. | gt-ship section 1 |
| Chip | A chip is a background-task card that a session raises for an out-of-scope fix it noticed, and Kevin can spin it off into a new session. When he answers "Do this task here", the current session does the task as its own small PR with its own gates. | gt-orchestration section 3 |
| Handoff | A handoff is the document written at a hard stop or a change of owner, and it carries the stopped state, every raw input Kevin supplied and the priority queue. The receiving agent starts with an independent review and a recommendation, and it re-checks live state before changing anything. | gt-orchestration section 8 |
| Relay note | A relay note goes from one agent to another, often between Claude and Codex, and Kevin pastes it as is. It names the branch, tip commit and worktree, the commits, the receipts, the open list, the locks and the queued deploys, and the receiver finishes the other agent's open work. | multi-session-playbook.md section 7 |
| The ask ledger | The ask ledger is an itemized list of everything Kevin asked for in a run, including the sub-items of long messages and the add-ons sent mid-run, each with its status. It closes every report on multi-ask work, and a long run keeps it in a file so it survives compaction. | [`gt-reporting`](https://www.prototemplate.com/skills/gt-reporting) section 3 |
| The PR slate | The PR slate answers "give me my PR list" with every open PR across gt-cloud, gt and content in merge order, in nine groups from merge now to the items only Kevin can do. Each line carries the full link, a one-line purpose and its line counts, and the Slack version is lowercase plain text in a code fence. | gt-reporting section 5, `scripts/pr-slate.mjs` |
| Explorations stay local | Exploration and redesign rounds stay uncommitted or on a branch until Kevin has reviewed them on localhost and says to land them, because Prototemplate main deploys the public site (2026-09-14). | gt-aesthetic section 5; gt-ship section 8; gt-explorations |
| Kevin merges | An agent merges a PR or runs `gh stack merge` only when Kevin says so in that session. | gt-ship sections 5 and 6 |
| The agent guide | `AGENTS.md` at the root of Prototemplate is the entry point for an agent: the read order, the principles in brief, which skill to load for a task, the house rules, and how to import the hub into another project. `CLAUDE.md` imports it for Claude Code. | `AGENTS.md`; `/docs/handbook/agents` |
## Kevin's shorthand [#kevins-shorthand]
| Term | Meaning | Where it lives |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| "image 1" | "Image 1" names the first image attached to the message, and "image 2" the second, in attach order. Each numbered note maps to a region of its image, and the image is the spec. | gt-reporting section 7; gt-aesthetic section 5 "Rules of the loop" |
| "equivalent" or "equal" | Both measures take the larger value (2026-09-30). | gt-aesthetic "Reading Kevin's asks", `references/verdicts.md` |
| "keep its aesthetic" | The geometry and the material stay, and only the named thing changes. | gt-aesthetic "Reading Kevin's asks" |
| "smaller" or "larger" | The value moves to the next rung of the existing ladder, as when the 13px card facts went to the 12px rung (2026-09-28). | gt-aesthetic "Reading Kevin's asks" |
| "fully" | The work covers every section, capability and detail with real diagrams, visuals and code. A placeholder or a partial pass does not count. | [operating-principles.md](https://www.prototemplate.com/docs/handbook/operating-principles) section 15 |
| "continue all" or "keep going" | Resume every open lane and every unfinished item, the hard ones included, without pausing between waves. In a forked session the words cover the fork's own lane, and after a restart or a compaction the work resumes from the plans kept on disk. | operating-principles.md section 1; gt-orchestration section 6; multi-session-playbook.md section 2 |
| "no new spawns" | Agents already running finish, their work is committed and pushed, and no new agent starts (2026-08-06). | gt-orchestration section 1 |
| "show me" | Put the result where Kevin can see or hear it: before and after crops, a running localhost URL, or a small HTML gallery or listening page for a set. | gt-reporting section 1; operating-principles.md section 8 |
| "second pass" | A second pass reviews a finished page against its reference before it is shown, and pages that skipped one are redone (2026-08-17). | gt-aesthetic section 2 |
| "try again" | After an API error or a spend limit, re-run the step that failed, starting from a fresh read of the state. | multi-session-playbook.md section 3 |
| "commit and push" | Commit and push at once to every target he names, staging explicit paths. | gt-ship sections 2 and 8 |
## Retired terms [#retired-terms]
These terms still appear in older messages, commits and skills. The ruling that retired each one, its date and its reason are recorded in [decisions.md](https://www.prototemplate.com/docs/handbook/decisions).
| Term | What it was | What replaced it |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Switzer | Switzer was a second typeface used beside Inter in the July rounds. | Retired 2026-09-18: Inter is the only face, gt-cloud #4887 removed the files, and `inter-only` holds it ([decisions.md](https://www.prototemplate.com/docs/handbook/decisions)). |
| Lenis | Lenis was the smooth-scroll library behind the July scroll stories. | Retired from the site 2026-07-31: scrolling is native and `no-smooth-scroll` holds it. The presenter's last Lenis code was removed on 2026-10-08. Its paging still animates the jumps between slides, under a named exemption in `.oxlintrc.json` ([decisions.md](https://www.prototemplate.com/docs/handbook/decisions)). |
| Double rails | The double rails were a second pair of lines 10px outside each rail, also called the outer pair or doubled rails. | Retired 2026-09-28 in gt-cloud #5007: one rail per side, held by `single-rail` and the practices ratchet's rail checks ([decisions.md](https://www.prototemplate.com/docs/handbook/decisions)). |
| DirectionDock | DirectionDock was the control pill on the direction pages in July. | Retired 2026-07-31 and deleted 2026-09-08. `DirectionCorner` (`src/components/viewer/DirectionCorner.tsx`) took its place and hides under `?chrome=0` ([decisions.md](https://www.prototemplate.com/docs/handbook/decisions)). |
| apps/redesign on port 3006 | The July explorations app ran from `apps/redesign` in a gt-cloud worktree on the branch `redesign/diagram-standard`. | Retired as the primary copy on 2026-09-08: Prototemplate main holds the canon and serves on 3005, and prose that names 3006 is stale ([decisions.md](https://www.prototemplate.com/docs/handbook/decisions)). |
| The dictionary pictures | These artifact pictures showed pages of readable English: the dictionary, Johnson, OED and Oxford pictures. | Retired 2026-10-05: artifact pictures carry no readable English prose, and the picture lint rejects the retired names ([decisions.md](https://www.prototemplate.com/docs/handbook/decisions)). |
## Sources [#sources]
* Prototemplate: BRAND.md sections 1, 2, 5, 7 and 8; DESIGN.md sections 1 to 5, 7, 8 and 10 to 14; ARCHITECTURE.md; docs/ARTIFACT-PICTURES.md; `package.json`; `.oxlintrc.json`; `src/lib/directions.ts`, `src/lib/surfaces.ts` and `src/components/viewer/tokens.css`; `scripts/lint/practices.mjs`; `motion/kit/gemsmoke.js` (header); all read 2026-10-05.
* Skills: `prototemplate`, `gt-aesthetic`, `gt-ship`, `gt-lints`, `gt-dither`, `gt-landing-pages`, `gt-website`, `gt-components`, `gt-brand`, `gt-deck`, `gt-films`, `gt-motion`, `gt-diagrams`, `gt-orchestration`, `gt-reporting`, `gt-local-dev` and `gt-explorations`. The handbook pages [gt-product-map.md](https://www.prototemplate.com/docs/handbook/gt-product-map), [operating-principles.md](https://www.prototemplate.com/docs/handbook/operating-principles), [multi-session-playbook.md](https://www.prototemplate.com/docs/handbook/multi-session-playbook) and [decisions.md](https://www.prototemplate.com/docs/handbook/decisions) hold the procedures behind the working terms and the rulings behind the retired ones.
* gt-cloud at origin/main e17fce499 (2026-10-05): `apps/landing/package.json` (`dev`), `apps/dashboard` (`components/frame/PlateFrame.tsx`, `components/brand/`, the context routes), `apps/landing/src/lib/` (`studio-field.ts`, `horizon-field.ts`, `report-card/`) and `apps/landing/src/components/blog/`.
* The gt repository: `packages/*/package.json` for the package names.
* Kevin's messages to Claude Code and Codex from 2026-07-20 to 2026-10-05 and the session transcripts behind them, for the shorthand and the working terms.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Numbers
> Every load-bearing number in one place, grouped by area, each with its reason, its token or constant, the lint that holds it and the page that explains it.
URL: https://www.prototemplate.com/docs/handbook/numbers
This page collects the numbers that General Translation (GT) design and engineering work in Prototemplate depends on, grouped by area. Each row gives the value, the reason for it, the token or constant that carries it, the lint or gate that holds it, and the page that explains it. The explanation lives on the linked page and the value lives in its source file, so a change starts in those two places and this row follows. [Traps and fixes](https://www.prototemplate.com/docs/handbook/traps) indexes the failures behind many of these numbers in the same way.
`tokens.css` is `src/components/viewer/tokens.css`, and every other path is relative to the root of the Prototemplate repository. A value in brackets applies under 900px wide and on a phone on its side. In the Held by column a `pnpm` command names the lint or gate, with its rule where the lint numbers its rules, and Review means that no lint holds the value, so a person or a critic checks it on the render. Every value was read from its source on 2026-10-21.
## Type [#type]
The site sets one face, the self-hosted rsms InterVariable 4.1, with an optical-size axis from 14 to 32 and a weight axis from 100 to 900.
| Value | Reason | Token or constant | Held by | Explained in |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
| 44px at line height 1.04 and -0.025em (32px) | The page title sits in Inter's Display design, which starts at 32px. | `--pt-d1`, `--pt-d1-lh`, `--pt-d1-track` in `tokens.css` | `pnpm lint:type` T7; `pnpm lint:type:live` L3 | [Design system: book type](https://www.prototemplate.com/docs/handbook/design#book-type) |
| 32px at 1.05 and -0.025em (26px at 1.15) | A section title is the second step of the display ladder. | `--pt-d2`, `--pt-d2-lh`, `--pt-d2-track` in `tokens.css` | `pnpm lint:type` T7; `pnpm lint:type:live` L3 | [Design system: book type](https://www.prototemplate.com/docs/handbook/design#book-type) |
| 24px at 1.25 and -0.02em (21px) | An h2 in prose and a record's title track less at a smaller size. | `--pt-d3`, `--pt-d3-lh`, `--pt-d3-track` in `tokens.css` | `pnpm lint:type` T7; `pnpm lint:type:live` L3 | [Type: tracking by role](https://www.prototemplate.com/docs/craft/type#tracking-by-role) |
| 18px at 1.35 | An h3 and a row's title take this step at weight 500 and -0.01em. | `--pt-t-title` in `tokens.css` | `pnpm lint:type` R1 ratchets literal sizes | [Design system: book type](https://www.prototemplate.com/docs/handbook/design#book-type) |
| 17px at 1.55 | A head's lead takes this step, and one lead line, 26.35px, is also the panel's row pitch. | `--pt-t-lead`, `--pt-t-lead-lh` in `tokens.css` | `pnpm lint:heads:live` H5 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 16px at 1.6 | Prose, notes and section leads take the body step. | `--pt-t-body` in `tokens.css` | `pnpm lint:type` R1 | [Design system: book type](https://www.prototemplate.com/docs/handbook/design#book-type) |
| 14px at 1.55, 13px at 1.5 and 12.5px | Table cells and contents links take the small step, captions and table heads the meta step, and group labels in chrome the group step. | `--pt-t-small`, `--pt-t-meta`, `--pt-t-group` in `tokens.css` | `pnpm lint:type` R1 | [Design system: book type](https://www.prototemplate.com/docs/handbook/design#book-type) |
| -0.01em and -0.005em | Labels at 13 to 18px and group labels at 12 to 12.5px are set at weight 500, which tightens with size. | `--pt-track-label`, `--pt-track-group` in `tokens.css` | `pnpm lint:type` R2 ratchets literal tracking | [Type: tracking by role](https://www.prototemplate.com/docs/craft/type#tracking-by-role) |
| 0 at weight 400, and nothing positive | Running text is never tracked, and positive tracking on Inter is a defect at every size. | The comment under the text ladder in `tokens.css` | `pnpm lint:type` T8; `pnpm lint:type:live` L3 | [Type: tracking by role](https://www.prototemplate.com/docs/craft/type#tracking-by-role) |
| 500 at most | The brand stops at 500, and the browser's `bolder` computes `b` and `strong` to 700. | `--pt-w-display`, `--pt-w-strong` and the `:is(b, strong)` base rule in `tokens.css` | `pnpm lint:type` T6; `pnpm lint:type:live` L5 | [Type: weight and stack traps](https://www.prototemplate.com/docs/craft/type#weight-and-stack-traps) |
| opsz equal to the font size, clamped to 14 to 32 | With `font-optical-sizing: auto` the browser follows the size, so the Display design starts at 32px and the axis tightens spacing by itself. | No token; `font-variation-settings` is never written | `pnpm lint:type` T5; `pnpm lint:type:live` L4 | [Type: optical size](https://www.prototemplate.com/docs/craft/type#optical-size) |
| 398.55px against 380.81px | A 44px line tracked -0.025em measures the first without `calt` named and the second with it, because Chrome drops contextual alternates under letter-spacing. | `--pt-ff-text` and `--pt-ff-display` in `tokens.css` | `pnpm lint:type` T4; `pnpm lint:type:live` L2 and L7 | [Type: contextual alternates under letter-spacing](https://www.prototemplate.com/docs/craft/type#contextual-alternates-under-letter-spacing) |
| 32em for body text and 30em for a lead | Inter prose averages about 0.45em a character, so both hold about 66 characters a line. | `--pt-measure`, `--pt-measure-lead` in `tokens.css` | `skills/gt-aesthetic/scripts/measure-type.mjs --strict` exits 1 past 75 characters; `pnpm lint:type:live` L8 | [Type: measure](https://www.prototemplate.com/docs/craft/type#measure) |
| 83 to 86 characters in `62ch` at 17px | The `ch` unit is the width of a zero, about 0.63em in Inter, so a measure in `ch` holds far more text than its number suggests. | None; measures are set in em | `measure-type.mjs --strict` | [Type: measure](https://www.prototemplate.com/docs/craft/type#measure) |
| 1 to 3 lead lines at 1440 (6 at 390), 200 characters at most | A head's lead reads in two or three lines. | `--pt-measure-lead` in `tokens.css`; `H4` in `scripts/lint/heads.mjs` | `pnpm lint:heads:live` H4 | [Pages: the book page](https://www.prototemplate.com/docs/pages#the-book-page) |
| 352,240 and 112,748 bytes | The full roman file is the subsets' source, and its latin subset is the only Inter file every route preloads. | `public/fonts/InterVariable.woff2`; `ptInter` in `src/lib/fonts.ts` | `pnpm lint:type` T3 | [Type: subsets and glyph names](https://www.prototemplate.com/docs/craft/type#subsets-and-glyph-names) |
| 107.89% | next/font's fallback face is `local("Arial")` at this `size-adjust`, and Arial draws Hebrew and Arabic before any face listed after Inter. | next/font's `ptInter Fallback` | Review | [Type: scripts and the Arial fallback](https://www.prototemplate.com/docs/craft/type#scripts-and-the-arial-fallback) |
| 0.8638em and 0.728em | The baseline sits 0.8638em below the top of a line-height-1 box, and the cap height is 1490 of 2048 units, so display type is seated by its ink. | None; Inter's own metrics | Review | [Type: seating display type](https://www.prototemplate.com/docs/craft/type#seating-display-type) |
## Corners [#corners]
Controls are rounded and shells are square. Kevin's toolbar of 2026-10-05 set the values.
| Value | Reason | Token or constant | Held by | Explained in |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| 0 | The viewer frame, the sidebar, the toolbar bar, the reading column, the book head, the dividers and full-width rows hold the interface, so they are square. | `--pt-radius-shell` in `tokens.css` | `pnpm lint:radius`; `pnpm lint:radius:live` | [Design system: corners](https://www.prototemplate.com/docs/handbook/design#corners-rounded-controls-square-shells) |
| 6px | Buttons, fields, segmented groups and the sidebar's pills are things a reader presses or types into. | `--pt-radius-control` in `tokens.css` | `pnpm lint:radius`; `pnpm lint:radius:live` | [Design system: corners](https://www.prototemplate.com/docs/handbook/design#corners-rounded-controls-square-shells) |
| 5px | A part flush inside a control's 1px border stays concentric with it. | `--pt-radius-inner` in `tokens.css` | `pnpm lint:radius` | [Design system: corners](https://www.prototemplate.com/docs/handbook/design#corners-rounded-controls-square-shells) |
| 4px | Key caps, chips, tags, inline code and a control set 2 to 7px inside a field take the chip corner. | `--pt-radius-chip` in `tokens.css` | `pnpm lint:radius`; `pnpm lint:radius:live` | [Design system: corners](https://www.prototemplate.com/docs/handbook/design#corners-rounded-controls-square-shells) |
| 6px | Cards, tiles, thumbnails, figures and popovers are objects a reader looks at. | `--pt-radius-card` in `tokens.css` | `pnpm lint:radius`; `pnpm lint:radius:live` | [Design system: corners](https://www.prototemplate.com/docs/handbook/design#corners-rounded-controls-square-shells) |
| 50% | Dots and avatars on a square box take a full round. | `--pt-radius-round` in `tokens.css` | `pnpm lint:radius:live` | [Docs site traps: the full round corner](https://www.prototemplate.com/docs/engineering/docs-traps#the-full-round-corner) |
| The role's radius minus 1 to 3px | A part 1 to 3px inside a rounded box takes the concentric radius. | `calc(var(--pt-radius-) - npx)`, `TOKEN_FORM` in `scripts/lint/radius.mjs` | `pnpm lint:radius` | [Design system: corners](https://www.prototemplate.com/docs/handbook/design#corners-rounded-controls-square-shells) |
| 8px | Present's solid button is the one named exception, a chrome request of Kevin's. | `EXCEPTIONS` in `scripts/lint/radius.mjs` | `pnpm lint:radius` K3 and L3 | [Design system: chrome exceptions](https://www.prototemplate.com/docs/handbook/design#15-chrome-exceptions-kevin-asked-for) |
| 33,554,400px | Chrome computes Tailwind 4's `rounded-full`, `calc(infinity * 1px)`, to this value, so the radius lint reports it as an illegal corner. | None; a square box takes `--pt-radius-round` | `pnpm lint:radius:live` | [Docs site traps: the full round corner](https://www.prototemplate.com/docs/engineering/docs-traps#the-full-round-corner) |
## Lines [#lines]
Every line is drawn once by one owner. In the shell's chrome every rule is 1px in one of three roles, so a line's weight says what it divides.
| Value | Reason | Token or constant | Held by | Explained in |
| --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Ink at 0.18 in light, 242 at 0.22 in dark | The structural role draws large surfaces and the lines that divide the shell. | `--pt-hair` in `tokens.css` | `pnpm lint:lines:shell` | [Design system: line law for chrome](https://www.prototemplate.com/docs/handbook/design#line-law-for-chrome) |
| Ink at 0.09 in light, 242 at 0.1 in dark | The row role draws list rows, panel rows and the sidebar's rail. | `--pt-hair-soft` in `tokens.css` | `pnpm lint:lines:shell` | [Design system: line law for chrome](https://www.prototemplate.com/docs/handbook/design#line-law-for-chrome) |
| Ink at 0.62 in light, 242 at 0.55 in dark | The frame role is the darkest line in chrome, because it holds a picture in place against the paper. | `--pt-edge` in `tokens.css` | `pnpm lint:lines:shell` | [Design system: line law for chrome](https://www.prototemplate.com/docs/handbook/design#line-law-for-chrome) |
| 59 and 99 in dark, 210 and 174 in light | One and two stacked strokes of `--pt-hair` composite to these greys, so a seam's grey counts its strokes. | `--pt-hair` in `tokens.css` | `skills/gt-verify/scripts/probe.mjs --scan` | [Lines and seams: reading a seam by its grey](https://www.prototemplate.com/docs/craft/lines#reading-a-seam-by-its-grey) |
| 4 device pixels at 2x | Two touching 1px rules of an opaque hairline keep one grey and show as a run twice as wide. | `--tc-hair` on the GT landing | `probe.mjs --dsf 2` | [Lines and seams: reading a seam by its grey](https://www.prototemplate.com/docs/craft/lines#reading-a-seam-by-its-grey) |
| 1 to 2.5px wide and over 24px long | The line auditor counts a border side, an outline, a border-like shadow, a thin fill or an exposed-ground strip in this range as a line. | Thresholds in `scripts/lint/lines.mjs` | `pnpm lint:lines`; `pnpm lint:lines:shell` | [Lines and seams: the line auditor's thresholds](https://www.prototemplate.com/docs/craft/lines#the-line-auditors-thresholds) |
| 1 to 4px apart, overlapping 75% of the shorter line and 80px | Two parallel lines from different owners this close read as one doubled line. | `scripts/lint/lines.mjs` | `pnpm lint:lines` | [Lines and seams: the line auditor's thresholds](https://www.prototemplate.com/docs/craft/lines#the-line-auditors-thresholds) |
| Under 1px apart | Two owners draw one seam and their alphas stack, which the auditor reports as a junction. | `scripts/lint/lines.mjs` | `pnpm lint:lines` | [Gates: what the line auditor counts](https://www.prototemplate.com/docs/gates#what-the-line-auditor-counts) |
| Within 45 summed RGB steps of the ground | A strip this close to the page's ground is an invisible seam. | `scripts/lint/lines.mjs` | `pnpm lint:lines` | [Gates: what the line auditor counts](https://www.prototemplate.com/docs/gates#what-the-line-auditor-counts) |
| Fill alpha 0.12 to 0.95 on an edge of 120px or longer | A self-stack fails only at this size, so chips and small controls are reported without failing. | `scripts/lint/lines.mjs` | `pnpm lint:lines` | [Lines and seams: self-stacks and stacked grounds](https://www.prototemplate.com/docs/craft/lines#self-stacks-and-stacked-grounds) |
| Opacity 0.05 or less | The auditor skips such elements, with SVG and canvas subtrees, so those are read by eye at 2x crops. | `scripts/lint/lines.mjs` | Review of 2x crops | [Lines and seams: the line auditor's thresholds](https://www.prototemplate.com/docs/craft/lines#the-line-auditors-thresholds) |
| 100vmax | A book's rules paint as a border image outset this far past both ends, so they run across the stage while the element keeps the column's layout. | `--pt-bleed-top`, `--pt-bleed-bottom`, `--pt-bleed-block` in `tokens.css` | `pnpm lint:heads:live` H6; the practices lint's `border-image-none` | [Lines and seams: rules that run the full width](https://www.prototemplate.com/docs/craft/lines#rules-that-run-the-full-width) |
| 1104px | The GT landing's original pages ran `max-w-[1120px] px-2`, so their side lines were 1104px apart, and a 1100px rail doubled every hairline by 2px a side. | `--tc-rail` in gt-cloud's landing engine | The practices lint's retired-rail checks | [Lines and seams: rails drawn as borders](https://www.prototemplate.com/docs/craft/lines#rails-drawn-as-borders) |
| 9px arms hanging 5px past the rail, at 0.38 in light and 0.34 in dark | A registration cross marks where a section seam meets the rail, and the page root takes `overflow-x: clip` for its arms. | `--cross-ink` in gt-cloud's landing engine | Review | [Lines and seams: registration crosses and horizontal clipping](https://www.prototemplate.com/docs/craft/lines#registration-crosses-and-horizontal-clipping) |
## The book page [#the-book-page]
Every page with a book head renders one structure, and every space in it is a token.
| Value | Reason | Token or constant | Held by | Explained in |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------- | -------------------------------------------------------------------------------- |
| 44px (24px) | The title sits this far under the stage's top, nothing is drawn in that space, and no line crosses a title. | `--pt-title-clear` in `tokens.css` | `pnpm lint:heads` S6; `pnpm lint:heads:live` H3 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 14px | This space separates the title's box from the lead's box. | `--pt-head-gap` in `tokens.css` | `pnpm lint:heads` S6 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 56px | This gap separates the lead's column from the panel. | `--pt-head-col-gap` in `tokens.css` | `pnpm lint:heads` S6 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 304px | The panel's column fits its longest value, a date with its hint such as "Sep 10, 2026 4 weeks ago", which measures 168px. | `--pt-head-panel` in `tokens.css` | `pnpm lint:heads` S6; `pnpm lint:heads:live` H5 | [Badges and heads: the head's numbers](https://www.prototemplate.com/docs/components/heads#the-heads-numbers) |
| 26.35px | One lead line sets the panel's row pitch, so every fact sits on a lead baseline. | `--pt-row` in `tokens.css` | `pnpm lint:heads:live` H5 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 26px | The mast's rule sits this far under the taller of the lead and the panel. | `--pt-head-rule-pad` in `tokens.css` | `pnpm lint:heads:live` H6 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 42px | The hatch band measures this with both of its rules, and its 1px diagonal repeats every 7px. | `--pt-band-h`, `--pt-hatch` in `tokens.css` | `pnpm lint:heads` S3; `pnpm lint:heads:live` H7 | [Design system: sanctioned devices](https://www.prototemplate.com/docs/handbook/design#sanctioned-devices) |
| 48px (40px) | A rule sits this far under the block above it. | `--pt-sec-over` in `tokens.css` | `pnpm lint:heads:live` H7 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 30px | An h2's box sits this far under its rule. | `--pt-sec-pad` in `tokens.css` | `pnpm lint:heads:live` H3 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 32px (24px) and 56px (16px) | Blocks in a book column sit this far apart, and the column takes this side padding. | `--pt-book-gap`, `--pt-col-pad-x` in `tokens.css` | `pnpm lint:heads` S6 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 193.16px | At 1440 a one-line title's mast rule sits this far below the title's top on every page; the panel's four rows set it. | `H9_GAP` in `scripts/lint/heads.mjs` | `pnpm lint:heads:live` H9 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 35.5px at 1440 and 79px at 390 | Every section's h2 sits the same distance under its rule. | `scripts/lint/heads.mjs` | `pnpm lint:heads:live` H8 | [Pages: the book page's numbers](https://www.prototemplate.com/docs/pages#the-book-pages-numbers) |
| 52px, and 208px or 256px | The toolbar is 52px tall, and the sidebar is 208px wide in outline density and 256px with thumbnails. | `--pt-bar-h`, `--pt-sb-w` in `tokens.css`; `ViewerShell.css` | Review | [Pages: the viewer shell](https://www.prototemplate.com/docs/pages#the-viewer-shell) |
## Motion [#motion]
Bounce, elastic and back overshoot are not used, and every number here has a reduced-motion still.
| Value | Reason | Token or constant | Held by | Explained in |
| --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------- |
| 0.5s | Film arrivals and scene changes land on this beat grid. | The film kit's beat grid; `skills/gt-motion/SKILL.md` | Review | [SVG lines in motion: timing numbers](https://www.prototemplate.com/docs/craft/svg-motion#timing-numbers) |
| (words / 3) + 1s | A sentence holds this long after it has fully arrived, so it can be read. | `skills/gt-motion/SKILL.md` | Review | [SVG lines in motion: timing numbers](https://www.prototemplate.com/docs/craft/svg-motion#timing-numbers) |
| 40 to 90ms | Staggers run in reading direction at this spacing. | `skills/gt-motion/SKILL.md` | Review | [SVG lines in motion: timing numbers](https://www.prototemplate.com/docs/craft/svg-motion#timing-numbers) |
| 0.62s with a 0.055s stagger, from 16px down | The GT landing reveals its content with this tween. | gt-cloud's `reveal.ts` | Review | [SVG lines in motion: timing numbers](https://www.prototemplate.com/docs/craft/svg-motion#timing-numbers) |
| 180ms `ease-out` from 4px down | Rows on the dashboard's sign-in and onboarding plates reveal with this tween. | gt-cloud's `brand-tokens.css` | Review | [SVG lines in motion: timing numbers](https://www.prototemplate.com/docs/craft/svg-motion#timing-numbers) |
| 120 to 220ms, 0 under reduced motion | The shell's chrome transitions run in this range, from a button's colour to the sidebar column. | `--pt-dur-fast` to `--pt-dur-sb` in `tokens.css` | Review | [SVG lines in motion: timing numbers](https://www.prototemplate.com/docs/craft/svg-motion#timing-numbers) |
| 350ms and 150ms | A dithered resolve and a dithered step take these times, halved from 700 and 300ms on Kevin's request of 2026-09-29. | `RESOLVE_MS`, `STEP_MS` in `src/app/craft/TransitionDemo.tsx` | Review | [Dither in practice: transitions on one grid](https://www.prototemplate.com/docs/craft/dither#transitions-on-one-grid) |
| 240ms `ease-out` | A field's first paint is a keyframe fade, because a CSS transition never runs on the first frame. | gt-cloud's `brand-field-picture-in` keyframe | Review | [SVG lines in motion: transitions at first paint](https://www.prototemplate.com/docs/craft/svg-motion#transitions-at-first-paint) |
| 0.25s or more | An assembly moves one group at a time and rests this long between groups. | `skills/gt-motion/SKILL.md` | Review | [SVG lines in motion: timing numbers](https://www.prototemplate.com/docs/craft/svg-motion#timing-numbers) |
| 0.7s `power2.inOut`, requests debounced 0.25s, none under 720px | The moving type law allows one width tween per cycle, and phones found it slow, so the em pins to the column there. | `skills/gt-motion/SKILL.md` | Review | [SVG lines in motion: moving type](https://www.prototemplate.com/docs/craft/svg-motion#moving-type) |
| Scale 1.00 to 1.04 over a scene | A camera drift is allowed on a picture or a field, and type holds still. | `skills/gt-motion/SKILL.md` | Review | [SVG lines in motion: timing numbers](https://www.prototemplate.com/docs/craft/svg-motion#timing-numbers) |
| 30 fps | The CPU dither loop runs at this rate by default, which keeps the main thread free. | `src/lib/dither.ts` | Review | [Dither and the studio field: what a field costs](https://www.prototemplate.com/docs/components/dither#what-a-field-costs) |
## SVG lines [#svg-lines]
| Value | Reason | Token or constant | Held by | Explained in |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `'100 200'` parked at +101 or -101 | The gap keeps every dash edge clear of both ends, and the sign picks the end a draw-on grows from: + from the first point, - from the last. | The draw-on tweens; `skills/gt-motion/references/traps.md` | Review of 2x crops | [SVG lines in motion: the sign of the parked offset](https://www.prototemplate.com/docs/craft/svg-motion#the-sign-of-the-parked-offset) |
| `pathLength` 1000 | GSAP integer-rounds pixel CSS properties, so a looping dash on 1000 units moves by sub-pixel steps. | `autoRound: false` on every dash tween | Review | [SVG lines in motion: rounding, cached paths and empty paths](https://www.prototemplate.com/docs/craft/svg-motion#rounding-cached-paths-and-empty-paths) |
| About 100ms early | A capture synced to a GSAP state polls a CSS variable and fires early, so its own latency lands it inside the state. | The capture harness | Review | [SVG lines in motion: GSAP from outside the page](https://www.prototemplate.com/docs/craft/svg-motion#gsap-from-outside-the-page) |
| 22 units for 20.1px | Labels in an 800-unit viewBox that renders at 0.914 are set after the scale. | `skills/gt-diagrams/SKILL.md` | `skills/gt-diagrams/scripts/figure-check.mjs` | [SVG lines in motion: drawing under a stretched viewBox](https://www.prototemplate.com/docs/craft/svg-motion#drawing-under-a-stretched-viewbox) |
| `y1="70.5"` | A 1px line at 1:1 sits on a half-pixel coordinate to fill one row of device pixels. | `skills/gt-diagrams/SKILL.md` | Review of 2x crops | [SVG lines in motion: drawing under a stretched viewBox](https://www.prototemplate.com/docs/craft/svg-motion#drawing-under-a-stretched-viewbox) |
| `-8 214 1213 771`, aspect about 1.573 | The GT monogram symbol carries this viewBox, so an svg that copies it draws the mark 214 units too high; the referencing svg takes only a width and height, such as 132 by 84. | `#gt-mark` in `deck/parts/head.html`; `src/lib/marks.ts` | Review | [SVG lines in motion: symbols and masks](https://www.prototemplate.com/docs/craft/svg-motion#symbols-and-masks) |
## Isometric drawings [#isometric-drawings]
| Value | Reason | Token or constant | Held by | Explained in |
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------- |
| 30 degrees, tan 30 (0.577) and the square root of 1.5 | Flat art reaches the iso plane by a 45 degree turn, y scaled by 0.577 and the whole scaled by the square root of 1.5. A 2:1 squash scales y by 0.5 and lies flatter than the face under it. | `project()` and `plane()` in `src/app/d/toolchain/diagrams/iso.ts` | Review | [Isometric drawings: numbers and traps](https://www.prototemplate.com/docs/components/iso#numbers-and-traps) |
| 2.4, and 1.2 on diff slats | One corner radius serves the family; at 2.4 a thin slat reads as a capsule. | `ISO_RADIUS` in `iso.ts` | Review | [Isometric drawings: numbers and traps](https://www.prototemplate.com/docs/components/iso#numbers-and-traps) |
| About 4% of the footprint thick, about 40% air between plates | Shared proportions make separate drawings read as one set. | `skills/gt-diagrams/references/isometric.md` | The gt-diagrams review checklist | [Isometric drawings: numbers and traps](https://www.prototemplate.com/docs/components/iso#numbers-and-traps) |
| Rim 0.12 + 0.08 d, top edge 0.24 + 0.24 d, front edge 0.08 | Depth comes from each plate's stroke alpha, where d runs from 0 at the bottom plate to 1 at the top. | `skills/gt-diagrams/references/isometric.md` | Review | [Isometric drawings: numbers and traps](https://www.prototemplate.com/docs/components/iso#numbers-and-traps) |
| 240 by 180 | The shared viewBox fixes the relative scale of the family. | `ISO_VIEW_W`, `ISO_VIEW_H` in `src/app/d/toolchain/diagrams/IsoFrame.tsx` | Review | [Isometric drawings: the kit](https://www.prototemplate.com/docs/components/iso#the-kit) |
## Dither [#dither]
| Value | Reason | Token or constant | Held by | Explained in |
| -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------- |
| 8 by 8 Bayer, 65 levels | A constant tone k/64 lights exactly k cells of every tile, and a cell is lit when its tone exceeds (m + 0.5) / 64. | `BAYER_8` in `src/lib/dither.ts` | Review | [Dither in practice: ordered dither](https://www.prototemplate.com/docs/craft/dither#ordered-dither) |
| 1, 2, 3, 4 and 6 CSS px cells | The cell grows with the use: photographs, the sign-in globe, full-bleed fields and every film, an animated burst, then small stills. From 8px a screen reads as pixel art. | `scale` on the CPU loop; `skills/gt-dither/SKILL.md` | Review | [Dither in practice: cells are screen pixels](https://www.prototemplate.com/docs/craft/dither#cells-are-screen-pixels) |
| `min(devicePixelRatio, 2)` | The GPU studio field computes cells from device pixels, and a dpr of 1 upscaled blurs them together. | `dpr` in `src/lib/studio-field.ts` | Review | [Dither in practice: cells are screen pixels](https://www.prototemplate.com/docs/craft/dither#cells-are-screen-pixels) |
| Opacity 0.55 in screen blend, mask 0.72 at the edges to 0.12 at the centre | The landing hero's material is the strongest a product surface may carry. | Studio preset 02, `bayer-8x8`; `skills/gt-dither/SKILL.md` | Review | [Dither in practice: material strength](https://www.prototemplate.com/docs/craft/dither#material-strength) |
| Mean tone 0.361, standard deviation 0.342 | Every dithered photograph is cut to the Blue Marble's own statistics, accepted from 0.30 to 0.42 and 0.28 to 0.44. | `scripts/media/mood-tone/standard.json` | `node scripts/lint/pictures.mjs` | [Dither in practice: the picture standard](https://www.prototemplate.com/docs/craft/dither#the-picture-standard) |
| Gamma 1.2, 0.5% autocontrast, no blur | These settings are fixed for every picture, since a blur of sigma 3 erased the Rosetta Stone's inscriptions. | `scripts/media/mood-tone/standard.json` | `node scripts/lint/pictures.mjs` | [Artifact pictures: the tone grid](https://www.prototemplate.com/docs/handbook/artifact-pictures#3-the-tone-grid-is-the-blue-marbles) |
| JPEG quality 82, 75 over 573,440 bytes | The byte cap keeps every grid under 560KB. | `scripts/media/mood-tone/standard.json` | `node scripts/lint/pictures.mjs` | [Dither in practice: the picture standard](https://www.prototemplate.com/docs/craft/dither#the-picture-standard) |
| 144k cells at `scale` 3: 0.8 to 15.1ms a frame | The CPU loop's cost is linear in cells, and halving the cell size quadruples it, so a full-bleed field never animates at `scale` 1 (1.3 million calls). | The field functions in `src/lib/dither.ts` | Review | [Dither and the studio field: what a field costs](https://www.prototemplate.com/docs/components/dither#what-a-field-costs) |
| A disc 1.7 times the stack's height, its limb five sevenths along the ramp | The onboarding earth sits under the thick part of the field's ramp, where the first placement left it under the thin start. | `src/components/plate/brand/moodPictures.ts` | Review | [Dither in practice: placing a picture on a field](https://www.prototemplate.com/docs/craft/dither#placing-a-picture-on-a-field) |
## Interface [#interface]
| Value | Reason | Token or constant | Held by | Explained in |
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| 44px target, under 40px a defect | A phone tap target aims at 44px, and the page check fails one under 40px and notes 40 to 43px. | `TAP_DEFECT_UNDER`, `TAP_NOTE_UNDER` in `scripts/check/pagecheck/probes.mjs` | `pnpm check:pages` | [Interface details: tap targets that keep the look](https://www.prototemplate.com/docs/craft/interface-details#tap-targets-that-keep-the-look) |
| 0.001 per layout-shift entry | An entry within 500ms of an input stays out of the CLS score and is still a jump a reader sees. | `SHIFT_FLOOR` in `scripts/check/pagecheck/cls.mjs` | `pnpm check:pages --cls-trace` | [Interface details: layout shifts](https://www.prototemplate.com/docs/craft/interface-details#layout-shifts) |
| CLS over 0.1 fails, over 0.05 is a note | The first is the Web Vitals limit, and the second is a margin under it. | `CLS_DEFECT`, `CLS_NOTE` in `scripts/check/pagecheck/probes.mjs` | `pnpm check:pages` | [Proving a visual change: the stress matrix](https://www.prototemplate.com/docs/engineering/verification#the-stress-matrix) |
| 4.5:1 for text under 24px | Titanium `#8a8f98` on white is 3.25, so light captions take `#6e737c` at 4.77 or ink-2. | `--pt-titanium`, `--pt-ink-2` in `tokens.css` | Review; `measure-type.mjs` | [Interface details: contrast](https://www.prototemplate.com/docs/craft/interface-details#contrast) |
| About 1.6s | A copy control holds its check this long, announced to screen readers, and its label never changes. | `InstallField` in `src/components/viewer/InstallField.tsx` | Review | [Interface details: the copy control](https://www.prototemplate.com/docs/craft/interface-details#the-copy-control) |
| 350ms and 4.5s | A carousel drops a command within 350ms of the last one, and autoplays every 4.5s until hover, focus or reduced motion stops it. | The blog carousel in gt-cloud; `skills/gt-website/references/blog.md` | Review | [Interface details: carousels and galleries](https://www.prototemplate.com/docs/craft/interface-details#carousels-and-galleries) |
| 16px or larger | Inputs below the `md` breakpoint stay at this size so iOS does not zoom on focus. | `skills/gt-components/SKILL.md` | Review | [Interface details: third-party widgets and the site's theme](https://www.prototemplate.com/docs/craft/interface-details#third-party-widgets-and-the-sites-theme) |
## The deck [#the-deck]
| Value | Reason | Token or constant | Held by | Explained in |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------ | -------------------------------------------------------- | --------------------------------------------------------------------------------- |
| 1600 by 900 | Every slide is drawn on one sheet that scales to the window. | `deck/DECK-GRAMMAR.md` | `node shoot-slide.mjs` prints any element past the sheet | [The brand deck: the sheet and the grammar](https://www.prototemplate.com/docs/deck#the-sheet-and-the-grammar) |
| 56px | The viewer draws the rails and rules this far in from each edge, and a slide never redraws them. | `deck/DECK-GRAMMAR.md` | Review | [The brand deck: the sheet and the grammar](https://www.prototemplate.com/docs/deck#the-sheet-and-the-grammar) |
| h1 88px, h2 44px, `.big` 72px, `p` 22px, `.lead` 26px | The deck sets its type at these sizes on the sheet. | The shared styles in `deck/parts/` | Review | [The brand deck: the sheet and the grammar](https://www.prototemplate.com/docs/deck#the-sheet-and-the-grammar) |
| 15px for text, 18px for SVG labels | Text under 15px on the sheet is a defect, and an SVG label is never under 18px. | `.cap` and `.sm` in `deck/DECK-GRAMMAR.md` | Review | [Writing: slides and cards](https://www.prototemplate.com/docs/craft/writing#slides-and-cards) |
| 256px or 208px | The deck viewer's slide list takes these widths with thumbnails and in outline density. | `--sb-w` in `deck/parts/head.html` | Review | [The brand deck: the viewer](https://www.prototemplate.com/docs/deck#the-viewer) |
## Graphics [#graphics]
| Value | Reason | Token or constant | Held by | Explained in |
| --------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------ | --------------------- | ------------------------------------------------------------------------------- |
| 3 to 5x | Product captures are taken at this scale, lossless, so crops stay sharp after zoom. | `SHOTS` in `graphics/build/gen-lib.js`; `graphics/shots/hi/` | Review | [Graphics pipeline: the files](https://www.prototemplate.com/docs/handbook/graphics#the-files) |
| 26px after zoom-to-fit | No text on the 1600px stage is smaller than a label chip once the composition is fitted. | `MIN_TEXT` in `graphics/build/gen-lib.js` | `pnpm graphics:audit` | [Graphics pipeline: sizing](https://www.prototemplate.com/docs/handbook/graphics#sizing) |
| About 700 CSS px, 0.44x | A blog column shows the 1600px stage at this scale, so every label is sized for it. | The 1600px `stage` in `graphics/build/gen-lib.js` | `pnpm graphics:audit` | [Graphics pipeline: sizing](https://www.prototemplate.com/docs/handbook/graphics#sizing) |
| 3840 wide webp at quality 95; OG 2400 by 1260 | The exports serve a dense `deviceSizes` ladder through next/image. | `graphics/build/export-blog.py` | Review | [Graphics pipeline: sizing](https://www.prototemplate.com/docs/handbook/graphics#sizing) |
| 712px | The blog globe figure is laid out at this review column before it scales. | `src/components/blog-globe/blog-globe.css` | Review | [The blog globe figure: measurements](https://www.prototemplate.com/docs/components/blog-globe#measurements) |
## Films [#films]
| Value | Reason | Token or constant | Held by | Explained in |
| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------- |
| -16 LUFS within 0.5, true peak at or under -1 dBTP | A film meets these loudness targets, and the renderer lowers a track whose true peak passes -1 dBTP to -1.5 dBTP. | `skills/gt-films/references/sound.md` | `ffmpeg -af ebur128=peak=true` | [Films: the mix and its traps](https://www.prototemplate.com/docs/craft/films#the-mix-and-its-traps) |
| About -26 LUFS under speech, -20 LUFS alone | The music bed's duck is about 6dB in loudness terms. | `skills/gt-films/references/sound.md` | Review | [Films: the mix and its traps](https://www.prototemplate.com/docs/craft/films#the-mix-and-its-traps) |
| 0.1s of silence; a -9dB shelf at 100Hz | A clip at full level from its first sample bumps, and sub-bass downbeats made the AAC encoder overshoot by up to 2.6dB. | `skills/gt-films/references/sound.md` | Review | [Films: the mix and its traps](https://www.prototemplate.com/docs/craft/films#the-mix-and-its-traps) |
| 2.60 words a second | The narrator speaks at this rate, scripts are planned on it, and a take is never sped up. | `skills/gt-films/references/sound.md` | Review | [Films: speech synthesis](https://www.prototemplate.com/docs/craft/films#speech-synthesis) |
| 640 by 360 | A film plays at this size on a phone, so every thin line is checked there. | `skills/gt-films/SKILL.md` | The film critic | [Films: thin lines over a dithered ground](https://www.prototemplate.com/docs/craft/films#thin-lines-over-a-dithered-ground) |
| 3px cells, 8 by 8 Bayer | Every GT film uses one screen, set on 2026-10-08. | `skills/gt-films/SKILL.md` | The film critic | [Dither in practice: cells are screen pixels](https://www.prototemplate.com/docs/craft/dither#cells-are-screen-pixels) |
| 5 GiB free, 8 GiB for several workers | A render with several workers writes every frame before it encodes. | `skills/gt-films/references/kit.md` | Review | [Films: frames, probes and disks](https://www.prototemplate.com/docs/craft/films#frames-probes-and-disks) |
| The stakes in 6 to 8s; about two picture events a second | A film states its stakes early and moves one thing at a time. | `skills/gt-films/SKILL.md` | The film critic | [Films: pacing and scripts](https://www.prototemplate.com/docs/craft/films#pacing-and-scripts) |
## Skills [#skills]
| Value | Reason | Token or constant | Held by | Explained in |
| --------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------- | ------------------------------------------------- |
| 1024 characters | A skill's description says what it covers and when to use it within the length agents load. | `MAX_DESCRIPTION` in `scripts/build/skills.mjs` | `pnpm lint:skills` | [Skills: the contract](https://www.prototemplate.com/docs/skills#the-contract) |
| 24,000 bytes | A SKILL.md body stays under this budget, and detail moves to `references/` without deleting a rule. | `BUDGET` in `scripts/build/skills.mjs`; exemptions with reasons and expiry dates in `scripts/build/skills.budget.json` | `pnpm lint:skills` | [Skills: the contract](https://www.prototemplate.com/docs/skills#the-contract) |
| 30 days | A skill with no loads thirty days after distribution is cut unless Kevin keeps it by name. | `DAYS` in `scripts/skills/usage.mjs` | `pnpm skills:usage` | [Skills: kept by use](https://www.prototemplate.com/docs/skills#kept-by-use) |
## Docs and SEO [#docs-and-seo]
| Value | Reason | Token or constant | Held by | Explained in |
| -------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| 50 to 160 characters | A description of this length shows whole in a search snippet. | `DESCRIPTION_MIN`, `DESCRIPTION_MAX` in `scripts/lint/seo.mjs` | `pnpm lint:seo`; `pnpm lint:registries` | [The SEO system: what one call writes](https://www.prototemplate.com/docs/seo#what-one-call-writes) |
| 60 characters | A title drops its section, then the site name, when it passes this length. | `TITLE_MAX` in `src/lib/seo/route.ts` | `pnpm lint:seo` | [The SEO system: what one call writes](https://www.prototemplate.com/docs/seo#what-one-call-writes) |
| 1200 by 630 | The social card is cached for a year, because it is a pure function of its query. | `src/app/og/route.tsx`; `OG_VERSION` | `pnpm lint:seo:live` | [The SEO system: the social card](https://www.prototemplate.com/docs/seo#the-social-card) |
| Two segments under `/docs` | The Markdown twin rewrites cover docs URLs this deep, so a deeper folder needs a third rule. | `TWIN_REWRITES` in `next.config.ts` | `pnpm lint:seo:live` | [The SEO system: why the twins are prerendered](https://www.prototemplate.com/docs/seo#why-the-twins-are-prerendered) |
| `tokenizeTimeLimit: 0` | Shiki's default 500ms limit leaves part of a line plain on a loaded build machine, so two builds differ. | `source.config.ts` | Review of a production build | [Docs site traps: code highlighting across builds](https://www.prototemplate.com/docs/engineering/docs-traps#code-highlighting-across-builds) |
| `next` 16.2.12 | Next.js 16.3 holds memory for every prerendered page, and a 7,117-page build died at page 1,779. | `package.json` | Review | [Docs site traps: prerender memory on Next.js 16.3](https://www.prototemplate.com/docs/engineering/docs-traps#prerender-memory-on-nextjs-163) |
## Engines [#engines]
| Value | Reason | Token or constant | Held by | Explained in |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| About 16 live WebGL contexts | Past this budget Chrome's `getContext` returns null and a field draws black with no error. | One engine per module in `src/lib/studio-field.ts`, `horizon-field.ts` and `prismatic-field.ts` | Review; the frame probe's `gl` column | [Canvas and WebGL engines: the context budget](https://www.prototemplate.com/docs/engineering/engines#the-context-budget) |
| 1 context per engine module, 0 created by a probe | The context survives every `destroy()`, and a probe that calls `getContext` exhausts the budget it counts. | The same modules | Review | [The component library: the numbers behind it](https://www.prototemplate.com/docs/components#the-numbers-behind-it) |
| 180px | A lazy plate mounts its engine when it first comes this close to the viewport. | `rootMargin: '180px'` in `src/components/docs/demos/hooks.ts` | Review | [The component library: the numbers behind it](https://www.prototemplate.com/docs/components#the-numbers-behind-it) |
| 2.5s warmup, windows of 120 frames, gaps over 900ms skipped | The glyph rain judges its quality tier from measured frame time, because a tier chosen by window width gave weak hardware the heaviest one. | `GOV_WARMUP_MS`, `GOV_WINDOW`, `GOV_GAP_MS` in `src/lib/glyph-field.ts` | The frame probe's `--cpu 12` | [Canvas and WebGL engines: quality from measured frame time](https://www.prototemplate.com/docs/engineering/engines#quality-from-measured-frame-time) |
| 35% of frames over 22ms | The trip counts slow frames, because a median missed throttled hardware that ran over budget on 34% of its frames. | `GOV_TRIP`, `GOV_BUDGET_MS` in `src/lib/glyph-field.ts` | The frame probe's `--cpu 12` | [Canvas and WebGL engines: quality from measured frame time](https://www.prototemplate.com/docs/engineering/engines#quality-from-measured-frame-time) |
| Pixel-ratio cap 2 to 1.25, then 560 of 1,280 glyphs | The governor's two tiers only step down, so it never oscillates. | `DPR_CAP`, `DPR_CAP_NARROW`, `NARROW_POOL`, `POOL` in `src/lib/glyph-field.ts` | Review | [Canvas and WebGL engines: quality from measured frame time](https://www.prototemplate.com/docs/engineering/engines#quality-from-measured-frame-time) |
| About 1,000ms of every second | An engine that resized its one GL canvas to each field reallocated it twice a frame, so the canvas now only grows. | The blit in `src/lib/prismatic-field.ts` | Review | [Canvas and WebGL engines: a shared canvas that only grows](https://www.prototemplate.com/docs/engineering/engines#a-shared-canvas-that-only-grows) |
| 12 live pages, 1.3 GB and about 950ms of every second | A gallery that froze each preview still paid this, so previews are stills until hover. | `src/app/present/viewer/LazyFrame.tsx`; the rAF gate in `src/app/layout.tsx` | Review | [Canvas and WebGL engines: galleries of live previews](https://www.prototemplate.com/docs/engineering/engines#galleries-of-live-previews) |
| 6.5KB to 4.4KB | Comments inside a GLSL template literal ship to every visitor, so they move to a TypeScript comment. | The horizon shader in `src/lib/horizon-field.ts` | Pixel diff of a deterministic frame | [Canvas and WebGL engines: shader source weight](https://www.prototemplate.com/docs/engineering/engines#shader-source-weight) |
| 5 fps against 56 fps | A seam drag ran at these rates over 27,800 SVG nodes and over one canvas, at 4x CPU throttle. | `--seam-cut` on the reveal seam | Review | [Lottie on canvas: before and after](https://www.prototemplate.com/docs/engineering/lottie#before-and-after) |
## Gates [#gates]
| Value | Reason | Token or constant | Held by | Explained in |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------ |
| 0, 1 and 2 | Every lint exits 0 on a pass, 1 on findings and 2 when it could not judge, so a missing server stops a chain as a finding does. | Each script under `scripts/lint/` | Every gate | [Gates: exit codes](https://www.prototemplate.com/docs/gates#exit-codes) |
| 3 to 5 minutes | `pnpm exec tsc --noEmit` is a gate of its own, because `next build` never type-checks here. | `typescript.ignoreBuildErrors` in `next.config.ts` | The type check | [Gates: the type check](https://www.prototemplate.com/docs/gates#the-type-check) |
| About 25 minutes | `pnpm lint:all` runs every static lint, then the browser audits one at a time. | `package.json`; `skills/prototemplate/SKILL.md` | `pnpm lint:all` | [Gates: the gates, in order](https://www.prototemplate.com/docs/gates#the-gates-in-order) |
| One browser gate at a time | A parallel capture made `pnpm lint:lines:shell` fail on correct pages on 2026-10-01. | `siteRoutes()` in `scripts/lib/site-pages.mjs` | Every browser gate | [Gates: browser gates run one at a time](https://www.prototemplate.com/docs/gates#browser-gates-run-one-at-a-time) |
| Per file | A ratchet counts findings per file, so a line another session moves never reads as a new finding. | `scripts/lint/*.baseline.json` | `--update-baseline` after a cleanup | [Gates: ratchets](https://www.prototemplate.com/docs/gates#ratchets) |
| HTTP 400 or more exits 2 | A 404 page audits at about one line and would pass. | `scripts/lint/lines.mjs` | `pnpm lint:lines` | [Lines and seams: the line auditor's thresholds](https://www.prototemplate.com/docs/craft/lines#the-line-auditors-thresholds) |
| Five rows read by regex | The route list finds the first skill, motion package, archive entry and exploration and the newest post in data files, so a generator's output shape is load-bearing. | `firstSlug()` in `scripts/lib/site-pages.mjs` | `pnpm lint:registries` check 3 | [Scripts: first slugs read by regex](https://www.prototemplate.com/docs/scripts#first-slugs-read-by-regex) |
## Dev servers and the machine [#dev-servers-and-the-machine]
| Value | Reason | Token or constant | Held by | Explained in |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Port 3005 | The shared dev server runs here, and every other worktree runs its own server on its own port. | `pnpm dev`; `PT_BASE` in the browser gates | Review | [Get started: run the site](https://www.prototemplate.com/docs/get-started#run-the-site) |
| 64 GB | A long-running shared server's `.next/dev` grew this large, so the restart deletes it. | `.next/dev` | Review | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| 900s or more | A cold image request on a loaded dev server hangs this long and times out a page check. | The image optimizer of `next dev` | Review | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| 2,880 minutes | gt-cloud's pnpm refuses any version published in the last two days, so `pnpm add` can fail on an unrelated dependency. | `minimumReleaseAge` in gt-cloud's `pnpm-workspace.yaml` | pnpm itself | [Dev servers and builds: a minimum release age for dependencies](https://www.prototemplate.com/docs/engineering/dev-servers#a-minimum-release-age-for-dependencies) |
| Two hours, and about 90 minutes | Claude Code stops a background shell task at two hours, so a job that may run past 90 minutes starts detached and writes its own process id. | `skills/gt-orchestration/references/harness-traps.md` | Review | [Agents on one machine: long commands](https://www.prototemplate.com/docs/handbook/shared-machine#long-commands) |
| 128GB | The workstation ran out of application memory twice on 2026-10-12, so each heavy job is gated on its own memory estimate. | `headroom can-start --gb ` | Review | [Agents on one machine: memory and disk](https://www.prototemplate.com/docs/handbook/shared-machine#memory-and-disk) |
## Pull requests and workflows [#pull-requests-and-workflows]
| Value | Reason | Token or constant | Held by | Explained in |
| ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | --------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------- |
| 420 to 900 CSS px wide, 620px tall at most, 24px of padding | A before and after crop is readable in a pull request body, where full-page captures render as strips. | `skills/gt-ship/references/pr-body.md` | Review | [Pull requests and CI: size and shape](https://www.prototemplate.com/docs/handbook/pull-requests#size-and-shape) |
| 5/5 on the head commit | A gt-cloud pull request waits for this Greptile score, with every bot thread answered and resolved. | `skills/gt-ship/references/review-loop.md` | Review | [Pull requests and CI: review bots](https://www.prototemplate.com/docs/handbook/pull-requests#review-bots) |
| 4096MB | The dashboard's type check outgrew Node's default 2GB heap in CI. | `--max-old-space-size` in gt-cloud's build | CI | [Pull requests and CI: CI signals that mislead](https://www.prototemplate.com/docs/handbook/pull-requests#ci-signals-that-mislead) |
| About 1,800 words in, about 700 words out | A build fan-out starts from a spec of this size, and a build lane reports in this many words. | `skills/gt-orchestration/references/briefs.md` | Review | [Agent workflows: workflow shapes](https://www.prototemplate.com/docs/handbook/workflows#workflow-shapes) |
| Three refuters, two of three to stand | A critical or major finding stands only when at least two refuters fail to refute it. | `skills/gt-orchestration/SKILL.md` | Review | [Agent workflows: refuting findings](https://www.prototemplate.com/docs/handbook/workflows#refuting-findings) |
| 8.5 of 10 per dimension, 90 of 100 overall | A fresh critic scores quality work against a named reference, in every view. | `skills/gt-orchestration/references/convergence.md` | The critic | [Agent workflows: kinds of check](https://www.prototemplate.com/docs/handbook/workflows#kinds-of-check) |
| 35 of 50 | A draft whose humanizer score on five axes totals less goes back for another revision. | `skills/gt-voice/SKILL.md` | Review | [Writing: the humanizer pass](https://www.prototemplate.com/docs/craft/writing#the-humanizer-pass) |
## Sources [#sources]
* Prototemplate, read on 2026-10-21: `src/components/viewer/tokens.css`; `DESIGN.md` sections 2, 4 and 15; `deck/DECK-GRAMMAR.md`; `docs/GRAPHICS.md`; `scripts/lint/type.mjs`, `radius.mjs`, `lines.mjs`, `heads.mjs` and `seo.mjs`; `scripts/check/pagecheck/probes.mjs` and `cls.mjs`; `scripts/build/skills.mjs` and `scripts/skills/usage.mjs`; `src/lib/glyph-field.ts`, `studio-field.ts`, `prismatic-field.ts`, `dither.ts`, `fonts.ts` and `seo/route.ts`; `src/components/docs/demos/hooks.ts`; `src/app/craft/TransitionDemo.tsx`; `src/app/d/toolchain/diagrams/iso.ts` and `IsoFrame.tsx`; `graphics/build/gen-lib.js`; `scripts/media/mood-tone/standard.json`; `package.json`; the files in `public/fonts/`.
* The curated skills, read on 2026-10-21: `gt-brand` (`references/type.md`), `gt-motion` (section 2 and `references/traps.md`), `gt-diagrams` (`references/isometric.md`), `gt-dither` (`references/engines.md`, `references/pictures.md`), `gt-films` (`references/sound.md`, `references/kit.md`), `gt-performance` (`references/webgl-lifecycles.md`), `gt-website`, `gt-ship`, `gt-orchestration`, `gt-voice`, `gt-aesthetic` and `prototemplate`.
* The docs pages each row links to, which hold the measurements with their dates.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Traps and fixes
> One line per trap met in GT work, grouped by area: the symptom a reader sees, the fix in a few words and the section that explains the cause.
URL: https://www.prototemplate.com/docs/handbook/traps
Each row below is a failure met in General Translation (GT) work on Prototemplate, generaltranslation.com and the films between July and October 2026. A row gives the symptom a reader sees first, then the fix in a few words, and links the section that explains the cause, the proof and the date. When something breaks, find its symptom here; before a round of work in an area, read that area's rows. [Numbers](https://www.prototemplate.com/docs/handbook/numbers) indexes the values the fixes depend on in the same way.
The cause and the measurement live on the linked page, so a row changes when its section does. Paths are relative to the root of the Prototemplate repository.
## Dev servers [#dev-servers]
| Symptom | Fix | Explained in |
| ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| A second `next dev` for the same checkout refuses to start | One server per checkout; another worktree runs its own server on its own port | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| Every route answers 404 after a restart | Two servers shared one `.next`: stop both by PID, `rm -rf .next`, start one | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| Every route answers 500 with "Unexpected non-whitespace character after JSON" | Stop the server by PID, delete `.next/dev`, start it again | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| The server answers nothing after a large fast-forward | The same restart | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| The disk fills while a shared server runs | Delete `.next/dev` at the restart | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| A changed image still shows its old version | `rm -rf .next` and restart | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| A cold image request hangs for 900s and times out a page check | Retry once the machine's load drops | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| `next start` serves the old build after a rebuild reported success | Delete `.next` in the scratch tree before diagnosing | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| Every docs page answers 404 after a merge, with nothing in the log | `pnpm install --frozen-lockfile` and a restart | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| `Module not found` for a workspace package whose sources changed | Build the package, which resolves from a stale `dist/` | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| A pending navigation lasts longer than in production | Judge navigation timing on a production build | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| A route answers 200 and its body is the error overlay | Call a server ready only when a real page's body has no build error | [Dev servers and builds: failure modes of next dev](https://www.prototemplate.com/docs/engineering/dev-servers#failure-modes-of-next-dev) |
| A hydration mismatch appears at random under `next dev` | Judge it on a production build before chasing it | [Localized routing: links, routers and strings in gt-next](https://www.prototemplate.com/docs/engineering/i18n-routing#links-routers-and-strings-in-gt-next) |
| `pnpm add` fails on a dependency the change never touched | Add the one dependency by hand under the minimum release age | [Dev servers and builds: a minimum release age for dependencies](https://www.prototemplate.com/docs/engineering/dev-servers#a-minimum-release-age-for-dependencies) |
| "Can't resolve 'gt-next/link'" after a relink | Restart the dev server that ran during it | [Dev servers and builds: a minimum release age for dependencies](https://www.prototemplate.com/docs/engineering/dev-servers#a-minimum-release-age-for-dependencies) |
## Gates and tooling [#gates-and-tooling]
| Symptom | Fix | Explained in |
| ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| A failing build reached main through `pnpm build 2>&1 \| tail -2 && git push` | Capture output to a file and chain on the real exit status with `&&` | [Agents on one machine: exit-status gates](https://www.prototemplate.com/docs/handbook/shared-machine#exit-status-gates) |
| `next build` passes with type errors | It never type-checks here; run `pnpm exec tsc --noEmit` as its own gate | [Gates: the type check](https://www.prototemplate.com/docs/gates#the-type-check) |
| `tsc` reports errors in `.next/dev/types` that no change touched | Run the type check in the scratch worktree that runs the build | [Gates: the type check](https://www.prototemplate.com/docs/gates#the-type-check) |
| `pnpm lint:lines:shell` fails on pages that are correct | Run browser gates one at a time, then rerun the failing one alone | [Gates: browser gates run one at a time](https://www.prototemplate.com/docs/gates#browser-gates-run-one-at-a-time) |
| The line audit exits 2 on its first route | Load the route by hand; restart the server only when your session owns it | [Gates: before trusting a red browser gate](https://www.prototemplate.com/docs/gates#before-trusting-a-red-browser-gate) |
| A lint exits clean under `--report` | Read the findings; `--report` drops exits 1 and 2 | [Gates: exit codes](https://www.prototemplate.com/docs/gates#exit-codes) |
| A new violation passes its ratchet | Lower the baseline in the cleanup commit and read the JSON diff | [Gates: ratchets](https://www.prototemplate.com/docs/gates#ratchets) |
| A missing page or a list of URLs audits clean | A status of 400 or more and a URL with whitespace exit 2; pass lists as arrays | [Lines and seams: the line auditor's thresholds](https://www.prototemplate.com/docs/craft/lines#the-line-auditors-thresholds) |
| Every browser gate breaks at once after a generator change | Keep the single quotes and field names the route list's regexes read | [Scripts: first slugs read by regex](https://www.prototemplate.com/docs/scripts#first-slugs-read-by-regex) |
| A lint at rest misses the search dialog and the scroll thumb | Open the dialog and hover the list before collecting | [Proving a visual change: states that mount on demand](https://www.prototemplate.com/docs/engineering/verification#states-that-mount-on-demand) |
| `pnpm doctor` runs something other than the setup check | Write `pnpm run doctor`; the bare form is pnpm's own command | [Get started: run the site](https://www.prototemplate.com/docs/get-started#run-the-site) |
| A skill install replaces a project's own skill with no report | The installer refuses foreign entries; check a new slug against every skills folder | [Skills: slug collisions](https://www.prototemplate.com/docs/skills#slug-collisions) |
## Builds and deploys [#builds-and-deploys]
| Symptom | Fix | Explained in |
| ------------------------------------------------------------ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Docs HTML grows from 245KB to 731KB | Revert `experimental.inlineCss`, which embeds the entry CSS twice | [Docs site traps: inline CSS, built and reverted](https://www.prototemplate.com/docs/engineering/docs-traps#inline-css-built-and-reverted) |
| The build worker is killed partway through prerendering | Pin `next` 16.2.12 | [Docs site traps: prerender memory on Next.js 16.3](https://www.prototemplate.com/docs/engineering/docs-traps#prerender-memory-on-nextjs-163) |
| Every deploy fails with `TS6306` on a referenced package | Reference only the packages the app imports | [Dev servers and builds: filtered installs and project references](https://www.prototemplate.com/docs/engineering/dev-servers#filtered-installs-and-project-references) |
| CI fails on content a submodule never checked out | Guard the read itself and degrade the feature | [Dev servers and builds: CI without the content submodule](https://www.prototemplate.com/docs/engineering/dev-servers#ci-without-the-content-submodule) |
| A live count renders on localhost and is empty in production | A static minimum label and a cached same-origin route for the value | [Canvas and WebGL engines: static pages with live values](https://www.prototemplate.com/docs/engineering/engines#static-pages-with-live-values) |
| A merged change does not show on the site | Read the `dpl_` stamp on the production host against the newest Ready build | [Proving a visual change: whether it is live](https://www.prototemplate.com/docs/engineering/verification#whether-it-is-live) |
| Builds fail at random in the Google font loader | Self-host the faces | [Proving a visual change: whether it is live](https://www.prototemplate.com/docs/engineering/verification#whether-it-is-live) |
| A push that compiles cleanly fails its hosted build | Keep request-scoped server calls inside the server function's handler | [Reviewing with Kevin: ship states](https://www.prototemplate.com/docs/handbook/review#ship-states) |
## SEO and agent files [#seo-and-agent-files]
| Symptom | Fix | Explained in |
| --------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Every page names the home page as its canonical | Write each route's whole head with `seoRoute()`; the root layout sets no canonical | [The SEO system: the lint](https://www.prototemplate.com/docs/seo#the-lint) |
| A route's partial `openGraph` drops the parent's fields | `seoRoute()` writes every field every time | [The SEO system: what one call writes](https://www.prototemplate.com/docs/seo#what-one-call-writes) |
| A Markdown twin answers 200 locally and 500 in production | Prerender every twin with `dynamicParams = false` | [Docs site traps: Markdown twins in production](https://www.prototemplate.com/docs/engineering/docs-traps#markdown-twins-in-production) |
| A `.md` URL never reaches the middleware | Put the twin rules in `next.config.ts` rewrites or the route | [The SEO system: why the twins are prerendered](https://www.prototemplate.com/docs/seo#why-the-twins-are-prerendered) |
| Agent-readability checkers find no links in a closed menu | A machine-only `sr-only` anchor in the server-rendered body | [The SEO system: why the twins are prerendered](https://www.prototemplate.com/docs/seo#why-the-twins-are-prerendered) |
| A disallowed URL is still indexed | Put the policy in `noindex` and leave robots.txt open | [The SEO system: the policy](https://www.prototemplate.com/docs/seo#the-policy) |
## Docs adapters [#docs-adapters]
| Symptom | Fix | Explained in |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| A click on a docs folder paints the layout with no article for about 280ms | Link to leaf pages; redirect folders in `next.config.ts` | [Docs site traps: links that point at leaf pages](https://www.prototemplate.com/docs/engineering/docs-traps#links-that-point-at-leaf-pages) |
| The sidebar's rail and current-row tint pop in at hydration | Show only the row tint before `data-sb-ready` | [Docs site traps: marks that exist at first paint](https://www.prototemplate.com/docs/engineering/docs-traps#marks-that-exist-at-first-paint) |
| The sidebar's rail runs past the remaining rows while a folder folds | Read whether a folder is open from its collapsible | [Docs site traps: the sidebar after fumadocs 16.16](https://www.prototemplate.com/docs/engineering/docs-traps#the-sidebar-after-fumadocs-1616) |
| The pill and thumb stay on a row that is folding away | Treat an active link inside a closed collapsible as not current | [Docs site traps: the sidebar after fumadocs 16.16](https://www.prototemplate.com/docs/engineering/docs-traps#the-sidebar-after-fumadocs-1616) |
| The sidebar list jumps when a folder reopens | Replace the viewport's `scroll()` and write `scrollTop` | [Docs site traps: the sidebar after fumadocs 16.16](https://www.prototemplate.com/docs/engineering/docs-traps#the-sidebar-after-fumadocs-1616) |
| The sidebar list scrolls when a folder opens near its end | `overflow-anchor: none` on the viewport | [Docs site traps: the sidebar after fumadocs 16.16](https://www.prototemplate.com/docs/engineering/docs-traps#the-sidebar-after-fumadocs-1616) |
| The sticky sidebar lifts at the end of the page | `margin-bottom: -1px` on its grid column | [Docs site traps: the sidebar after fumadocs 16.16](https://www.prototemplate.com/docs/engineering/docs-traps#the-sidebar-after-fumadocs-1616) |
| Two builds of one page ship different code colours | `tokenizeTimeLimit: 0` wherever Shiki runs | [Docs site traps: code highlighting across builds](https://www.prototemplate.com/docs/engineering/docs-traps#code-highlighting-across-builds) |
| An MDX component renders with its props undefined and no build error | Components that take string attributes and child elements | [Docs site traps: MDX that drops props](https://www.prototemplate.com/docs/engineering/docs-traps#mdx-that-drops-props) |
| Every docs element computes `font-feature-settings: normal` | Type the docs root as a class in the token base rules | [Docs site traps: features that compute normal](https://www.prototemplate.com/docs/engineering/docs-traps#features-that-compute-normal) |
| A token set in the docs sheet's `@theme` reaches other routes | Scope docs rules to docs-only ids or `:root:has(#nd-notebook-layout)` | [Docs site traps: features that compute normal](https://www.prototemplate.com/docs/engineering/docs-traps#features-that-compute-normal) |
| The docs title renders at 28px, off the display ladder | Put the title, lead and prose on the ladder in `docs.css` | [Docs site traps: what fumadocs leaves for the lints](https://www.prototemplate.com/docs/engineering/docs-traps#what-fumadocs-leaves-for-the-lints) |
| Docs headings render at 600 and 700 | One weight cap at 500 in `docs.css` | [Use these docs as a template: the adapters](https://www.prototemplate.com/docs/template#the-adapters) |
| fumadocs' dark mode ignores `html[data-theme]` | `theme={{ enabled: false }}` and a `dark` variant on `:root[data-theme='dark']` | [Use these docs as a template: the adapters](https://www.prototemplate.com/docs/template#the-adapters) |
| Tailwind's theme layer resets the font tokens for the whole document | Point `--font-sans` and `--font-mono` at the site's type tokens in `@theme` | [Use these docs as a template: the adapters](https://www.prototemplate.com/docs/template#the-adapters) |
| A prose override restyles the table of contents | Scope it to `#nd-page .prose` | [Docs site traps: markup that hides from a lint](https://www.prototemplate.com/docs/engineering/docs-traps#markup-that-hides-from-a-lint) |
| The search dialog and the phone drawer keep shadows and blur | Name the portaled dialog, its overlay and the drawer in the flat rule | [Interface details: shadows and blur from a component library](https://www.prototemplate.com/docs/craft/interface-details#shadows-and-blur-from-a-component-library) |
| A script looks for `/docs/(internals)/gates` | Drop every `(name)` segment when a path becomes a route | [Use these docs as a template: adding a page](https://www.prototemplate.com/docs/template#adding-a-page) |
| A plate appears in the Markdown twin as a bare tag | A sentence beside every plate says what it shows | [Use these docs as a template: adding a page](https://www.prototemplate.com/docs/template#adding-a-page) |
## CSS and Tailwind [#css-and-tailwind]
| Symptom | Fix | Explained in |
| -------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `font-semibold`, `tracking-*` and `mt-6` do nothing on headings | Metrics in the section's own stylesheet, gaps on the parent | [Docs site traps: unlayered rules and layered utilities](https://www.prototemplate.com/docs/engineering/docs-traps#unlayered-rules-and-layered-utilities) |
| One ID in a list of root classes overrides component rules site-wide | Join an `:is()` list as a class | [Docs site traps: specificity of an is() list](https://www.prototemplate.com/docs/engineering/docs-traps#specificity-of-an-is-list) |
| `text-sm` beats `.prose` on a table-of-contents row | Scope prose rules under `#nd-page`, which breaks the tie with the utilities layer | [Docs site traps: the typography plugin in the utilities layer](https://www.prototemplate.com/docs/engineering/docs-traps#the-typography-plugin-in-the-utilities-layer) |
| A corner lint reports 33,554,400px | `rounded-full` is `calc(infinity * 1px)`; a square box takes `50%` | [Docs site traps: the full round corner](https://www.prototemplate.com/docs/engineering/docs-traps#the-full-round-corner) |
| A token read only by inline styles is missing from the built CSS | Declare it in `@theme static` | [Docs site traps: Tailwind 4 build traps](https://www.prototemplate.com/docs/engineering/docs-traps#tailwind-4-build-traps) |
| The CSS build breaks after an edit to a comment | Fix the bracketed utility in the comment, then `rm -rf .next` | [Docs site traps: Tailwind 4 build traps](https://www.prototemplate.com/docs/engineering/docs-traps#tailwind-4-build-traps) |
| Classes added to a workspace package never compile | `touch` the app's `globals.css` | [Docs site traps: Tailwind 4 build traps](https://www.prototemplate.com/docs/engineering/docs-traps#tailwind-4-build-traps) |
| `text-[var(--x)]` becomes a colour | `text-[length:var(--x)]` | [Docs site traps: Tailwind 4 build traps](https://www.prototemplate.com/docs/engineering/docs-traps#tailwind-4-build-traps) |
| A rule removed with `border-image: none` still paints | `border-image-source: none` | [Lines and seams: rules that run the full width](https://www.prototemplate.com/docs/craft/lines#rules-that-run-the-full-width) |
| A hover-scale reset in CSS does nothing | Reset the scale in the markup, because Lightning CSS folds `scale` into `transform` | [Lines and seams: rules that run the full width](https://www.prototemplate.com/docs/craft/lines#rules-that-run-the-full-width) |
| Margin utilities do nothing on a ported page | Put margins in the port's compatibility sheet | [The design lab and the directions: the port recipe](https://www.prototemplate.com/docs/directions#the-port-recipe) |
## WebGL and canvas [#webgl-and-canvas]
| Symptom | Fix | Explained in |
| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| A field draws black after a dozen client-side navigations, with no error | One engine and one context per engine module for the session | [Canvas and WebGL engines: the context budget](https://www.prototemplate.com/docs/engineering/engines#the-context-budget) |
| Fields go black while a probe counts contexts | Wrap `getContext` before the page's scripts run | [Canvas and WebGL engines: the context budget](https://www.prototemplate.com/docs/engineering/engines#the-context-budget) |
| A mark leaks one WebGL context per mount | Delete its buffers and shaders, then `loseContext()`, on unmount | [The component library: the numbers behind it](https://www.prototemplate.com/docs/components#the-numbers-behind-it) |
| Two fields of different sizes keep the main thread busy | Grow the shared canvas to the largest field and blit from its bottom-left corner | [Canvas and WebGL engines: a shared canvas that only grows](https://www.prototemplate.com/docs/engineering/engines#a-shared-canvas-that-only-grows) |
| The glyph rain lags on phones, worst on WebKit | Snapshot the readback atlas into an `ImageBitmap` for the blits | [Canvas and WebGL engines: readback canvases and the blit path](https://www.prototemplate.com/docs/engineering/engines#readback-canvases-and-the-blit-path) |
| A canvas goes soft after browser zoom | Watch the resolution media query and re-arm it on every change | [Canvas and WebGL engines: browser zoom](https://www.prototemplate.com/docs/engineering/engines#browser-zoom) |
| A wide window on weak hardware gets the heaviest quality tier | Pick the tier from measured frame time | [Canvas and WebGL engines: quality from measured frame time](https://www.prototemplate.com/docs/engineering/engines#quality-from-measured-frame-time) |
| Only a shader's fallback renders after an edit | No newline before `#version 300 es`; check that the shader draws | [Canvas and WebGL engines: shader source weight](https://www.prototemplate.com/docs/engineering/engines#shader-source-weight) |
| A wall of frozen previews still lags | Stills on every card, the live page only under the pointer | [Canvas and WebGL engines: galleries of live previews](https://www.prototemplate.com/docs/engineering/engines#galleries-of-live-previews) |
| A frozen preview keeps animating | Move the loop to `requestAnimationFrame`, the only thing the gate holds | [Canvas and WebGL engines: galleries of live previews](https://www.prototemplate.com/docs/engineering/engines#galleries-of-live-previews) |
| A duplicate canvas stays in the DOM in development | Remove every node an effect creates, and check for exactly one canvas | [Canvas and WebGL engines: strict mode and effects](https://www.prototemplate.com/docs/engineering/engines#strict-mode-and-effects) |
| Every listener is dead in development | Defer the mount effect's cleanup by one task, as `useMountEffect` does | [Pages and the viewer shell: effects under strict mode](https://www.prototemplate.com/docs/pages#effects-under-strict-mode) |
| Dragging a seam over a large figure runs at 5 fps | Keep the subtree under a moving inherited variable small, such as one canvas | [Canvas and WebGL engines: inherited properties on a moving subtree](https://www.prototemplate.com/docs/engineering/engines#inherited-properties-on-a-moving-subtree) |
| A canvas shows its stretched 300 by 150 store for a frame | Paint one frame before any `requestAnimationFrame` | [Dither and the studio field: engine copies and canvas traps](https://www.prototemplate.com/docs/components/dither#engine-copies-and-canvas-traps) |
| A cloned canvas is blank | Redraw clones from the theme tokens, sized from `clientWidth` | [Dither and the studio field: engine copies and canvas traps](https://www.prototemplate.com/docs/components/dither#engine-copies-and-canvas-traps) |
## Dither [#dither]
| Symptom | Fix | Explained in |
| ------------------------------------------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| A dithered transition flashes on its first frame | Anchor the tile: `phase.y = n % 8` for a canvas n cells lower | [Dither in practice: transitions on one grid](https://www.prototemplate.com/docs/craft/dither#transitions-on-one-grid) |
| Quick steps flash back to a picture that has gone | Start each new mix from the frame on screen | [Dither in practice: transitions on one grid](https://www.prototemplate.com/docs/craft/dither#transitions-on-one-grid) |
| A step through a new level becomes a cut | Decode all 65 mask levels before the first step | [Dither in practice: transitions on one grid](https://www.prototemplate.com/docs/craft/dither#transitions-on-one-grid) |
| A picture's edge fades in grey cells | A hard cut at the plate's edge, then a dissolve by tone | [Dither in practice: transitions on one grid](https://www.prototemplate.com/docs/craft/dither#transitions-on-one-grid) |
| A field arrives as a fade | Raise its tone from 0 | [Dither in practice: transitions on one grid](https://www.prototemplate.com/docs/craft/dither#transitions-on-one-grid) |
| A dithered pattern on a moving sprite flickers | Put dither on fields and stills; a moving sprite carries solid ink | [Dither and the studio field: dither on a moving sprite](https://www.prototemplate.com/docs/components/dither#dither-on-a-moving-sprite) |
| Dither dots alias into noise at 1x | Draw at 2x the stage height with `image-rendering: pixelated` | [Dither in practice: cells are screen pixels](https://www.prototemplate.com/docs/craft/dither#cells-are-screen-pixels) |
| A dithered photograph loses its inscriptions | No blur; the cutter solves the black and white points | [Dither in practice: the picture standard](https://www.prototemplate.com/docs/craft/dither#the-picture-standard) |
| The picture cutter refuses a source file | Its bytes changed upstream; the recorded sha256 pins the original | [Dither in practice: the picture standard](https://www.prototemplate.com/docs/craft/dither#the-picture-standard) |
| The hero's field has no effect in the light theme | A filter, because a screen blend is inert in an isolated host | [Dither in practice: material strength](https://www.prototemplate.com/docs/craft/dither#material-strength) |
| A placed picture reads as an empty window with a sliver | Anchor it to a share of the field's ramp | [Dither in practice: placing a picture on a field](https://www.prototemplate.com/docs/craft/dither#placing-a-picture-on-a-field) |
## Lines and seams [#lines-and-seams]
| Symptom | Fix | Explained in |
| --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| A seam reads at the two-stroke grey | Check the neighbouring pixels: a glow raises them and a double leaves them at the ground | [Lines and seams: reading a seam by its grey](https://www.prototemplate.com/docs/craft/lines#reading-a-seam-by-its-grey) |
| A bordered element's edge composites darker than every other hairline | `background-clip: padding-box` | [Lines and seams: self-stacks and stacked grounds](https://www.prototemplate.com/docs/craft/lines#self-stacks-and-stacked-grounds) |
| A new rail doubles every hairline by 2px a side | Seat it on the existing pages' edges | [Lines and seams: rails drawn as borders](https://www.prototemplate.com/docs/craft/lines#rails-drawn-as-borders) |
| Rules keep their author colour in forced colours | The hairline tokens become `CanvasText` | [Lines and seams: rules that run the full width](https://www.prototemplate.com/docs/craft/lines#rules-that-run-the-full-width) |
| A grid of links draws stacked lines | Only the first link of each row draws the rule | [Lines and seams: rules that run the full width](https://www.prototemplate.com/docs/craft/lines#rules-that-run-the-full-width) |
| Cards paint over the rule below them after a reveal | Set `will-change` only for the tween and clear what the tween set | [Lines and seams: stacking contexts over seams](https://www.prototemplate.com/docs/craft/lines#stacking-contexts-over-seams) |
| Sticky figures stop sticking | `overflow-x: clip` on the root, which clips without making a scroll container | [Lines and seams: registration crosses and horizontal clipping](https://www.prototemplate.com/docs/craft/lines#registration-crosses-and-horizontal-clipping) |
## SVG lines [#svg-lines]
| Symptom | Fix | Explained in |
| ----------------------------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| A dash meant as a fraction of a path draws as a short fleck | Drop `pathLength` under `non-scaling-stroke` and dash in user units | [SVG lines in motion: pathLength under a non-scaling stroke](https://www.prototemplate.com/docs/craft/svg-motion#pathlength-under-a-non-scaling-stroke) |
| One travelling pulse shows up as several | Move a short `` segment by translate | [SVG lines in motion: a travelling dash that tiles](https://www.prototemplate.com/docs/craft/svg-motion#a-travelling-dash-that-tiles) |
| An arc parked on a closed shape leaves part of it unpainted | Start the path where the arc starts | [SVG lines in motion: dashes on a closed path](https://www.prototemplate.com/docs/craft/svg-motion#dashes-on-a-closed-path) |
| A draw-on runs backwards | Read the first point of `d`, then flip the parked sign | [SVG lines in motion: the sign of the parked offset](https://www.prototemplate.com/docs/craft/svg-motion#the-sign-of-the-parked-offset) |
| A fleck stays at the end of a line that should be empty | `'100 200'` parked at 101 or -101 | [SVG lines in motion: a fleck at the end of the path](https://www.prototemplate.com/docs/craft/svg-motion#a-fleck-at-the-end-of-the-path) |
| A dash freezes for about four frames, then jumps | `autoRound: false`, and `pathLength` 1000 on a looping dash | [SVG lines in motion: rounding, cached paths and empty paths](https://www.prototemplate.com/docs/craft/svg-motion#rounding-cached-paths-and-empty-paths) |
| A rerun of an effect traces an empty path | Store the authored `d` once and restore it before measuring | [SVG lines in motion: rounding, cached paths and empty paths](https://www.prototemplate.com/docs/craft/svg-motion#rounding-cached-paths-and-empty-paths) |
| Curves warp and text distorts in a stretched strip | Straight taps with one elbow, labels in HTML | [SVG lines in motion: drawing under a stretched viewBox](https://www.prototemplate.com/docs/craft/svg-motion#drawing-under-a-stretched-viewbox) |
| The GT monogram renders 214 units too high | Reference the symbol from an svg with no viewBox | [SVG lines in motion: symbols and masks](https://www.prototemplate.com/docs/craft/svg-motion#symbols-and-masks) |
| A mask lands away from its shape | Write the mask in the masked shape's coordinates | [SVG lines in motion: symbols and masks](https://www.prototemplate.com/docs/craft/svg-motion#symbols-and-masks) |
| A second copy of a figure draws the first one's mask | A unique id prefix per figure | [SVG lines in motion: symbols and masks](https://www.prototemplate.com/docs/craft/svg-motion#symbols-and-masks) |
| A mark seated on an iso face lies flatter than the face | `plane()` in place of `scale(1 0.5) rotate(45)` | [Isometric drawings: numbers and traps](https://www.prototemplate.com/docs/components/iso#numbers-and-traps) |
## GSAP [#gsap]
| Symptom | Fix | Explained in |
| --------------------------------------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `window.gsap` is undefined in the page | Read state from the page, such as a computed CSS-variable dial | [SVG lines in motion: GSAP from outside the page](https://www.prototemplate.com/docs/craft/svg-motion#gsap-from-outside-the-page) |
| Overriding `requestAnimationFrame` does not freeze an animation | Poll the dial and capture about 100ms early | [SVG lines in motion: GSAP from outside the page](https://www.prototemplate.com/docs/craft/svg-motion#gsap-from-outside-the-page) |
| A harness that seeks a timeline gets stale frames | `tl.seek(t, false)` so `onUpdate` runs | [SVG lines in motion: GSAP from outside the page](https://www.prototemplate.com/docs/craft/svg-motion#gsap-from-outside-the-page) |
| A shimmer's sweep lands about 180 units off its mark | Pre-rotated windows moved by a pure translate | [SVG lines in motion: GSAP from outside the page](https://www.prototemplate.com/docs/craft/svg-motion#gsap-from-outside-the-page) |
| A CSS transition never runs on the first frame | A keyframe animation | [SVG lines in motion: transitions at first paint](https://www.prototemplate.com/docs/craft/svg-motion#transitions-at-first-paint) |
| Glyphs jump across the screen after the fonts load | Measure again and never resample | [SVG lines in motion: moving type](https://www.prototemplate.com/docs/craft/svg-motion#moving-type) |
## Lottie on canvas [#lottie-on-canvas]
| Symptom | Fix | Explained in |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| A translated animation draws nothing after one text layer | An empty glyph entry for every drawable character, `\r` and `\u0003` | [Lottie on canvas: a missing glyph stops the frame](https://www.prototemplate.com/docs/engineering/lottie#a-missing-glyph-stops-the-frame) |
| Content under a track matte stays clipped after the canvas grows | Resize every matte buffer after each resize and redraw | [Lottie on canvas: track-matte buffers are sized once](https://www.prototemplate.com/docs/engineering/lottie#track-matte-buffers-are-sized-once) |
| `drawImage` throws from a canvas parked at 0 by 0 | Park a hidden player at `resize(1, 1)` | [Lottie on canvas: track-matte buffers are sized once](https://www.prototemplate.com/docs/engineering/lottie#track-matte-buffers-are-sized-once) |
| A playing animation redraws 120 times a second | `setSubframe(false)`, and per-frame work only when the frame changes | [Lottie on canvas: subframes redraw at display rate](https://www.prototemplate.com/docs/engineering/lottie#subframes-redraw-at-display-rate) |
| A hidden layer builds its canvas at the wrong size | A `visibility: hidden` class in place of the `hidden` attribute | [Lottie on canvas: hidden layers that keep their box](https://www.prototemplate.com/docs/engineering/lottie#hidden-layers-that-keep-their-box) |
| Two players meant to match stay a frame apart | One leader; followers stay paused and take its raw frame | [Lottie on canvas: two players on one clock drift](https://www.prototemplate.com/docs/engineering/lottie#two-players-on-one-clock-drift) |
| The animation jumps at every loop | `loop: false`, a copy of the last frame, then a dither back to the start | [Lottie on canvas: the loop is a cut](https://www.prototemplate.com/docs/engineering/lottie#the-loop-is-a-cut) |
| Reduced motion shows an empty frame | A poster frame from the longest stretch with text on screen | [Lottie on canvas: a poster frame for reduced motion](https://www.prototemplate.com/docs/engineering/lottie#a-poster-frame-for-reduced-motion) |
| A lower canvas resolution barely speeds up text | Cut the text drawn; the cost is replaying glyph paths in script | [Lottie on canvas: canvas text costs JavaScript](https://www.prototemplate.com/docs/engineering/lottie#canvas-text-costs-javascript) |
## Type [#type]
| Symptom | Fix | Explained in |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| A page renders desktop Inter 3 when its font file fails | Bind the face to an identifier no installed font carries | [Type: the binding](https://www.prototemplate.com/docs/craft/type#the-binding) |
| A client-side navigation swaps one page's face for another's | A unique identifier for every `localFont` call | [Type: the binding](https://www.prototemplate.com/docs/craft/type#the-binding) |
| A subset renders a shade off the full file | Keep glyph names when subsetting | [Type: subsets and glyph names](https://www.prototemplate.com/docs/craft/type#subsets-and-glyph-names) |
| A tracked heading loses its `->` arrow and its centred colons | Name `calt` in the feature list | [Type: contextual alternates under letter-spacing](https://www.prototemplate.com/docs/craft/type#contextual-alternates-under-letter-spacing) |
| The brand deck's headings lose their contextual alternates | The same `calt`, which waits for the deck's owner | [The brand deck: the sheet and the grammar](https://www.prototemplate.com/docs/deck#the-sheet-and-the-grammar) |
| Optical sizing stops for a whole subtree | Never write `font-variation-settings` or `font-optical-sizing: none` | [Type: optical size](https://www.prototemplate.com/docs/craft/type#optical-size) |
| A measure of `62ch` holds 84 characters a line | Set measures in em | [Type: measure](https://www.prototemplate.com/docs/craft/type#measure) |
| Hebrew and Arabic render in Arial | A script stack with no Inter variable in front | [Type: scripts and the Arial fallback](https://www.prototemplate.com/docs/craft/type#scripts-and-the-arial-fallback) |
| Numerals in a weight 500 block render at 700 | A base rule sets `b, strong` to 500 | [Type: weight and stack traps](https://www.prototemplate.com/docs/craft/type#weight-and-stack-traps) |
| A second Inter appears only while the page loads | Stacks read `var(--font-inter)` and name no bare Inter | [Type: weight and stack traps](https://www.prototemplate.com/docs/craft/type#weight-and-stack-traps) |
| A label draws a different `a` from the row beside it | Labels read the text token | [Type: weight and stack traps](https://www.prototemplate.com/docs/craft/type#weight-and-stack-traps) |
| A heading sits 1.85px above its label from 1348px wide | A trim inside the media query where the rounding step occurs | [Type: seating display type](https://www.prototemplate.com/docs/craft/type#seating-display-type) |
| A heading painted on a canvas comes out 12px short | A `FontFace` built with `featureSettings` | [Type: canvas text](https://www.prototemplate.com/docs/craft/type#canvas-text) |
| WebKit canvas text changes its optical size | Copies of the font pinned to one opsz and `text-rendering: auto` | [Type: canvas text](https://www.prototemplate.com/docs/craft/type#canvas-text) |
| A face meant for one page is preloaded on every page | `preload: false` and a family name only that route's CSS names | [Type: preloads that leak across routes](https://www.prototemplate.com/docs/craft/type#preloads-that-leak-across-routes) |
| The theme button's glyph renders in a system face | Read the face with `CSS.getPlatformFontsForNode`, since the lint's range misses it | [Type: glyphs outside the subsets](https://www.prototemplate.com/docs/craft/type#glyphs-outside-the-subsets) |
## Interface [#interface]
| Symptom | Fix | Explained in |
| ------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| Two buttons with one CSS gap show different gaps beside their icons | Match the measured visible gaps | [Interface details: gaps beside a glyph](https://www.prototemplate.com/docs/craft/interface-details#gaps-beside-a-glyph) |
| A row of buttons moves when one label reads Copied | Size the face from the idle label through a grid sizer | [Interface details: gaps beside a glyph](https://www.prototemplate.com/docs/craft/interface-details#gaps-beside-a-glyph) |
| A copy button fails in an agent app's browser pane | Test it in Chrome; the pane blocks clipboard writes | [Interface details: the copy control](https://www.prototemplate.com/docs/craft/interface-details#the-copy-control) |
| The foot of a page jumps when a control mounts at hydration | Reserve the control's height in the server markup | [Interface details: layout shifts](https://www.prototemplate.com/docs/craft/interface-details#layout-shifts) |
| Controls move when the language changes | Anchor the language left and the theme toggle right | [Interface details: layout shifts](https://www.prototemplate.com/docs/craft/interface-details#layout-shifts) |
| A sign-in widget draws a white card on a dark page | Pass the resolved theme and key the widget on it | [Interface details: third-party widgets and the site's theme](https://www.prototemplate.com/docs/craft/interface-details#third-party-widgets-and-the-sites-theme) |
| Captions fail contrast in the light theme | `#6e737c` or ink-2 in place of titanium | [Interface details: contrast](https://www.prototemplate.com/docs/craft/interface-details#contrast) |
| A double click moves a carousel two slides | Drop commands within 350ms of the last one | [Interface details: carousels and galleries](https://www.prototemplate.com/docs/craft/interface-details#carousels-and-galleries) |
| An element that moves on hover flickers under the pointer | A still hit area with the moving drawing inside it | [Interface details: a still hit area for a moving target](https://www.prototemplate.com/docs/craft/interface-details#a-still-hit-area-for-a-moving-target) |
## Verification [#verification]
| Symptom | Fix | Explained in |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Shader and dither canvases come back blank in an embedded browser pane | Take pixels with Playwright in Chrome for Testing | [Proving a visual change: the in-app browser pane](https://www.prototemplate.com/docs/engineering/verification#the-in-app-browser-pane) |
| A capture comes out in the wrong theme | Seed the theme before load and assert it took | [Proving a visual change: the in-app browser pane](https://www.prototemplate.com/docs/engineering/verification#the-in-app-browser-pane) |
| An edit trims padding where the gap came from a margin | Quote the box model before editing | [Proving a visual change: the spot before the edit](https://www.prototemplate.com/docs/engineering/verification#the-spot-before-the-edit) |
| A scroll story locks in a different place scrolling up | Run the whole stress matrix | [Proving a visual change: the stress matrix](https://www.prototemplate.com/docs/engineering/verification#the-stress-matrix) |
| A fix shown with a scripted selection proves nothing about a drag | Perform the real gesture and read the result back | [Proving a visual change: real gestures](https://www.prototemplate.com/docs/engineering/verification#real-gestures) |
| A harness request leaves its origin | Build every URL as `new URL(ORIGIN + path)` | [Proving a visual change: real gestures](https://www.prototemplate.com/docs/engineering/verification#real-gestures) |
| A layout breaks in Safari alone | Check one invariant in Chromium and WebKit | [Proving a visual change: WebKit](https://www.prototemplate.com/docs/engineering/verification#webkit) |
| A route list read from a running dev server is truncated | Take the routes from the source or the sitemap | [Proving a visual change: parity across an upgrade](https://www.prototemplate.com/docs/engineering/verification#parity-across-an-upgrade) |
| Timings read slow and a dev-server Lighthouse run scores 0.65 | Record the load average, and run a production build in a clean profile | [Performance without visual loss: measure honestly](https://www.prototemplate.com/docs/engineering/performance#measure-honestly) |
| A lab score does not answer a complaint about a slow first paint | Read field data | [Performance without visual loss: field data against lab data](https://www.prototemplate.com/docs/engineering/performance#field-data-against-lab-data) |
| A structural audit passes every item while the visual bar fails | Report each kind of check on its own line | [Agent workflows: kinds of check](https://www.prototemplate.com/docs/handbook/workflows#kinds-of-check) |
## Films [#films]
| Symptom | Fix | Explained in |
| ------------------------------------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Two renders of one film differ | Compare every pair by `framemd5`; large animated type renders on the software path | [Films: compare every render pair](https://www.prototemplate.com/docs/craft/films#compare-every-render-pair) |
| One render loses its dither field and reports success | Guard every cached image read with `img.complete && img.naturalWidth > 0` | [Films: images and the first timeline update](https://www.prototemplate.com/docs/craft/films#images-and-the-first-timeline-update) |
| The render log reads "Fetched 11 font face(s)" | Set type through the kit's `var(--font)` | [Films: fonts in a composition](https://www.prototemplate.com/docs/craft/films#fonts-in-a-composition) |
| A thin blue stroke turns slate grey in the encoded file | Start it on an even pixel | [Films: thin coloured strokes in H.264](https://www.prototemplate.com/docs/craft/films#thin-coloured-strokes-in-h264) |
| 1px routes vanish at phone size | 2.5px routes over a keyline, checked at 640 by 360 | [Films: thin lines over a dithered ground](https://www.prototemplate.com/docs/craft/films#thin-lines-over-a-dithered-ground) |
| A louder mix comes out quieter | Put peak control in the ffmpeg masters | [Films: the mix and its traps](https://www.prototemplate.com/docs/craft/films#the-mix-and-its-traps) |
| A gain ramp clicks | `aeval` for any gain curve | [Films: the mix and its traps](https://www.prototemplate.com/docs/craft/films#the-mix-and-its-traps) |
| The music bed pumps between lines | Hold the duck across gaps under about 1.2s | [Films: the mix and its traps](https://www.prototemplate.com/docs/craft/films#the-mix-and-its-traps) |
| A voice model ignores its speed setting | Inline pace tags | [Films: speech synthesis](https://www.prototemplate.com/docs/craft/films#speech-synthesis) |
| A still pulled with `-ss` comes out near black | Select the frame by index | [Films: frames, probes and disks](https://www.prototemplate.com/docs/craft/films#frames-probes-and-disks) |
| A render that looks fine in its log is an error page | Flag frames whose grey standard deviation is under about 20 | [Films: frames, probes and disks](https://www.prototemplate.com/docs/craft/films#frames-probes-and-disks) |
| `page.evaluate(() => tl.seek(t))` hangs | Return a number from `evaluate` | [Films: frames, probes and disks](https://www.prototemplate.com/docs/craft/films#frames-probes-and-disks) |
## Routing [#routing]
| Symptom | Fix | Explained in |
| ------------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| A locale prefix outside the roster answers 500 | A locale guard ahead of every rewrite | [Localized routing: middleware order](https://www.prototemplate.com/docs/engineering/i18n-routing#middleware-order) |
| Every old URL redirects to a 404 | Deploy a redirect only after the moved pages exist | [Localized routing: middleware order](https://www.prototemplate.com/docs/engineering/i18n-routing#middleware-order) |
| Links to `/sitemap.xml` and other root files answer 404 | A plain `` for root files | [Localized routing: links, routers and strings in gt-next](https://www.prototemplate.com/docs/engineering/i18n-routing#links-routers-and-strings-in-gt-next) |
| A programmatic navigation loses the locale | Push a path that already carries the locale | [Localized routing: links, routers and strings in gt-next](https://www.prototemplate.com/docs/engineering/i18n-routing#links-routers-and-strings-in-gt-next) |
| Strings render in English in every locale | `const gt = await getGT();` on its own line | [Localized routing: links, routers and strings in gt-next](https://www.prototemplate.com/docs/engineering/i18n-routing#links-routers-and-strings-in-gt-next) |
| The language menu breaks on default-locale pages | Map `usePathname()` back to the public path | [Localized routing: links, routers and strings in gt-next](https://www.prototemplate.com/docs/engineering/i18n-routing#links-routers-and-strings-in-gt-next) |
| A CLI setup command waits forever under an agent | `--no-interactive` and a flag for every answer | [Localized routing: a start prompt that must run unchanged](https://www.prototemplate.com/docs/engineering/i18n-routing#a-start-prompt-that-must-run-unchanged) |
## The shared machine [#the-shared-machine]
| Symptom | Fix | Explained in |
| ---------------------------------------------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| A `pkill -f` stops other sessions' servers, browsers and renders | Stop a process by the PID recorded when it started | [Agents on one machine: stopping a process](https://www.prototemplate.com/docs/handbook/shared-machine#stopping-a-process) |
| A kill by port closes a browser | `kill $(lsof -ti tcp: -sTCP:LISTEN)` | [Agents on one machine: stopping a process](https://www.prototemplate.com/docs/handbook/shared-machine#stopping-a-process) |
| Every later command reports "command not found" | Never name a zsh variable `path` | [Agents on one machine: shell traps in zsh](https://www.prototemplate.com/docs/handbook/shared-machine#shell-traps-in-zsh) |
| `"$B:apps/landing"` rewrites the string | Brace the name: `"${B}:apps/landing"` | [Agents on one machine: shell traps in zsh](https://www.prototemplate.com/docs/handbook/shared-machine#shell-traps-in-zsh) |
| A loop over an unquoted variable runs once | An array, an explicit list or `${=urls}` | [Agents on one machine: shell traps in zsh](https://www.prototemplate.com/docs/handbook/shared-machine#shell-traps-in-zsh) |
| A Python heredoc becomes a pushed commit message | Write each message to a file first, then `git commit -F` | [Agents on one machine: shell traps in zsh](https://www.prototemplate.com/docs/handbook/shared-machine#shell-traps-in-zsh) |
| `echo ====` stops a `&&` chain | Quote it | [Agents on one machine: shell traps in zsh](https://www.prototemplate.com/docs/handbook/shared-machine#shell-traps-in-zsh) |
| A grep over two folders greps nothing | A glob with no match aborts the line; use `find` or quote the pattern | [Agents on one machine: shell traps in zsh](https://www.prototemplate.com/docs/handbook/shared-machine#shell-traps-in-zsh) |
| A browser starts while the memory check said to wait | Chain on the check's own exit status with `&&` and no pipe | [Agents on one machine: exit-status gates](https://www.prototemplate.com/docs/handbook/shared-machine#exit-status-gates) |
| One `git grep` grows from 42.6 to 166GB | `-F` with a pattern file, `-I` and a thread count | [Agents on one machine: memory and disk](https://www.prototemplate.com/docs/handbook/shared-machine#memory-and-disk) |
| A reboot empties the sessions' scratch folders | Keep specs and helpers that must outlive the day in a repository | [Agents on one machine: memory and disk](https://www.prototemplate.com/docs/handbook/shared-machine#memory-and-disk) |
| Lane agents hang for hours on shell calls that never start | No `rm` in a lane, edits in separate calls, network calls under an alarm | [Agents on one machine: long commands](https://www.prototemplate.com/docs/handbook/shared-machine#long-commands) |
| A commit publishes another session's staged deletions | Commit with a pathspec | [Agents on one machine: one checkout and several sessions](https://www.prototemplate.com/docs/handbook/shared-machine#one-checkout-and-several-sessions) |
| A copy into the tree erases commits another session pushed | Fetch and read `HEAD..origin/main` before any copy or push | [Agents on one machine: one checkout and several sessions](https://www.prototemplate.com/docs/handbook/shared-machine#one-checkout-and-several-sessions) |
## Pull requests and workflows [#pull-requests-and-workflows]
| Symptom | Fix | Explained in |
| --------------------------------------------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| A pull request's checks are stale, cancelled or missing | Resolve the merge conflicts first | [Pull requests and CI: CI signals that mislead](https://www.prototemplate.com/docs/handbook/pull-requests#ci-signals-that-mislead) |
| The latest push shows a red e2e it did not cause | List the runs and find the first red one | [Pull requests and CI: CI signals that mislead](https://www.prototemplate.com/docs/handbook/pull-requests#ci-signals-that-mislead) |
| The build dies in "Running TypeScript" | Raise `--max-old-space-size` | [Pull requests and CI: CI signals that mislead](https://www.prototemplate.com/docs/handbook/pull-requests#ci-signals-that-mislead) |
| A bot's summary describes a diff that no longer exists | Compare its reviewed commit with the head before acting | [Pull requests and CI: review bots](https://www.prototemplate.com/docs/handbook/pull-requests#review-bots) |
| A force push erases a collaborator's commits | Fetch, then lease against the sha you expect | [Pull requests and CI: git on shared trees](https://www.prototemplate.com/docs/handbook/pull-requests#git-on-shared-trees) |
| A fast-forward overwrites ignored files without a warning | Copy the ignored originals aside first | [Pull requests and CI: git on shared trees](https://www.prototemplate.com/docs/handbook/pull-requests#git-on-shared-trees) |
| Commits meant for a pull request never reach it | Check the branch before each commit and compare the head with `HEAD` | [Pull requests and CI: git on shared trees](https://www.prototemplate.com/docs/handbook/pull-requests#git-on-shared-trees) |
| A lane builds nothing and verifies something unrelated | Open every lane prompt with the user's own words for that lane | [Agent workflows: lane prompts](https://www.prototemplate.com/docs/handbook/workflows#lane-prompts) |
| A resumed workflow pays for its finished agents again | Resume by run id with byte-identical arguments | [Agent workflows: resuming a run](https://www.prototemplate.com/docs/handbook/workflows#resuming-a-run) |
## Sources [#sources]
* The pages each row links to, read on 2026-10-21: the Craft and Engineering tabs of /docs, the Components and Internals pages with trap sections, and the handbook's documents on one machine, workflows, pull requests and review.
* The curated skills those pages cite: `gt-motion` (`references/traps.md`), `gt-performance` (`references/webgl-lifecycles.md`), `gt-website` (`references/docs.md`, `references/deploys.md`), `gt-local-dev`, `gt-verify`, `gt-films`, `gt-dither`, `gt-brand` (`references/type.md`), `gt-orchestration` and `gt-ship`.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Brand
> The identity canon: the name, the idea, the character and voice, the mark, color, type, language as material, and where the identity ships.
URL: https://www.prototemplate.com/docs/handbook/brand
General Translation's identity, laid out for anyone who has to build with
it, including our partners at basement studio. This document is the written
canon. The living version is the [`/brand`](https://www.prototemplate.com/docs/handbook/brand) page, and the visual
laws live in [`DESIGN.md`](https://www.prototemplate.com/docs/handbook/design).
***
## 1. The name [#1-the-name]
**General Translation** was chosen deliberately, in this order:
1. **Ambition.** Like General Motors or General Electric, the name says we
intend to be the trustworthy, technologically innovative number one in
the category, an enterprise in the old sense.
2. **Generality.** A reference to "artificial general intelligence": general
AI models outperform specific translation models because they understand
context and can be directed.
3. **Distinction.** Every other localization company seemed to begin with an
"L".
### The naming system [#the-naming-system]
| name | what it is |
| ------------------------------------------------------- | ------------------------------------------------------------------------------- |
| General Translation, Inc. | the company |
| GT | the short form, and the mark |
| `gt` | the open-source code library; you run `gt translate` |
| `gt-next`, `gt-react`, `gt-vue`, `gt-node`, `gt-python` | the framework-specific packages |
| Locadex | the AI agent product |
| generaltranslation.com | the domain (also held: gt.sh, generaltranslation.ai/.dev, locadex.com/.ai/.dev) |
| glyphfield.com | the companion tooling site (shader library, animation studio) |
## 2. The idea [#2-the-idea]
**Every product in every language.** Native-level speed and quality, from
day one. That's the whole thesis, executed insanely hard.
The positioning: **the Vercel of localization.** Two halves designed
together: open-source developer tools (the Next.js of the analogy: the
`gt` libraries) and closed-source infrastructure (the Vercel: context-aware
translation APIs, versioning, editing, integrations, agents) that is the
best-in-class way to use those tools. Because we build the entire stack,
we can promise what point solutions can't: consistent, high-quality
translation across a whole business, integrated in an afternoon.
Two registers, one family: the open source should feel community-owned;
the platform should feel enterprise-grade.
The values, which the visual identity must carry:
* **Engineering-first.** Built by people with deep technical roots, for the
world's best engineering teams.
* **Craft.** We care about the difference between drawn-once and drawn-twice
lines. That is literal: see the line law in `DESIGN.md`.
* **Infrastructure-grade.** Reliable, fast, secure. The brand should feel
like something an enterprise stands on, not an app it tries.
* **Cosmopolitan.** Urbane, sophisticated, connecting the world and its
languages. Language is our material, not just our market.
* **Hand-crafted.** The brand reads as made by people who care, not
assembled from a template.
## 3. The character [#3-the-character]
The brand carries itself like a **"fullstack director"**: it writes the
script and it pushes the camera. Creative and technically innovative,
never one without the other. On time, under budget, over-delivering,
always working with the best people, with a keen sense of the market and
for making things people love.
### Personality (working readings, from the completed system) [#personality-working-readings-from-the-completed-system]
| | position | |
| ------------ | -------------------------- | -------------------- |
| Classic | ●──── toward → | **Modern** |
| **Reserved** | ← toward ────● | Playful |
| **Minimal** | ← firmly | Expressive |
| **Clever** | ← leaning | Warm |
| **Rational** | ← firmly | Quirky |
| Understated | toward → | **Confident** |
| **Serious** | ← leaning | Witty |
| **Neutral** | ← leaning, a glint allowed | Slightly mischievous |
### Aesthetic (working readings) [#aesthetic-working-readings]
| | position | |
| -------------- | -------------------------------------------- | ----------- |
| **Clean** | texture only as ordered dither | Textured |
| Soft | → | **Sharp** |
| **Geometric** | ← firmly | Organic |
| **Light** | paper-first; dark mode is one ink surface | Dark |
| **Muted** | one spectral accent per page | Vibrant |
| **Flat** | depth from lines and material, never shadows | Dimensional |
| **Monochrome** | four absolute colors + one accent | Colorful |
| **Structured** | ← firmly | Playful |
| Warm | → | **Cool** |
| **Elegant** | ← | Fun |
These are read from the shipped system for basement to confirm or push.
### Voice [#voice]
Measured, declarative, precise, quietly confident. Every sentence is
complete and makes one claim. A caption states the mechanism: "A framed
cell has a 1px padding reveal that shows the ground underneath, so the
cell draws no border." Copy uses no exclamation marks, no hedging and no
marketing adjectives where a fact would do. Wit is allowed when it is
precise. Technical terms are used precisely and sparingly, then explained
plainly. The register sits closer to a well-written spec or a good
engineering blog than to marketing copy, and the copy is about the
product.
* Say: "Translations are generated at build time and deploy with the app."
* Not: "Supercharge your global growth with cutting-edge AI!"
## 4. The mark [#4-the-mark]
The GT monogram (`/brand/gt-logo-light.svg`, `gt-logo-dark.svg` +
transparent PNG variants): every stroke of the mark is two parallel lines,
the doubled-line grammar at brand scale. Locadex carries its own mark
(`/brand/locadex-mark.svg`).
Rules:
* **One ink.** The mark renders in ink on paper or paper on ink. Never a
third color, never a gradient, never a shadow.
* **The dark surface inverts the drawn mark's ink**, either as an alpha
mask taking the surface's ink or as a clean invert. The mark is a
drawing, not a picture.
* In illustration systems (the iso family), marks render as **alpha masks**
so the shape takes the surface's ink; the sanctioned flourish is the
Bayer-dithered specular shimmer (`DitheredMark`), never a GIF, never a
filter glow.
* At text size, the wordmark sits inline with prose at the cap height of
the line it lives in, as in the generaltranslation.com hero's "GT builds
full-stack localization for apps, docs, and websites".
* **The identity must survive compression:** a favicon, a CLI banner, a
README, a syntax-highlighted code block. Developers meet the brand in a
terminal as often as on a website.
## 5. Color [#5-color]
Four absolute colors (ink `#070707`, raised ink `#101010`, titanium
`#8a8f98`, paper `#ffffff`) plus **exactly one spectral accent per page**
(the working accent: `#2f5ce0`; its dark-band lift `#86a8ff`). Structural
color everywhere derives from the four as alpha steps; dark mode is a pure
token remap. Full law: `DESIGN.md` §1. The accent is a controlled edge,
never a wash; one bright white; depth from lines and material, not shadows.
## 6. Type [#6-type]
* **Inter** is the one typeface: display, interface and text. Headlines,
interface chrome, captions, long-form reading and documentation prose are
all set in it. The build is the real rsms.me Inter (v4.1 variable, roman +
italic, opsz axis), self-hosted rather than loaded from Google Fonts.
* **Headings use weight 500 at most.** Display text never goes bolder than
500; long-form text is set at weight 400.
* **Multilingual-first.** Headlines, UI, and marks must hold up in CJK,
RTL, and Indic scripts as well as Latin. A wordmark or layout that only
works in English contradicts the company. Inter covers Latin, Greek and
Cyrillic; other scripts fall back to the system face for that script, and
every layout is checked in them. Licensed type needs credible CJK and RTL
coverage, or well-matched companion faces.
* **Inter is the working typeface for the identity project.** It is not a
final decision. Alternatives remain open if they satisfy the
script-coverage constraint.
* **Monospace is an instrument voice, not a brand voice.** It appears where
code artifacts appear (tokens, terminals, file paths, small labels in
technical diagrams and product UI) and nowhere else, and even those
labels are avoided where possible. The direction explicitly avoids
monospace as the brand voice in headlines, body, and marketing.
* The prototemplate chrome (this site's own serif/grotesk pairing) is the
lab's stationery, not the product brand.
## 7. Language as material [#7-language-as-material]
The signature device: **glyphs, characters that make up greater wholes.**
Writing systems are the raw material the brand keeps returning to:
* The **sentence reassembler** (`EverySentence`): a headline dissolves into
glyph dust and reassembles in the next language. Matter is conserved; the
same swarm becomes the next sentence.
* The **glyph field**: rain from eight writing systems condensing into the
word "language," script after script.
* **Locale pills** (`LocaleTag`): flag print + code, the one way a locale is
named anywhere. The prints are SVG, never emoji; a flag is a functional
data chip, never decoration.
* The **1-bit Bayer language**: density as ordered dither, never alpha
veils. This is the texture of the brand.
* The **doubled line**: every connector one path stroked twice; the mark's
own grammar running through every diagram.
All of them run live in the build log on `/docs/handbook/libraries`,
with their APIs.
## 8. Where it ships [#8-where-it-ships]
The identity is applied on four kinds of surface today.
* **The site.** Marketing pages ship on generaltranslation.com, built in
gt-cloud's `apps/landing`. The production landing page (gt-cloud #4213)
has been canonical for the site since 2026-08-11.
* **Product surfaces.** The dashboard, onboarding, the sign-in plate and
the Prototemplate shell have followed the brand deck (`/deck`) since
2026-09-25.
* **Motion.** The films on `/motion` apply the identity to film: the blog
trailers, the product films and the translation-history series.
* **The marks.** The speed marks chosen on 2026-09-29 (`/marks`) sit
beside the doubled-line monogram, which stays the current mark
(section 4). The title badges in the `/brand` and `/marks` heads cycle
through a selection of the marks on `/marks`.
When in doubt about how the brand behaves, read the shipped surface the
work belongs to.
The site grew from the direction of the **Dossier**
(`/d/singularity-dossier`). It stays in the gallery with the other
directions as the working record of how we got there. From 2026-08-06 to
2026-10-07 this section named it the completed reference for the brand.
## 9. Context for partners [#9-context-for-partners]
* **Industry:** AI developer tools; the full stack for localization,
meaning i18n libraries, context-aware translation APIs, and the
infrastructure for versioning, editing, and integrations.
* **Audience:** technical and product executives at growth-stage startups;
their engineering and growth teams are the users.
* **Public names:** a customer or partner is named only where
generaltranslation.com shows it. On 2026-10-10 the home page showed
Cursor, Ramp, Mintlify, Profound, Partiful and ClickHouse, and a quote
from Theo, CEO of T3 Chat. `/enterprise` showed Ramp with 11+ locales
across its dashboard, landing page and iOS, Cursor with 14+ across web
and docs, Profound with 47+ across platform and docs, Partiful with 2+
across web, iOS and Android, and Sierra with 7+ across web and GTM, with
a quote from Lee Robinson, VP of Developer Experience at Cursor.
`/enterprise/contact` had partner pages for YC, Mercury, Slash,
speedrun, a16z and The Residency. Every other name stays off public
surfaces, this repository included. Read the live site again before a
new surface names anyone.
* **Against:** legacy TMS (seat-based, partial-stack). GT is usage-based
and owns the whole stack, so it can own the whole experience.
* **Admired:** Vercel, Resend, Stripe, for reliable, developer-first
infrastructure with engineering excellence and customer experience.
* **Direction:** International Style discipline with Art Deco's
future-embracing stance. Swiss grids, blueprints, boxes, no rounded
corners. Water and ocean as the recurring theme, connecting the globe.
Bespoke material textures (reference: materialarchiv.ch).
* **References:** Josef Müller-Brockmann and the Swiss poster tradition;
Otl Aicher's Munich 1972 pictograms; Vignelli's subway map; split-flap
departure boards; undersea cable maps and nautical charts; the Rosetta
Stone; the Chrysler Building; Powers of Ten; vintage National Geographic;
Borges' Library of Babel; the Whole Earth Catalog; transit signage; NYRB
Classics; Dieter Rams; vintage Olympics stamps.
* **Avoid (final):**
* monospace as the brand voice in headlines, body, or marketing; small
mono labels inside technical diagrams and product UI remain
instruments, avoided where possible.
* smooth scrolling, scroll-hijacking, and inertia libraries; native
scroll everywhere.
* robot and sparkle iconography for AI.
* the flag-soup cliche; flags are functional data chips only, printed as
SVG, never emoji.
* iridescent AI gradients and glassmorphism.
* eyebrow text that has not earned its place; three stacked lines saying
the same thing is noise, functional tags and labels are fine.
* em dashes in rendered prose.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Design system
> The design canon: the four-color system, the line law, rails and seams, the doubled line, iso, the 1-bit language, moving type and motion.
URL: https://www.prototemplate.com/docs/handbook/design
The canon for every page in Prototemplate: the laws the directions and the
shipped site run on, distilled from the founder rounds. The build log on
`/docs/handbook/libraries` is the living version of this document, with the
diagrams drawn and the engines running. This file is the reference you
read before touching a page.
***
## 1. The four-color system [#1-the-four-color-system]
Four absolute colors, declared once in `src/app/globals.css`:
| token | value | name |
| -------------------- | --------- | ---------- |
| `--color-ink` | `#070707` | ink |
| `--color-ink-raised` | `#101010` | raised ink |
| `--color-titanium` | `#8a8f98` | titanium |
| `--color-paper` | `#ffffff` | paper |
* Structural color everywhere derives from these plus alpha: every text step
is ink or white at some alpha, every hairline is titanium at some alpha,
every hatch is a thin ink or white veil.
* **Each page adds exactly one spectral accent** (toolchain: `#2f5ce0`;
its dark-band lift: `#86a8ff`). One bright white. An accent is a
controlled edge, never a wash.
* Pages never touch the raw values. Each root class (`.pt-root`,
`.toolchain-root`, fork roots) publishes a **semantic layer** — surfaces,
ink steps (`-2/-3/-4`), hairlines (`--*-hair`, `--*-hair-2`), hatch — and
everything downstream reads those.
* **Dark mode is a token remap, nothing else**: under `[data-theme='dark'] ` the paper family collapses onto ink, ink flips to white, and
hairline alphas rise so a 1px seam survives between two ink surfaces.
One surface family in the dark, the way light mode is one white.
* The second surface: light diagrams sit on exactly one sanctioned second
surface (`--tc-plate`), mirroring the ink / raised-ink pair dark mode
runs on. `--tc-panel` (`#101010`) is the one dark artifact surface for
code, config, and diffs.
## 2. The line law [#2-the-line-law]
Structure comes from hairlines, and **every line is drawn exactly once**.
The auditor (`scripts/lint/lines.mjs`) enforces it mechanically — see
`docs/SHIP-LOOP.md`. Four defect classes:
1. **Doubled lines** — two parallel strokes from different owners within
4px, including coincident strokes that composite darker than either.
2. **Missing seams** — section and row junctions no rule closes.
3. **Self-stacks** — a translucent border over the element's own translucent
background. Fix: `background-clip: padding-box`, everywhere.
4. **Invisible seams** — rules that exist geometrically but sit within a few
RGB steps of the surface they cross.
### Ownership [#ownership]
* Exactly one thing draws the page rails for any section — a rails wrapper,
or the section's own full-bleed pair. Never both. The pair is the column's
inner pair only: one hairline at each column edge, nothing outside it.
* The row owns every structural line; cells never draw borders that parallel
a row seam. A framed cell has a **1px padding reveal** that shows the
ground underneath, so the cell draws no border.
* **Flush at the rail**: where a row meets a line that already exists, the
cell sits flush and that side's reveal is dropped. A reveal never runs
beside a rail; a border never runs beside a seam.
### The named antipattern [#the-named-antipattern]
The overlap: two owners each drawing a real line along the same edge,
compositing into a band darker and thicker than any line the system allows.
The auditor cannot see SVG strokes — reconstructed lines come from computed
CSS — so figures must be checked by eye at 2× pixel crops of the junctions.
### Sanctioned devices [#sanctioned-devices]
* **The diagonal-hatch band** marks the boundary between a book's front
matter and its first section, once per book: 42px of
`repeating-linear-gradient(-45deg, transparent 0 6px, var(--pt-hatch) 6px 7px)`
between two hairlines it draws itself, `border-block: 1px solid var(--pt-hair)`
(`.pt-book-band`, BookView\.css). Its rules and its hatch run across the
whole stage, as every rule of a book does (see The reading column), and
nothing else draws a line within 4px of either rule; the first section's
divider draws no rule of its own.
The gallery's article (`.pt-hatch`, prototemplate.css) is the one place
a band draws only its bottom rule, because every section there draws its
own bottom rule and owns the band's top seam.
* **Border crosses**: where two hairlines must legitimately cross, a small
plus seated exactly on the intersection (ink, 1px, non-scaling) declares
the crossing deliberate — the one ornament a junction is allowed.
* **The doubled line** is the one sanctioned double — one owner, one path,
stroked twice (see §5). The auditor's allow list holds deliberate devices
by name; everything else stays strict.
* **The fixed sheet's ring** is the one sanctioned doubled line in chrome.
It is the edge of a fixed-size artifact: a slide, the gallery's live
1440x900 exhibit, the compare rig's panes, and the live page on
`/directions/` (`.dr-sheet`). The shell draws it as a 1px
`--pt-hair` border on `.sheet`, a 1px paper gap from the padding of
`.sheet-mat`, and a 1px `--pt-hair-soft` outline on the mat, with no
shadow, on the `--pt-plate` letterbox of the fixed stage, as the deck's
slide view draws it. A reading page has no ring and no plate. The active
thumbnail frame and the active book page frame carry the same border plus
offset outline. The auditor allows them under `sheet`, `thumb-frame` and
`page-frame`.
### The reading column [#the-reading-column]
A reading page sits straight on the stage's paper. That covers the book
mode of /brand, /motion, /graphics, /skills and /marks,
their record pages, `/directions/` and `/archive/`: every route
that renders `Sheet variant='flow'`. Its column is the deck's book column
(`deck/parts/head.html` `.book-in`): 1280px at most and centered in the
stage, with `--pt-col-pad-x` (56px, 16px under 900px) on each side,
`--pt-title-clear` over the title and 120px (80px under 900px) under the
last block. The column draws no border, no ground and no mat. The
toolbar's bottom rule is the only line above the title, and the sidebar's
right edge is the only line beside the page. A fixed-size artifact inside
a reading page keeps a frame, because the frame is its edge: the live page
on a direction page keeps the fixed sheet's ring, and a capture takes the
frame role with the card corner. Kevin asked for this on 2026-10-06, after
the grey mat had made every page a framed picture of a page.
Every shell rule written for 900px and under also matches a phone on its
side, `(pointer: coarse) and (max-height: 500px)`, and `ViewerShell.tsx`
`isNarrow()` reads the same query: a 932x430 phone gets the phone's
composition and touch sizes (the list as the overlay, 44px book links)
instead of the desktop list column of 28px rows. A tablet is taller and
keeps the desktop composition.
Every structural horizontal rule of a book runs across the whole stage,
from the sidebar's edge to the stage's right edge: the mast's rule, the
contents rows, the band and the dividers, the full-width list rows of
/skills, /graphics, /motion, /marks and a direction page, an archive
record's rows, and the rule over a blog post's footer. The element keeps
its 1px border for layout and paints it as a border image outset past
both ends (`--pt-bleed-top`, `--pt-bleed-bottom` and `--pt-bleed-block` in
tokens.css); the outset never scrolls, and the scroll region clips it at
the stage's edges. A rule that drops its border also writes
`border-image-source: none`, because the image ignores border-width and
the build empties the shorthand `border-image: none` (lint:practices
holds this). Under forced colors the hairs take `CanvasText`. A contents
row is one line: the first link of each row draws it and the others draw
none. Rules
inside the content keep their measure: the head panel's rows, tables,
prose lists, the `---` rule, ledgers and file lists. Kevin asked for
full-width rules on 2026-10-07.
### Line law for chrome [#line-law-for-chrome]
Chrome is everything the viewer shell draws around content: the toolbar,
the sidebar, the index panel, the search, the fixed sheet's ring, the grid, the
book frame, the help card, the direction corner, and the standalone deck
viewer's own chrome. Every rule in chrome is 1px, drawn once, in one of
three roles, and this is part of the identity: a page reads as
Prototemplate because its lines are single and their weights mean
something.
The three roles, and only three:
| role | token | draws |
| ---------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| structural | `--pt-hair` | large surfaces and the lines that divide the shell: the fixed sheet's ring, the search card, the index panel's left edge, the toolbar bottom, the sidebar right edge, the deck surface index's group headers (the sidebar's group headers draw no rule), the book head's rule, the hatch band's two rules, the section dividers, the segmented control, the field boxes at rest, the install field at rest |
| row | `--pt-hair-soft` | list rows, search results, panel rows, the book head's panel rows, the help card's table rows, the fixed sheet's outer ring, the progress track, the sidebar's rail (`.pt-sb-rail`, outline density) and the run guides (thumbnail density) |
| frame | `--pt-edge` | frames of images and tiles only: thumbnails, the book's page frames, the grid tiles, the 96x54 and 64x36 captures, the hover preview's frame, and the help card |
The weights carry meaning. A frame at 0.62 alpha is the darkest line in
chrome because it holds a picture in place: the eye must find the edge of
a capture against the paper around it. A large surface (a fixed sheet, a card,
a panel, a head) is not a picture; it is the paper itself, so its edge is
the structural hairline, and its outer ring (where it has one) steps down
again to the row weight. A fixed sheet drawn in the frame weight reads as a
boxed image, which is the bug Kevin named in round six ("make the borders
around these areas the proper border colors"). The help card is the one
card that keeps the frame weight: it floats over a scrim, where the
hairline would vanish.
Nothing in chrome sets a border color from any other token or literal.
`--pt-ink` appears on a border only as a state: a pressed button
(`.is-on`), the active thumbnail or page frame (`.is-active`), the count
while it is being edited, the solid call to action, the sidebar's current
thumb on its rail, and a field while it holds focus. Book heads, table headings and the deck surface index's group
headers draw `--pt-hair`, never ink; the sidebar's group headers draw no
rule at all. Outlines are rings: the three roles, ink for focus and active
rings, paper for a ring on an ink plate.
Where two bordered components touch, exactly one draws the line:
| junction | owner | the other side |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| sidebar and stage | the sidebar's right edge | the main region draws no left edge |
| toolbar and stage | the toolbar's bottom edge | the stage, the hint row and the index panel draw no top edge |
| index panel and stage | the panel's left edge | a fixed sheet's ring runs under the panel; the panel covers the progress track while open |
| group header and its first row | no one: the header draws no rule, and the group's boundary is the 16px gap above its header | the first row draws no top rule |
| a page row and its run | the group's rail (`.pt-sb-rail`, `--pt-hair-soft`), bending 45 degrees under the page row into the run; in thumbnail density the run's guide | the page row draws no bottom rule; run rows and labels draw no left border |
| a run and the deep run in it | the same rail, one more bend; in thumbnail density each run its own guide, 16px or more apart | no row draws a left border |
| the marked row and the rail | the rail; the 2px ink thumb is a state over it | the rail under the thumb is covered, not doubled; the row draws no bar |
| a row and the pills | no one: the pills are grounds and draw no line | the row draws no box |
| a page row and its fold | no one: the fold draws no border at rest, and its focus ring is a state | the row draws no right rule |
| last row of a group and what follows | the last row's bottom edge | the next header carries no top rule |
| a fixed sheet and its content | the ring (hair border, paper gap, hair-soft outline) | content draws no outer border |
| a reading column and the stage | no one: the column draws no edge | the toolbar's bottom rule is the only line above the page and the sidebar's right edge the only line beside it; content draws no outer border |
| book head and its contents | the mast's rule (`--pt-hair`), then the note when there is one | the note draws no rule; the contents grid draws no top rule; its rows draw their own bottom rules |
| the title and what is above it | no one | nothing is drawn in the `--pt-title-clear` space between the toolbar's bottom rule (the stage's top) and the h1's box, and no line crosses a title |
| book head and its panel | the panel's rows draw `--pt-hair-soft` under every row but the last | the panel draws no frame; side by side, the mast's rule closes the mast under the taller of lead and panel; on a narrow head the panel draws a row rule over its first row and the mast's rule is its last row's rule; the install field draws its own `--pt-hair` box and the row above it drops its rule |
| front matter and the first section | the band, both rules | the contents grid draws no rule against it; the first section's divider draws no rule |
| two sections | the lower section's divider rule | the upper section draws no bottom rule |
| tile and its shot | the tile's frame | the shot draws no border |
| segmented control and its options | the control's outer border | options draw no dividers; the active option is an ink pill 2px inside it with the chip corner, and the hover and the focus ring trace the same pill |
| stacked corner buttons | the upper button's bottom edge | the lower button's top edge is transparent at rest |
| sidebar head and toolbar | each owns its own side of the vertical seam | the two bottom rules meet at the sidebar's edge and never overlap |
The auditor enforces this from computed CSS. `pnpm lint:lines:shell` walks
`/`, `/brand`, `/compare`, `/archive/`,
`/directions/`, `/skills`, `/skills/`,
`/motion`, `/motion/`, `/graphics`, `/marks`,
`/d/production` and `/deck` (the deck's own document) at 1440, 1280 and 390
in both themes against the dev server on port 3005, with the list toggled,
the index panel open, the search open, and the grid and book modes on `/`
and `/deck`. It
fails on any doubled line (two owners within 4px), any junction (two owners
coincident on one seam), and any border color in chrome outside the three
roles. The sidebar's rail is a masked box the walk cannot see, so the
auditor reads its vertical runs from its path (`data-rail-path`), holds its
ink to the row role, and fails a state audited with the list open in
outline density when the rail layer is not live. `pnpm lint:all` runs it.
The allow list in `scripts/lint/lines.mjs`
names every sanctioned multi-stroke device with its reason inline; for
chrome those are the fixed sheet's ring (`sheet`: a hair border, a paper
gap, a hair-soft outline, on /compare, in slide mode and around a
direction's live page), the active frames (`thumb-frame`, `page-frame`, the
sidebar's site tiles as `pt-tile`) and the hover preview's mat
(`pt-preview`).
Scroll regions belong to the same law: one thin scrollbar everywhere in
chrome, a 4px gutter with no track rule and a 2px thumb in `--pt-thumb`
that widens to 4px on hover, owned by `.pt-scroll` in
`src/components/viewer/tokens.css` and mirrored by the deck's `.scroll`
rule. No scroll region draws a rule beside its thumb.
### Corners: rounded controls, square shells [#corners-rounded-controls-square-shells]
Kevin's toolbar is the reference (2026-10-05): the search pill and the segmented control round at 6px, the key chip at 4px. Everything a reader presses, types into, picks up or looks at as an object is rounded; the surfaces that hold the interface are square. `src/components/viewer/tokens.css` holds the corners as six tokens, and nothing in the shell or the pages writes a radius any other way.
| class | token | value | members |
| ------- | --------------------- | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| shell | `--pt-radius-shell` | 0 | the viewer frame, the sidebar column, the toolbar bar, the fixed sheet and its ring, the reading column, the index panel's column, the overlay layers and scrims, the progress track, scroll thumbs, the book head, the contents, the dividers and the bands; full-width list rows, which own their seams and never draw a box; an input inside its field |
| control | `--pt-radius-control` | 6px | every button (`.pt-ib`), segmented groups, fields and field-shaped buttons (the search pill, the count, the filters, the palette's field, the install field), buttons on pages, the sidebar's pills, which are grounds the pointer is on |
| inner | `--pt-radius-inner` | 5px | a part flush inside a control's 1px border: the install field's copy segment |
| chip | `--pt-radius-chip` | 4px | key caps, chips, pills, tags, inline code, a segmented control's active and hover pill (2px inside its option), and a control set 2 to 7px inside a field |
| card | `--pt-radius-card` | 6px | cards, tiles, thumbnails, figures, and popovers: the palette, the help card, the toast, the hover preview |
| round | `--pt-radius-round` | 50% | dots and avatars on a square box |
* A part n px inside a rounded box (n from 1 to 3) takes `calc(var(--pt-radius-) - npx)`.
* A picture in a rounded frame is clipped by the frame or takes the concentric radius.
* Named exceptions: Present keeps 8px (section 15); the marks page's app tile keeps the platform's 22% and its browser tab mock stays square, because they are specimens. The /d/ directions, the deck, the presenter, the craft article and the dashboard plate keep their own grammar.
* `scripts/lint/radius.mjs` holds the law: statically in `pnpm lint:radius` and the build, and on the rendered pages in `pnpm lint:radius:live`.
The corner notches on hero cards are not drawn — they are the ground showing
through, so a corner can never disagree with the seam that meets it.
## 3. The rails [#3-the-rails]
The page's spine is a ruled column with ONE rail on each side.
* The column wrapper draws the pair once, with its own `border-inline`.
* A band mounted inside the wrapper draws no side rails of its own: the
wrapper already owns them.
* A full-bleed band that sits outside the wrapper draws its own inner pair
once, at the column edges, from its own `-in` column, in the band's rule
ink. It never draws a pair beside the column.
* Retired everywhere: the outer pair at ±10px that earlier directions drew
from a wrapper pseudo (the "doubled rail"). A second stroke beside a rail
is defect class 1 above, and a coincident second stroke stacks alphas and
reads as a different color.
The doubled LINE of section 5 is a different device: one path stroked
twice, a connector, never a page rail.
The sidebar's rail (section 16) is a different device: a row-weight line
inside the list that marks the place, never a page rail.
## 4. Typography and voices [#4-typography-and-voices]
* Three voices: the serif face for brand moments, the grotesk for labels
(11px, `letter-spacing: 0.06em`), the mono for numbers and tokens only.
* Hairline-boxed code blocks; figcaptions under figures; one type scale per
page. Labels never shout; the active element is the only color.
### Book type [#book-type]
The shell's type is one family, the rsms InterVariable (v4.1), cut into
unicode-range subsets by `scripts/build/subset-inter.py` (`pnpm build:inter`):
Google Fonts' latin, latin-ext, vietnamese, greek, greek-ext, cyrillic and
cyrillic-ext, plus Latin Extended-A, the private use area and the remaining
symbols, each with every feature and both axes. The roman's latin subset
comes through next/font, bound as `ptInter` in `src/lib/fonts.ts` so its
family name matches no installed Inter, and every route preloads it. The
other subsets and the italic are plain `@font-face` rules in the same
`ptInter` family in `src/app/inter-subsets.css`, each fetched only where
the page draws a code point in its range. Any other
`localFont` call sets `preload: false` (`pnpm lint:type`, T3). Every stylesheet reads the type tokens of
`src/components/viewer/tokens.css` and declares no family, feature list or
display size of its own. The /d/ directions keep their own type.
* **Stacks.** `--pt-text` is `var(--font-inter), system-ui, sans-serif`;
`--pt-display` reads it. `--pt-mono` is for code, numbers and tokens
only. The per-language stacks (`--pt-text-hant`, `-hans`, `-ja`, `-he`)
name system faces after Inter. The nameplate's faces are
`--pt-face-serif` and `--pt-face-grot`.
* **Features.** h1 and h2 (and a display sentence such as the brand
plate's `.ptc-every`) take `--pt-ff-display`: the single-storey a
(cv11) and the open digits (ss01). Everything else takes
`--pt-ff-text`. Both name `'liga' 1, 'calt' 1`, because Chrome turns
contextual forms off under any letter-spacing. The base rules on the
shell's roots set them; a rule never writes a feature list.
* **Weight.** 400 for text, 500 for labels, headings and `strong`.
Nothing above 500.
* **The display ladder.** Optical size follows the size, so 32px and up
is the Display design.
| step | role | size / line | tracking | 900px and under |
| ---- | ----------------------------------------------- | ----------- | -------- | --------------- |
| d1 | page title (the book head's h1) | 44 / 1.04 | -0.025em | 32 |
| d2 | section title (a divider's h2, a brand chapter) | 32 / 1.05 | -0.025em | 26 / 1.15 |
| d3 | h2 in prose, a record's title | 24 / 1.25 | -0.02em | 21 |
* **The text ladder.** Title 18/1.35 at 500 and -0.01em (h3, a row's
title); lead 17/1.55 in ink; body 16/1.6 in ink-2; small 14/1.55
(table cells, contents links, ledgers); meta 13/1.5 in titanium (meta
tables, gutter notes, captions, th); group labels 12.5 at 500 and
-0.005em. Weight 400 text is never tracked, and nothing on Inter is
tracked positive.
* **Measure.** Body text at `--pt-measure` (32em, about 66 characters);
a head's lead at `--pt-measure-lead` (30em). Tables, figures, code and
ledgers keep the full column.
* **The book page.** Every page with a book head has one structure, rendered by `BookHead` (BookView\.tsx), and differs from another only in its words and its facts:
1. nothing is drawn in the `--pt-title-clear` space between the toolbar's bottom rule and the title (the reading column's top padding), and no line crosses a title;
2. the title, the page's plain name from `src/lib/page-names.ts` (Brand, Documentation, Motion) or a record's own title, at d1 across the mast; on /brand alone (Kevin, 2026-10-21), a badge after the name on the title's line (BookHead's `badge`: a 1px `--pt-hair` box at the card corner, its content at most the cap height tall and set on the baseline, hidden from the accessible name) cuts every 1.4s through the GT monogram and the register's monograms (`src/components/viewer/BadgeCycle.tsx`, steps(n) on one strip, so the count lives in the frames; under reduced motion the first frame stands), and `pnpm lint:heads` fails a badge on any other page;
3. the lead (one to three lines at `--pt-measure-lead`, at most 200 characters, plain declarative sentences) and the panel on one row under the title, both starting on the lead's first line;
4. the panel: Updated first (the day of the last commit that touched the page's own sources, from `src/lib/updated.ts`, linked to its commit, with a relative hint after hydration), then three facts, or one fact and the install field; each row a Heroicons 20 solid glyph in titanium, a label in ink-2 and a value in ink at 500, one lead line tall with its text centered between 2px of air above and below, and a `--pt-hair-soft` rule between rows, none over the first row or under the last; beside the lead the panel starts 2px under the lead's top, so each row's baseline lands on a lead baseline;
5. one `--pt-hair` rule `--pt-head-rule-pad` under the taller of lead and panel, across the stage;
6. the note at the body step, then the contents;
7. one hatch band ruled on both edges and running across the stage, `--pt-sec-over` under the block above it;
8. the sections, each a `section.pt-book-part` opened by a divider: a `--pt-hair` rule (the first section's rule is the band's), `--pt-sec-pad`, a gutter note of two lines in titanium (`Section n`, then one fact) on the h2's last baseline, the h2 at d2.
Under 880px of head width the panel stacks under the lead, ruled the same way, and the mast's rule sits `--pt-head-rule-pad` under it. The gallery (`/`) is the site's front page, the nameplate hero and the redesign post in the article's own grammar, and has no book head; `/compare` is a tool and has none. `scripts/lint/heads.mjs` holds the structure, statically and on the rendered pages.
* **The gutter.** Sections and rows keep the deck's 128px gutter and 28px
gap. A gutter number takes the size, line height and baseline of the
title beside it, in titanium (ink while active); under 900px it sits
above the title at the meta step.
* **The lint.** `scripts/lint/type.mjs` holds all of this: statically in
`pnpm lint:type` and the build, and on the rendered pages with
`pnpm lint:type:live`. Its allowlist names every exception with its
reason: the nameplate, the gallery's grotesk labels, the mono numbers
and tokens, the specimens, and other sessions' code.
`scripts/lint/heads.mjs` holds the book page (`pnpm lint:heads`,
`pnpm lint:heads:live`).
## 5. The doubled line (thread grammar) [#5-the-doubled-line-thread-grammar]
The brand's connector: **one SVG path stroked twice** — a full-gauge ink
stroke under a narrower surface-colored core (`stroke-width: gap`), carving
two parallel hairline threads at a constant gap along any curve. Tokens:
`--thread-gauge: 1.5px`, `--thread-gap: 3px`.
* All three roles carry `vector-effect: non-scaling-stroke`.
* The core's stroke must match the actual surface behind the diagram, or the
carve reads as a painted stripe.
* Layer order is load-bearing: threads first, pulses next, cores last. Draw
a later sandwich over an earlier one and the junction re-carves into one
clean pair — merges cost zero parallel-curve math.
* The live pulse is a third copy of the same path in accent at full sandwich
gauge, between threads and cores — carved into two accent hairlines, never
a filled band. The traveling window is **real geometry** (a sub-polyline
rewritten per tick), never `stroke-dasharray` — dash distances drift under
anisotropic stretch.
* **Two-tone** (one white thread, one gray): clip the white copy to a
half-plane closed along the same center path — the split seam lies inside
the carve. Componentized as
`src/components/shared/diagrams/DoubledLine.tsx`. Offset clones collapse
on curves; concentric restrokes only make symmetric rings.
This plate draws `DoubledLine`. Two source paths merge into one trunk, each path is one stroke carved into two hairlines by the plate's ink, and the trunk carries a static accent window in its pulse slot.
## 6. The isometric family [#6-the-isometric-family]
One 30° axonometric map for every iso drawing
(`src/app/d/toolchain/diagrams/iso.ts`):
`project(x, y, z) = [(x−y)·cos30, (x+y)·sin30 − z]`, camera at (+,+,+).
* **Light from the upper left, always**: exactly three faces visible, shaded
top 4% / left 9% / right 15% (currentColor mixes; accent faces keep the
same order). Reordering is forbidden.
* The extrusion recipe: opaque hull from `roundedPolygon(silhouette(...))`
(the occluder), then right/left/top face fills, then hairlines — rim, top
contour, and the interior front edge(s) the silhouette doesn't draw.
* `IsoPrism` extrudes any convex plan polygon under the same visibility and
tone law; `plane(z, ox, oy)` seats whole flat drawings into a surface with
one matrix; `markPath()` lays rounded bars in a face; brand marks render
as alpha masks so the shape takes the surface's ink.
* One corner radius family-wide (`ISO_RADIUS = 2.4`); plate thickness ≈4% of
footprint, air between stacked plates ≈40%; depth cues live in per-plate
stroke alphas, never group opacity; each drawing spends its accent on
exactly one element.
* The mark shimmer is `DitheredMark` (§7's 1-bit language as a specular
band): nested Bayer coverage tiers windowed by pre-rotated 60° clip paths,
swept by pure horizontal translate — `rotate()` windows are GSAP-origin
fragile.
This plate draws with the isometric kit: a slab extruded from its rounded silhouette carries two boxes and one hexagonal prism, every face lit from the upper left.
## 7. The 1-bit language (Bayer dither) [#7-the-1-bit-language-bayer-dither]
Density ramps render as ordered dither, never alpha veils.
* The 4×4 matrix (`[0,8,2,10 / 12,4,14,6 / 3,11,1,9 / 15,7,13,5]`) and the
8×8 (an exact permutation of 0..63 — 65 tonally linear levels) are the
house screens.
* Coverage tiers **nest by construction** — every tier's lit cells are a
subset of the next — so non-overlapping regions filled with different
tiers compose exact ramps, and opaque glint ink means doubled cells never
brighten.
* Cells are square screen pixels: transforms that would foreshorten them
(a plane seat) go **inside** the alpha mask; `crispEdges` keeps cells
1-bit at any zoom; CSS upscales with `image-rendering: pixelated`.
* Engines: `src/lib/dither.ts` (CPU, any scalar field, 1 device px per cell)
and `src/lib/studio-field.ts` (GPU, the authentic `BAYER_PRESETS` roster of
ten variants, one shared GL context, switch by remount).
* Artifact pictures (the dithered photographs and scans on the plate's field, the deck's mood slides and the transition demo on /docs/handbook/libraries) follow the Blue Marble standard in `docs/ARTIFACT-PICTURES.md`, held by `scripts/lint/pictures.mjs`.
This plate runs `createDitherLoop()`: wavy streak bands pass through the 8x8 Bayer screen, and every dot is one cell thresholded against the matrix.
## 8. The moving type law [#8-the-moving-type-law]
* The morphing unit is **one shaped text node** — never per-character spans,
which break Arabic joining and Devanagari matras. `lang` + `dir` on the
node; `unicode-bidi: isolate` on the container.
* Width is measured from a hidden probe carrying the word's own lang/dir —
never a sum of per-character boxes — cached, device-pixel snapped, and the
container's width is the **only layout-affecting property that animates**,
one continuous tween per cycle. Re-measure on resize and `fonts.ready`.
* One clock per page: the component never runs a timer; the host drives it
(the dossier's locale belt, a craft plate's interval). Engine:
`src/components/shared/EverySentence.tsx`.
* Locale pills render through one component (`LocaleTag`): flag first
(fixed 15×11 SVG print), code in the host's mono on the baseline; the host
supplies the box.
This plate runs `EverySentence`: one shaped sentence breaks into glyphs and reassembles in the next language, and its width moves once per change, measured from a hidden probe. The chips set the number of re-spread beats from 1 to 5.
## 9. Motion discipline [#9-motion-discipline]
* Every loop is created paused; ScrollTrigger (or an IntersectionObserver)
plays/pauses it while the section is on screen; multi-phase choreography
lives on ONE timeline so phases can never drift.
* `prefers-reduced-motion` short-circuits setup entirely; the markup pose IS
the still (static accent pair, parked seam cut, single dither frame).
* Dash gotchas: normalize `pathLength` to 1000 (GSAP integer-rounds
offsets); dashes clip at a subpath's end rather than wrapping closed
loops; Chromium computes dash patterns in screen space under
non-scaling-stroke and ignores `pathLength` there — rings that dash use
raw user units with neither.
* Cache a path's source `d` (`el.dataset.traceD`) before an animation blanks
it per tick — a re-run would otherwise trace an emptied path.
* Leader joints overshoot into opaque hulls so joints are gapless; leaning
shapes (scan beams) are re-projected per phase (`beamAt(t)`), never a
translated constant.
* The sidebar's thumbs and pills move on transform only, by WAAPI, at
`--pt-dur-sb` (a pick) and `--pt-dur-toast` (the pointer), eased by
`--pt-ease`. Their geometry is read once per layout change (a
ResizeObserver per group, a MutationObserver for rows and marks), never
per frame and never on hover. Before the shell settles they are placed,
not moved. Reduced motion places them at once.
## 10. The seam (slide-to-reveal) [#10-the-seam-slide-to-reveal]
Both layers full-width and pinned; the handle writes one CSS var
(`--seam-cut`) and the top layer clips to it — content never travels with
the handle. State lives in the var: drags cause zero re-renders, GSAP tweens
drive the same dial, the keyboard path re-reads the live computed value.
The handle is the **dossier refit**: a 64px transparent hitbox, solid
two-tone threads with the payload's ink filling the run, and a 16×40
rectangular grip tab — the light surface wears the dark chip, the dark
surface the light chip. Component:
`src/app/d/toolchain/sections/RevealSeam.tsx` (host CSS supplies the skin).
This plate mounts `RevealSeam`. Drag the handle, or focus it and press the arrow keys, to reveal the served translation payload under the rendered string.
## 11. Engine lifecycle [#11-engine-lifecycle]
Every canvas/GL engine follows one contract: mount lazily (an
IntersectionObserver arms the plate), pause offscreen and on hidden tabs by
its own observer, render exactly one still under reduced motion, and
`destroy()` releases everything the instance owns (shared GL contexts
persist for the session by design). Ink re-resolves on `data-theme` flips.
Where an engine has quality tiers, quality follows **measured** frame cost,
not just the window: glyph-field's frame-time governor ratchets a slow
device down the phone cut's own ladder (lean device-pixel cap, then the
lean pool), down only, with pool cuts applied at idle.
## 12. The mobile type ladder [#12-the-mobile-type-ladder]
Under 720px, type and spacing are **one token ladder, not per-rule
values** — `--tcm-*` slots declared on `.toolchain-root` in the engine's
LATE 720px block (`src/app/d/toolchain/styles.css`), consumed by every
floor below:
| slot | value |
| --------------------------------------- | ------------------ |
| `--tcm-h2` / `-h2-lh` | 2.25rem / 1.18 |
| `--tcm-h3` / `-h3-lh` | 1.375rem / 1.3 |
| `--tcm-h4` / `-h4-lh` | 1.125rem / 1.35 |
| `--tcm-lead` / `-lead-lh` | 17px / 1.55 |
| `--tcm-body` / `-body-lh` | 16px / 1.6 |
| `--tcm-small` / `-small-lh` | 14px / 1.55 |
| `--tcm-kick` | 13px |
| `--tcm-quote` / `-quote-lh` | 22px / 1.4 |
| `--tcm-head-pt` / `-head-pb` | 72px / 36px |
| `--tcm-gap-h2` / `--tcm-gap-h3` | 18px / 14px |
| `--tcm-cell-pad` | 28px |
| `--tcm-box-pt` / `-box-pb` / `-box-gap` | 36px / 38px / 28px |
* **The px-fallback consumption law**: every consumer reads
`var(--tcm-X, )` with the slot's canonical value as the
fallback — a rule the ladder doesn't reach (a 721–900px cut, a fork that
hasn't declared it) degrades to the same number, never to unstyled. New
mobile rules never hardcode a size the ladder has a slot for.
* **Unlayered engine beats utilities**: the engine's plain CSS is
unlayered and Tailwind utilities live in a `@layer`, so engine floors
outrank utility metrics (the box-gap rule beats a head's `max-lg:mb-6`).
Heading and paragraph metrics therefore live in engine CSS, never in
page utilities.
* **The late block**: the ladder and its floors sit in the engine's LAST
720px block because several base rules they override appear after the
earlier 720px block — same-specificity declarations only win by
following them. New mobile floors go there, not in the early block.
* **The sg cut outranks the engine**: `v0-pages.css`'s mobile cut
(`.toolchain-root:is(.sgdh-root, …)`) carries higher specificity than
any engine floor, so it must consume the same tokens — an engine-only
raise silently fails to render on the singularity homes. Change one,
change both.
### The box-air standard [#the-box-air-standard]
Boxed cells — framed cards, bento plates, stacked dark-band cells —
breathe alike on mobile: block padding `--tcm-box-pt`/`--tcm-box-pb`
(36/38), and `--tcm-box-gap` (28px) between a box's head and its
artifact. The gap is card-scoped (`.tc-card > .shell-cell-head`) on
purpose: cells are flex columns, margins never collapse, so an unscoped
head margin would stack onto the copy cells' own body margins. The seam
floor rides alongside: copy never sits within 20px of a hairline
(`--tc-card-pad: 20px`; the trust lead's 20px bottom pad).
## 13. The svh/dvh law [#13-the-svhdvh-law]
A mobile stage measures the viewport twice, and the two units never
trade jobs:
* **Reach is dvh.** Whatever must touch the true screen bottom — the
stage's rails, the text zone — sizes from `100dvh`, the real viewport
with browser chrome collapse included.
* **Layout is svh.** Any height that participates in layout rides
`100svh`, the stable viewport: a dvh layout height grows the document
on every chrome toggle and jitters the scroll under it.
* The difference is a token — the stack stage's `--v0sm-bar-gap`
(`dvh − svh`, 0 while the URL bar shows) — and only overhangs (the
rails' lower reach) spend it. Anything SIZED from the stage derives
from the stable var, or it breathes with the URL bar.
## 14. The two read lines [#14-the-two-read-lines]
The stack story runs on two ladders of scroll anchors, measured per beat
and re-anchored on every ScrollTrigger refresh
(`src/app/d/_v0/sections/FullStack.tsx`):
* **The read line (55%) is structural.** A beat LOCKS IN when its COPY
BLOCK's center takes the 55% line — the same line the sticky figure's
seat centers the tower on, and, for the finale, its pin-engage. The
tower's build clock and the capstone scrub both key on it. Anchors are
measured on the copy itself, from FLOW geometry (the sticky finale's
own rect would read the stuck pose on a mid-dwell refresh) — never on
the beat window's top, which runs nearly half a viewport ahead of the
copy and fires every arrival early.
* **The highlight line (80%) is the spotlight's alone.** A beat's copy
lights as its center rises through the 80% line — just after entering
the screen, while the arriving layer is still mid-build beside it.
One scrubbed dial spans the whole read; a piecewise map (measured
lock-ins in, story time out) HOLDS the clock while a row is being read
and spends each gap hold → build → lock, so a layer stands locked before
its own copy takes the line.
## 15. Chrome exceptions Kevin asked for [#15-chrome-exceptions-kevin-asked-for]
The shell's chrome is Inter only, weight 500 or less, corners as section 2
sets them (square shells, 6px controls and cards, 4px chips), one hairline
per rule, colors from `src/components/viewer/tokens.css` and
borders in the three roles of section 2. Kevin's round six directives
override those rules for exactly five elements. Each exception is listed
here with its owner file so nothing else reaches for it, and so the next
sweep does not "fix" it back.
| element | exception | owner |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| Search pill (toolbar) | hover border `--pt-ink-2`, a fourth border color in chrome, reachable only under the pointer (the line auditor never drives hover). At rest the pill stays in the `hair` role, and while its palette is open (`aria-expanded="true"`, a state the auditor does drive) it draws `--pt-ink`, the active-state color every open field takes | `Toolbar.css`, `.pt-toolbar .pt-search-btn` |
| Search key chip | `kbd.pt-search-kbd`: ground `--pt-hair-soft`, 11px weight 500 titanium; reads ⌘K, and `Ctrl K` on Windows and Linux (`Search.tsx` swaps the text after mount from the user agent) | `Toolbar.css`, `Search.tsx` |
| Present | the one `.is-solid` button: `border-radius: 8px` (the one named corner exception, hatched in lint/radius.mjs), 14px sides, the label first and the 12px play glyph after it (`flex-direction: row-reverse`, so ToolButton keeps one markup), hover drops the ink ground for ink text in the ink frame, the old `.pt-nav-present` from 430e3c7 | `ToolButton.css`, `.pt-ib.is-solid`; `Toolbar.tsx` passes `solid` |
| Prototemplate mark | the rainbow core: five chroma stops (`#4b3bff`, `#00b3ff`, `#27d17e`, `#ffc53b`, `#ff3b6b`, display-p3 where supported) declared as `--pt-mark-c1` to `--pt-mark-c5` on `.pt-mark`, the one color in chrome outside the site icons; hovering the head link (or any `a` or `.pt-mark-host` around the mark) fades the hatched paper fill in over the core, opacity only, over `--pt-dur-enter` (200ms, 0 under reduced motion). The markup is the old nav's span with four `i.pt-mark-line` and `i.pt-mark-fill` | `PtMark.tsx`, `PtMark.css` |
| Sidebar nameplate | the name beside the mark on every Prototemplate route is `span.pt-brand-word` with `b.pt-face-serif` `proto` in Fraunces 600 and `b.pt-face-grot` `template` in Space Grotesk 500 at 14.5px, two faces outside Inter and a weight above 500; the fonts load from `src/lib/brand-fonts.ts` with their variable classes on the span, so `/skills` and `/brand` carry them too. The deck keeps its Inter title beside the GT mark | `Sidebar.tsx` (head), `Sidebar.css` (head rules) |
Everything else in chrome keeps the rules above: every other toolbar button takes the control corner, the palette and the help card take the card corner, the index panel is a shell column and stays square, and no other element carries a chroma or a face outside Inter.
## 16. The sidebar's rows [#16-the-sidebars-rows]
Three rules govern the list in column one (`src/components/viewer/Sidebar.tsx`),
on every route that shows the site map.
**Every row is a link to a page.** A site map row navigates to its route
through the router; a row that leaves the site opens a new tab. A route's
own item navigates too when its href names a page other than the one the
reader is on: a direction row on `/` opens `/directions/`, an archive
row `/archive/`, a skill row `/skills/`. The shell selects in
place only an item with no address of its own (a slide, a brand section),
an item that asks for it (`ShellItem.inPlace`, for a page whose own
scroll writes the address), or the item of the page
the reader is already on. No row scrolls the gallery. The grid's tiles and
the filter's Enter follow the same rule.
**A page's sections open under its row.** On the page's own routes, its
sections open as a run under the page's row, in the row's group
(`ShellSection.under`: `brand`, `atlas`, `marks`, `graphics`, `motion`,
`skills`). A run is flush under the row. Each row of the run draws the
route's own number in the icon's slot, in the deck's number style, and a
name that wraps (a run row to two lines at most, a deep heading to three)
and is never cut; a title that is a sentence takes a short name
(`ShellItem.short`). When two or more of the page's sections hold more than
one row, each gets a label with a chevron and a count inside the run; a
section of one row is that row. The
headings of the item being read hang under it as a deep run, at 12.5px
titanium, ink while read. A chevron button at the right
end of the page row folds the run for the visit; the run opens again on
the page's next visit. A labelled group opens when the run has 40 rows or
fewer, and past 40 only the group holding the active item opens; those
folds persist under `gt-shell-groups`. A route section that stands for a
site map group (Shipped, Sites, Explorations, Archive) keeps replacing that
group. The sidebar is 208px in outline density and 256px with thumbnails,
the same two columns as the deck's list.
**The rail marks the place.** In outline density each top-level group
carries one rail: a 1px `--pt-hair-soft` line drawn by `.pt-sb-rail`
(`src/components/viewer/SidebarRails.ts`) and masked to an SVG path down the
group's rows. The rail runs in a column 16px before each level's first
glyph: x 18, under the group header's chevron, for the tree rows; x 34 for
a run's rows and labels, a site's enterprise page and the live site's rows,
whose icons and numbers start at 50; x 50 for the deep headings, which
start at 66. Where the level changes, the path bends at 45 degrees across
one 16px step. The marked row carries a 2px ink thumb on the rail and a
`--pt-sb-pill-current` ground with the control corner. The row under the
pointer, or under keyboard focus, carries a `--pt-thumb` thumb and a
`--pt-plate` ground. The marked row is the deep heading being read when
the deep run is shown, else the active item when its row is shown, else
the current page's row, else the page row the reader is inside. A plain
click moves both marks to the clicked row over `--pt-dur-sb` and turns it
ink before the page arrives. When the click opens another route, the new
page's list keeps the clicked row where it was and the marks travel from
it to that page's mark once the shell settles. Thumbnail density has no
rail: its rows lead with their captures, each run keeps its guide and the
active row its 2px bar.
**The current page is always marked.** The row whose path is the longest
one covering the pathname is current, site map row or route item alike: on
`/skills/` the skill's row, on `/directions/` the direction's,
on `/d/production/enterprise` the Enterprise row and not Home. While no
item is marked (a direction page, the gallery at its top) that row
carries the rail's thumb and ink text; while an item is, it draws ink text
(`.is-current`, `aria-current="page"`), as does the page row the reader is
inside (Skills on `/skills/`). Exactly one row is
`aria-current="page"`: the current row whose own path is the pathname; a
page row the reader is inside is `"true"`.
**The list is cheap to change.** Rows are memoized on data built once per
route, so a fold renders only the rows it adds or removes, a pick renders
the rows whose state changed, and a hover renders nothing in React. Rows
are opaque in their first frame; nothing fades in on mount. A row that
opens another route prefetches it after the pointer rests on it for 80ms
or on keyboard focus, never on pointer down: the click's own navigation
follows within milliseconds, and a prefetch there fetches the route twice
and renders the arriving page twice. The index panel builds its rows on
first open.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Libraries
> The index of the componentized instruments, then the build log: every library running live with its plates and API snippets.
URL: https://www.prototemplate.com/docs/handbook/libraries
The index of the componentized instruments. The living version, with the
bodies, live plates and API snippets, is "The libraries" in the build log
that follows this index on `/docs/handbook/libraries`
(`src/app/craft/libraries.ts`; `/craft` redirects there). Keep the two in step: when an engine gains an option,
update its entry in `libraries.ts` in the same round. Once perfected these
graduate to their own repos.
| library | entry point | one line |
| ------------------ | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| horizon-field | `src/lib/horizon-field.ts` | WebGL lensing black hole; handle: setParams / pause / resume / renderStatic / destroy. Draws nothing until given a geometry (center + radius). |
| glyph-field | `src/lib/glyph-field.ts` | Canvas glyph rain, 1,280-glyph typed-array pool, Bayer-dithered far tier, matter-conserving morphs. Options: `drift: 'fall'\|'rise'`, `copy: 'auto'\|'left'\|'top'\|'none'`, `glyphScale`. A frame-time governor steps quality down (lean dpr, then the lean pool) when measured cadence proves the device can't keep up — down only, pool cuts at idle. |
| prismatic-field | `src/components/shared/PrismaticField.tsx` | The chroma wash behind dark bands; presets `'1'`/`'2'`, `exposureScale` is the dimmer. |
| dither | `src/lib/dither.ts` | CPU 1-bit renderer: any `fn(u,v,t)→0..1` through the 8×8 Bayer screen; field factories (radialBurst, globe, streakBands, gradientRamp, makeGlyphField) + combinators. |
| studio-field | `src/lib/studio-field.ts` | GPU Bayer family — the codified `BAYER_PRESETS` roster (10 variants, default `BAYER_DEFAULT_ID` = 02 bayer-8x8). Switch by remount; one shared GL context. React wrapper: `src/components/shared/StudioField.tsx`. |
| iso | `src/app/d/toolchain/diagrams/iso.ts` | The isometric kit: project/faces/silhouette for boxes, `IsoPrism` for convex plan polygons, `plane()` seats flat art, `markPath()` lays bars. |
| DitheredMark | `src/app/d/toolchain/diagrams/DitheredMark.tsx` | A masked brand mark + Bayer specular shimmer; `shineTravel()` gives drivers their tween endpoints. Worn by the tower capstone. |
| DoubledLine | `src/components/shared/diagrams/DoubledLine.tsx` | The two-thread stroke as a component; optional two-tone via half-plane clip; pulse slot between threads and core. |
| EdgeGlobe | `src/app/d/toolchain/diagrams/EdgeGlobe.tsx` | The delivery globe — ink-only orthographic sphere, five PoPs, one accent route; pairs with a static Bayer atmosphere (dossier `GlobeAtmosphere`). |
| LocaleTag | `src/app/d/toolchain/components/LocaleTag.tsx` | The one locale pill: flag print + mono code; hosts supply the box. |
| RevealSeam | `src/app/d/toolchain/sections/RevealSeam.tsx` | The slide-to-reveal slider; writes `--seam-cut`; skins are host CSS (the dossier refit is the house handle). |
| EverySentence | `src/components/shared/EverySentence.tsx` | The sentence-rewriting glyph reassembler; host-owned clock via `ref.setLocale(loc)` (calls landing before boot are buffered); `hops` sets the re-spread beats, 1–5, default 2 — the dossier hero runs 1. |
| TranslateWindow | `src/app/d/_v0/TranslateWindow.tsx` | The dossier hero's windowed demo, extracted whole so any home can mount it — and the home of the **locale belt**: an infinite conveyor of LocaleTag chips whose crossing of the strip zone's centre is the page's one clock (render and payload retype from the same dial). Hover pauses it, any interaction holds it, a click slides the picked chip to centre; `onLocaleChange` vents the active locale to hosts (the dossier headline runs on it). |
| V0FullStack | `src/app/d/_v0/sections/FullStack.tsx` | The scroll-scrubbed stack story: beats anchor on the copy block's centre taking the 55% read line, the spotlight fires early at the 80% line, and a piecewise clock holds at each lock-in (`DESIGN.md` §14). The figure is CSS sticky — JS never moves it; the mobile stage runs the svh/dvh law (§13). |
| gallery-shoot | `scripts/check/gallery-shoot.mjs` | The anatomy wall's tile factory: section-anchored element shots of the flagship (desk/mob × light/dark), theme pre-set via `localStorage['gt-theme']`, `manifest.json` written beside the tiles; a missed selector is reported, never fatal. Not a mounted engine — a harness. |
| mobile type ladder | `src/app/d/toolchain/styles.css` (the late 720px block) | The ≤720px `--tcm-*` token roster every mobile floor consumes as `var(--tcm-X, )`. Not an engine — a contract; full law in `DESIGN.md` §12. |
Lifecycle contract for every mounted instrument above: lazy mount behind an
IntersectionObserver, self-pause offscreen, one still under
`prefers-reduced-motion`, `destroy()` tears down everything the instance
owns, ink re-resolves on theme flips.
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Graphics pipeline
> How the blog illustrations are made with the toolchain in graphics/: captures, labelled crops, the sizing rules, clips, export and hand-off.
URL: https://www.prototemplate.com/docs/handbook/graphics
How the illustrations for the General Translation blog are made, from the
brief to the carousel, with the toolchain that lives in `graphics/`. It
produced the thirty-six visuals of "Designing docs for humans" and is the
procedure every post after it runs. The `gt-graphics` skill
(`skills/gt-graphics`, `/skills/gt-graphics`) carries the same rules into
agent sessions; this document is the long form.
## What a visual is [#what-a-visual-is]
One HTML page, 1600 by 900, rendered headlessly at 7680 wide and
downsampled to 3840. The page holds real screenshots of the product cut
into padded crops, labels and leader lines drawn once, and a glyphfield
export as the ground. Nothing in it is invented: every rectangle is a
measured region of a captured page, every label names something the reader
can find in the product.
The rules the set settled on, each learned from a review:
* No text except labels. No titles, captions or descriptions inside an
image; the post carries the prose.
* One idea per slide. A carousel is a set of different points; a slide
that restates its neighbour gets new content, not a new style.
* Real crops, not mockups. The one illustrative mock in the set is
labelled as a mock.
* Red for what was removed, blue for the page and what replaced it.
* No glass panels, no sparkle icons, no over-rounded boxes: the graphics
obey the same hit list the post publishes.
## Sizing [#sizing]
The article column is about 700 CSS px wide, so a 1600px stage is shown at
0.44x. Everything is sized for that, not for a full-screen viewer:
| element | size on the stage |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| any text | 26px or more after zoom-to-fit; `audit.js` fails the run below that |
| label chip | 28px Inter 600, 46px tall; tags and badges 30px, 54px and 50px tall |
| numbered dot | 56px disc, 28px numeral |
| panel header | 32px, icon 34px |
| measurement label | 28px Geist Mono on a dark backing pill |
| lines and rulers | 3px; ruler caps 18 by 3px |
| crops | 1.2x or larger; a sparse composition is zoomed to fill 90% of the frame |
| background | drawn at 2x the stage height with its own aspect and square pixels (`image-rendering: pixelated`), so a 1920 export shows as crisp 2px dots and a card is never stretched; dimmed to 36% under article visuals, full strength under covers |
| export | 3840 wide webp, quality 95; covers 3840 webp in a dark and a light version; OG 2400 by 1260 PNG; clips as 1400 wide GIFs |
| delivery | served through next/image at the column's device width (a dense `deviceSizes` ladder plus an accurate `sizes`), quality 95 |
Resolution was never the blur. At 1x the dither's one-pixel dots landed on
less than a device pixel and aliased into noise; at 2x with smooth scaling
they read as a halftone. Small labels were the other half of it.
The floor is measured after zoom-to-fit, not as declared. A composition
wider than 90% of the frame is scaled down, and its 28px labels with it, so
when the audit reports text under the floor the usual fix is to make the
composition narrower (smaller crops, shorter labels, one label column)
rather than to enlarge the type. `MIN_TEXT` in `gen-lib.js` holds the floor.
## The files [#the-files]
| path | what it is |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `graphics/build/gen-lib.js` | the primitives and the asset maps: `SHOTS` (captures with their device pixel ratio), `BG` (backgrounds), `crop`, `hl`, `tag`, `dot`, `line`, `elbow`, `badge`, `panel`, and `stage`, which wraps a visual with the fonts, the ground and the centering script |
| `graphics/build/gen-visuals.js` | the visuals, one `add()` each, the page rectangles (`N` new docs, `O` old docs), `ASSIGN` (which export each visual sits on) and `BG_WASH` |
| `graphics/build/render.sh` | shoots every visual, or the ids given, through agent-browser at 7680 and downsamples with Pillow |
| `graphics/build/export-blog.py` | writes the webp set and the GIF clips into `public/static/blogs` or `--dest` |
| `graphics/build/composite-videos.sh` | lays a recording over a still, reading the crop rectangle from the rendered page |
| `graphics/build/capture-sidebar.sh` | the stop-motion capture of the docs sidebar |
| `graphics/build/rewriting-covers.py` | both theme covers of the earlier post: keeps the published cover's ground and framing (`graphics/shots/rewriting-cover-ground.png`) and lays the light and dark captures into its page frame at one scale, so a theme switch moves nothing |
| `graphics/build/sheet.py` | contact sheets for review |
| `graphics/build/manifest.json` | the generated index of visuals: id, area, name, background, why, size, animated; `/graphics` reads it |
| `graphics/serve/server.js` | the static server on 127.0.0.1:8765; also accepts POSTs into `inbox/` for the DOM-capture trick |
| `graphics/glyph/` | the glyphfield studio scripts and Kevin's project source |
| `public/graphics/bg/` | the glyphfield exports, lossless webp identical to the PNG originals: `user/` the palette, `blue/` the blue duotone and light variants; `graphics/bg` links here so the toolchain and the site read one set |
| `graphics/shots/hi/` | the product captures at 3 to 5x, lossless webp |
| `graphics/fonts/` | Inter and Geist Mono variable |
| `graphics/rec/` | the recordings the two clips composite from |
Generated folders (`graphics/build/visuals/`, `graphics/out/`,
`graphics/rec/stopmo*/`) are ignored by git; everything in them comes
back from the scripts.
## Procedure [#procedure]
1. Install once: `pnpm install` at the root (heroicons for the label
icons), `pip install pillow`, and `agent-browser` and `ffmpeg` on the
PATH.
2. Serve: `pnpm graphics:serve` keeps `graphics/` on port 8765.
3. Capture sources into `graphics/shots/hi/` (see "Capturing") and
register them in `SHOTS` with their density.
4. Measure the rectangles you will cut, in CSS px at 1440 by 900, into
the page objects in `gen-visuals.js`.
5. Write each visual as one `add(id, area, name, bg, why, () => html)`.
Assign it its own export in `ASSIGN`.
6. `pnpm graphics:gen` writes the HTML and the manifest;
`pnpm graphics:audit [ids]` measures every text against the floor and
lists overlapping boxes (fix the failures, judge the warnings);
`pnpm graphics:render [ids]` shoots them; `python3
graphics/build/sheet.py [ids]` tiles them for review.
7. For a clip, record (see "Clips"), then `graphics/build/composite-videos.sh`.
8. `pnpm graphics:export` writes the webp set and GIFs into
`public/static/blogs`; `--dest` points at a landing checkout. Bump the
`?v=` stamp on every reference in the post.
9. Check the set on `/graphics` and the post on `/blog`.
10. Let the page serve each image at the width it is shown. The masters
are 3840px wide and the column is about 700 CSS px, so a browser left
to shrink them itself blurs them (measured: about an eighth of the
edge contrast on a 2x screen, none for a variant at the device width).
Every blog image goes through `next/image` with the column's `sizes`
and the dense `images.deviceSizes` ladder in `next.config.ts`, at
quality 95; clips are cut at 1400px, the column's 2x width.
## Capturing [#capturing]
Sources come from a landing dev server built from `main`, captured with
agent-browser at a device pixel ratio of 4 or 5 at 1440 by 900, the
Next.js dev portal hidden, the pointer parked on plain text. Themes come
from `agent-browser set media light|dark`; the docs follow the preference
when no theme is stored. Menus open with their real control. The old docs
lived on an SSO-protected Vercel preview; those were captured by
serializing the DOM from a signed-in Chrome to the local server and
screenshotting the saved page. Convert captures to lossless webp; the
library reads webp sizes.
## Backgrounds [#backgrounds]
The exports are Kevin's glyphfield project, rendered headlessly through
`window.glyphfield.studio` (`graphics/glyph/gfexport.sh`). The generator
draws one export per visual at exactly 2x the stage and dims it under
article visuals; covers keep the full export. Blue duotone variants carry
the covers. Every cover has a light-theme twin (`light: true` on
`coverExploded` and `coverWiremap`): the same ground and scale, the docs
captured in their light theme, the wireframe plate in paper and ink. The
post lists the light cover under `imagesLight` and the blog shows the one
for the reader's theme.
## Clips [#clips]
The recorder keeps one or two frames per second at 4x, so interactions
are captured as stop-motion: pause the Web Animations, step `currentTime`
between screenshots, assemble with ffmpeg at variable frame durations.
Screenshots re-fire trusted pointer events on the last clicked element, so
the capture blocks real pointer events in the region and drives hovers
synthetically. The composite reads the crop rectangle from the rendered
visual, overlays the clip, and writes a 30fps MP4 master and the GIF the
post embeds: 1600 wide, 256 colours, sierra dither, rectangle diffing.
## Handing off to a post [#handing-off-to-a-post]
The post embeds the set with the `Carousel` and `HitList` MDX components
of the landing blog (children with string attributes; the blog's MDX
renderer strips expression props). Covers ship as 3840 webp and the OG
image as a 2400 by 1260 PNG; the landing app serves webp covers at
quality 95, because dithered artwork smears at the default 75. Posts live
in the `generaltranslation/content` submodule, so a change is two pull
requests. When the post needs anything from gt-cloud (a new MDX component,
images under `public/static/blogs/`, redirects or navigation entries),
the gt-cloud pull request merges first and the content pull request
second; in the other order the post publishes with missing images or a
failed build. The content repository's preview app needs a simple
version of every component or its build fails. `gt-website`
(`references/blog.md`, read against gt-cloud main on 2026-10-05) holds
both rules. This repository keeps the
authoritative copy of the three docs-redesign posts under `content/blog`
and their graphics under `public/static/blogs`, read by `/blog` and
`/graphics`.
## Where it went wrong, and the fix [#where-it-went-wrong-and-the-fix]
* A captured Lucide glyph is a `` plus a path (copy, sidebar). The
inliner used to strip `width`/`height` from every element, so the rect
collapsed and only a corner path drew. It now resizes the root tag only.
* With the static server down, `render.sh` shot Chrome's error page and the
export shipped it. The render now skips a page that never centres.
| symptom | cause | fix |
| ----------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------- |
| "pixelated" cover | 1x dither aliasing, plus the optimizer re-encoding at quality 75 | 2x smooth background; webp cover at quality 95 |
| "blurry" diagrams | 12px labels at 0.44x | labels 26px, lines 3px, zoom-to-fit |
| lines clipped | 1px rules and 1.5px caps under a device pixel | 3px everywhere, labels on backing pills |
| hover pill jumped after every click in the clip | screenshots re-fired trusted pointer events | block real pointer events; synthetic hovers |
| carousel prop `items` undefined | next-mdx-remote strips expression props | child elements with string attributes |
| content preview build failed | unknown component | stub every component in `apps/content` |
| PR policy failed | `feat` title without a Linear issue | `docs(blog)` title, or link the issue |
---
The index of every page on this site, for agents: https://www.prototemplate.com/llms.txt
# Artifact pictures
> The standard for the dithered photographs: the rules, the Blue Marble tone grid and screen, the cutter, adding a picture and its lint.
URL: https://www.prototemplate.com/docs/handbook/artifact-pictures
An artifact picture is a photograph or scan of an object, artwork or place,
screened through the house dither. In this repository they appear in three
places:
| Surface | Pictures |
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| The plate port's field (`src/components/plate`) | earth, rosetta, calligraphy, tablet, gloss |
| The brand deck's mood slides (`deck/`) | earth, rosetta, tablet, calligraphy, lighthouse, devanagari, gloss, cable, wave, compass |
| The transition demo on /docs/handbook/libraries (`src/app/craft`) | earth and rosetta, the deck's grids |
On the plate port, the onboarding steps show earth, rosetta, calligraphy and
tablet, the OAuth consent states show rosetta, the device flow shows
calligraphy, and the CLI wizard shows gloss (`gallery/devStates.ts`), as on
the dashboard.
Procedural fields (the sign-in globe, the ramp), marks, glyph fields, the
deck's shader openers and blog covers are not artifact pictures, and these
rules do not apply to them.
The same standard covers gt-cloud's dashboard sign-in and onboarding field
(`.agents/skills/artifact-pictures` there). `standard.json` and
`mood_tone.py` are the same files in both repositories.
## Files [#files]
| File | Role |
| -------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `scripts/media/mood-tone/standard.json` | The standard: screen, tone, file sizes, windows, retired names |
| `scripts/media/mood-tone/mood_tone.py` | The cutter (Python 3 with Pillow) |
| `scripts/media/mood-tone/mood-tone.mjs` | The recipes for the deck and plate sets, and the wrapper |
| `deck/shots/tone/mood-{name}.jpg` | The deck's tone grids |
| `deck/shots/tone/manifest.json` | One entry per deck grid, written by the wrapper |
| `public/brand/mood/mood-{name}.jpg` | The plate's tone grids, the same bytes as gt-cloud's |
| `public/brand/mood/manifest.json` | One entry per plate grid, written by the wrapper |
| `public/craft/mood-{earth,rosetta}.jpg` | Byte copies of the deck's earth and rosetta grids for the transition demo on /docs/handbook/libraries |
| `src/app/craft/CraftArticle.tsx` | The text around the transition demo, with the demo's credit line |
| `src/components/plate/brand/moodPictures.ts` | The plate registry: src, placement and caption per picture |
| `deck/slides/NN-mood-{name}.html` | The deck's mood slides, one canvas per grid, with the credit |
| `deck/parts/tail.html` | The deck engine that screens the grids |
| `scripts/lint/pictures.mjs` | The lint |
## The rules [#the-rules]
### 1. No plain English prose [#1-no-plain-english-prose]
A picture may not be a page of readable English: dictionary entries, book
pages, documents, signs or captions. That text reads as copy and distracts
from the form beside it.
Writing is welcome when it is the artistic or design subject of the object:
carved inscriptions (the Rosetta Stone), calligraphy, manuscripts in other
scripts or old hands (Devanagari, the gloss), signs pressed in clay (the
tablet), and the lettering engraved on a historical chart or instrument (the
cable chart, the compass rose).
Each recipe declares `writing: 'none' | 'artistic'`. The cutter's text-line
detector counts rows of six or more letter-sized marks and records the count
as `textLines`. A picture with any text lines must declare `'artistic'`. The
detector cannot read meaning, so a reviewer checks every `'artistic'`
declaration against this rule. Plain English prose never qualifies.
### 2. Sources [#2-sources]
* Cut from the original scan or photograph. Never cut from a screened,
two-tone or resized copy.
* The license is public domain or Creative Commons, taken in this order:
public domain and CC0 first (Wikimedia Commons public domain files and
the open-access collections of the Met, the Smithsonian, the Cleveland
Museum of Art, the Rijksmuseum and the Library of Congress), then CC BY,
then CC BY-SA only when nothing else shows the object. A CC BY-SA print
is a derived work under the same license, and its credit says so.
Non-commercial (NC) and no-derivatives (ND) licenses are refused, so
the British Museum's images, which carry a non-commercial license, are
refused.
* The subject is the original object. A cast, a replica or a modern
reprint is refused when the original can be shown. A picture shows no
flag, emblem or coat of arms, no map with borders, no caption that
states sovereignty, and no private person. The license order and these
subject rules come from the artifact pictures of the language map
(gt-cloud branch `k/language-map`, 2026-10-03).
* The credit is shown with the picture: on the deck slide's plate, in the
picture's caption in `moodPictures.ts`, which the plate port's field shows,
and in the credit line under the transition demo on /docs/handbook/libraries
(`CraftArticle.tsx`). The demo's line carries the deck slide's credit for
each picture the demo shows, without the label ("Image:", "Photograph:").
The lint checks the deck slides and the demo's line.
* Sources are never committed. Each person keeps a sources directory and
passes it to the wrapper. `scripts/media/mood-tone/README.md` lists each file's
name, origin, pixel size and sha256, and the wrapper refuses a source whose
sha256 differs from `SOURCES` in `mood-tone.mjs`.
### 3. The tone grid is the Blue Marble's [#3-the-tone-grid-is-the-blue-marbles]
The Blue Marble on the onboarding field is the reference. Its numbers are in
`standard.json` under `tone`.
Fixed for every picture:
* no blur;
* gamma 1.2;
* autocontrast that clips 0.5 percent at each tail, over the frame, or over
the subject mask for a masked object;
* an 8-bit gray JPEG at quality 82, or 75 when 82 is over the cap.
Chosen per picture, in the recipe:
* the crop;
* the channel: `red` (the earth's) or `gray`;
* the polarity: `invert` so the subject is lit on a black ground;
* the kind: `scene` or `marks`.
Solved per picture by the cutter, never set by hand: the black and white
points.
* A **scene** lands on the Blue Marble's mean tone 0.361 and standard
deviation 0.342, over the region of the grid that is shown.
* **Marks** (writing, engraving, lines on a plain ground) put the ground at
black with an Otsu threshold and the 90th percentile of the marks at white.
The solver returns levels 80 and 230 for the plate's earth, which is the
earth's own recipe.
Sizes: a cover is 1600 by 900, one grid cell per CSS px at a 1440 by 900
view. A disc is 2400 by 1350. The cap is 560 KB (573440 bytes).
### 4. The screen is the Blue Marble's [#4-the-screen-is-the-blue-marbles]
`standard.json` under `screen`:
* an ordered 8x8 Bayer matrix with threshold `(m + 0.5) / 64`;
* cells of 1 CSS px, screened live at display size. Never ship a pre-screened
bitmap that is then scaled;
* tone floor 10: bytes at or under 10 read as 0;
* the loop runs at gamma 1 and bias 0, because the whole curve is in the grid;
* dark theme: white cells at opacity 0.62 over the #070707 ground. Light
theme: #070707 cells at opacity 0.7 over white.
Where each surface states these:
| Surface | Cell | Tone floor | Bayer and threshold | Ink and opacity |
| ----------------------------- | ---------------------------------------- | -------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Plate port | `PICTURE_SCALE` in `FieldStack.tsx` | `TONE_FLOOR` in `lib/picture-field.ts` | `BAYER_8` in `lib/dither.ts` | `--tc-picture-ink`, `--field-picture-opacity` in `plate.css` |
| Deck | `MOOD_CELL_PX` in `deck/parts/tail.html` | `MOOD_TONE_FLOOR` in `tail.html` | `bayer8` in `tail.html` | `--mood-ink`, `--mood-opacity` in `deck/parts/head.html` |
| /docs/handbook/libraries demo | `CELL` in `TransitionDemo.tsx` | `TONE_FLOOR` in `TransitionDemo.tsx` | `BAYER_8` in `src/lib/dither.ts` | `--ptc-picture-ink`, `--ptc-picture-opacity` in `craft.css`, the dark values, because the plate is dark in both themes |
The deck engine sizes each mood canvas's backing store to its box on screen
(`getBoundingClientRect`, because the stage is CSS-scaled), so a cell is 1
CSS px on the sheet, in a thumbnail, in the book view and on the full-stage
backdrop. It reads the grid at cover fit, centred, and draws again on slide
activation, resize and a theme flip.
### 5. The windows [#5-the-windows]
The cutter measures each grid over the region shown (the deck's full 1600 by
900 sheet; on the plate, the part right of the ramp at 1440 by 900; only the
disc or the masked subject where there is one) and records the stats in the
manifest. The lint holds them to `standard.json` under `windows`:
| Kind | Mean | Std | At white (250 and up) | At the floor (10 and under) |
| ----- | ------------ | ------------ | --------------------- | --------------------------- |
| scene | 0.30 to 0.42 | 0.28 to 0.44 | at least 2% | at least 5% |
| marks | at most 0.35 | any | at least 0.5% | at least 50% (the ground) |
## The cutter [#the-cutter]
From the repository root:
```sh
pnpm mood-tone [--set deck|plate] [--preview ] [--check]
```
The wrapper sends the recipes and the standard to `mood_tone.py`, which
writes `mood-{name}.jpg` for each recipe (the deck set to `deck/shots/tone`,
the plate set to `public/brand/mood`) and prints one manifest entry per
picture. The wrapper writes those entries to `manifest.json` and prints each
picture's levels and stats. With `--preview`, the cutter also saves the 1 px
screen of each grid at the view size as `preview-{name}.png`.
The cutter is deterministic: a run on the same sources writes the same
bytes. A grid's `sha256` ties the file to its manifest entry, and the lint
checks that. It does not show that the entry came from the recipe: an entry
edited by hand next to an untouched grid passes the lint. Only `--check`,
run with the sources, proves that. It cuts into a temporary folder and fails
unless every grid and the manifest equal the committed files byte for byte.
The lint cannot run it, because the sources are not committed. Never edit a
grid or a manifest by hand.
A recipe holds only: `name`, `source`, the size and cap from `standard.json`,
`crop`, `channel`, `invert`, `kind`, `writing` and `placement`. It holds no
tone numbers. The crop kinds are documented above `DECK` in `mood-tone.mjs`.
## Adding a picture [#adding-a-picture]
1. Choose the object against rule 1. Find the original scan or photograph and
confirm its license (rule 2).
2. Put the source file in your sources directory, add its origin and sha256
to `SOURCES` in `mood-tone.mjs`, and add its row to the source table in
`scripts/media/mood-tone/README.md`.
3. Add a recipe to `DECK` or `PLATE` in `mood-tone.mjs`. Spread `COVER` for a
cover. Set `kind: 'marks'` for writing or engraving on a plain ground and
`kind: 'scene'` for anything else. Declare `writing`. A deck recipe's
placement is a cover at focus 0.5, 0.5.
4. Run the wrapper with `--preview` and look at `preview-{name}.png`.
5. If the subject is not where it should be, or the stats miss the window,
change the crop, the channel, the polarity, the kind or the placement and
run it again. If no crop puts a scene in its window, the picture does not
meet the standard. Do not add tone settings to make it pass.
6. Show it.
* On the deck: add `deck/slides/NN-mood-{name}.html` from an existing mood
slide, with `