From 51ed7ff35bc8cd8284efe202f6f8b599862b4c2b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 19 Aug 2025 17:26:20 +0000
Subject: [PATCH 1/2] Initial plan
From 649daf70854ac447f9fcf83fedba0957244542c3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 19 Aug 2025 17:38:14 +0000
Subject: [PATCH 2/2] Complete 3D portfolio enhancement with Three.js,
interactive particles, and advanced animations
Co-authored-by: nishant9083 <132076277+nishant9083@users.noreply.github.com>
---
index.html | 1 +
script.js | 382 +++++++++++++++++++++++++++++++++++++++++++++++++++++
styles.css | 215 ++++++++++++++++++++++++++++--
3 files changed, 585 insertions(+), 13 deletions(-)
diff --git a/index.html b/index.html
index c8a9865..460f0e1 100644
--- a/index.html
+++ b/index.html
@@ -1122,6 +1122,7 @@
Technologies
+
diff --git a/script.js b/script.js
index 7505870..589004b 100644
--- a/script.js
+++ b/script.js
@@ -16,6 +16,7 @@ class ModernPortfolio {
this.setupProjectFilter();
this.setupFormHandling();
this.setupParticleAnimation();
+ this.setup3DCardEffects();
this.initializeLucideIcons();
}
@@ -583,6 +584,88 @@ class ModernPortfolio {
document.body.classList.remove('keyboard-navigation');
});
}
+
+ // 3D Card Effects with Mouse Tracking
+ setup3DCardEffects() {
+ const cards = document.querySelectorAll('.project-card, .floating-card, .skill-item');
+
+ cards.forEach(card => {
+ card.addEventListener('mousemove', (e) => {
+ const rect = card.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ const centerX = rect.width / 2;
+ const centerY = rect.height / 2;
+
+ const rotateX = (y - centerY) / centerY * -10;
+ const rotateY = (x - centerX) / centerX * 10;
+
+ card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateZ(20px)`;
+ card.style.boxShadow = '0 20px 40px rgba(99, 102, 241, 0.3)';
+ });
+
+ card.addEventListener('mouseleave', () => {
+ card.style.transform = '';
+ card.style.boxShadow = '';
+ });
+ });
+
+ // Enhanced floating cards interaction
+ const floatingCards = document.querySelectorAll('.floating-card');
+ floatingCards.forEach(card => {
+ card.addEventListener('click', () => {
+ card.style.animation = 'none';
+ card.style.transform = 'rotateY(360deg) scale(1.2)';
+
+ setTimeout(() => {
+ card.style.animation = '';
+ card.style.transform = '';
+ }, 600);
+ });
+ });
+
+ // 3D Progress bars for skills
+ this.enhance3DProgressBars();
+ }
+
+ enhance3DProgressBars() {
+ const skillItems = document.querySelectorAll('.skill-item');
+
+ skillItems.forEach(skill => {
+ const progressBar = skill.querySelector('.skill-progress');
+ if (progressBar) {
+ const progress = progressBar.style.width || '0%';
+ progressBar.style.background = 'linear-gradient(45deg, var(--color-primary), var(--color-secondary))';
+ progressBar.style.borderRadius = '10px';
+ progressBar.style.position = 'relative';
+ progressBar.style.overflow = 'hidden';
+
+ // Add animated shine effect
+ const shine = document.createElement('div');
+ shine.style.cssText = `
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent);
+ animation: shine 2s infinite;
+ `;
+ progressBar.appendChild(shine);
+ }
+ });
+
+ // Add shine animation to CSS
+ const shineStyle = document.createElement('style');
+ shineStyle.textContent = `
+ @keyframes shine {
+ 0% { left: -100%; }
+ 100% { left: 100%; }
+ }
+ `;
+ document.head.appendChild(shineStyle);
+ }
}
// Add CSS for animations
@@ -634,8 +717,307 @@ document.head.appendChild(style);
// Initialize the portfolio when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new ModernPortfolio();
+
+ // Initialize 3D system after a short delay to ensure Three.js is loaded
+ setTimeout(() => {
+ if (typeof THREE !== 'undefined') {
+ new Portfolio3D();
+ }
+ }, 500);
});
+// 3D Engine for Portfolio Enhancements
+class Portfolio3D {
+ constructor() {
+ this.scene = null;
+ this.camera = null;
+ this.renderer = null;
+ this.geometricShapes = [];
+ this.particles = null;
+ this.mouse = { x: 0, y: 0 };
+ this.raycaster = new THREE.Raycaster();
+ this.clock = new THREE.Clock();
+ this.animationId = null;
+
+ this.init();
+ }
+
+ init() {
+ this.createScene();
+ this.createGeometricBackground();
+ this.createInteractiveParticles();
+ this.setupEventListeners();
+ this.animate();
+ }
+
+ createScene() {
+ // Create scene
+ this.scene = new THREE.Scene();
+
+ // Create camera
+ this.camera = new THREE.PerspectiveCamera(
+ 75,
+ window.innerWidth / window.innerHeight,
+ 0.1,
+ 1000
+ );
+ this.camera.position.z = 5;
+
+ // Create renderer
+ this.renderer = new THREE.WebGLRenderer({
+ alpha: true,
+ antialias: true,
+ powerPreference: "high-performance"
+ });
+ this.renderer.setSize(window.innerWidth, window.innerHeight);
+ this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
+ this.renderer.setClearColor(0x000000, 0);
+
+ // Add to hero background
+ const heroBackground = document.querySelector('.hero-particles');
+ if (heroBackground) {
+ heroBackground.innerHTML = '';
+ heroBackground.appendChild(this.renderer.domElement);
+ this.renderer.domElement.style.position = 'absolute';
+ this.renderer.domElement.style.top = '0';
+ this.renderer.domElement.style.left = '0';
+ this.renderer.domElement.style.zIndex = '-1';
+ }
+ }
+
+ createGeometricBackground() {
+ const geometries = [
+ new THREE.BoxGeometry(0.5, 0.5, 0.5),
+ new THREE.SphereGeometry(0.3, 32, 32),
+ new THREE.TetrahedronGeometry(0.4),
+ new THREE.OctahedronGeometry(0.4),
+ new THREE.IcosahedronGeometry(0.3)
+ ];
+
+ const materials = [
+ new THREE.MeshPhongMaterial({
+ color: 0x6366f1,
+ transparent: true,
+ opacity: 0.6,
+ wireframe: false
+ }),
+ new THREE.MeshPhongMaterial({
+ color: 0x8b5cf6,
+ transparent: true,
+ opacity: 0.4,
+ wireframe: true
+ }),
+ new THREE.MeshPhongMaterial({
+ color: 0x0ea5e9,
+ transparent: true,
+ opacity: 0.5
+ })
+ ];
+
+ // Create floating geometric shapes
+ for (let i = 0; i < 15; i++) {
+ const geometry = geometries[Math.floor(Math.random() * geometries.length)];
+ const material = materials[Math.floor(Math.random() * materials.length)].clone();
+ const mesh = new THREE.Mesh(geometry, material);
+
+ // Random position
+ mesh.position.x = (Math.random() - 0.5) * 20;
+ mesh.position.y = (Math.random() - 0.5) * 20;
+ mesh.position.z = (Math.random() - 0.5) * 10;
+
+ // Random rotation
+ mesh.rotation.x = Math.random() * Math.PI;
+ mesh.rotation.y = Math.random() * Math.PI;
+
+ // Physics properties
+ mesh.userData = {
+ velocity: {
+ x: (Math.random() - 0.5) * 0.02,
+ y: (Math.random() - 0.5) * 0.02,
+ z: (Math.random() - 0.5) * 0.02
+ },
+ rotationSpeed: {
+ x: (Math.random() - 0.5) * 0.05,
+ y: (Math.random() - 0.5) * 0.05,
+ z: (Math.random() - 0.5) * 0.05
+ }
+ };
+
+ this.geometricShapes.push(mesh);
+ this.scene.add(mesh);
+ }
+
+ // Add ambient light
+ const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
+ this.scene.add(ambientLight);
+
+ // Add directional light
+ const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
+ directionalLight.position.set(5, 5, 5);
+ this.scene.add(directionalLight);
+ }
+
+ createInteractiveParticles() {
+ const particleCount = 500;
+ const geometry = new THREE.BufferGeometry();
+ const positions = new Float32Array(particleCount * 3);
+ const colors = new Float32Array(particleCount * 3);
+ const velocities = new Float32Array(particleCount * 3);
+
+ for (let i = 0; i < particleCount; i++) {
+ const i3 = i * 3;
+
+ // Positions
+ positions[i3] = (Math.random() - 0.5) * 20;
+ positions[i3 + 1] = (Math.random() - 0.5) * 20;
+ positions[i3 + 2] = (Math.random() - 0.5) * 10;
+
+ // Colors
+ const colorChoice = Math.random();
+ if (colorChoice < 0.33) {
+ colors[i3] = 0.39; colors[i3 + 1] = 0.40; colors[i3 + 2] = 0.94; // Primary
+ } else if (colorChoice < 0.66) {
+ colors[i3] = 0.55; colors[i3 + 1] = 0.36; colors[i3 + 2] = 0.96; // Purple
+ } else {
+ colors[i3] = 0.05; colors[i3 + 1] = 0.65; colors[i3 + 2] = 0.91; // Blue
+ }
+
+ // Velocities
+ velocities[i3] = (Math.random() - 0.5) * 0.01;
+ velocities[i3 + 1] = (Math.random() - 0.5) * 0.01;
+ velocities[i3 + 2] = (Math.random() - 0.5) * 0.01;
+ }
+
+ geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
+ geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
+ geometry.setAttribute('velocity', new THREE.BufferAttribute(velocities, 3));
+
+ const material = new THREE.PointsMaterial({
+ size: 2,
+ vertexColors: true,
+ transparent: true,
+ opacity: 0.8,
+ blending: THREE.AdditiveBlending
+ });
+
+ this.particles = new THREE.Points(geometry, material);
+ this.scene.add(this.particles);
+ }
+
+ setupEventListeners() {
+ // Mouse movement
+ document.addEventListener('mousemove', (event) => {
+ this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
+ this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
+ });
+
+ // Resize
+ window.addEventListener('resize', () => {
+ this.camera.aspect = window.innerWidth / window.innerHeight;
+ this.camera.updateProjectionMatrix();
+ this.renderer.setSize(window.innerWidth, window.innerHeight);
+ });
+
+ // Reduced motion preference
+ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
+ if (prefersReducedMotion.matches) {
+ this.renderer.domElement.style.display = 'none';
+ }
+ }
+
+ animate() {
+ this.animationId = requestAnimationFrame(() => this.animate());
+
+ const deltaTime = this.clock.getDelta();
+ const elapsedTime = this.clock.getElapsedTime();
+
+ // Animate geometric shapes
+ this.geometricShapes.forEach((shape) => {
+ // Physics movement
+ shape.position.x += shape.userData.velocity.x;
+ shape.position.y += shape.userData.velocity.y;
+ shape.position.z += shape.userData.velocity.z;
+
+ // Rotation
+ shape.rotation.x += shape.userData.rotationSpeed.x;
+ shape.rotation.y += shape.userData.rotationSpeed.y;
+ shape.rotation.z += shape.userData.rotationSpeed.z;
+
+ // Boundary checks
+ if (Math.abs(shape.position.x) > 10) shape.userData.velocity.x *= -1;
+ if (Math.abs(shape.position.y) > 10) shape.userData.velocity.y *= -1;
+ if (Math.abs(shape.position.z) > 5) shape.userData.velocity.z *= -1;
+
+ // Mouse interaction
+ const distance = shape.position.distanceTo(new THREE.Vector3(this.mouse.x * 10, this.mouse.y * 10, 0));
+ if (distance < 3) {
+ const force = 0.1 / (distance + 0.1);
+ shape.userData.velocity.x += (shape.position.x - this.mouse.x * 10) * force * 0.001;
+ shape.userData.velocity.y += (shape.position.y - this.mouse.y * 10) * force * 0.001;
+ }
+ });
+
+ // Animate particles with mouse interaction
+ if (this.particles) {
+ const positions = this.particles.geometry.attributes.position.array;
+ const velocities = this.particles.geometry.attributes.velocity.array;
+
+ for (let i = 0; i < positions.length; i += 3) {
+ // Magnetic effect towards mouse
+ const px = positions[i];
+ const py = positions[i + 1];
+ const mouseWorldX = this.mouse.x * 10;
+ const mouseWorldY = this.mouse.y * 10;
+
+ const dx = mouseWorldX - px;
+ const dy = mouseWorldY - py;
+ const distance = Math.sqrt(dx * dx + dy * dy);
+
+ if (distance < 5) {
+ const force = 0.05 / (distance + 0.1);
+ velocities[i] += dx * force * 0.001;
+ velocities[i + 1] += dy * force * 0.001;
+ }
+
+ // Apply velocities
+ positions[i] += velocities[i];
+ positions[i + 1] += velocities[i + 1];
+ positions[i + 2] += velocities[i + 2];
+
+ // Damping
+ velocities[i] *= 0.98;
+ velocities[i + 1] *= 0.98;
+ velocities[i + 2] *= 0.98;
+
+ // Boundary wrapping
+ if (positions[i] > 10) positions[i] = -10;
+ if (positions[i] < -10) positions[i] = 10;
+ if (positions[i + 1] > 10) positions[i + 1] = -10;
+ if (positions[i + 1] < -10) positions[i + 1] = 10;
+ }
+
+ this.particles.geometry.attributes.position.needsUpdate = true;
+ this.particles.geometry.attributes.velocity.needsUpdate = true;
+ }
+
+ // Camera gentle movement
+ this.camera.position.x = Math.sin(elapsedTime * 0.1) * 0.5;
+ this.camera.position.y = Math.cos(elapsedTime * 0.15) * 0.3;
+ this.camera.lookAt(0, 0, 0);
+
+ this.renderer.render(this.scene, this.camera);
+ }
+
+ destroy() {
+ if (this.animationId) {
+ cancelAnimationFrame(this.animationId);
+ }
+ if (this.renderer) {
+ this.renderer.dispose();
+ }
+ }
+}
+
// Service Worker for offline support (Progressive Web App)
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
diff --git a/styles.css b/styles.css
index 0ad1e92..dcff59e 100644
--- a/styles.css
+++ b/styles.css
@@ -259,14 +259,17 @@ filter: brightness(0);
color: var(--color-text-secondary);
text-decoration: none;
font-weight: 500;
- transition: color var(--transition-fast);
+ transition: all var(--transition-fast);
position: relative;
padding: var(--space-sm) 0;
+ transform-style: preserve-3d;
}
.nav-link:hover,
.nav-link.active {
color: var(--color-primary);
+ transform: translateY(-2px) rotateX(15deg) scale(1.05);
+ text-shadow: 0 2px 4px rgba(99, 102, 241, 0.3);
}
.nav-link::after {
@@ -277,12 +280,14 @@ filter: brightness(0);
width: 0;
height: 2px;
background: var(--gradient-primary);
- transition: width var(--transition-normal);
+ transition: all var(--transition-normal);
+ transform-origin: left;
}
.nav-link:hover::after,
.nav-link.active::after {
width: 100%;
+ transform: rotateY(360deg);
}
.nav-actions {
@@ -500,10 +505,19 @@ section {
font-weight: 900;
line-height: 1.1;
margin-bottom: var(--space-lg);
+ text-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+ transform-style: preserve-3d;
}
.name-part {
display: inline-block;
+ transition: all 0.3s ease;
+ animation: textFloat 3s ease-in-out infinite;
+}
+
+.name-part:hover {
+ transform: rotateX(15deg) rotateY(10deg) translateZ(20px);
+ text-shadow: 0 8px 16px rgba(99, 102, 241, 0.4);
}
.name-part.highlight {
@@ -511,6 +525,16 @@ section {
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
+ animation-delay: 0.5s;
+}
+
+@keyframes textFloat {
+ 0%, 100% {
+ transform: translateY(0px) rotateX(0deg);
+ }
+ 50% {
+ transform: translateY(-5px) rotateX(5deg);
+ }
}
.hero-roles {
@@ -650,10 +674,18 @@ section {
align-items: center;
gap: var(--space-sm);
box-shadow: var(--shadow-lg);
- animation: float 3s ease-in-out infinite;
+ animation: float3d 3s ease-in-out infinite;
font-weight: 600;
font-size: 0.875rem;
color: var(--color-text-primary);
+ transform-style: preserve-3d;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.floating-card:hover {
+ transform: rotateY(15deg) rotateX(10deg) scale(1.1);
+ box-shadow: var(--shadow-xl), 0 0 20px rgba(99, 102, 241, 0.4);
}
.floating-card:nth-child(1) {
@@ -674,13 +706,16 @@ section {
animation-delay: 2s;
}
-@keyframes float {
+@keyframes float3d {
0%,
100% {
- transform: translateY(0px);
+ transform: translateY(0px) rotateX(0deg) rotateY(0deg);
}
- 50% {
- transform: translateY(-10px);
+ 33% {
+ transform: translateY(-10px) rotateX(5deg) rotateY(5deg);
+ }
+ 66% {
+ transform: translateY(-5px) rotateX(-3deg) rotateY(-3deg);
}
}
@@ -872,7 +907,7 @@ section {
}
}
-/* Button Styles */
+/* Enhanced 3D Button Styles */
.btn {
display: inline-flex;
align-items: center;
@@ -887,6 +922,7 @@ section {
font-size: 1rem;
position: relative;
overflow: hidden;
+ transform-style: preserve-3d;
}
.btn-primary {
@@ -896,8 +932,9 @@ section {
}
.btn-primary:hover {
- transform: translateY(-2px);
- box-shadow: var(--shadow-lg);
+ transform: translateY(-4px) rotateX(15deg) scale(1.05);
+ box-shadow: var(--shadow-lg), 0 0 20px rgba(99, 102, 241, 0.5);
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.btn-secondary {
@@ -911,7 +948,9 @@ section {
background: var(--color-primary);
color: var(--color-text-inverse);
border-color: var(--color-primary);
- transform: translateY(-2px);
+ transform: translateY(-4px) rotateX(15deg) scale(1.05);
+ box-shadow: 0 8px 25px rgba(99, 102, 241, 0.3);
+}
box-shadow: var(--shadow-lg);
}
@@ -1215,10 +1254,12 @@ section {
box-shadow: var(--shadow-md);
}
+/* 3D Enhanced Styles */
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: var(--space-xl);
+ perspective: 1000px;
}
.project-card {
@@ -1229,11 +1270,13 @@ section {
transition: all var(--transition-normal);
backdrop-filter: blur(10px);
box-shadow: var(--shadow-md);
+ transform-style: preserve-3d;
+ position: relative;
}
.project-card:hover {
- transform: translateY(-8px);
- box-shadow: var(--shadow-xl);
+ transform: translateY(-12px) rotateX(5deg) rotateY(5deg) scale(1.02);
+ box-shadow: var(--shadow-xl), 0 0 30px rgba(99, 102, 241, 0.3);
}
.project-image {
@@ -1998,3 +2041,149 @@ img[data-loading="true"] {
animation: none;
}
}
+
+/* ========== 3D ENHANCEMENT STYLES ========== */
+
+/* Global 3D settings */
+* {
+ transform-style: preserve-3d;
+}
+
+/* 3D Loading Animation */
+@keyframes loader3D {
+ 0% {
+ transform: perspective(120px) rotateX(0deg) rotateY(0deg);
+ }
+ 50% {
+ transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
+ }
+ 100% {
+ transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
+ }
+}
+
+.loading-3d {
+ animation: loader3D 1.5s infinite ease-in-out;
+}
+
+/* 3D Hover Effects for Interactive Elements */
+.project-link:hover {
+ transform: translateZ(10px) rotateY(20deg) scale(1.1);
+ box-shadow: 0 10px 20px rgba(99, 102, 241, 0.4);
+}
+
+/* Enhanced 3D Text Effects */
+.hero-description {
+ transform-style: preserve-3d;
+ transition: transform 0.3s ease;
+}
+
+.hero-description:hover {
+ transform: perspective(1000px) rotateX(10deg) translateZ(10px);
+}
+
+/* 3D Skill Progress Bars */
+.skill-progress {
+ position: relative;
+ transform-style: preserve-3d;
+}
+
+.skill-progress::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(45deg, transparent, rgba(255,255,255,0.1), transparent);
+ transform: translateZ(1px);
+ animation: progressShine 3s infinite;
+}
+
+@keyframes progressShine {
+ 0% { transform: translateX(-100%) translateZ(1px); }
+ 100% { transform: translateX(100%) translateZ(1px); }
+}
+
+/* 3D Theme Toggle Button */
+.theme-toggle {
+ transform-style: preserve-3d;
+ transition: all 0.3s ease;
+}
+
+.theme-toggle:hover {
+ transform: perspective(1000px) rotateY(180deg) scale(1.1);
+}
+
+/* 3D Contact Form */
+.contact-form {
+ perspective: 1000px;
+}
+
+.form-group {
+ transform-style: preserve-3d;
+ transition: transform 0.3s ease;
+}
+
+.form-group:focus-within {
+ transform: perspective(1000px) rotateX(5deg) translateZ(10px);
+}
+
+/* 3D Footer */
+.footer {
+ perspective: 2000px;
+}
+
+/* Enhanced Mobile 3D Effects */
+@media (max-width: 768px) {
+ .floating-card:hover {
+ transform: scale(1.05) rotateY(5deg);
+ }
+
+ .project-card:hover {
+ transform: translateY(-8px) scale(1.02);
+ }
+
+ .btn:hover {
+ transform: translateY(-2px) scale(1.02);
+ }
+}
+
+/* Touch-friendly 3D effects */
+@media (hover: none) and (pointer: coarse) {
+ .project-card:active {
+ transform: scale(0.98) rotateX(2deg);
+ }
+
+ .floating-card:active {
+ transform: scale(0.95) rotateY(10deg);
+ }
+
+ .btn:active {
+ transform: scale(0.98) translateY(1px);
+ }
+}
+
+/* Accessibility: Respect reduced motion preferences */
+@media (prefers-reduced-motion: reduce) {
+ .name-part {
+ animation: none;
+ }
+
+ .textFloat {
+ animation: none;
+ }
+
+ .float3d {
+ animation: none;
+ }
+
+ .progressShine {
+ animation: none;
+ }
+
+ * {
+ transform: none !important;
+ animation: none !important;
+ }
+}