For Creators
Dynamic NFTs
Tutorials
Advanced Usage

Advanced Dynamic NFT Techniques

This guide covers advanced techniques for creating more complex and performant Dynamic NFTs.

Responsive Canvas

When working with P5.js, you might want your artwork to be responsive to different window sizes:

let scale = 1;
 
function setup() {
  // Create a responsive canvas
  createCanvas(windowWidth, windowHeight);
  // Calculate scale based on minimum dimension
  scale = min(width, height) / 1024;
  // Scale all subsequent drawing operations
  scale(scale);
}
 
function windowResized() {
  // Update canvas and scale when window is resized
  resizeCanvas(windowWidth, windowHeight);
  scale = min(width, height) / 1024;
  redraw(); // Trigger redraw with new dimensions
}

Always test your artwork at different screen sizes to ensure a consistent experience.

Progressive Rendering with Generators

For complex artworks that might cause browser lag, you can use JavaScript generators to break down the rendering process:

function* generateArtwork() {
  // Initial setup
  background(220);
 
  // Generate parameters
  const particles = Array(1000)
    .fill()
    .map(() => ({
      x: genify.random() * width,
      y: genify.random() * height,
      size: genify.randFloat(2, 10),
    }));
 
  // Render in batches
  for (let i = 0; i < particles.length; i += 10) {
    const batch = particles.slice(i, i + 10);
    batch.forEach((p) => {
      circle(p.x, p.y, p.size);
    });
 
    // Yield after each batch to prevent browser freeze
    yield i / particles.length; // Return progress (0-1)
  }
}
 
let generator;
let isRendering = false;
 
function setup() {
  createCanvas(1024, 1024);
  noLoop();
 
  // Create loading UI
  loadingText = createDiv("Rendering: 0%");
  loadingText.position(10, 10);
 
  // Start rendering
  startRendering();
}
 
async function startRendering() {
  if (isRendering) return;
  isRendering = true;
 
  generator = generateArtwork();
 
  while (true) {
    const result = generator.next();
 
    if (result.done) {
      loadingText.html("Rendering Complete!");
      genify.renderDone();
      break;
    }
 
    // Update loading progress
    loadingText.html(`Rendering: ${(result.value * 100).toFixed(1)}%`);
 
    // Allow browser to update UI
    await new Promise((resolve) => setTimeout(resolve, 0));
  }
 
  isRendering = false;
}
⚠️

For more complex examples and in-depth understanding of generators in creative coding, check out this excellent guide on using generators for animated sketches (opens in a new tab).

Memory Management

When creating complex artworks, it's important to manage memory efficiently:

function draw() {
  // Clear any existing objects
  cleanup();
 
  // Create new objects
  const particles = createParticles();
 
  // Render in batches
  renderBatches(particles);
 
  // Clean up after rendering
  cleanup();
}
 
function cleanup() {
  // Remove any existing DOM elements
  while (document.getElementsByClassName("temp").length > 0) {
    document.getElementsByClassName("temp")[0].remove();
  }
 
  // Clear graphics buffers
  if (buffer) {
    buffer.remove();
    buffer = null;
  }
}

Using Off-screen Buffers

For complex effects, use P5.js graphics buffers to render off-screen:

let buffer;
 
function setup() {
  createCanvas(1024, 1024);
  // Create off-screen buffer
  buffer = createGraphics(1024, 1024);
}
 
function draw() {
  // Render complex effects to buffer
  buffer.push();
  buffer.translate(width / 2, height / 2);
  // ... complex rendering ...
  buffer.pop();
 
  // Draw buffer to main canvas
  image(buffer, 0, 0);
}

Performance Tips

  1. Batch Processing

    • Group similar operations together
    • Process in small chunks using generators
    • Use requestAnimationFrame for smooth animations
  2. Memory Management

    • Clean up unused objects and buffers
    • Reuse objects instead of creating new ones
    • Use object pools for particle systems
  3. Rendering Optimization

    • Use off-screen buffers for complex effects
    • Implement level of detail based on performance
    • Cache repeated calculations

Error Handling

Always implement error handling to ensure your artwork degrades gracefully:

try {
  // Attempt complex rendering
  await startRendering();
} catch (error) {
  console.error("Rendering failed:", error);
  // Fallback to simple rendering
  renderFallback();
  genify.renderDone();
}

Next Steps