> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs-sepolia.modularium.art/api/mcp` to find what you need.

# Make a generative artwork

A generative artwork is a web page that draws a different piece for every token. Each token loads the page with its own mint data, and the page must always draw the same piece for the same data. This guide takes you from a template to an artwork that's ready for a [generative drop](/create/generative).

## How a token is drawn

When a token is minted, Modularium:

1. Opens your `index.html` in Chrome with the token's mint data in the URL: `?tokenId=7&recipient=0x…&blockNumber=…&blockHash=0x…&seedSalt=0x…`.
2. `mod.js` reads those values into [`$mod.mint`](/generative/api#mint-data), seeds [`$mod.prng`](/generative/api#randomness-modprng) from them, and seeds p5.js's `random()` and `noise()` if you use p5.
3. Your code draws. The page is 1000px on its longer side, at your drop's aspect ratio.
4. When your code calls `$mod.preview.capture()`, or 10 seconds after the page loads if it never does, Modularium saves a snapshot of the first `<canvas>` as the token's image and reads the name, description and traits your code set with [`$mod.token`](/generative/api#token-metadata-modtoken).

The same page, with the same URL, is the token's `animation_url`. Marketplaces that support it show your piece live, at whatever size they have.

## 1. Start from a template

Pick a [template](/generative/templates), download its `.zip` and unzip it. Each one is a folder with an `index.html` and a `sketch.js`:

* [p5.js](/generative/templates#p5js): draws once with p5.js. The simplest place to start.
* [Animated p5.js](/generative/templates#animated-p5js): draws over many frames, then captures.
* [Plain canvas](/generative/templates#plain-canvas): no library, just a `<canvas>` and `$mod.prng`.
* [three.js](/generative/templates#threejs): a 3D scene, rendered once.
* [Animated three.js](/generative/templates#animated-threejs): a 3D scene that keeps moving in the live view.
* [Shader](/generative/templates#shader): a GLSL fragment shader that colours every pixel.
* [Paper.js](/generative/templates#paperjs): vector paths on a canvas.
* [SVG](/generative/templates#svg): an SVG drawing, copied to a hidden canvas for the preview.

## 2. Work on it locally

Serve the folder with any static server, rather than opening the file directly, so scripts and images load the way they will once uploaded:

```sh
npx serve --cors .
```

`--cors` lets the [artwork tester](#6-test-it) load the page's module scripts (the three.js templates use them). Any other static server works too, if it sends `Access-Control-Allow-Origin: *`.

The templates load `https://sepolia.modularium.art/mod.js`. With no mint data in the URL, it makes up a random token on every load, so each refresh shows another variation. To see one again, put its values in the URL:

```
http://localhost:8080/?tokenId=7&blockHash=0x19b6…&seedSalt=0x5fbd…
```

## 3. Keep it deterministic

A token must draw exactly the same piece every time, on every machine: when it's rendered, on a collector's phone, and years from now.

* Take every random choice from `$mod.prng`, or p5's `random()`, `noise()` and their friends. Never use `Math.random()`.
* Don't let the date, the time, `performance.now()` or anything fetched from a server decide what you draw. Animating over time is fine, as long as the preview is drawn at a fixed moment, like the [animated three.js template](/generative/templates#animated-threejs).
* Draw at a fixed size, like the templates' `W` × `H`, and let CSS scale the canvas to the window. Don't size the drawing from the window, or every screen gets a different piece. In p5.js, call `pixelDensity(1)`.
* If it animates, count frames rather than seconds. A slower machine then draws the same frames, just later.
* Load fonts and images before you draw, e.g. in p5's `preload()`.
* Ship your libraries in the folder, or load them from a versioned URL that won't change, like `https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js`.

Only the values in `$mod.mint` differ between tokens.

## 4. Name it and give it traits

Traits show on the token page and on marketplaces, and collectors filter by them. Set them while you draw:

```js
$mod.token.setAttributes({ Palette: "Dusk", Circles: 42 });
```

The token's name and description come from the drop, e.g. `My Drop #7`. Your code can replace them with `$mod.token.setName()` and `$mod.token.setDescription()`. See [Token metadata](/generative/api#token-metadata-modtoken).

## 5. Capture the preview

Call `$mod.preview.capture()` as soon as the drawing is done. If you never call it, the image is taken 10 seconds after the page loads, wherever your drawing has got to.

* Only the first `<canvas>` on the page is captured. HTML and SVG outside it aren't: for SVG work, draw the finished SVG onto a hidden canvas, like the [SVG template](/generative/templates#svg).
* `capture()` takes its snapshot at the moment you call it, so an animation can keep running afterwards. Call it at a fixed point (a frame count or a fixed moment), not whenever the page happens to get there.
* WebGL (three.js, p5's `WEBGL` mode): call `capture()` right after you render the frame you want, while it's still in the WebGL buffer. If you rely on the 10-second fallback instead, create the context with `preserveDrawingBuffer: true`, or the image is blank.
* Rendering has no GPU: WebGL runs in software. Keep scenes and shaders light enough to finish well within 10 seconds.
* Images drawn onto the canvas from another site need CORS, or the canvas can't be read. Put them in your folder instead.

## 6. Test it

The [artwork tester](https://sepolia.modularium.art/create/generative/test) renders your artwork the way Modularium renders tokens. Upload your folder, or enter the URL of your local server (e.g. `http://localhost:3000/`), and pick any mint data. For each render it shows:

* whether your code called `capture()`, and when
* the canvas it found, and the preview image a token would get
* the name, description and traits your code set
* whether loading the same mint data twice draws the same image

Try a handful of seeds and token IDs, including your first and last token, before you create the drop.

## 7. Upload it

On [`/create/generative`](https://sepolia.modularium.art/create/generative), upload the folder (or a `.zip` of it) with `index.html` at its root, up to 50MB and 1,000 files. Modularium adds `mod.js` to your `index.html`, replacing the `<script src="…/mod.js">` tag, so your tokens keep the exact copy they were uploaded with.

:::warning
The artwork locks when the first token is minted. Test it before you open the mint.
:::

## Checklist

* \[ ] Every random choice comes from `$mod.prng` or p5's seeded functions.
* \[ ] The same mint data draws the same image (the tester says **Yes**).
* \[ ] The drawing size matches the drop's aspect ratio, and doesn't depend on the window.
* \[ ] Your code calls `$mod.preview.capture()` when the drawing is done, well within 10 seconds.
* \[ ] Traits are set for every token.
* \[ ] Libraries, fonts and images are in the folder or on versioned URLs.
* \[ ] It looks right at small sizes and in a tall or wide window, since marketplaces show `animation_url` at their own size.
