main
  1/**
  2 * ═══════════════════════════════════════════════════════════════════════════
  3 *                  P5.JS GENERATIVE ART - BEST PRACTICES
  4 * ═══════════════════════════════════════════════════════════════════════════
  5 *
  6 * This file shows STRUCTURE and PRINCIPLES for p5.js generative art.
  7 * It does NOT prescribe what art you should create.
  8 *
  9 * Your algorithmic philosophy should guide what you build.
 10 * These are just best practices for how to structure your code.
 11 *
 12 * ═══════════════════════════════════════════════════════════════════════════
 13 */
 14
 15// ============================================================================
 16// 1. PARAMETER ORGANIZATION
 17// ============================================================================
 18// Keep all tunable parameters in one object
 19// This makes it easy to:
 20// - Connect to UI controls
 21// - Reset to defaults
 22// - Serialize/save configurations
 23
 24let params = {
 25    // Define parameters that match YOUR algorithm
 26    // Examples (customize for your art):
 27    // - Counts: how many elements (particles, circles, branches, etc.)
 28    // - Scales: size, speed, spacing
 29    // - Probabilities: likelihood of events
 30    // - Angles: rotation, direction
 31    // - Colors: palette arrays
 32
 33    seed: 12345,
 34    // define colorPalette as an array -- choose whatever colors you'd like ['#d97757', '#6a9bcc', '#788c5d', '#b0aea5']
 35    // Add YOUR parameters here based on your algorithm
 36};
 37
 38// ============================================================================
 39// 2. SEEDED RANDOMNESS (Critical for reproducibility)
 40// ============================================================================
 41// ALWAYS use seeded random for Art Blocks-style reproducible output
 42
 43function initializeSeed(seed) {
 44    randomSeed(seed);
 45    noiseSeed(seed);
 46    // Now all random() and noise() calls will be deterministic
 47}
 48
 49// ============================================================================
 50// 3. P5.JS LIFECYCLE
 51// ============================================================================
 52
 53function setup() {
 54    createCanvas(800, 800);
 55
 56    // Initialize seed first
 57    initializeSeed(params.seed);
 58
 59    // Set up your generative system
 60    // This is where you initialize:
 61    // - Arrays of objects
 62    // - Grid structures
 63    // - Initial positions
 64    // - Starting states
 65
 66    // For static art: call noLoop() at the end of setup
 67    // For animated art: let draw() keep running
 68}
 69
 70function draw() {
 71    // Option 1: Static generation (runs once, then stops)
 72    // - Generate everything in setup()
 73    // - Call noLoop() in setup()
 74    // - draw() doesn't do much or can be empty
 75
 76    // Option 2: Animated generation (continuous)
 77    // - Update your system each frame
 78    // - Common patterns: particle movement, growth, evolution
 79    // - Can optionally call noLoop() after N frames
 80
 81    // Option 3: User-triggered regeneration
 82    // - Use noLoop() by default
 83    // - Call redraw() when parameters change
 84}
 85
 86// ============================================================================
 87// 4. CLASS STRUCTURE (When you need objects)
 88// ============================================================================
 89// Use classes when your algorithm involves multiple entities
 90// Examples: particles, agents, cells, nodes, etc.
 91
 92class Entity {
 93    constructor() {
 94        // Initialize entity properties
 95        // Use random() here - it will be seeded
 96    }
 97
 98    update() {
 99        // Update entity state
100        // This might involve:
101        // - Physics calculations
102        // - Behavioral rules
103        // - Interactions with neighbors
104    }
105
106    display() {
107        // Render the entity
108        // Keep rendering logic separate from update logic
109    }
110}
111
112// ============================================================================
113// 5. PERFORMANCE CONSIDERATIONS
114// ============================================================================
115
116// For large numbers of elements:
117// - Pre-calculate what you can
118// - Use simple collision detection (spatial hashing if needed)
119// - Limit expensive operations (sqrt, trig) when possible
120// - Consider using p5 vectors efficiently
121
122// For smooth animation:
123// - Aim for 60fps
124// - Profile if things are slow
125// - Consider reducing particle counts or simplifying calculations
126
127// ============================================================================
128// 6. UTILITY FUNCTIONS
129// ============================================================================
130
131// Color utilities
132function hexToRgb(hex) {
133    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
134    return result ? {
135        r: parseInt(result[1], 16),
136        g: parseInt(result[2], 16),
137        b: parseInt(result[3], 16)
138    } : null;
139}
140
141function colorFromPalette(index) {
142    return params.colorPalette[index % params.colorPalette.length];
143}
144
145// Mapping and easing
146function mapRange(value, inMin, inMax, outMin, outMax) {
147    return outMin + (outMax - outMin) * ((value - inMin) / (inMax - inMin));
148}
149
150function easeInOutCubic(t) {
151    return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
152}
153
154// Constrain to bounds
155function wrapAround(value, max) {
156    if (value < 0) return max;
157    if (value > max) return 0;
158    return value;
159}
160
161// ============================================================================
162// 7. PARAMETER UPDATES (Connect to UI)
163// ============================================================================
164
165function updateParameter(paramName, value) {
166    params[paramName] = value;
167    // Decide if you need to regenerate or just update
168    // Some params can update in real-time, others need full regeneration
169}
170
171function regenerate() {
172    // Reinitialize your generative system
173    // Useful when parameters change significantly
174    initializeSeed(params.seed);
175    // Then regenerate your system
176}
177
178// ============================================================================
179// 8. COMMON P5.JS PATTERNS
180// ============================================================================
181
182// Drawing with transparency for trails/fading
183function fadeBackground(opacity) {
184    fill(250, 249, 245, opacity); // Anthropic light with alpha
185    noStroke();
186    rect(0, 0, width, height);
187}
188
189// Using noise for organic variation
190function getNoiseValue(x, y, scale = 0.01) {
191    return noise(x * scale, y * scale);
192}
193
194// Creating vectors from angles
195function vectorFromAngle(angle, magnitude = 1) {
196    return createVector(cos(angle), sin(angle)).mult(magnitude);
197}
198
199// ============================================================================
200// 9. EXPORT FUNCTIONS
201// ============================================================================
202
203function exportImage() {
204    saveCanvas('generative-art-' + params.seed, 'png');
205}
206
207// ============================================================================
208// REMEMBER
209// ============================================================================
210//
211// These are TOOLS and PRINCIPLES, not a recipe.
212// Your algorithmic philosophy should guide WHAT you create.
213// This structure helps you create it WELL.
214//
215// Focus on:
216// - Clean, readable code
217// - Parameterized for exploration
218// - Seeded for reproducibility
219// - Performant execution
220//
221// The art itself is entirely up to you!
222//
223// ============================================================================