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.

01

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.

npm i -g m0saic
m0saic setup
m0saic hello-world
02

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.

git clone https://github.com/m0saic-project/m0saic-template-repo-starter && cd m0saic-template-repo-starter
m0saic make '@m0saic-starter/basics/hello-world/v1' --template-repo . -w 1280 -h 720 -o hello.mp4

Read CURRICULUM.md for the map and template-manifest.json for the whole inventory as JSON. Change the -w/-h and render again: the same template, a different canvas, no letterbox — that is the point of the layout string.

03

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
// 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
});
git clone https://github.com/m0saic-project/m0saic-template-repo-starter-base my-templates && cd my-templates
npm install && npm run build && npm run verify
m0saic make '@m0saic-starter-base/basics/hello-world/v1' --template-repo . -o mine.mp4

Honest status: the @m0saic/* packages the scaffold builds against are not on npm yet, so npm install here needs the m0saic monorepo as a sibling checkout today. That is the one step between you and a from-scratch template, and it is next on the launch list. Steps 01, 02 and the agent contract below work now; the curriculum’s committed dist/ is the zero-build path in the meantime.

04

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.

prompt
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.

What makes this work is not the agent; it is that verify is the same gate a human runs. The agent loops on its own JSON findings until the template renders at its defaults, on the standard canvases, with every prop bound. The shipping Alpine pack and the Weekly Pulse hero were built this way — receipts here.

05

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.

Template library — opening with the programSee the MAsk on Discord

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.

src/basics/hello-world/v1/hello-world.ts
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