The component library
Prototemplate's live component library: every instrument mounted on its page with controls, its import path, its props and its reduced-motion still.
These pages mount the real components of the hub: the dithered fields, the light fields, the glyph rain, the doubled line, the isometric kit, the globes, the locale chips, the moving text, the marks and the heads. Every plate is the component itself, running, with controls for its props. Each section gives the import path, the props, when to use the component and what it does under reduced motion. The plate below is the studio field, the dithered material of the landing hero, with its ten presets.
The pages
The pages sit in ten groups, as the sidebar shows them: the instruments first (fields, the dither lab, drawings, 2D and 3D), then the pieces a reader handles (interactables, language and motion, marks and heads), then what the system makes and where it puts it (artifacts, page layouts, pages). Each card names the components its page mounts.
Fields
Dither and the studio field
The ordered Bayer screens, the CPU dither loop and its field factories, the ten studio field presets.
Horizon and prismatic fields
The event-horizon shader and the prismatic burst, with their cursor effects.
Glyph field and ink field
The eight-script glyph rain, the ink field and its pointer play.
Dither lab
The dither lab
Ordered dither, error diffusion and halftone side by side on pictures, gradients and noise, or a picture you drop in.
Dithered type and marks
Words and marks set in dither cells, a mark that erodes and resolves, and a screen of characters.
Dithered transitions and brushes
Tone-mix wipes on one grid, a lens under the pointer and a brush that paints in cells.
Drawings
Doubled lines and connectors
DoubledLine with its pulse, and TranslationFlow, the connector in production.
Isometric drawings
The isometric kit: boxes, prisms, faces and a seated mark, with the numbers that make separate drawings one set.
Globes and maps
EdgeGlobe, the dithered globe field, the blog globe figures in all three rounds.
The blog globe figure
Four directions for a blog figure that turns a globe along the path of Euclid's Elements, with all three rounds live and their ranking.
2D and 3D
3D scenes
three.js scenes through a Bayer post pass: an extruded GT mark, a lit globe and an isometric stack.
2D canvas pieces
Particle fields, generative lines and glyph rain on canvas 2D, each with its frame budget.
Interactables
Controls
Segmented switches, toggles, sliders, steppers, the install field and copy buttons, with every state.
Search, filters and menus
The command search, the list filter, the language selector, the help card and the toast.
Kinetic text and carousels
Split-flap text, the language wheel and the carousel, with their timing and stills.
Language and motion
Locale tags and language pieces
LocaleTag against LocaleFlag, and the seven language diagrams.
Reveal seam and sentence motion
RevealSeam and EverySentence.
Marks and heads
Speed marks and the GT mark
The speed marks and the globe concepts, GtWord and gtText(), DitheredMark.
Badges and heads
BadgeCycle, badgeMark() and BookHead.
Artifacts
Live artifact pictures
Dithered photographs under the Blue Marble standard, screened live from their tone grids.
Covers and social cards
Post covers, social cards and banners generated from a title and a field at their export sizes.
Films and contact sheets
The film player, scrubbable contact sheets and the report card.
Page layouts
Rails, bands and spacers
The landing grammar as parts: a page skeleton built from bands at any width from 390 to 1440.
Grids and bentos
Bento and feature grids with columns, gaps and spans to adjust, lines drawn once at each junction.
Shells and frames
The viewer shell, the sheet frame and the plate, taken apart region by region.
Pages
Page gallery
Every shipped page live in a frame at the desktop and the phone width, in both themes.
Page templates
The book page, the docs page, the article and the error page, each with an anatomy overlay.
Every component
| Component | File | Client | Page |
|---|---|---|---|
createDitherLoop and the field factories | src/lib/dither.ts | yes | Dither |
BAYER_8, BAYER4 | src/lib/dither.ts, src/app/d/toolchain/diagrams/DitheredMark.tsx | no | Dither |
StudioField, createStudioField | src/components/shared/StudioField.tsx, src/lib/studio-field.ts | yes | Dither |
createHorizonField | src/lib/horizon-field.ts | yes | Fields |
PrismaticField, createPrismaticField | src/components/shared/PrismaticField.tsx, src/lib/prismatic-field.ts | yes | Fields |
createGlyphField | src/lib/glyph-field.ts | yes | Glyph field |
createInkField | src/app/d/glyph-rain/sections/band/inkField.ts | yes | Glyph field |
DoubledLine | src/components/shared/diagrams/DoubledLine.tsx | no | Lines |
TranslationFlow | src/app/d/toolchain/diagrams/TranslationFlow.tsx | yes | Lines |
The isometric kit, IsoFrame | src/app/d/toolchain/diagrams/iso.ts, IsoFrame.tsx | no | Isometric |
EdgeGlobe | src/app/d/toolchain/diagrams/EdgeGlobe.tsx | yes | Globes |
globe() | src/lib/dither.ts | yes | Globes |
GlobeFrame | src/components/blog-globe/GlobeFrame.tsx | yes | Globes |
LocaleTag | src/app/d/toolchain/components/LocaleTag.tsx | no | Language |
LocaleFlag | src/components/shared/LocaleFlag.tsx | no | Language |
| The language diagrams | src/app/d/toolchain/diagrams/lang/ | yes | Language |
RevealSeam | src/app/d/toolchain/sections/RevealSeam.tsx | yes | Motion |
EverySentence | src/components/shared/EverySentence.tsx | yes | Motion |
MARKS, GLOBE_CONCEPTS | src/lib/marks.ts, public/marks/ | no | Marks |
GtWord, gtText, GtMark | src/components/viewer/GtWord.tsx, src/components/viewer/GtMark.tsx | no | Marks |
DitheredMark | src/app/d/toolchain/diagrams/DitheredMark.tsx | no, the host animates | Marks |
BadgeCycle, badgeMark | src/components/viewer/BadgeCycle.tsx | no | Heads |
BookHead | src/components/viewer/BookView.tsx | yes | Heads |
Client means the module is a 'use client' component or a canvas engine that needs the DOM. The rest render on the server and ship no JavaScript of their own. Several components live in src/app/d/toolchain, the direction that the later directions fork. The radius, type and oxlint gates skip that folder, and the site imports the components from there.
The lifecycle every instrument keeps
- Mount late. A canvas or WebGL engine starts when its plate comes within 180 pixels of the viewport, through one IntersectionObserver that disconnects after it fires.
- Pause when unseen. From then on the engine pauses itself when it leaves the viewport and when the tab is hidden.
- Draw one still under reduced motion. With
prefers-reduced-motion: reducean engine draws one designed frame and schedules no animation frames. A Still control on a plate shows that frame without changing the system setting. - Release on unmount.
destroy()disconnects every observer and listener. The WebGL contexts of the studio, horizon and prismatic fields persist for the session, one per engine, because a context per mount exhausts the browser's budget. - Follow the theme. The theme is
html[data-theme]. An engine reads its ink from a custom property and reads it again when the attribute changes; an SVG drawing readscurrentColorand the tokens.
The fields tuned to an ink ground, the studio, horizon, prismatic and ink fields, sit on an ink plate in both themes. Everything else follows the docs theme.
The numbers behind it
The browser keeps a fixed budget of live WebGL contexts, and a page that runs past it gets a black canvas and no error in the console. The lifecycle above keeps every page inside that budget, and these numbers set it.
| Number | Value | What it decides | Where it is held |
|---|---|---|---|
| Live WebGL contexts in Chrome | about 16 | Past the budget getContext returns null and a field draws black. On 2026-07-29 a direction's shader rendered on a fresh load and was black after 12 client-side switches between directions. | One module-level engine per engine type, each drawing into one offscreen GL canvas and blitting into every mount's 2D canvas: src/lib/studio-field.ts, horizon-field.ts, prismatic-field.ts |
| Contexts per engine module | 1 for the session | The context survives a mount's destroy(), so route changes never create another. | The same three modules |
| Contexts a probe may create | 0 | A probe that calls getContext on the page's canvases to count them creates contexts and exhausts the budget it measures. | Wrap getContext before the page's scripts run, or screenshot after real navigation |
| Contexts a component may leak | 0 | A component that owns its context deletes its buffer, its program and both shaders, then calls WEBGL_lose_context.loseContext() on unmount. A footer mark that skipped this leaked one context per mount (2026-08-08). | The component's own cleanup |
| Arm margin | 180 px | A lazy plate mounts its engine when it first comes within 180 px of the viewport. A plate the reader never scrolls near never starts its engine. | rootMargin: '180px' in src/components/docs/demos/hooks.ts |
| Live previews on one page | stills until hover | 22 live iframes running shaders made the presenter wall lag (2026-07-31). A gallery that froze each frame 2.8 s after load still held 12 live pages, 4 WebGL contexts and about 1.3 GB of renderer memory, and stayed busy about 950 ms of every second at rest (2026-10-08). A frozen same-origin frame still hydrates, composites and runs its CSS animations on the parent's main thread. | src/app/present/viewer/LazyFrame.tsx shows a thumbnail and mounts the live page only while a mouse is over the card |
| An off-screen live stage | about 110 ms of every second | The presenter's live prototype stage cost that much through the slides before it, so it is frozen whenever no part of its section is on screen. | The rAF gate in src/app/layout.tsx, driven by postMessage({ type: 'gt:freeze', frozen }) |
The rAF gate wraps requestAnimationFrame only, so a loop on setInterval or setTimeout keeps running inside a frozen preview. Canvas and WebGL engines explains each of these with the shared canvas that only grows, the readback canvases, zoom and the quality governor.
Mounting a component in a docs page
A docs page imports a component at the top of its MDX file and renders it as JSX. The page and its MDX are server components, so a component with state, a canvas or GSAP must be a 'use client' module. fumadocs-mdx imports every docs page into the one /docs/[[...slug]] route, so a plate imported directly would put its code and its stylesheets into every docs page's first load. The pages therefore import their plates from src/components/docs/demos/lazy.tsx, which wraps each one in next/dynamic: the server still renders the plate, and its chunk and CSS load only on the page that shows it.
import { StudioFieldDemo } from '@/components/docs/demos/lazy';
The plate runs the studio field with its ten presets.
<StudioFieldDemo />Put a sentence beside every plate that says what it shows. The Markdown twin of the page and /llms-full.txt drop the import and keep the plate as a bare tag, such as <StudioFieldDemo />, so the sentence is what a reader of the twin gets.
The plates on these pages are built from one small kit in src/components/docs/demos/:
| Part | What it does |
|---|---|
Plate | The card: the stage, the entry point's name in its corner, and the controls row. night pins the stage to ink, lazy mounts the children when the plate nears the viewport, fit takes the content's height, and moves adds the reduced-motion note. |
Choice, Range, Toggle, Action | The controls: a radio group drawn as a segmented row, a range with its value, a pressed button and a plain button. |
useArmed, useReducedMotion, useTheme, readToken, useReplay | The lifecycle hooks behind the list above. |
lazy.tsx | Every plate wrapped in next/dynamic, with a fallback at about the plate's height for a client navigation. A new plate gets its line here. |
The build log
The handbook's Libraries document indexes the same instruments and ends with the build log, where every library runs with its plates and API snippets.