Write a template. Ship it. Earn your tile.
A m0saic template is a TypeScript function that returns a document: a layout string, one source per tile, and typed props the editor turns into controls. Here is the path from nothing to a template of your own that renders — and how to hand the typing to a coding agent while you get on with something else.
Render something in your terminal
The CLI is the engine. setup fetches the pinned ffmpeg once; hello-world renders the first template — the Mosaic Home screen saying hello — and prints a link that opens the same template in Mosaic Web.
Clone the curriculum and render a lesson
m0saic-template-repo-starter is ~80 minimal templates, one concept each, in reading order: the layout string, props, controls, media, connections, quality. Its dist/ is committed, so a clone renders with no build step. --template-repo points the CLI at the folder.
Make one of your own
m0saic-template-repo-starter-base is the clean scaffold: one pack, one hello-world, the build and the gates, nothing else. Rename the repo id in src/repo.ts, edit the template, and verify runs the same checks a reviewer would — it renders your defaults, checks every displayed prop is bound, and measures the layout against its own canvas.
The hello-world you get is the same card every m0saic repo ships — the field, the M, the wordmark — with your subline under it. It is your repo’s front door: m0saic hello-world --template-repo . renders it, and repo.helloWorld in src/repo.ts is where you point at your own template instead once you have one.
// src/basics/hello-world/v1/hello-world.ts — your repo's front door
const card = defineHelloWorldTemplate({
id: "@my-templates/basics/hello-world/v1",
subline: `by ${TEMPLATE_REPO.displayName}`, // the one line that is yours
});Hand the typing to an agent
Both repos ship AGENTS.md: the contract a coding agent reads first. It points the agent at the machine index instead of crawling src/, names the loop — npm run build, npm run verify, node tools/check-registry.mjs --json — and says which files are generated and must never be hand-edited. Open the repo in Claude Code, Codex or Cursor, paste a brief, and let the gate do the reviewing while you demo the rest.
Read AGENTS.md first. Add a new template to the `basics` pack: a title card that takes `title`, `subtitle` and `accent` props, 1920x1080, 4 seconds, with the subtitle fading in after the title. Match the house style in docs/style.md, bind every displayed prop, and run `npm run verify` until it is green. Then give me the exact `m0saic make` command that renders it at its defaults.
Submit it. Earn your tile.
Your first accepted community template puts your mark on the Community M — the brand mark itself, one person per tile, forever, with a provenance video rendered by m0saic — and takes the attribution mark off your renders for a stretch of Pro. Details on the pricing page.
The whole anatomy, abridged from the scaffold’s hello-world. A typed props surface, an id, a suggested canvas, and a render that places rectangles and returns the layout string with one source per tile. No timeline, no browser: the string compiles to pixels.
export const AnatomyV1 = defineMosaicTemplate<AnatomyProps>({
id: asTemplateId("@my-templates/basics/anatomy/v1"),
label: "Anatomy",
version: 1,
outputHints: { width: 1280, height: 720, fps: 30, durationMs: 2000 },
propsSchema, // typed knobs; Make draws the controls
defaultProps: { text: "Hello, m0saic", backgroundColor: "#0d1117" },
async render(props, ctx) {
const { width, height } = ctx.target;
const side = Math.round(Math.min(width, height) * 0.32);
const placed = placeInsetPieces({
rootW: width, rootH: height,
pieces: [
{ rect: { x: 0, y: 0, w: width, h: height, importance: 0 },
source: makeColorTile(fill) },
{ rect: { x: gx, y: gy, w: side, h: side, importance: 2 },
source: brandGlyphTile(HEADER_M_GLYPH, BRAND_ORANGE) },
{ rect: label, importance: 1,
source: bindProp(svgLabel(text, label.w, label.h), "text") },
],
});
return {
kind: "mosaic_document",
version: 1,
m0: toM0String(placed.m0, ID), // the layout string — validated here
sources: placed.sources, // one source per tile, in order
backgroundColor: fill,
assets: {},
};
},
});Next: the Community M · templates written by an agent · why rectangles