|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Flower Wisdom Spinner</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> |
|
|
<style> |
|
|
body { |
|
|
margin: 0; |
|
|
overflow: hidden; |
|
|
font-family: 'Courier New', monospace; |
|
|
cursor: grab; |
|
|
user-select: none; |
|
|
background: linear-gradient(135deg, #000428, #004e92); |
|
|
} |
|
|
|
|
|
#spinner-container { |
|
|
position: fixed; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
} |
|
|
|
|
|
#ui-overlay { |
|
|
position: fixed; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
pointer-events: none; |
|
|
z-index: 100; |
|
|
color: white; |
|
|
padding: 1rem; |
|
|
box-sizing: border-box; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
align-items: center; |
|
|
justify-content: flex-start; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
|
|
|
@media (max-width: 600px) { |
|
|
#ui-overlay { |
|
|
padding: 0.5rem; |
|
|
font-size: 0.9rem; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.title { |
|
|
font-size: 2.5rem; |
|
|
margin-bottom: 1rem; |
|
|
text-shadow: 0 0 10px rgba(255,255,255,0.5); |
|
|
background: linear-gradient(to right, #fbc2eb, #a6c1ee); |
|
|
-webkit-background-clip: text; |
|
|
-webkit-text-fill-color: transparent; |
|
|
animation: pulse 2s infinite; |
|
|
} |
|
|
|
|
|
@keyframes pulse { |
|
|
0% { transform: scale(1); } |
|
|
50% { transform: scale(1.05); } |
|
|
100% { transform: scale(1); } |
|
|
} |
|
|
|
|
|
.subtitle { |
|
|
font-size: 1rem; |
|
|
margin-bottom: 2rem; |
|
|
color: rgba(255,255,255,0.7); |
|
|
max-width: 500px; |
|
|
text-align: center; |
|
|
line-height: 1.5; |
|
|
} |
|
|
|
|
|
#wisdom-container { |
|
|
position: fixed; |
|
|
bottom: 2rem; |
|
|
left: 50%; |
|
|
transform: translateX(-50%); |
|
|
width: 80%; |
|
|
max-width: 600px; |
|
|
max-height: 200px; |
|
|
overflow-y: auto; |
|
|
background: rgba(0, 0, 0, 0.5); |
|
|
border: 1px solid rgba(255,255,255,0.2); |
|
|
border-radius: 1rem; |
|
|
padding: 1rem; |
|
|
backdrop-filter: blur(10px); |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
align-items: center; |
|
|
} |
|
|
|
|
|
.wisdom-bubble { |
|
|
background: rgba(255,255,255,0.1); |
|
|
border-radius: 1rem; |
|
|
padding: 0.8rem 1.2rem; |
|
|
margin-bottom: 0.8rem; |
|
|
animation: fadeIn 0.5s ease-out; |
|
|
border: 1px solid rgba(255,255,255,0.2); |
|
|
width: 90%; |
|
|
text-align: center; |
|
|
font-style: italic; |
|
|
color: #fff; |
|
|
position: relative; |
|
|
} |
|
|
|
|
|
.wisdom-bubble::before { |
|
|
content: "❝"; |
|
|
position: absolute; |
|
|
left: 0.5rem; |
|
|
top: 0.5rem; |
|
|
font-size: 1.5rem; |
|
|
opacity: 0.5; |
|
|
} |
|
|
|
|
|
.wisdom-bubble::after { |
|
|
content: "❞"; |
|
|
position: absolute; |
|
|
right: 0.5rem; |
|
|
bottom: 0.5rem; |
|
|
font-size: 1.5rem; |
|
|
opacity: 0.5; |
|
|
} |
|
|
|
|
|
@keyframes fadeIn { |
|
|
from { opacity: 0; transform: translateY(10px); } |
|
|
to { opacity: 1; transform: translateY(0); } |
|
|
} |
|
|
|
|
|
.control-btn { |
|
|
position: fixed; |
|
|
width: 80px; |
|
|
height: 80px; |
|
|
border-radius: 50%; |
|
|
background: rgba(255,255,255,0.1); |
|
|
border: 2px solid rgba(255,255,255,0.3); |
|
|
backdrop-filter: blur(5px); |
|
|
pointer-events: auto; |
|
|
cursor: pointer; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
color: white; |
|
|
font-size: 0.8rem; |
|
|
text-align: center; |
|
|
transition: all 0.3s; |
|
|
z-index: 200; |
|
|
} |
|
|
|
|
|
.control-btn:hover { |
|
|
background: rgba(255,255,255,0.2); |
|
|
transform: scale(1.1); |
|
|
} |
|
|
|
|
|
#color-btn { |
|
|
bottom: 12rem; |
|
|
left: 2rem; |
|
|
} |
|
|
|
|
|
#reset-btn { |
|
|
bottom: 2rem; |
|
|
right: 2rem; |
|
|
} |
|
|
|
|
|
#speed-indicator { |
|
|
position: fixed; |
|
|
bottom: 12rem; |
|
|
right: 2rem; |
|
|
width: 80px; |
|
|
height: 80px; |
|
|
border-radius: 50%; |
|
|
background: rgba(255,255,255,0.1); |
|
|
border: 2px solid rgba(255,255,255,0.3); |
|
|
backdrop-filter: blur(5px); |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
color: white; |
|
|
font-size: 0.9rem; |
|
|
} |
|
|
|
|
|
#speed-value { |
|
|
font-size: 1.2rem; |
|
|
font-weight: bold; |
|
|
margin-top: 0.2rem; |
|
|
} |
|
|
|
|
|
.particle { |
|
|
position: absolute; |
|
|
width: 10px; |
|
|
height: 10px; |
|
|
border-radius: 50%; |
|
|
pointer-events: none; |
|
|
z-index: 10; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
<div id="spinner-container"></div> |
|
|
|
|
|
<div id="ui-overlay"> |
|
|
<div class="title">FLOWER OF WISDOM</div> |
|
|
<div class="subtitle">Spin the flower to release petals of Kabir's wisdom. The faster you spin, the more wisdom blossoms.</div> |
|
|
</div> |
|
|
|
|
|
<div id="wisdom-container"> |
|
|
<div class="wisdom-bubble">"Between the conscious and the unconscious, the mind has put up a swing."</div> |
|
|
</div> |
|
|
|
|
|
<div class="control-btn" id="color-btn">CHANGE<br>FLOWER</div> |
|
|
<div class="control-btn" id="reset-btn">RESET</div> |
|
|
|
|
|
<div id="speed-indicator"> |
|
|
<div>SPEED</div> |
|
|
<div id="speed-value">0%</div> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
const container = document.getElementById('spinner-container'); |
|
|
const width = container.clientWidth; |
|
|
const height = container.clientHeight; |
|
|
|
|
|
|
|
|
const scene = new THREE.Scene(); |
|
|
scene.background = new THREE.Color(0x000428); |
|
|
|
|
|
|
|
|
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000); |
|
|
camera.position.z = 5; |
|
|
|
|
|
|
|
|
const renderer = new THREE.WebGLRenderer({ antialias: true }); |
|
|
renderer.setSize(width, height); |
|
|
renderer.setPixelRatio(window.devicePixelRatio); |
|
|
container.appendChild(renderer.domElement); |
|
|
|
|
|
|
|
|
const bloomParams = { |
|
|
exposure: 1, |
|
|
bloomStrength: 1.5, |
|
|
bloomThreshold: 0, |
|
|
bloomRadius: 0.5 |
|
|
}; |
|
|
|
|
|
|
|
|
const ambientLight = new THREE.AmbientLight(0x404040); |
|
|
scene.add(ambientLight); |
|
|
|
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); |
|
|
directionalLight.position.set(1, 1, 1); |
|
|
scene.add(directionalLight); |
|
|
|
|
|
|
|
|
let flower; |
|
|
let flowerSpeed = 0; |
|
|
let maxSpeed = 30; |
|
|
let isDragging = false; |
|
|
let previousMousePosition = { x: 0, y: 0 }; |
|
|
let currentColor = 0xff69b4; |
|
|
let colorChangeInterval; |
|
|
let lastWisdomDropTime = 0; |
|
|
let wisdomDropped = false; |
|
|
let particles = []; |
|
|
let particleSystem; |
|
|
|
|
|
|
|
|
const flowerColors = [ |
|
|
0xff69b4, |
|
|
0x9370db, |
|
|
0xffa500, |
|
|
0x32cd32, |
|
|
0x00bfff, |
|
|
0xff6347, |
|
|
0xda70d6, |
|
|
0x20b2aa |
|
|
]; |
|
|
|
|
|
|
|
|
const kabirWisdom = [ |
|
|
"Between the conscious and the unconscious, the mind has put up a swing.", |
|
|
"The river that flows in you also flows in me.", |
|
|
"When the drop merges into the ocean, who can find it?", |
|
|
"The guest is inside you, and also inside me.", |
|
|
"Wherever you are is the entry point.", |
|
|
"The truth was a mirror in the hands of God. It fell, and broke into pieces.", |
|
|
"I laugh when I hear that the fish in the water is thirsty.", |
|
|
"The moon shines in my body, but my blind eyes cannot see it.", |
|
|
"What you are searching for is seeking you.", |
|
|
"If you don't break your ropes while you're alive, do you think ghosts will do it after?", |
|
|
"The water in the vessel is sparkling; the water in the sea is dark.", |
|
|
"When you really look for me, you will see me instantly.", |
|
|
"The lane of love is narrow—there is room for only one.", |
|
|
"What is seen is not the Truth; what is unseen is not a lie.", |
|
|
"The flute of the infinite is played without ceasing." |
|
|
]; |
|
|
|
|
|
|
|
|
function createFlowerPetal() { |
|
|
const shape = new THREE.Shape(); |
|
|
const x = 0, y = 0; |
|
|
|
|
|
shape.moveTo(x, y); |
|
|
shape.bezierCurveTo(x + 0.5, y + 0.5, x + 1, y + 0.8, x + 1.5, y); |
|
|
shape.bezierCurveTo(x + 1, y - 0.8, x + 0.5, y - 0.5, x, y); |
|
|
|
|
|
const extrudeSettings = { |
|
|
steps: 1, |
|
|
depth: 0.1, |
|
|
bevelEnabled: true, |
|
|
bevelThickness: 0.1, |
|
|
bevelSize: 0.1, |
|
|
bevelSegments: 8 |
|
|
}; |
|
|
|
|
|
return new THREE.ExtrudeGeometry(shape, extrudeSettings); |
|
|
} |
|
|
|
|
|
|
|
|
function createSmallFlower() { |
|
|
const group = new THREE.Group(); |
|
|
|
|
|
|
|
|
const centerGeo = new THREE.SphereGeometry(0.05, 16, 16); |
|
|
const centerMat = new THREE.MeshPhongMaterial({ |
|
|
color: 0xffff00, |
|
|
emissive: 0xffff00, |
|
|
emissiveIntensity: 0.5 |
|
|
}); |
|
|
const center = new THREE.Mesh(centerGeo, centerMat); |
|
|
group.add(center); |
|
|
|
|
|
|
|
|
const petalGeo = new THREE.ConeGeometry(0.1, 0.2, 4, 1); |
|
|
const petalMat = new THREE.MeshPhongMaterial({ |
|
|
color: currentColor, |
|
|
emissive: currentColor, |
|
|
emissiveIntensity: 0.3, |
|
|
flatShading: true |
|
|
}); |
|
|
|
|
|
for (let i = 0; i < 5; i++) { |
|
|
const petal = new THREE.Mesh(petalGeo, petalMat); |
|
|
petal.rotation.z = (i * Math.PI * 2) / 5; |
|
|
petal.position.x = Math.cos(petal.rotation.z) * 0.15; |
|
|
petal.position.y = Math.sin(petal.rotation.z) * 0.15; |
|
|
petal.rotation.x = Math.PI / 2; |
|
|
group.add(petal); |
|
|
} |
|
|
|
|
|
return group; |
|
|
} |
|
|
|
|
|
|
|
|
function createFlowerSpinner() { |
|
|
const group = new THREE.Group(); |
|
|
|
|
|
|
|
|
const centerGeometry = new THREE.SphereGeometry(0.4, 32, 32); |
|
|
const centerMaterial = new THREE.MeshPhongMaterial({ |
|
|
color: 0xffff00, |
|
|
emissive: 0xffff00, |
|
|
emissiveIntensity: 0.8, |
|
|
shininess: 100 |
|
|
}); |
|
|
const center = new THREE.Mesh(centerGeometry, centerMaterial); |
|
|
group.add(center); |
|
|
|
|
|
|
|
|
const petalGeometry = createFlowerPetal(); |
|
|
const petalMaterial = new THREE.MeshPhongMaterial({ |
|
|
color: currentColor, |
|
|
emissive: currentColor, |
|
|
emissiveIntensity: 0.5, |
|
|
side: THREE.DoubleSide, |
|
|
specular: 0xffffff, |
|
|
shininess: 30 |
|
|
}); |
|
|
|
|
|
|
|
|
for (let i = 0; i < 8; i++) { |
|
|
const petal = new THREE.Mesh(petalGeometry, petalMaterial); |
|
|
petal.rotation.z = (i * Math.PI * 2) / 8; |
|
|
petal.position.x = Math.cos(petal.rotation.z) * 0.8; |
|
|
petal.position.y = Math.sin(petal.rotation.z) * 0.8; |
|
|
group.add(petal); |
|
|
|
|
|
|
|
|
const lineGeometry = new THREE.BufferGeometry().setFromPoints([ |
|
|
new THREE.Vector3(0, 0, 0), |
|
|
new THREE.Vector3(1.5, 0, 0) |
|
|
]); |
|
|
const lineMaterial = new THREE.LineBasicMaterial({ |
|
|
color: 0xffff00, |
|
|
linewidth: 2 |
|
|
}); |
|
|
const line = new THREE.Line(lineGeometry, lineMaterial); |
|
|
line.position.x = Math.cos(petal.rotation.z) * 0.8; |
|
|
line.position.y = Math.sin(petal.rotation.z) * 0.8; |
|
|
line.rotation.z = petal.rotation.z; |
|
|
line.scale.set(0.7, 0.7, 0.7); |
|
|
group.add(line); |
|
|
} |
|
|
|
|
|
|
|
|
const leafGeometry = new THREE.ConeGeometry(0.3, 0.8, 4, 1); |
|
|
const leafMaterial = new THREE.MeshPhongMaterial({ |
|
|
color: 0x32cd32, |
|
|
emissive: 0x228b22, |
|
|
emissiveIntensity: 0.3 |
|
|
}); |
|
|
|
|
|
for (let i = 0; i < 3; i++) { |
|
|
const leaf = new THREE.Mesh(leafGeometry, leafMaterial); |
|
|
leaf.rotation.z = (i * Math.PI * 2) / 3; |
|
|
leaf.rotation.x = Math.PI / 2; |
|
|
leaf.position.y = -0.8; |
|
|
group.add(leaf); |
|
|
} |
|
|
|
|
|
return group; |
|
|
} |
|
|
|
|
|
flower = createFlowerSpinner(); |
|
|
scene.add(flower); |
|
|
|
|
|
|
|
|
function createParticleSystem() { |
|
|
const particles = []; |
|
|
const particleCount = 100; |
|
|
|
|
|
for (let i = 0; i < particleCount; i++) { |
|
|
const particle = createSmallFlower(); |
|
|
|
|
|
|
|
|
const radius = 5 * Math.random() * 0.5; |
|
|
const theta = Math.random() * Math.PI * 2; |
|
|
const phi = Math.random() * Math.PI * 2; |
|
|
|
|
|
particle.position.x = radius * Math.sin(theta) * Math.cos(phi); |
|
|
particle.position.y = radius * Math.sin(theta) * Math.sin(phi); |
|
|
particle.position.z = radius * Math.cos(theta); |
|
|
|
|
|
|
|
|
const scale = 0.2 + Math.random() * 0.3; |
|
|
particle.scale.set(scale, scale, scale); |
|
|
particle.rotation.set( |
|
|
Math.random() * Math.PI, |
|
|
Math.random() * Math.PI, |
|
|
Math.random() * Math.PI |
|
|
); |
|
|
|
|
|
|
|
|
particle.userData = { |
|
|
velocity: new THREE.Vector3( |
|
|
(Math.random() - 0.5) * 0.01, |
|
|
(Math.random() - 0.5) * 0.01, |
|
|
(Math.random() - 0.5) * 0.01 |
|
|
), |
|
|
rotationSpeed: new THREE.Vector3( |
|
|
(Math.random() - 0.5) * 0.01, |
|
|
(Math.random() - 0.5) * 0.01, |
|
|
(Math.random() - 0.5) * 0.01 |
|
|
) |
|
|
}; |
|
|
|
|
|
particles.push(particle); |
|
|
} |
|
|
|
|
|
return particles; |
|
|
} |
|
|
|
|
|
|
|
|
particleSystem = createParticleSystem(); |
|
|
particleSystem.forEach(particle => scene.add(particle)); |
|
|
|
|
|
|
|
|
window.addEventListener('resize', () => { |
|
|
const newWidth = container.clientWidth; |
|
|
const newHeight = container.clientHeight; |
|
|
|
|
|
camera.aspect = newWidth / newHeight; |
|
|
camera.updateProjectionMatrix(); |
|
|
|
|
|
renderer.setSize(newWidth, newHeight); |
|
|
}); |
|
|
|
|
|
|
|
|
function emitParticles() { |
|
|
const speedPercent = (Math.abs(flowerSpeed) / maxSpeed) * 100; |
|
|
|
|
|
if (speedPercent > 30) { |
|
|
const particlesToEmit = Math.floor(speedPercent / 20); |
|
|
|
|
|
for (let i = 0; i < particlesToEmit; i++) { |
|
|
const particle = createSmallFlower(); |
|
|
|
|
|
|
|
|
const angle = Math.random() * Math.PI * 2; |
|
|
const distance = 1.5 + Math.random() * 0.5; |
|
|
|
|
|
particle.position.x = Math.cos(angle) * distance; |
|
|
particle.position.y = Math.sin(angle) * distance; |
|
|
|
|
|
|
|
|
const scale = 0.1 + Math.random() * 0.2; |
|
|
particle.scale.set(scale, scale, scale); |
|
|
|
|
|
|
|
|
particle.userData = { |
|
|
velocity: new THREE.Vector3( |
|
|
Math.cos(angle) * 0.02, |
|
|
Math.sin(angle) * 0.02, |
|
|
(Math.random() - 0.5) * 0.01 |
|
|
), |
|
|
rotationSpeed: new THREE.Vector3( |
|
|
(Math.random() - 0.5) * 0.02, |
|
|
(Math.random() - 0.5) * 0.02, |
|
|
(Math.random() - 0.5) * 0.02 |
|
|
), |
|
|
lifetime: 100 + Math.random() * 100 |
|
|
}; |
|
|
|
|
|
scene.add(particle); |
|
|
particleSystem.push(particle); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function updateParticles() { |
|
|
for (let i = particleSystem.length - 1; i >= 0; i--) { |
|
|
const particle = particleSystem[i]; |
|
|
|
|
|
|
|
|
particle.position.add(particle.userData.velocity); |
|
|
|
|
|
|
|
|
particle.rotation.x += particle.userData.rotationSpeed.x; |
|
|
particle.rotation.y += particle.userData.rotationSpeed.y; |
|
|
particle.rotation.z += particle.userData.rotationSpeed.z; |
|
|
|
|
|
|
|
|
if (particle.userData.lifetime !== undefined) { |
|
|
particle.userData.lifetime--; |
|
|
|
|
|
|
|
|
if (particle.userData.lifetime < 30) { |
|
|
particle.children.forEach(child => { |
|
|
if (child.material) { |
|
|
child.material.opacity = particle.userData.lifetime / 30; |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
if (particle.userData.lifetime <= 0) { |
|
|
scene.remove(particle); |
|
|
particleSystem.splice(i, 1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (particle.position.length() > 10) { |
|
|
scene.remove(particle); |
|
|
particleSystem.splice(i, 1); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function dropWisdom() { |
|
|
const now = Date.now(); |
|
|
const speedPercent = (Math.abs(flowerSpeed) / maxSpeed) * 100; |
|
|
|
|
|
|
|
|
if (speedPercent > 5 && (now - lastWisdomDropTime > 3000 || !wisdomDropped)) { |
|
|
const wisdom = kabirWisdom[Math.floor(Math.random() * kabirWisdom.length)]; |
|
|
|
|
|
const bubble = document.createElement('div'); |
|
|
bubble.className = 'wisdom-bubble'; |
|
|
bubble.textContent = wisdom; |
|
|
|
|
|
const container = document.getElementById('wisdom-container'); |
|
|
container.insertBefore(bubble, container.firstChild); |
|
|
|
|
|
|
|
|
if (container.children.length > 5) { |
|
|
container.removeChild(container.lastChild); |
|
|
} |
|
|
|
|
|
lastWisdomDropTime = now; |
|
|
wisdomDropped = true; |
|
|
|
|
|
|
|
|
const originalColor = currentColor; |
|
|
currentColor = 0xffffff; |
|
|
scene.remove(flower); |
|
|
flower = createFlowerSpinner(); |
|
|
scene.add(flower); |
|
|
|
|
|
setTimeout(() => { |
|
|
currentColor = originalColor; |
|
|
scene.remove(flower); |
|
|
flower = createFlowerSpinner(); |
|
|
scene.add(flower); |
|
|
}, 200); |
|
|
} else if (speedPercent < 30) { |
|
|
wisdomDropped = false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function updateSpeedIndicator() { |
|
|
const speedPercent = (Math.abs(flowerSpeed) / maxSpeed) * 100; |
|
|
document.getElementById('speed-value').textContent = Math.floor(speedPercent) + '%'; |
|
|
|
|
|
|
|
|
const speedIndicator = document.getElementById('speed-indicator'); |
|
|
if (speedPercent > 70) { |
|
|
speedIndicator.style.background = 'rgba(255, 50, 50, 0.3)'; |
|
|
speedIndicator.style.borderColor = 'rgba(255, 100, 100, 0.5)'; |
|
|
} else if (speedPercent > 40) { |
|
|
speedIndicator.style.background = 'rgba(255, 165, 0, 0.3)'; |
|
|
speedIndicator.style.borderColor = 'rgba(255, 200, 0, 0.5)'; |
|
|
} else { |
|
|
speedIndicator.style.background = 'rgba(255, 255, 255, 0.1)'; |
|
|
speedIndicator.style.borderColor = 'rgba(255, 255, 255, 0.3)'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function animate() { |
|
|
requestAnimationFrame(animate); |
|
|
|
|
|
|
|
|
flower.rotation.z += flowerSpeed; |
|
|
|
|
|
|
|
|
if (!isDragging) { |
|
|
flowerSpeed *= 0.98; |
|
|
if (Math.abs(flowerSpeed) < 0.001) flowerSpeed = 0; |
|
|
} |
|
|
|
|
|
|
|
|
emitParticles(); |
|
|
updateParticles(); |
|
|
dropWisdom(); |
|
|
updateSpeedIndicator(); |
|
|
|
|
|
|
|
|
if (Math.abs(flowerSpeed) < 0.5) { |
|
|
const pulse = Math.sin(Date.now() * 0.002) * 0.05 + 1; |
|
|
flower.scale.set(pulse, pulse, pulse); |
|
|
} else { |
|
|
flower.scale.set(1, 1, 1); |
|
|
} |
|
|
|
|
|
renderer.render(scene, camera); |
|
|
} |
|
|
|
|
|
animate(); |
|
|
|
|
|
|
|
|
container.addEventListener('mousedown', (e) => { |
|
|
isDragging = true; |
|
|
previousMousePosition = { x: e.clientX, y: e.clientY }; |
|
|
container.style.cursor = 'grabbing'; |
|
|
}); |
|
|
|
|
|
window.addEventListener('mouseup', () => { |
|
|
isDragging = false; |
|
|
container.style.cursor = 'grab'; |
|
|
}); |
|
|
|
|
|
container.addEventListener('mousemove', (e) => { |
|
|
if (isDragging) { |
|
|
const deltaMove = { x: e.clientX - previousMousePosition.x }; |
|
|
|
|
|
|
|
|
flowerSpeed = deltaMove.x * 0.02; |
|
|
flowerSpeed = Math.min(Math.max(flowerSpeed, -maxSpeed), maxSpeed); |
|
|
|
|
|
previousMousePosition = { x: e.clientX, y: e.clientY }; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
container.addEventListener('touchstart', (e) => { |
|
|
isDragging = true; |
|
|
previousMousePosition = { x: e.touches[0].clientX, y: e.touches[0].clientY }; |
|
|
container.style.cursor = 'grabbing'; |
|
|
e.preventDefault(); |
|
|
}); |
|
|
|
|
|
window.addEventListener('touchend', () => { |
|
|
isDragging = false; |
|
|
container.style.cursor = 'grab'; |
|
|
}); |
|
|
|
|
|
container.addEventListener('touchmove', (e) => { |
|
|
if (isDragging) { |
|
|
const deltaMove = { x: e.touches[0].clientX - previousMousePosition.x }; |
|
|
|
|
|
|
|
|
flowerSpeed = deltaMove.x * 0.03; |
|
|
flowerSpeed = Math.min(Math.max(flowerSpeed, -maxSpeed), maxSpeed); |
|
|
|
|
|
previousMousePosition = { x: e.touches[0].clientX, y: e.touches[0].clientY }; |
|
|
e.preventDefault(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('color-btn').addEventListener('click', () => { |
|
|
|
|
|
let newColor; |
|
|
do { |
|
|
newColor = flowerColors[Math.floor(Math.random() * flowerColors.length)]; |
|
|
} while (newColor === currentColor); |
|
|
|
|
|
currentColor = newColor; |
|
|
|
|
|
|
|
|
scene.remove(flower); |
|
|
|
|
|
|
|
|
flower = createFlowerSpinner(); |
|
|
scene.add(flower); |
|
|
|
|
|
|
|
|
particleSystem.forEach(particle => { |
|
|
particle.children.forEach(child => { |
|
|
if (child.material && child.material.color) { |
|
|
if (child.material.color.getHex() !== 0xffff00) { |
|
|
child.material.color.setHex(currentColor); |
|
|
child.material.emissive.setHex(currentColor); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('reset-btn').addEventListener('click', () => { |
|
|
flowerSpeed = 0; |
|
|
document.getElementById('speed-value').textContent = '0%'; |
|
|
|
|
|
|
|
|
const container = document.getElementById('wisdom-container'); |
|
|
while (container.children.length > 1) { |
|
|
container.removeChild(container.lastChild); |
|
|
} |
|
|
|
|
|
|
|
|
currentColor = 0xff69b4; |
|
|
scene.remove(flower); |
|
|
flower = createFlowerSpinner(); |
|
|
scene.add(flower); |
|
|
|
|
|
|
|
|
const speedIndicator = document.getElementById('speed-indicator'); |
|
|
speedIndicator.style.background = 'rgba(255, 255, 255, 0.1)'; |
|
|
speedIndicator.style.borderColor = 'rgba(255, 255, 255, 0.3)'; |
|
|
|
|
|
|
|
|
particleSystem.forEach(particle => scene.remove(particle)); |
|
|
particleSystem = []; |
|
|
}); |
|
|
</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=db69/flowers" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |