memoscan
← all memos

Memo 0x6697f0bd…354f1c on Ethereum

ipfs://bafybeic44kygkk5donu3b3kbo4srwi5hlcmgpzrwydr5kewb4ty4gwdqmelet canvasSize = 0; let centerX = 0; let centerY = 0; let plumes = []; let layerColors = []; let animationProgress = 0; let animationSpeed = 0.001; let breathProgress = 0; let lastRegenerationTime = 0; let cycleDuration = 2000; let expandDuration = 800; let holdDuration = 200; let contractDuration = 1000; function getRandomColor() { colorMode(HSB, 360, 100, 100); let c = color(random(360), 100, 100); colorMode(RGB, 255); return c; } function generatePlumes() { plumes = []; layerColors = []; let scaleFactor = canvasSize / 500; let numLayers = floor(random(3, 6)); let innerRadius = canvasSize / 30; let maxOuterRadius = canvasSize * 0.48; for (let layer = 0; layer < numLayers; layer++) { if (layer === 0) { layerColors[layer] = getRandomColor(); } else { layerColors[layer] = color(255, 255, 255); } let isOuterLayer = (layer === numLayers - 1); let layerProgress = layer / max(1, numLayers - 1); let layerInnerRadius = innerRadius + (maxOuterRadius - innerRadius) * layerProgress * random(0.7, 0.9); let layerOuterRadius = layerInnerRadius + (maxOuterRadius - layerInnerRadius) * random(0.4, 0.9); if (isOuterLayer) { layerOuterRadius = maxOuterRadius; } let numPlumesInLayer = floor(random(12, 25)); let angleStep = TWO_PI / numPlumesInLayer; for (let i = 0; i < numPlumesInLayer; i++) { let angle = i * angleStep + random(-angleStep * 0.4, angleStep * 0.4); let plumeInnerRadius = layerInnerRadius + random(-layerInnerRadius * 0.3, layerInnerRadius * 0.4); plumeInnerRadius = max(0, plumeInnerRadius); let plumeOuterRadius = layerOuterRadius + random(-layerOuterRadius * 0.2, layerOuterRadius * 0.15); plumeOuterRadius = constrain(plumeOuterRadius, plumeInnerRadius + canvasSize * 0.02, maxOuterRadius); let baseWidth = (canvasSize / 8) * (1 + layer * 0.5); let width = baseWidth * random(0.5, 2.5); let maxWidthRadius = random(0.2, 0.8); plumes.push({ angle: angle, innerRadius: plumeInnerRadius, outerRadius: plumeOuterRadius, width: width, maxWidthRadius: maxWidthRadius, layer: layer, turbulence: random(0.5, 2.0), density: random(0.6, 1.0) }); } } } function getPlumeWidthAtRadius(plume, radius) { let normalizedRadius = (radius - plume.innerRadius) / (plume.outerRadius - plume.innerRadius); if (normalizedRadius < 0 || normalizedRadius > 1) return 0; let distanceFromMax = abs(normalizedRadius - plume.maxWidthRadius); let widthFactor = 1 - pow(distanceFromMax, 0.8); widthFactor = max(0, widthFactor); let noiseFactor = 1 + noise(plume.angle * 10 + animationProgress * 2, normalizedRadius * 5) * 0.4 - 0.2; let taperFactor = 1 - pow(normalizedRadius, 2.5) * 0.3; return plume.width * widthFactor * taperFactor * noiseFactor; } function getBreathState() { let elapsed = millis() - lastRegenerationTime; if (elapsed < expandDuration) { let progress = elapsed / expandDuration; return { phase: 'expand', progress: progress, size: progress, opacity: 1 }; } else if (elapsed < expandDuration + holdDuration) { return { phase: 'hold', progress: 1, size: 1, opacity: 1 }; } else if (elapsed < expandDuration + holdDuration + contractDuration) { let contractElapsed = elapsed - expandDuration - holdDuration; let progress = contractElapsed / contractDuration; return { phase: 'contract', progress: progress, size: 1 - progress, opacity: 1 - progress }; } else { return { phase: 'complete', progress: 1, size: 0, opacity: 0 }; } } function drawGaseousPlume(plume, breathState) { let col = layerColors[plume.layer]; let maxRadius = map(breathState.size, 0, 1, plume.innerRadius, plume.outerRadius); maxRadius = constrain(maxRadius, plume.innerRadius, plume.outerRadius); if (maxRadius <= plume.innerRadius) return; let passes = 2; for (let pass = 0; pass < passes; pass++) { let passAlpha = map(pass, 0, passes - 1, 20, 8); if (plume.layer !== 0) { passAlpha *= breathState.opacity; } else { passAlpha = map(pass, 0, passes - 1, 50, 25); } let passRadiusStep = map(pass, 0, passes - 1, 8, 15); for (let r = plume.innerRadius; r < maxRadius; r += passRadiusStep) { let normalizedR = (r - plume.innerRadius) / (plume.outerRadius - plume.innerRadius); let plumeWidth = getPlumeWidthAtRadius(plume, r); if (plumeWidth <= 0) continue; let densityFactor = 1 - abs(normalizedR - plume.maxWidthRadius) * 0.5; densityFactor *= plume.density; let distanceFromEdge = maxRadius - r; let edgeFadeDist = (plume.outerRadius - plume.innerRadius) * 0.1; let edgeFade = constrain(distanceFromEdge / edgeFadeDist, 0, 1); densityFactor *= edgeFade; let angleWidth = plumeWidth / r; let numSegments = max(2, floor(angleWidth * r / 10)); for (let seg = 0; seg < numSegments; seg++) { let segmentProgress = seg / numSegments; let offsetAngle = map(segmentProgress, 0, 1, -angleWidth * 0.5, angleWidth * 0.5); let currentAngle = plume.angle + offsetAngle; let noiseOffset = noise( currentAngle * 3 + animationProgress, r * 0.01, plume.layer * 0.5 ) * plume.turbulence * 0.3; currentAngle += noiseOffset; let x = centerX + cos(currentAngle) * r; let y = centerY + sin(currentAngle) * r; let edgeFactor = 1 - abs((segmentProgress - 0.5) * 2); edgeFactor = pow(edgeFactor, 0.7); let alpha = passAlpha * densityFactor * edgeFactor; let scaleFactor = canvasSize / 500; let particleSize = (500 / 80) * (1 + pass * 0.8) * sqrt(scaleFactor); fill(red(col), green(col), blue(col), alpha); noStroke(); ellipse(x, y, particleSize, particleSize); } } } } function setup() { canvasSize = min(windowWidth, windowHeight); createCanvas(canvasSize, canvasSize); centerX = width / 2; centerY = height / 2; generatePlumes(); background(0); lastRegenerationTime = millis(); } function draw() { let breathState = getBreathState(); if (breathState.phase === 'complete') { generatePlumes(); lastRegenerationTime = millis(); background(0); breathState = getBreathState(); } background(0, 0, 0, 25); animationProgress += animationSpeed; for (let plume of plumes) { drawGaseousPlume(plume, breathState); } } function windowResized() { canvasSize = min(windowWidth, windowHeight); resizeCanvas(canvasSize, canvasSize); centerX = width / 2; centerY = height / 2; generatePlumes(); lastRegenerationTime = millis(); background(0); } function mousePressed() { generatePlumes(); lastRegenerationTime = millis(); background(0); }