ArtNamespace

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. 1. Make a folder for one collection, such as curvefields.
  2. 2. Add manifest.json, params.schema.json, and sketch.js.
  3. 3. Add preview.png and README.md if you have them.
  4. 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.js contains window.ArtNamespace = { ... }.
  • Make sure every value you read from ctx.params exists in params.schema.json.
  • Use ctx.rand() instead of Math.random().
  • Call p5.createCanvas() in setup(ctx).
  • Keep the ZIP small enough to upload comfortably. Large generated images should not be placed inside the package.