diff --git a/index.html b/index.html index e59f257..b217639 100644 --- a/index.html +++ b/index.html @@ -71,6 +71,27 @@ transform: translateX(100%); } + /* 3D Thumbnail Container Styles */ + .threejs-thumb { + position: relative; + width: 100%; + height: 120px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + background: linear-gradient(135deg, rgba(31, 41, 55, 0.8), rgba(17, 24, 39, 0.9)); + border-radius: 0.5rem 0.5rem 0 0; + } + .threejs-thumb canvas { + display: block; + } + @media (min-width: 768px) { + .threejs-thumb { + height: 140px; + } + } + @@ -206,7 +227,7 @@

Engineering Proje
-
🏆
+

ASME IMECE BrainBolt 2025

@@ -226,7 +247,7 @@

ASME IMECE BrainBolt 2025

-
🚣
+

Kayak Paddle Optimization

@@ -246,7 +267,7 @@

Kayak Paddle Optimization

-
🤖
+

Glass Cleaning Robot

@@ -276,6 +297,7 @@

Web Demos & Mini-
+

Pitchathon Site

A simple, clean website for a pitching competition. Built with HTML & CSS.

@@ -287,17 +309,19 @@

Pitchathon Site

+

Job Application Form

A responsive job application form layout. A pure HTML & CSS exercise.

+

Drestein

A landing page concept. (Feel free to update this description!)

@@ -309,6 +333,7 @@

Drestein

+

SIH Campus 2

A website for the Smart India Hackathon campus event.

@@ -320,6 +345,7 @@

SIH Campus 2

+

SIH Cam

Another project related to the Smart India Hackathon.

@@ -331,12 +357,13 @@

SIH Cam

+

Robot Project Page

A simple HTML page for the Smart Glass Cleaning Robot project.

@@ -728,10 +755,176 @@

Let's work together

}); } + // --- 3D Thumbnail Data Storage --- + const thumbnailDataMap = new Map(); + + // --- 3D Thumbnail Generator for Project/Demo Cards --- + function createThumb3D(container, shapeType, accentColor) { + if (!container) return null; + + const width = container.clientWidth; + const height = container.clientHeight; + + // Scene + const scene = new THREE.Scene(); + + // Camera - adjusted FOV for better fit + const camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 1000); + camera.position.z = 4; + + // Renderer + const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); + renderer.setSize(width, height); + renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); + container.appendChild(renderer.domElement); + + // Colors - Metallic palette with neon accents + const accentHex = accentColor === 'pink' ? 0xec4899 : 0x3b82f6; + const metallicColor = 0x9ca3af; // Silver/gray + + // Geometry creation based on shape type + let geometry; + const scale = 1.2; // Base scale for all objects + + switch(shapeType) { + case 'trophy': + geometry = new THREE.ConeGeometry(0.8 * scale, 1.4 * scale, 6); + break; + case 'torus': + geometry = new THREE.TorusGeometry(0.7 * scale, 0.25 * scale, 16, 50); + break; + case 'robot': + geometry = new THREE.BoxGeometry(1 * scale, 1.2 * scale, 0.8 * scale); + break; + case 'octahedron': + geometry = new THREE.OctahedronGeometry(0.9 * scale, 0); + break; + case 'dodecahedron': + geometry = new THREE.DodecahedronGeometry(0.85 * scale, 0); + break; + case 'icosahedron': + geometry = new THREE.IcosahedronGeometry(0.9 * scale, 0); + break; + case 'torusKnot': + geometry = new THREE.TorusKnotGeometry(0.5 * scale, 0.18 * scale, 80, 12); + break; + case 'gear': + geometry = new THREE.CylinderGeometry(0.8 * scale, 0.8 * scale, 0.3 * scale, 12); + break; + default: + geometry = new THREE.IcosahedronGeometry(0.9 * scale, 0); + } + + // Metallic material for the main object + const mainMaterial = new THREE.MeshStandardMaterial({ + color: metallicColor, + metalness: 0.7, + roughness: 0.2 + }); + const mainMesh = new THREE.Mesh(geometry, mainMaterial); + mainMesh.position.set(0, 0, 0); + scene.add(mainMesh); + + // Wireframe overlay with accent color + const wireframeMaterial = new THREE.MeshBasicMaterial({ + color: accentHex, + wireframe: true, + transparent: true, + opacity: 0.4 + }); + const wireframeMesh = new THREE.Mesh(geometry, wireframeMaterial); + wireframeMesh.position.set(0, 0, 0); + scene.add(wireframeMesh); + + // Lighting setup + const ambientLight = new THREE.AmbientLight(0xffffff, 0.4); + scene.add(ambientLight); + + const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); + directionalLight.position.set(2, 3, 4); + scene.add(directionalLight); + + // Colored rim light for glow effect + const rimLight = new THREE.PointLight(accentHex, 0.6, 10); + rimLight.position.set(-2, 1, 2); + scene.add(rimLight); + + // Second accent light + const secondLight = new THREE.PointLight(accentColor === 'pink' ? 0x3b82f6 : 0xec4899, 0.3, 8); + secondLight.position.set(2, -1, 1); + scene.add(secondLight); + + // Animation with cleanup capability + let animationId = null; + let isAnimating = true; + + function animate() { + if (!isAnimating) return; + animationId = requestAnimationFrame(animate); + mainMesh.rotation.x += 0.005; + mainMesh.rotation.y += 0.008; + wireframeMesh.rotation.x += 0.005; + wireframeMesh.rotation.y += 0.008; + renderer.render(scene, camera); + } + animate(); + + // Cleanup function to stop animation and dispose resources + function cleanup() { + isAnimating = false; + if (animationId !== null) { + cancelAnimationFrame(animationId); + } + geometry.dispose(); + mainMaterial.dispose(); + wireframeMaterial.dispose(); + renderer.dispose(); + thumbnailDataMap.delete(container); + } + + // Store reference in Map for resize handling + const thumbData = { camera, renderer, scene, mainMesh, wireframeMesh, cleanup }; + thumbnailDataMap.set(container, thumbData); + + return thumbData; + } + + // --- Initialize all 3D Thumbnails --- + function initThumbnails() { + const thumbContainers = document.querySelectorAll('.threejs-thumb'); + thumbContainers.forEach(container => { + const shape = container.dataset.shape || 'icosahedron'; + const accent = container.dataset.accent || 'blue'; + createThumb3D(container, shape, accent); + }); + + // Debounced resize handler for performance + let resizeTimeout; + function handleResize() { + thumbContainers.forEach(container => { + const thumbData = thumbnailDataMap.get(container); + if (thumbData) { + const { camera, renderer } = thumbData; + const width = container.clientWidth; + const height = container.clientHeight; + camera.aspect = width / height; + camera.updateProjectionMatrix(); + renderer.setSize(width, height); + } + }); + } + + window.addEventListener('resize', () => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(handleResize, 150); + }); + } + // Start everything initAboutCanvas(); // Initialize the new canvas initTypingAnimation(); // Start the typing effect initMobileMenu(); // Initialize the mobile menu + initThumbnails(); // Initialize 3D thumbnails });