Start with a working sketch

Download a self-contained starter and test the wizard's built-in studies.

On this page

Use these for a new project. Changing an existing artwork's seed recipe changes its rendered editions, so this is not an instruction to patch released artwork.

A complete p5 starter

Download the complete script, paste it into the wizard's script editor, choose p5js, and use Preview in UI. The file includes the seed helper; it has no package imports or remote asset requirements.

It demonstrates a stable composition, a separate noise seed, fixed logical coordinates, resize handling, flat metadata, an Animate toggle and an explicit PNG export. The complete script is also included in the LLM reference.

// Immutables.art edition seed convention v1 — for NEW projects.
// Deterministic mixing, not cryptographic randomness or bot prevention.
// Keep props.transactionHash unchanged for metadata and provenance.
function immutablesSeed(props, stream = 'art') {
  const hash = String(props.transactionHash || '').toLowerCase();
  if (!/^0x[0-9a-f]{64}$/.test(hash)) throw new Error('A full mint transaction hash is required');
  const decimal = (value, name, allowZero) => {
    if (typeof value === 'number' && !Number.isSafeInteger(value)) throw new Error(name + ' must be a safe integer or decimal string');
    const text = String(value);
    if (!/^\d+$/.test(text)) throw new Error(name + ' is required');
    const normalized = text.replace(/^0+(?=\d)/, '');
    if (!allowZero && normalized === '0') throw new Error(name + ' must be positive');
    return normalized;
  };
  const input = ['immutables.art/edition-seed/v1', hash,
    decimal(props.projectId, 'projectId', true), decimal(props.editionId, 'editionId', false), stream].join('|');
  let hex = '0x';
  for (let word = 0; word < 8; word++) {
    let state = (2166136261 ^ Math.imul(word + 1, 0x9e3779b9)) >>> 0;
    for (let i = 0; i < input.length; i++) state = Math.imul(state ^ input.charCodeAt(i), 16777619) >>> 0;
    state = Math.imul(state ^ (state >>> 16), 0x85ebca6b);
    state = Math.imul(state ^ (state >>> 13), 0xc2b2ae35);
    hex += ((state ^ (state >>> 16)) >>> 0).toString(16).padStart(8, '0');
  }
  return hex;
}

// A local drawing stream. Do not replace Math.random globally.
function immutablesRandom(props, stream = 'art') {
  let state = parseInt(immutablesSeed(props, stream).slice(2, 10), 16) >>> 0;
  return () => {
    state = (state + 0x6d2b79f5) >>> 0;
    let value = Math.imul(state ^ (state >>> 15), state | 1);
    value ^= value + Math.imul(value ^ (value >>> 7), value | 61);
    return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
  };
}

// Include edition-seed.js above this body. MIT; see examples/LICENSE.txt.
let edition = null;
let composition = [];
let motion = true;
let frame = 0;

p.setup = () => { p.createCanvas(1, 1); p.noLoop(); };

function fitCanvas() {
  if (!edition) return;
  const size = Math.max(1, Math.floor(Math.min(window.innerWidth, window.innerHeight) * 0.8 / Number(edition.square)));
  p.resizeCanvas(size, size);
}

p.myCustomRedrawAccordingToNewPropsHandler = props => {
  if (!props || !props.transactionHash || !props.editionId || !props.square) return;
  const identity = immutablesSeed(props);
  if (!edition || edition.identity !== identity) {
    p.randomSeed(parseInt(identity.slice(2, 10), 16));
    p.noiseSeed(parseInt(immutablesSeed(props, 'noise').slice(2, 10), 16));
    composition = Array.from({ length: 18 }, () => ({ x: p.random(40, 360), y: p.random(40, 360), radius: p.random(8, 35) }));
    frame = 0;
    console.log('metadata: ', { transactionHash: props.transactionHash, Structure: 'Orbits', Circles: composition.length });
  }
  edition = { ...props, identity };
  fitCanvas();
  motion ? p.loop() : p.redraw();
};

p.draw = () => {
  if (!edition) return;
  p.background(0);
  p.push();
  p.scale(p.width / 400);
  p.noFill();
  p.stroke(255);
  p.strokeWeight(1.5);
  for (const circle of composition) {
    p.circle(circle.x, circle.y, circle.radius * 2 + Math.sin(frame / 45 + circle.x) * 6);
  }
  p.pop();
  if (motion) frame++;
};
p.windowResized = () => { fitCanvas(); if (!motion) p.redraw(); };
function toggleMotion() { motion = !motion; motion ? p.loop() : p.noLoop(); }
p.keyTyped = () => { if (p.key === 'A' || p.key === 'a') toggleMotion(); };
p.immutablesControls = {
  version: 1,
  actions: [
    { id: 'motion', label: 'Animate', type: 'toggle', key: 'A' },
    { id: 'png', label: 'Save PNG', type: 'export' }
  ],
  getState: () => ({ values: { motion } }),
  onAction: id => { if (id === 'png' && edition) p.saveCanvas('orbits-' + edition.editionId, 'png'); }
};

Seed helper by itself

Download edition-seed.js if you already have a drawing. Copy its functions into the posted source; do not add a runtime fetch dependency on the documentation website.

Use immutablesRandom(props, 'composition') for a local random() function in vanilla or three.js artwork. For p5, initialize p.randomSeed from immutablesSeed(props) and use a separate domain for noise. See seed limitations.

Built-in wizard studies

The wizard contains four renderer boilerplates and 16 studies across p5.js, three.js, vanilla canvas and GLSL. Their current seed paths mix the full transaction hash and full project/edition IDs. The particle example uses a local seeded stream rather than Math.random() for its persistent structure.

Examples based on existing projects are adapted studies. Their seed behavior is intentionally different from the historical releases. Preserve credits and check the applicable license before reusing artwork code. The generic starter is available under the MIT license.

The wizard only replaces the current editor after the example-load confirmation. Saved drafts and already-posted scripts are not automatically migrated. To adopt a new recipe in your own unreleased draft, explicitly replace its seed initialization and retest the work.

What a good preview demonstrates

Compare different hashes, then reuse one hash with different edition IDs. Reload a fixed input, resize the viewport, and compare both traits and a fixed animation moment. Preview in a grid and as a selected edition. Test native mobile typing, exports and control styling in the full UI.

Use this guide with an assistantRead the Artists & Coders brief