Artist Template
p5.js Package Format
Create one ZIP file with a manifest, parameter schema, and sketch. Add a preview image and README when you want collectors to see more context before minting.
ZIP structure
art-project.zip ├── manifest.json ├── sketch.js ├── params.schema.json ├── preview.png └── README.md
The three required files are manifest.json, params.schema.json, and sketch.js. The ZIP can contain those files at the top level or inside one project folder.
Start from a folder
- 1. Make a folder for one collection, such as
curvefields. - 2. Add
manifest.json,params.schema.json, andsketch.js. - 3. Add
preview.pngandREADME.mdif you have them. - 4. Zip the files and upload the ZIP on the Create page.
cd curvefields zip -r curvefields.zip manifest.json params.schema.json sketch.js preview.png README.md
What each file does
manifest.json
required
Collection metadata. The slug becomes the collection subname, such as curvefields.artist.eth. artistENS can be a placeholder while drafting; the create flow replaces it with the ENS root you enter before publishing.
params.schema.json
required
The list of traits ArtNamespace can generate for each mint. Every key becomes available in sketch.js as ctx.params.keyName.
sketch.js
required
The drawing code. It must assign window.ArtNamespace and include draw(ctx). setup(ctx) and features(ctx) are optional.
preview.png
optional
A representative render from the project. If present, it appears while reviewing the package before publishing.
README.md
optional
Human notes for the artist, collector, or curator. It is stored with the algorithm bundle but does not change rendering.
manifest.json
This file describes the collection. Keep renderer as p5js. Use a short lowercase slug with no spaces because it becomes part of the collection name.
{
"name": "Curvefields",
"slug": "curvefields",
"artistENS": "artist.eth",
"description": "A deterministic field study of curves, density, symmetry, and quiet motion.",
"renderer": "p5js",
"rendererVersion": "1.9.0",
"aspectRatio": "1:1",
"license": "CC BY-NC 4.0",
"maxSupply": 512
}params.schema.json
This file defines the variables ArtNamespace generates for each output. Supported field types are color, number, integer, and boolean. Numeric fields need min and max, and color fields need a values palette.
{
"background": {
"type": "color",
"mode": "palette",
"values": [
"#0B0B0F",
"#F7F4EF",
"#16324F"
]
},
"foreground": {
"type": "color",
"mode": "palette",
"values": [
"#B45309",
"#0F766E",
"#C2410C",
"#1F2937"
]
},
"curveIntensity": {
"type": "number",
"min": 0.1,
"max": 1,
"step": 0.01
},
"loop": {
"type": "boolean"
},
"density": {
"type": "integer",
"min": 80,
"max": 280
},
"symmetry": {
"type": "integer",
"min": 2,
"max": 8
}
}Runtime contract
Assign window.ArtNamespace in sketch.js. The renderer calls setup(ctx) once if it exists, then draw(ctx). Use ctx.rand() for visual randomness so the same seed always produces the same image.
ctx includes
p5, seed, rand, params, tokenId, artistENS, collectionENS, artworkENS
features(ctx)
Return simple trait labels to show on minted artwork pages. Use strings, numbers, or values that can be displayed as text.
window.ArtNamespace = {
setup(ctx) {
const { p5 } = ctx;
p5.createCanvas(1000, 1000);
p5.noLoop();
},
draw(ctx) {
const { p5, params, rand } = ctx;
p5.background(params.background);
p5.stroke(params.foreground);
p5.strokeWeight(1.4);
p5.noFill();
const center = p5.width / 2;
const count = params.density;
const turns = params.symmetry;
for (let i = 0; i < count; i++) {
const angle = rand() * Math.PI * 2;
const radius = 30 + rand() * 430;
const wobble = 18 + rand() * 160 * params.curveIntensity;
const x = center + Math.cos(angle) * radius;
const y = center + Math.sin(angle) * radius;
for (let arm = 0; arm < turns; arm++) {
const theta = angle + (Math.PI * 2 * arm) / turns;
const ax = center + Math.cos(theta) * radius;
const ay = center + Math.sin(theta) * radius;
p5.bezier(
ax,
ay,
ax + Math.cos(theta + 0.9) * wobble,
ay + Math.sin(theta + 0.9) * wobble,
x + Math.cos(theta - 1.4) * wobble,
y + Math.sin(theta - 1.4) * wobble,
center + Math.cos(theta) * (radius * 0.2),
center + Math.sin(theta) * (radius * 0.2)
);
}
}
},
features(ctx) {
const { params } = ctx;
return {
Palette: params.background + " / " + params.foreground,
Curve: params.curveIntensity > 0.7 ? "Wild" : params.curveIntensity > 0.4 ? "Lyrical" : "Calm",
Density: params.density > 210 ? "Dense" : params.density > 130 ? "Balanced" : "Sparse",
Symmetry: String(params.symmetry),
Motion: params.loop ? "Loop" : "Still"
};
}
};README.md
Use the README for plain-language context: what the work is, how it was made, what the parameters mean, and any license or exhibition notes. It can be short.
# Curvefields A deterministic p5.js collection exploring curves, density, symmetry, and motion. Parameters: - background: palette used behind the drawing - foreground: stroke palette - density: number of curve groups - symmetry: number of repeated arms - loop: still or motion study License: CC BY-NC 4.0
Common checks
- Make sure
sketch.jscontainswindow.ArtNamespace = { ... }. - Make sure every value you read from
ctx.paramsexists inparams.schema.json. - Use
ctx.rand()instead ofMath.random(). - Call
p5.createCanvas()insetup(ctx). - Keep the ZIP small enough to upload comfortably. Large generated images should not be placed inside the package.