trippy-deepsite / index.html
maydayjeffk's picture
Add 2 files
e99323d verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Psychedelic Vortex Generator</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background: #000;
touch-action: none;
}
#controls {
position: absolute;
bottom: 20px;
left: 20px;
z-index: 100;
background: rgba(0,0,0,0.5);
padding: 10px;
border-radius: 8px;
color: white;
font-family: monospace;
}
.control-item {
margin: 8px 0;
}
.hidden {
display: none;
}
#toggleControls {
position: absolute;
bottom: 20px;
right: 20px;
z-index: 100;
background: rgba(0,0,0,0.5);
color: white;
border: none;
padding: 8px 12px;
border-radius: 8px;
cursor: pointer;
}
#audioToggle {
position: absolute;
top: 20px;
right: 20px;
z-index: 100;
background: rgba(0,0,0,0.5);
color: white;
border: none;
padding: 8px 12px;
border-radius: 8px;
cursor: pointer;
}
#title {
position: absolute;
top: 20px;
left: 20px;
z-index: 100;
color: white;
font-family: monospace;
font-size: 24px;
text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #e60073, 0 0 40px #e60073;
opacity: 0.8;
}
</style>
</head>
<body>
<div id="title">PSYCHEDELIC VORTEX GENERATOR</div>
<button id="audioToggle">ENABLE AUDIO</button>
<div id="controls" class="hidden">
<div class="control-item">
<label for="particleCount">Particle Count: </label>
<input type="range" id="particleCount" min="100" max="5000" value="2000" step="100">
<span id="particleCountValue">2000</span>
</div>
<div class="control-item">
<label for="vortexStrength">Vortex Strength: </label>
<input type="range" id="vortexStrength" min="0" max="2" value="0.5" step="0.01">
<span id="vortexStrengthValue">0.5</span>
</div>
<div class="control-item">
<label for="noiseScale">Noise Scale: </label>
<input type="range" id="noiseScale" min="0.001" max="0.05" value="0.01" step="0.001">
<span id="noiseScaleValue">0.01</span>
</div>
<div class="control-item">
<label for="colorSpeed">Color Speed: </label>
<input type="range" id="colorSpeed" min="0" max="0.1" value="0.02" step="0.001">
<span id="colorSpeedValue">0.02</span>
</div>
<div class="control-item">
<label for="trailOpacity">Trail Opacity: </label>
<input type="range" id="trailOpacity" min="0" max="50" value="10" step="1">
<span id="trailOpacityValue">10</span>
</div>
<div class="control-item">
<label for="particleSize">Particle Size: </label>
<input type="range" id="particleSize" min="0.5" max="5" value="2" step="0.1">
<span id="particleSizeValue">2</span>
</div>
<div class="control-item">
<label for="mouseInfluence">Mouse Influence: </label>
<input type="range" id="mouseInfluence" min="0" max="2" value="1" step="0.1">
<span id="mouseInfluenceValue">1</span>
</div>
<div class="control-item">
<label for="audioSensitivity">Audio Sensitivity: </label>
<input type="range" id="audioSensitivity" min="0" max="500" value="100" step="10">
<span id="audioSensitivityValue">100</span>
</div>
</div>
<button id="toggleControls">TOGGLE CONTROLS</button>
<script>
// Main sketch
let particles = [];
let audioContext;
let analyser;
let microphone;
let audioEnabled = false;
let dataArray;
let fft;
let bassLevel = 0;
let midLevel = 0;
let highLevel = 0;
let hue = 0;
// Parameters with default values
let params = {
particleCount: 2000,
vortexStrength: 0.5,
noiseScale: 0.01,
colorSpeed: 0.02,
trailOpacity: 10,
particleSize: 2,
mouseInfluence: 1,
audioSensitivity: 100
};
function setup() {
createCanvas(windowWidth, windowHeight);
colorMode(HSB, 360, 100, 100, 100);
// Initialize particles
initParticles();
// Setup UI event listeners
setupUI();
}
function initParticles() {
particles = [];
for (let i = 0; i < params.particleCount; i++) {
particles.push(new Particle());
}
}
function setupUI() {
// Slider controls
document.getElementById('particleCount').addEventListener('input', function() {
params.particleCount = parseInt(this.value);
document.getElementById('particleCountValue').textContent = params.particleCount;
initParticles();
});
document.getElementById('vortexStrength').addEventListener('input', function() {
params.vortexStrength = parseFloat(this.value);
document.getElementById('vortexStrengthValue').textContent = params.vortexStrength;
});
document.getElementById('noiseScale').addEventListener('input', function() {
params.noiseScale = parseFloat(this.value);
document.getElementById('noiseScaleValue').textContent = params.noiseScale;
});
document.getElementById('colorSpeed').addEventListener('input', function() {
params.colorSpeed = parseFloat(this.value);
document.getElementById('colorSpeedValue').textContent = params.colorSpeed;
});
document.getElementById('trailOpacity').addEventListener('input', function() {
params.trailOpacity = parseInt(this.value);
document.getElementById('trailOpacityValue').textContent = params.trailOpacity;
});
document.getElementById('particleSize').addEventListener('input', function() {
params.particleSize = parseFloat(this.value);
document.getElementById('particleSizeValue').textContent = params.particleSize;
});
document.getElementById('mouseInfluence').addEventListener('input', function() {
params.mouseInfluence = parseFloat(this.value);
document.getElementById('mouseInfluenceValue').textContent = params.mouseInfluence;
});
document.getElementById('audioSensitivity').addEventListener('input', function() {
params.audioSensitivity = parseInt(this.value);
document.getElementById('audioSensitivityValue').textContent = params.audioSensitivity;
});
// Toggle controls button
document.getElementById('toggleControls').addEventListener('click', function() {
const controls = document.getElementById('controls');
controls.classList.toggle('hidden');
});
// Audio toggle button
document.getElementById('audioToggle').addEventListener('click', toggleAudio);
}
function toggleAudio() {
if (!audioEnabled) {
// Initialize audio context
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
// Get microphone input
navigator.mediaDevices.getUserMedia({ audio: true, video: false })
.then(function(stream) {
microphone = audioContext.createMediaStreamSource(stream);
microphone.connect(analyser);
dataArray = new Uint8Array(analyser.frequencyBinCount);
fft = new p5.FFT();
fft.setInput(microphone);
audioEnabled = true;
document.getElementById('audioToggle').textContent = 'DISABLE AUDIO';
})
.catch(function(err) {
console.error('Error accessing microphone:', err);
alert('Could not access microphone. Please check permissions.');
});
} else {
// Disable audio
if (microphone) {
microphone.disconnect();
}
audioEnabled = false;
document.getElementById('audioToggle').textContent = 'ENABLE AUDIO';
}
}
function draw() {
// Update color cycle
hue = (hue + params.colorSpeed) % 360;
// Background with trail effect
background(0, 0, 0, params.trailOpacity);
// Update audio analysis if enabled
if (audioEnabled) {
updateAudioAnalysis();
}
// Draw center vortex
drawVortex();
// Update and draw particles
for (let particle of particles) {
particle.update();
particle.display();
}
// Draw interactive elements
drawInteractiveElements();
}
function updateAudioAnalysis() {
// Get frequency data
analyser.getByteFrequencyData(dataArray);
// Calculate frequency ranges
let bassSum = 0;
let midSum = 0;
let highSum = 0;
for (let i = 0; i < dataArray.length; i++) {
if (i < 5) {
bassSum += dataArray[i];
} else if (i < 15) {
midSum += dataArray[i];
} else {
highSum += dataArray[i];
}
}
bassLevel = bassSum / 5 / 255;
midLevel = midSum / 10 / 255;
highLevel = highSum / (dataArray.length - 15) / 255;
}
function drawVortex() {
push();
translate(width/2, height/2);
// Base vortex effect
let vortexSize = width * 0.4;
let audioBoost = audioEnabled ? (1 + bassLevel * 0.5) : 1;
for (let i = 0; i < 360; i += 5) {
let angle = radians(i);
let dynamicSize = vortexSize * (1 + 0.2 * sin(millis() * 0.001 + i * 0.1)) * audioBoost;
let x1 = cos(angle) * dynamicSize * 0.5;
let y1 = sin(angle) * dynamicSize * 0.5;
let x2 = cos(angle) * dynamicSize;
let y2 = sin(angle) * dynamicSize;
let col = color((hue + i) % 360, 80, 90, 30);
stroke(col);
strokeWeight(2);
line(x1, y1, x2, y2);
// Add some sparkles
if (i % 30 === 0) {
let sparkleSize = 3 + 5 * (0.5 + 0.5 * sin(millis() * 0.005 + i));
fill(col);
noStroke();
ellipse(x2, y2, sparkleSize, sparkleSize);
}
}
pop();
}
function drawInteractiveElements() {
// Draw mouse influence area
if (mouseIsPressed) {
let pulseSize = 50 + 20 * sin(millis() * 0.01);
let col = color((hue + 180) % 360, 90, 100, 20);
fill(col);
noStroke();
ellipse(mouseX, mouseY, pulseSize, pulseSize);
}
// Draw audio visualization if enabled
if (audioEnabled) {
drawAudioVisualization();
}
}
function drawAudioVisualization() {
push();
translate(width/2, height/2);
// Draw frequency bars
let barWidth = width / (dataArray.length / 2);
for (let i = 0; i < dataArray.length / 2; i++) {
let barHeight = dataArray[i] * params.audioSensitivity / 255;
let col = color((hue + i * 5) % 360, 80, 90, 50);
fill(col);
noStroke();
rectMode(CENTER);
rect(
(i - dataArray.length / 4) * barWidth,
height * 0.4,
barWidth * 0.8,
-barHeight
);
}
pop();
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
// Particle class
class Particle {
constructor() {
this.reset();
this.velocity = p5.Vector.random2D().mult(random(0.5, 2));
this.size = random(params.particleSize * 0.5, params.particleSize * 1.5);
this.hueOffset = random(360);
this.life = random(100, 200);
this.age = 0;
this.z = random(-100, 100);
}
reset() {
this.position = createVector(random(width), random(height));
this.velocity = p5.Vector.random2D().mult(random(0.5, 2));
this.acceleration = createVector(0, 0);
this.size = random(params.particleSize * 0.5, params.particleSize * 1.5);
this.hueOffset = random(360);
this.life = random(100, 200);
this.age = 0;
this.z = random(-100, 100);
}
update() {
this.age++;
if (this.age > this.life) {
this.reset();
this.age = 0;
}
// Apply vortex force
let center = createVector(width/2, height/2);
let toCenter = p5.Vector.sub(center, this.position);
let distance = toCenter.mag();
toCenter.normalize();
// Vortex effect with audio modulation
let audioMod = audioEnabled ? (1 + bassLevel * 0.5) : 1;
let vortexForce = toCenter.copy();
vortexForce.rotate(HALF_PI);
vortexForce.mult(params.vortexStrength * audioMod * (1 + 0.2 * sin(distance * 0.01 - millis() * 0.001)));
vortexForce.mult(map(distance, 0, width/2, 2, 0.1));
// Apply noise force
let noiseForce = createVector(
noise(this.position.x * params.noiseScale, this.position.y * params.noiseScale, millis() * 0.0001) - 0.5,
noise(this.position.y * params.noiseScale, millis() * 0.0001, this.position.x * params.noiseScale) - 0.5
);
noiseForce.mult(0.5);
// Apply mouse influence if mouse is pressed
let mouseForce = createVector(0, 0);
if (mouseIsPressed) {
let toMouse = p5.Vector.sub(createVector(mouseX, mouseY), this.position);
let mouseDist = toMouse.mag();
if (mouseDist < 200) {
toMouse.normalize();
mouseForce = toMouse.mult(params.mouseInfluence * map(mouseDist, 0, 200, 1, 0));
}
}
// Combine all forces
this.acceleration.add(vortexForce);
this.acceleration.add(noiseForce);
this.acceleration.add(mouseForce);
// Apply audio forces if enabled
if (audioEnabled) {
// Bass pushes particles outward
let audioOutwardForce = toCenter.copy();
audioOutwardForce.mult(-bassLevel * 0.5);
// High frequencies add randomness
let audioRandomForce = p5.Vector.random2D().mult(highLevel * 0.3);
this.acceleration.add(audioOutwardForce);
this.acceleration.add(audioRandomForce);
}
// Update physics
this.velocity.add(this.acceleration);
this.velocity.limit(3);
this.position.add(this.velocity);
this.acceleration.mult(0);
// Wrap around edges
if (this.position.x < 0) this.position.x = width;
if (this.position.x > width) this.position.x = 0;
if (this.position.y < 0) this.position.y = height;
if (this.position.y > height) this.position.y = 0;
// Z-depth movement
this.z += random(-0.5, 0.5);
this.z = constrain(this.z, -100, 100);
}
display() {
let distanceToCenter = dist(this.position.x, this.position.y, width/2, height/2);
let distanceFactor = map(distanceToCenter, 0, width/2, 0.3, 1);
// Calculate color with audio modulation
let particleHue = (hue + this.hueOffset + (audioEnabled ? midLevel * 50 : 0)) % 360;
let saturation = map(distanceToCenter, 0, width/2, 30, 90);
let brightness = 70 + (audioEnabled ? highLevel * 30 : 0);
let alpha = map(this.age, 0, this.life, 30, 80) * distanceFactor;
// Size with audio modulation
let displaySize = this.size * (1 + (audioEnabled ? bassLevel * 0.5 : 0));
// Draw particle
noStroke();
fill(particleHue, saturation, brightness, alpha);
// Add some depth with z position
let zFactor = map(this.z, -100, 100, 0.7, 1.3);
ellipse(
this.position.x,
this.position.y,
displaySize * zFactor,
displaySize * zFactor
);
// Add glow effect for some particles
if (random() < 0.1) {
fill(particleHue, saturation, brightness, alpha * 0.3);
ellipse(
this.position.x,
this.position.y,
displaySize * zFactor * 3,
displaySize * zFactor * 3
);
}
}
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=maydayjeffk/trippy-deepsite" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
</html>