1. ( index.html )

3D Particle Morphing Presented By Code Zing

html
<!DOCTYPE html>
<html lang="az">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D Particle Morphing @codezing</title>
   </head>
<body>

    <div id="canvas-container"></div>

    <div class="ui-container">
        <input type="text" id="text-input" maxlength="15" autocomplete="off">
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

    <script>
        let scene, camera, renderer, particles;
        const particleCount = 40000;
        let targetPositions = [];
        let velocities = [];
        let mouse = new THREE.Vector2(-1000, -1000);
        let isTextMode = false;
        
        const textCanvas = document.createElement('canvas');
        const textCtx = textCanvas.getContext('2d');
        textCanvas.width = 800; 
        textCanvas.height = 300;

        function getHeartPoint(t, u) {
            const x = 16 * Math.pow(Math.sin(u), 3) * Math.sin(t);
            const y = (13 * Math.cos(u) - 5 * Math.cos(2 * u) - 2 * Math.cos(3 * u) - Math.cos(4 * u)) * Math.sin(t);
            const z = 10 * Math.cos(t);
            return new THREE.Vector3(x * 0.75, y * 0.75, z * 0.75);
        }

        function sampleText(text) {
            if (!text || text.trim() === "") return null;
            
            textCtx.clearRect(0, 0, textCanvas.width, textCanvas.height);
            textCtx.fillStyle = "white";
            
            const fontSize = text.length > 10 ? 70 : 100;
            textCtx.font = `900 ${fontSize}px sans-serif`;
            textCtx.textAlign = "center";
            textCtx.textBaseline = "middle";
            
            textCtx.fillText(text, textCanvas.width / 2, textCanvas.height / 2);

            const imageData = textCtx.getImageData(0, 0, textCanvas.width, textCanvas.height).data;
            const points = [];
            
            for (let y = 0; y < textCanvas.height; y += 1) {
                for (let x = 0; x < textCanvas.width; x += 1) {
                    const alpha = imageData[(y * textCanvas.width + x) * 4 + 3];
                    if (alpha > 150) {
                        points.push({
                            x: (x - textCanvas.width / 2) * 0.1,
                            y: -(y - textCanvas.height / 2) * 0.1,
                            z: (Math.random() - 0.5) * 1.5
                        });
                    }
                }
            }
            return points;
        }

        function updateTargets(text) {
            const textPoints = sampleText(text);
            isTextMode = textPoints !== null && textPoints.length > 0;
            
            // Fırlanmanı hər iki rejimdə sıfırlayırıq ki, obyekt düz qalsın
            if (particles) {
                particles.rotation.y = 0;
                particles.rotation.x = 0;
                particles.rotation.z = 0;
            }

            for (let i = 0; i < particleCount; i++) {
                if (isTextMode) {
                    const target = textPoints[i % textPoints.length];
                    targetPositions[i] = {
                        x: target.x + (Math.random() - 0.5) * 0.1,
                        y: target.y + (Math.random() - 0.5) * 0.1,
                        z: target.z + (Math.random() - 0.5) * 0.1
                    };
                } else {
                    const t = Math.acos(Math.random() * 2 - 1);
                    const u = Math.random() * Math.PI * 2;
                    const p = getHeartPoint(t, u);
                    targetPositions[i] = { 
                        x: p.x + (Math.random()-0.5) * 0.4, 
                        y: p.y + (Math.random()-0.5) * 0.4, 
                        z: p.z + (Math.random()-0.5) * 0.4 
                    };
                }
            }
        }

        function init() {
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            camera.position.z = 35;

            renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.setPixelRatio(window.devicePixelRatio);
            document.getElementById('canvas-container').appendChild(renderer.domElement);

            const geometry = new THREE.BufferGeometry();
            const posArray = new Float32Array(particleCount * 3);
            const colorArray = new Float32Array(particleCount * 3);

            for (let i = 0; i < particleCount; i++) {
                posArray[i * 3] = (Math.random() - 0.5) * 200;
                posArray[i * 3 + 1] = (Math.random() - 0.5) * 200;
                posArray[i * 3 + 2] = (Math.random() - 0.5) * 200;

                velocities.push({x: 0, y: 0, z: 0});

                const r = 0.7 + Math.random() * 0.3;
                const g = 0.1 + Math.random() * 0.15;
                const b = 0.3 + Math.random() * 0.25;
                
                colorArray[i * 3] = r;
                colorArray[i * 3 + 1] = g;
                colorArray[i * 3 + 2] = b;
            }

            geometry.setAttribute('position', new THREE.BufferAttribute(posArray, 3));
            geometry.setAttribute('color', new THREE.BufferAttribute(colorArray, 3));

            const material = new THREE.PointsMaterial({
                size: 0.12,
                vertexColors: true,
                transparent: true,
                opacity: 0.85,
                blending: THREE.AdditiveBlending
            });

            particles = new THREE.Points(geometry, material);
            scene.add(particles);

            updateTargets(""); 

            window.addEventListener('resize', onWindowResize);
            window.addEventListener('mousemove', onMouseMove);
            document.getElementById('text-input').addEventListener('input', (e) => {
                updateTargets(e.target.value);
            });
            
            animate();
        }

        function onMouseMove(event) {
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        function animate() {
            requestAnimationFrame(animate);

            const posAttr = particles.geometry.attributes.position;

            const vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
            vector.unproject(camera);
            const dir = vector.sub(camera.position).normalize();
            const distance = -camera.position.z / dir.z;
            const mPos = camera.position.clone().add(dir.multiplyScalar(distance));

            for (let i = 0; i < particleCount; i++) {
                let px = posAttr.getX(i);
                let py = posAttr.getY(i);
                let pz = posAttr.getZ(i);

                const target = targetPositions[i];
                
                const dx = px - mPos.x;
                const dy = py - mPos.y;
                const dz = pz - mPos.z;
                const distSq = dx*dx + dy*dy + dz*dz;
                const dist = Math.sqrt(distSq);
                
                if (dist < 8) {
                    const force = (8 - dist) / 8;
                    velocities[i].x += (dx / dist) * force * 1.8;
                    velocities[i].y += (dy / dist) * force * 1.8;
                    velocities[i].z += (dz / dist) * force * 1.8;
                }

                velocities[i].x += (target.x - px) * 0.08;
                velocities[i].y += (target.y - py) * 0.08;
                velocities[i].z += (target.z - pz) * 0.08;

                velocities[i].x *= 0.78;
                velocities[i].y *= 0.78;
                velocities[i].z *= 0.78;

                posAttr.setXYZ(i, px + velocities[i].x, py + velocities[i].y, pz + velocities[i].z);
            }

            posAttr.needsUpdate = true;

            // Bütün rotasiya kodları silindi və ya sıfırlandı
            particles.rotation.y = 0;
            particles.rotation.z = 0;
            particles.rotation.x = 0;

            renderer.render(scene, camera);
        }

        window.onload = init;
    </script>
</body>
</html>