| <!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> |