223 lines
7.6 KiB
JavaScript
223 lines
7.6 KiB
JavaScript
/**
|
|
* ═══════════════════════════════════════════════════════════════════════════
|
|
* 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!
|
|
//
|
|
// ============================================================================
|