| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- /**
- * ═══════════════════════════════════════════════════════════════════════════
- * 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!
- //
- // ============================================================================
|