Making templates
Make templates the way PopCraft's own are made: every official template's source to start from, the Kit and every style system, the build, every check the gallery's templates pass, the gallery's pictures, and publishing to your account.
Making templates
Every template in PopCraft's gallery is a source file written with the Kit, built, checked and pictured by a pipeline.
All of it is public. @popcraft/kit ships:
- Every official template's source, all 1,275 of them, to read and to start from.
- Every module they are made with: the Kit, the helpers, the twelve SaaS style systems, the fifty-odd theme kits, the comic and anime engines, the Lottie kit, 3D devices and stages, and the music library.
- The build, which finishes a template exactly as the official build does.
- Every check the official templates pass in PopCraft's own test suites.
The command line runs that pipeline in one command. It also adds two things PopCraft's own authoring never had: a searchable catalogue to start from, and a review render of every size, moment and brand kit.
This page is for people and coding agents alike. An agent should read it, then Designing with an AI agent for the look-and-fix method, and the design reference for the Kit.
Twenty-five of them, one or more in every format, are set up as a ready project in
getpopcraft/examples/templates: clone it, npm install,
npm run check.
Set up
mkdir my-templates && cd my-templates
npm init -y && npm pkg set type=module
npm i @popcraft/kit
npm i -D @popcraft/cli puppeteer # puppeteer: the pictures and the review are drawn by the appNode 24 or later runs TypeScript sources as they are, so a template is a plain .ts file.
Start from the best match
npx popcraft template list black friday countdown # best matches first
npx popcraft template list --format reel --platform tiktok --use-case launch --animated
npx popcraft template new templates/spring-sale.ts --from motion-promo-sale-drop
npx popcraft template new templates/hours.ts # a starter that already passes every check--from copies the official source as written, points its imports at the kit (@popcraft/kit/templates/…,
@popcraft/kit/lib/…) and gives it your id. To read any official source first, look in
node_modules/@popcraft/kit/src/templates/. The catalogue, with each template's file and listing, is
node_modules/@popcraft/kit/dist/templates/index.json.
A source
import { Kit, preset, type Cue } from '@popcraft/kit/templates/kit'
import { defineTemplate } from '@popcraft/kit/templates/build'
import { pill, postVariants, outro } from '@popcraft/kit/templates/social/shared'
import { media } from '@popcraft/kit'
const cues: Cue[] = [
{ layer: 'Headline', preset: 'rise-in', at: 300 },
outro(['Headline'], 5900),
]
export default defineTemplate({
id: 'spring-sale', // yours, and stable: publishing again updates the template
meta: {
name: 'Spring sale post', description: 'What it is for, in a sentence.',
category: 'animation', tags: ['sale', 'spring'],
platforms: ['instagram'], formats: ['post', 'story'], useCases: ['sale'],
created: '2026-10-04', updated: '2026-10-04',
},
motion: { cues, loop: true }, // the cues it plays, so every one is checked at every size
stableNumbers: true, // builds the same file on every machine
build() {
const k = new Kit('Spring sale post', preset('ig-post'))
k.brand({ paper: '#FBF6EE', text: '#2A1E14', primary: '#9A3412', onPrimary: '#FFFFFF' })
// … styles, components, stacks, your own picture: k.image(parent, media('assets/shot.png'), 600, 400)
k.cues(k.sheet, cues)
k.variants(k.sheet, postVariants({ portrait: 96 }))
return k.finish()
},
})What a source can say is the same as an official one:
| Field | What it does |
|---|---|
id, meta | Its id and listing. category must suit the design's kind; platforms, formats and useCases come from the gallery's vocabulary (TEMPLATE_CATEGORIES, TEMPLATE_PLATFORMS, TEMPLATE_FORMATS, TEMPLATE_USE_CASES). Whether it plays, how long and at what frame rate come from its timeline. |
motion | The motion as data: { cues, counts, swaps, loop, components } for one sheet, { slides } for a deck, { scenes } for a film in scenes. With it, the checks verify every cue on its curve, every count and swap, every scene boundary and transition, every click build, and that a loop closes. |
breakpoints | A web page's copies are its laptop, tablet and phone sizes. |
sequence | The sheets are one ordered document (a deck, a booklet), not sizes. |
stableNumbers | Every fraction held to a millionth, so the file is the same on every machine. |
Your own pictures and sounds. media('assets/file') returns the media:// reference for an image fill or a
timeline's audio. The build writes the file beside the template, and pictures and publishing take it from there.
PopCraft's music library is already there: @popcraft/kit/templates/audio/media names every track, and the music
helpers (templates/music/shared, beat) time cuts to its beats. A build that needs a track fetches it from the app
once, into ~/.cache/popcraft/media.
Your own fonts. k.font(family, media('fonts/Brand.ttf'), { weight, style, face }) puts a font file in the
template, and a text style set in that family uses it: k.textStyle('Title', { size: 64, fontFamily: 'Brand' }).
Register one face per weight and style; face chooses a face of a collection (.ttc), from 0. A file URL
(new URL('./fonts/Brand.ttf', import.meta.url)) works as well as media(); a web address does not, since a
template carries its files and does not fetch them. Text is measured in the font as it is laid out (TrueType,
OpenType and collections; a WOFF2 is measured in the stand-in face), the build ships the file with the template, and
every file made from the template carries it. Only use a font whose licence lets you share it this way.
What to build with. Read the shared modules before writing your own:
templates/shared/*: drawing, marks, motion recipes, captions, cursors, windows, devices, type pairs.templates/web/shared: responsive pages.templates/web/shop-shared: storefronts a Next.js Commerce store renders:standardStore(config)makes a whole store (home with a carousel, search, a page per category and per product, the cart, or a one-product launch), andproductGrid,carousel,categoryChipsand the page builders compose your own. Their products, cart and menu are collections with a commerce schema, exported as a storefront (a Next.js Commerce store, or with the Ecommerce plugin a Shopify theme). The Fieldwork, Kiln and Ode templates are the worked examples.templates/social/shared: post and feed variants, outros and pills.templates/saas/*: twelve complete visual languages (bento, brutalist, editorial, glass, Swiss, terminal and more), each with its own shared module.templates/themes/*-shared: the theme kits (gothic, noir, art deco, Bauhaus, risograph, solarpunk, the holiday sales and more).templates/anime,templates/game,templates/motion3dandtemplates/lottie/lottie-kit: the comic and anime engines, game UI, 3D devices and stages, and Lottie-exportable motion.
Build, check, look, picture, publish
npx popcraft template check # every source under templates/: build, then every check
npx popcraft template look templates/spring-sale.ts # render every size at rest, at four moments, under two brand kits
npx popcraft template pictures # the gallery's thumbnail, detail still and hover loop
POPCRAFT_TOKEN=pop_… npx popcraft template publish # all of the above, then upload to your accountEach source builds into build/<id>/:
| File | What it is |
|---|---|
template.json | What your account takes |
media/ | Your own files |
<id>.popcraft | A file to open in PopCraft and look at |
look/<size>/ | The review pictures |
pictures/ | What the gallery shows |
The checks are the ones PopCraft's own test suites run over every official template:
| Check | What it holds a template to |
|---|---|
practice | Brand colour roles (three or more); text styles; components and instances; leaves in auto layout, never at picked coordinates; every text on a style and a brand role; every solid fill on a brand variable; no unused style; print sheets as columns; prototypes wired. |
contrast | AA contrast for every text against what is really painted under it. |
text-size | Type above its kind's floor. |
safe-area | Words clear of what TikTok, Reels and Shorts draw over a vertical video. |
trim | Print words an eighth of an inch inside the trim. |
end-screen | A YouTube end screen's element slots left empty. |
motion | Every size has a rated timeline that its keys fit inside, and no dead curves. With motion data, every cue plays on its preset's curve, counts and swaps read right, scenes and transitions fall where their formulas put them, builds wait for their clicks, loops close, and the clip runs as long as its kind should. |
layout | Measured with real type, every text holds its lines and every instance fits its content. |
hug | Every container set to hug is as wide as its content. |
responsive | A web page changes on a tablet and a phone, and the exported page carries both rules. |
brand | Re-skinned by a light and a dark brand kit it holds AA; under long names and a serif pair its words still fit; a logo slot takes a kit's logo. |
editability | Everything it uses can be changed with the editor's own controls. |
page | Every frame fits what a graphics card can picture. |
The checks measure. They cannot judge composition: run template look and look at every picture, name what is wrong,
fix it and look again, as Designing with an AI agent describes.
From code
The command line is a thin layer over the kit. The same pipeline from a script:
import { prepareFonts, buildFromSource, checkTemplate } from '@popcraft/kit'
import source from './templates/spring-sale.ts'
import { readFileSync } from 'node:fs'
await prepareFonts([readFileSync('./templates/spring-sale.ts', 'utf8')]) // real type before anything is laid out
const template = await buildFromSource(source) // the official build; fetches any PopCraft music it uses
const issues = await checkTemplate(template, { source })Templates you publish land private in your account's template gallery; list one publicly from the gallery.