Weird Idea - Surreal Generative Art
Day 26Weird Idea is a surreal generative art experience built entirely with vanilla JavaScript and HTML5 Canvas. No external libraries - just pure creative coding.
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.
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:
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));
}
}
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.
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.
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:
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
}
};
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: