|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Cherry Blossoms & Snowfall</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: 'Arial', sans-serif; |
|
|
} |
|
|
#info { |
|
|
position: absolute; |
|
|
bottom: 20px; |
|
|
width: 100%; |
|
|
text-align: center; |
|
|
color: white; |
|
|
text-shadow: 0 0 5px rgba(0,0,0,0.5); |
|
|
z-index: 100; |
|
|
pointer-events: none; |
|
|
} |
|
|
#title { |
|
|
position: absolute; |
|
|
top: 20px; |
|
|
width: 100%; |
|
|
text-align: center; |
|
|
color: white; |
|
|
font-size: 2.5rem; |
|
|
text-shadow: 0 0 10px rgba(0,0,0,0.7); |
|
|
z-index: 100; |
|
|
font-weight: 300; |
|
|
letter-spacing: 2px; |
|
|
pointer-events: none; |
|
|
} |
|
|
.petal { |
|
|
position: absolute; |
|
|
width: 15px; |
|
|
height: 15px; |
|
|
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><path fill="%23ffb6c1" d="M50 0 Q75 25 100 50 Q75 75 50 100 Q25 75 0 50 Q25 25 50 0"/></svg>') no-repeat; |
|
|
background-size: contain; |
|
|
opacity: 0.8; |
|
|
animation: petal-fall linear infinite; |
|
|
filter: drop-shadow(0 0 2px rgba(255,182,193,0.7)); |
|
|
} |
|
|
@keyframes petal-fall { |
|
|
0% { |
|
|
transform: translate(0, -10px) rotate(0deg); |
|
|
} |
|
|
100% { |
|
|
transform: translate(calc(var(--sway) * 100px), calc(100vh + 10px)) rotate(360deg); |
|
|
} |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gradient-to-b from-blue-900 to-purple-900"> |
|
|
<div id="title">春の舞 (Spring Dance)</div> |
|
|
<div id="info">Cherry blossoms and snowflakes dancing together</div> |
|
|
|
|
|
<script> |
|
|
document.addEventListener('DOMContentLoaded', () => { |
|
|
|
|
|
const scene = new THREE.Scene(); |
|
|
scene.background = new THREE.Color(0x0a1128); |
|
|
|
|
|
|
|
|
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); |
|
|
camera.position.set(0, 5, 30); |
|
|
camera.lookAt(0, 0, 0); |
|
|
|
|
|
|
|
|
const renderer = new THREE.WebGLRenderer({ antialias: true }); |
|
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
|
renderer.setPixelRatio(window.devicePixelRatio); |
|
|
document.body.appendChild(renderer.domElement); |
|
|
|
|
|
|
|
|
createCherryTree(scene); |
|
|
|
|
|
|
|
|
const snowflakes = createSnowflakes(scene); |
|
|
|
|
|
|
|
|
const petals = createPetals(scene); |
|
|
|
|
|
|
|
|
const stars = createStars(scene); |
|
|
|
|
|
|
|
|
const ambientLight = new THREE.AmbientLight(0x404040); |
|
|
scene.add(ambientLight); |
|
|
|
|
|
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.7); |
|
|
directionalLight.position.set(1, 1, 1); |
|
|
scene.add(directionalLight); |
|
|
|
|
|
|
|
|
const moonGeometry = new THREE.SphereGeometry(3, 32, 32); |
|
|
const moonMaterial = new THREE.MeshBasicMaterial({ |
|
|
color: 0xffffcc, |
|
|
transparent: true, |
|
|
opacity: 0.9 |
|
|
}); |
|
|
const moon = new THREE.Mesh(moonGeometry, moonMaterial); |
|
|
moon.position.set(-20, 20, -30); |
|
|
scene.add(moon); |
|
|
|
|
|
|
|
|
function animate() { |
|
|
requestAnimationFrame(animate); |
|
|
|
|
|
|
|
|
snowflakes.forEach(flake => { |
|
|
flake.position.y -= flake.speed; |
|
|
flake.position.x += Math.sin(Date.now() * 0.001 + flake.id) * 0.05; |
|
|
|
|
|
if (flake.position.y < -20) { |
|
|
flake.position.y = 20; |
|
|
flake.position.x = Math.random() * 40 - 20; |
|
|
flake.position.z = Math.random() * 40 - 20; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
petals.forEach(petal => { |
|
|
petal.position.y -= petal.speed; |
|
|
petal.position.x += Math.sin(Date.now() * 0.001 + petal.id) * 0.03; |
|
|
petal.rotation.y += 0.01; |
|
|
|
|
|
if (petal.position.y < -5) { |
|
|
petal.position.y = 15; |
|
|
petal.position.x = Math.random() * 10 - 5; |
|
|
petal.position.z = Math.random() * 10 - 5; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
stars.rotation.x += 0.0001; |
|
|
stars.rotation.y += 0.0001; |
|
|
|
|
|
renderer.render(scene, camera); |
|
|
} |
|
|
|
|
|
|
|
|
window.addEventListener('resize', () => { |
|
|
camera.aspect = window.innerWidth / window.innerHeight; |
|
|
camera.updateProjectionMatrix(); |
|
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
|
}); |
|
|
|
|
|
|
|
|
animate(); |
|
|
|
|
|
|
|
|
for (let i = 0; i < 20; i++) { |
|
|
const petal = document.createElement('div'); |
|
|
petal.className = 'petal'; |
|
|
|
|
|
|
|
|
const size = Math.random() * 15 + 10; |
|
|
petal.style.width = `${size}px`; |
|
|
petal.style.height = `${size}px`; |
|
|
petal.style.left = `${Math.random() * 100}vw`; |
|
|
petal.style.top = `${Math.random() * 20 - 10}vh`; |
|
|
petal.style.setProperty('--sway', Math.random() * 2 - 1); |
|
|
|
|
|
|
|
|
const duration = Math.random() * 10 + 5; |
|
|
petal.style.animationDuration = `${duration}s`; |
|
|
|
|
|
|
|
|
petal.style.opacity = Math.random() * 0.5 + 0.3; |
|
|
|
|
|
document.body.appendChild(petal); |
|
|
} |
|
|
}); |
|
|
|
|
|
function createCherryTree(scene) { |
|
|
|
|
|
const trunkGeometry = new THREE.CylinderGeometry(0.5, 1, 10, 8); |
|
|
const trunkMaterial = new THREE.MeshPhongMaterial({ |
|
|
color: 0x8B4513, |
|
|
flatShading: true |
|
|
}); |
|
|
const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial); |
|
|
trunk.position.y = 5; |
|
|
trunk.rotation.z = Math.PI / 20; |
|
|
scene.add(trunk); |
|
|
|
|
|
|
|
|
const branchMaterial = new THREE.MeshPhongMaterial({ |
|
|
color: 0x8B4513, |
|
|
flatShading: true |
|
|
}); |
|
|
|
|
|
for (let i = 0; i < 5; i++) { |
|
|
const length = 5 + Math.random() * 3; |
|
|
const angle = Math.PI * 0.2 + Math.random() * Math.PI * 0.3; |
|
|
const branchGeometry = new THREE.CylinderGeometry(0.2, 0.4, length, 6); |
|
|
const branch = new THREE.Mesh(branchGeometry, branchMaterial); |
|
|
|
|
|
branch.position.y = 8 + i * 0.5; |
|
|
branch.position.x = (Math.random() - 0.5) * 3; |
|
|
branch.rotation.z = angle * (Math.random() > 0.5 ? 1 : -1); |
|
|
|
|
|
scene.add(branch); |
|
|
} |
|
|
|
|
|
|
|
|
const blossomGeometry = new THREE.SphereGeometry(0.1, 8, 8); |
|
|
const blossomMaterial = new THREE.MeshPhongMaterial({ |
|
|
color: 0xffb6c1, |
|
|
transparent: true, |
|
|
opacity: 0.9 |
|
|
}); |
|
|
|
|
|
for (let i = 0; i < 100; i++) { |
|
|
const blossom = new THREE.Mesh(blossomGeometry, blossomMaterial); |
|
|
|
|
|
|
|
|
const angle = Math.random() * Math.PI * 2; |
|
|
const radius = 1 + Math.random() * 4; |
|
|
const height = 5 + Math.random() * 8; |
|
|
|
|
|
blossom.position.x = Math.cos(angle) * radius; |
|
|
blossom.position.y = height; |
|
|
blossom.position.z = Math.sin(angle) * radius; |
|
|
|
|
|
scene.add(blossom); |
|
|
} |
|
|
} |
|
|
|
|
|
function createSnowflakes(scene) { |
|
|
const snowflakes = []; |
|
|
const snowflakeGeometry = new THREE.BufferGeometry(); |
|
|
const snowflakeMaterial = new THREE.PointsMaterial({ |
|
|
color: 0xffffff, |
|
|
size: 0.15, |
|
|
transparent: true, |
|
|
opacity: 0.8, |
|
|
blending: THREE.AdditiveBlending |
|
|
}); |
|
|
|
|
|
const snowflakeCount = 1500; |
|
|
const positions = new Float32Array(snowflakeCount * 3); |
|
|
|
|
|
for (let i = 0; i < snowflakeCount; i++) { |
|
|
positions[i * 3] = Math.random() * 40 - 20; |
|
|
positions[i * 3 + 1] = Math.random() * 40 - 10; |
|
|
positions[i * 3 + 2] = Math.random() * 40 - 20; |
|
|
} |
|
|
|
|
|
snowflakeGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); |
|
|
|
|
|
const snowflakeSystem = new THREE.Points(snowflakeGeometry, snowflakeMaterial); |
|
|
scene.add(snowflakeSystem); |
|
|
|
|
|
|
|
|
for (let i = 0; i < snowflakeCount; i++) { |
|
|
snowflakes.push({ |
|
|
position: snowflakeSystem.geometry.attributes.position, |
|
|
index: i, |
|
|
speed: 0.05 + Math.random() * 0.1, |
|
|
id: i |
|
|
}); |
|
|
} |
|
|
|
|
|
return snowflakes; |
|
|
} |
|
|
|
|
|
function createPetals(scene) { |
|
|
const petals = []; |
|
|
const petalGeometry = new THREE.PlaneGeometry(0.3, 0.3); |
|
|
const petalMaterial = new THREE.MeshPhongMaterial({ |
|
|
color: 0xffb6c1, |
|
|
transparent: true, |
|
|
opacity: 0.7, |
|
|
side: THREE.DoubleSide |
|
|
}); |
|
|
|
|
|
const petalCount = 100; |
|
|
|
|
|
for (let i = 0; i < petalCount; i++) { |
|
|
const petal = new THREE.Mesh(petalGeometry, petalMaterial); |
|
|
|
|
|
petal.position.x = Math.random() * 10 - 5; |
|
|
petal.position.y = 5 + Math.random() * 10; |
|
|
petal.position.z = Math.random() * 10 - 5; |
|
|
|
|
|
petal.rotation.x = Math.random() * Math.PI; |
|
|
petal.rotation.y = Math.random() * Math.PI; |
|
|
petal.rotation.z = Math.random() * Math.PI; |
|
|
|
|
|
petal.speed = 0.02 + Math.random() * 0.03; |
|
|
petal.id = i; |
|
|
|
|
|
scene.add(petal); |
|
|
petals.push(petal); |
|
|
} |
|
|
|
|
|
return petals; |
|
|
} |
|
|
|
|
|
function createStars(scene) { |
|
|
const starGeometry = new THREE.BufferGeometry(); |
|
|
const starMaterial = new THREE.PointsMaterial({ |
|
|
color: 0xffffff, |
|
|
size: 0.1, |
|
|
transparent: true, |
|
|
opacity: 0.7 |
|
|
}); |
|
|
|
|
|
const starCount = 1000; |
|
|
const starPositions = new Float32Array(starCount * 3); |
|
|
|
|
|
for (let i = 0; i < starCount; i++) { |
|
|
starPositions[i * 3] = (Math.random() - 0.5) * 2000; |
|
|
starPositions[i * 3 + 1] = (Math.random() - 0.5) * 2000; |
|
|
starPositions[i * 3 + 2] = (Math.random() - 0.5) * 2000; |
|
|
} |
|
|
|
|
|
starGeometry.setAttribute('position', new THREE.BufferAttribute(starPositions, 3)); |
|
|
const stars = new THREE.Points(starGeometry, starMaterial); |
|
|
scene.add(stars); |
|
|
|
|
|
return stars; |
|
|
} |
|
|
</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=joung/t-t" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |