Tech Details

Weird Idea - Surreal Generative Art

Day 26

Table of Contents

Tech Stack Overview

Weird Idea is a surreal generative art experience built entirely with vanilla JavaScript and HTML5 Canvas. No external libraries - just pure creative coding.

Design Philosophy

The "weird" factor comes from combining multiple generative techniques: random creature attributes, continuous mutation, organic movement patterns, and surreal visual elements like multiple eyes and tentacles.

Procedural Creature Generation

Each creature is generated with randomized attributes that define its appearance and behavior. This creates endless variety without any predefined sprites.

class Creature { constructor(x, y) { // Position and movement this.x = x || Math.random() * width; this.y = y || Math.random() * height; this.vx = (Math.random() - 0.5) * 2; this.vy = (Math.random() - 0.5) * 2; // Visual attributes - all randomized this.size = 20 + Math.random() * 60; this.segments = 3 + Math.floor(Math.random() * 8); this.tentacles = Math.floor(Math.random() * 12); this.eyes = 1 + Math.floor(Math.random() * 7); this.shape = Math.floor(Math.random() * 5); // Animation properties this.hue = Math.random() * 360; this.pulseRate = 0.5 + Math.random() * 2; this.phase = Math.random() * Math.PI * 2; } }

Key randomized attributes include:

Mutation System

Creatures don't stay static - they mutate over time, changing their attributes randomly. This creates an ever-evolving ecosystem of bizarre life forms.

mutate() { mutationCount++; // Random attribute changes if (Math.random() > 0.5) { this.segments = Math.max(2, this.segments + Math.floor(Math.random() * 3) - 1 ); } if (Math.random() > 0.5) { this.tentacles = Math.max(0, this.tentacles + Math.floor(Math.random() * 4) - 2 ); } if (Math.random() > 0.7) { this.shape = Math.floor(Math.random() * 5); } // Spawn particles on mutation for (let i = 0; i < 10; i++) { particles.push(new Particle(this.x, this.y, this.hue)); } }
Mutation Probability

Different attributes have different mutation chances. Shape changes are rarer (30% chance) than segment/tentacle changes (50% chance), creating gradual evolution rather than chaotic jumps.

Multi-Shape Rendering

Each creature can have one of 5 different body shapes, each rendered with unique algorithms. This adds visual diversity to the ecosystem.

drawBody(s) { switch (this.shape) { case 0: // Blob - organic wobbling shape for (let i = 0; i < this.segments; i++) { const angle = (i / this.segments) * Math.PI * 2; const wobble = Math.sin(this.phase + i * 0.5) * s * 0.2; const r = s * 0.5 + wobble; // Draw vertex... } break; case 1: // Star - alternating inner/outer vertices for (let i = 0; i < this.segments * 2; i++) { const r = i % 2 === 0 ? s * 0.6 : s * 0.3; // Alternating radii create star points } break; case 2: // Spiral - Archimedean spiral for (let i = 0; i < 100; i++) { const angle = (i / 100) * Math.PI * 4 + this.phase; const r = (i / 100) * s * 0.5; // Radius grows with angle } break; case 4: // Organic - noise-based outline const noiseVal = Math.sin(angle * this.segments + this.phase) * 0.3 + Math.sin(angle * this.segments * 2) * 0.2; // Layered sine waves create organic edges break; } }

The Fractal shape (case 3) is special - it renders 3 nested layers with decreasing size and shifting hues, creating a depth illusion.

Particle Effects & Trails

Visual feedback comes from two systems: mutation particles that burst when a creature mutates, and position trails that follow each creature.

// Trail system - stores recent positions this.trail.unshift({ x: this.x, y: this.y }); if (this.trail.length > this.trailLength) { this.trail.pop(); } // Drawing the trail with fading opacity for (let i = 1; i < this.trail.length; i++) { const alpha = 1 - i / this.trail.length; ctx.fillStyle = `hsla(${this.hue}, 70%, 50%, ${alpha * 0.3})`; const trailSize = s * 0.3 * (1 - i / this.trail.length); ctx.beginPath(); ctx.arc(this.trail[i].x, this.trail[i].y, trailSize, 0, Math.PI * 2); ctx.fill(); }

The particle class handles mutation effects:

Mode System & Game Loop

Four distinct modes change the entire feel of the experience by adjusting mutation rate, speed, and population.

const modes = { normal: { speed: 1, mutationRate: 0.005, spawnRate: 0.02, maxCreatures: 15 }, chaos: { speed: 2, mutationRate: 0.02, // 4x mutation! spawnRate: 0.05, maxCreatures: 30 }, zen: { speed: 0.5, // Slow, peaceful mutationRate: 0.001, spawnRate: 0.005, maxCreatures: 8 }, nightmare: { speed: 1.5, mutationRate: 0.03, // Constant mutation spawnRate: 0.03, maxCreatures: 20 } };
Delta Time

The animation loop uses delta time (dt) to ensure consistent speed regardless of frame rate. All updates are multiplied by dt and the mode's speed multiplier.

The background also changes based on mode: