/** * ═══════════════════════════════════════════════════════════════════════════ * P5.JS GENERATIVE ART - BEST PRACTICES * ═══════════════════════════════════════════════════════════════════════════ * * This file shows STRUCTURE and PRINCIPLES for p5.js generative art. * It does NOT prescribe what art you should create. * * Your algorithmic philosophy should guide what you build. * These are just best practices for how to structure your code. * * ═══════════════════════════════════════════════════════════════════════════ */ // ============================================================================ // 1. PARAMETER ORGANIZATION // ============================================================================ // Keep all tunable parameters in one object // This makes it easy to: // - Connect to UI controls // - Reset to defaults // - Serialize/save configurations let params = { // Define parameters that match YOUR algorithm // Examples (customize for your art): // - Counts: how many elements (particles, circles, branches, etc.) // - Scales: size, speed, spacing // - Probabilities: likelihood of events // - Angles: rotation, direction // - Colors: palette arrays seed: 12345, // define colorPalette as an array -- choose whatever colors you'd like ['#d97757', '#6a9bcc', '#788c5d', '#b0aea5'] // Add YOUR parameters here based on your algorithm }; // ============================================================================ // 2. SEEDED RANDOMNESS (Critical for reproducibility) // ============================================================================ // ALWAYS use seeded random for Art Blocks-style reproducible output function initializeSeed(seed) { randomSeed(seed); noiseSeed(seed); // Now all random() and noise() calls will be deterministic } // ============================================================================ // 3. P5.JS LIFECYCLE // ============================================================================ function setup() { createCanvas(800, 800); // Initialize seed first initializeSeed(params.seed); // Set up your generative system // This is where you initialize: // - Arrays of objects // - Grid structures // - Initial positions // - Starting states // For static art: call noLoop() at the end of setup // For animated art: let draw() keep running } function draw() { // Option 1: Static generation (runs once, then stops) // - Generate everything in setup() // - Call noLoop() in setup() // - draw() doesn't do much or can be empty // Option 2: Animated generation (continuous) // - Update your system each frame // - Common patterns: particle movement, growth, evolution // - Can optionally call noLoop() after N frames // Option 3: User-triggered regeneration // - Use noLoop() by default // - Call redraw() when parameters change } // ============================================================================ // 4. CLASS STRUCTURE (When you need objects) // ============================================================================ // Use classes when your algorithm involves multiple entities // Examples: particles, agents, cells, nodes, etc. class Entity { constructor() { // Initialize entity properties // Use random() here - it will be seeded } update() { // Update entity state // This might involve: // - Physics calculations // - Behavioral rules // - Interactions with neighbors } display() { // Render the entity // Keep rendering logic separate from update logic } } // ============================================================================ // 5. PERFORMANCE CONSIDERATIONS // ============================================================================ // For large numbers of elements: // - Pre-calculate what you can // - Use simple collision detection (spatial hashing if needed) // - Limit expensive operations (sqrt, trig) when possible // - Consider using p5 vectors efficiently // For smooth animation: // - Aim for 60fps // - Profile if things are slow // - Consider reducing particle counts or simplifying calculations // ============================================================================ // 6. UTILITY FUNCTIONS // ============================================================================ // Color utilities function hexToRgb(hex) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } function colorFromPalette(index) { return params.colorPalette[index % params.colorPalette.length]; } // Mapping and easing function mapRange(value, inMin, inMax, outMin, outMax) { return outMin + (outMax - outMin) * ((value - inMin) / (inMax - inMin)); } function easeInOutCubic(t) { return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; } // Constrain to bounds function wrapAround(value, max) { if (value < 0) return max; if (value > max) return 0; return value; } // ============================================================================ // 7. PARAMETER UPDATES (Connect to UI) // ============================================================================ function updateParameter(paramName, value) { params[paramName] = value; // Decide if you need to regenerate or just update // Some params can update in real-time, others need full regeneration } function regenerate() { // Reinitialize your generative system // Useful when parameters change significantly initializeSeed(params.seed); // Then regenerate your system } // ============================================================================ // 8. COMMON P5.JS PATTERNS // ============================================================================ // Drawing with transparency for trails/fading function fadeBackground(opacity) { fill(250, 249, 245, opacity); // Anthropic light with alpha noStroke(); rect(0, 0, width, height); } // Using noise for organic variation function getNoiseValue(x, y, scale = 0.01) { return noise(x * scale, y * scale); } // Creating vectors from angles function vectorFromAngle(angle, magnitude = 1) { return createVector(cos(angle), sin(angle)).mult(magnitude); } // ============================================================================ // 9. EXPORT FUNCTIONS // ============================================================================ function exportImage() { saveCanvas('generative-art-' + params.seed, 'png'); } // ============================================================================ // REMEMBER // ============================================================================ // // These are TOOLS and PRINCIPLES, not a recipe. // Your algorithmic philosophy should guide WHAT you create. // This structure helps you create it WELL. // // Focus on: // - Clean, readable code // - Parameterized for exploration // - Seeded for reproducibility // - Performant execution // // The art itself is entirely up to you! // // ============================================================================