Ctrl+K
add these features: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Alex Portfolio - Premium Full Stack Developer</title> <link rel="stylesheet" href="style.css"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Orbitron:wght@400;700;900&display=swap" rel="stylesheet"> </head> <body> <!-- Loading Screen --> <div id="loading-screen" class="loading-screen"> <div class="loading-content"> <div class="loading-particles"></div> <div class="loading-text">Loading Experience...</div> <div class="loading-progress"> <div class="progress-bar"></div> </div> </div> </div> <!-- Navigation --> <nav class="nav" id="nav"> <div class="nav-container"> <a href="#hero" class="nav-logo"> <span class="logo-text">ALEX</span> <span class="logo-accent">PORTFOLIO</span> </a> <div class="nav-menu" id="nav-menu"> <a href="#hero" class="nav-link">Home</a> <a href="#about" class="nav-link">About</a> <a href="#skills" class="nav-link">Skills</a> <a href="#projects" class="nav-link">Projects</a> <a href="#contact" class="nav-link">Contact</a> </div> <div class="nav-toggle" id="nav-toggle"> <span></span> <span></span> <span></span> </div> </div> </nav> <!-- Hero Section --> <section id="hero" class="hero"> <canvas id="particle-canvas" class="particle-canvas"></canvas> <div class="hero-content"> <div class="hero-text"> <h1 class="hero-title"> <span class="typewriter" id="typewriter"></span> <span class="cursor" id="cursor">|</span> </h1> <p class="hero-subtitle">Full Stack Developer & UI/UX Designer</p> <p class="hero-description">Crafting digital experiences with cutting-edge technology and premium design</p> <div class="hero-buttons"> <a href="#projects" class="btn btn-primary"> <span>View My Work</span> <div class="btn-particles"></div> </a> <a href="#contact" class="btn btn-outline"> <span>Get In Touch</span> <div class="btn-particles"></div> </a> </div> </div> </div> <div class="scroll-indicator"> <div class="scroll-mouse"> <div class="scroll-wheel"></div> </div> <span>Scroll to explore</span> </div> </section> <!-- About Section --> <section id="about" class="about section"> <div class="container"> <div class="section-header"> <h2 class="section-title">About Me</h2> <div class="section-subtitle">Passionate about creating exceptional digital experiences</div> </div> <div class="about-content"> <div class="about-card glass-card"> <div class="about-text"> <p>I'm a passionate full-stack developer and UI/UX designer with over 5 years of experience creating premium digital solutions. I specialize in building scalable web applications with modern technologies and crafting intuitive user experiences.</p> <p>My expertise spans across frontend frameworks, backend development, cloud architecture, and 3D web technologies. I believe in the power of clean code, beautiful design, and seamless user interactions.</p> </div> <div class="about-stats"> <div class="stat-item"> <div class="stat-number" data-target="50">0</div> <div class="stat-label">Projects Completed</div> </div> <div class="stat-item"> <div class="stat-number" data-target="5">0</div> <div class="stat-label">Years Experience</div> </div> <div class="stat-item"> <div class="stat-number" data-target="100">0</div> <div class="stat-label">Client Satisfaction</div> </div> </div> </div> </div> </div> </section> <!-- Skills Section --> <section id="skills" class="skills section"> <div class="container"> <div class="section-header"> <h2 class="section-title">Technical Skills</h2> <div class="section-subtitle">Technologies I work with</div> </div> <div class="skills-grid"> <div class="skill-item" data-skill="95"> <div class="skill-header"> <span class="skill-name">JavaScript</span> <span class="skill-percentage">95%</span> </div> <div class="skill-bar"> <div class="skill-progress"></div> </div> </div> <div class="skill-item" data-skill="90"> <div class="skill-header"> <span class="skill-name">React</span> <span class="skill-percentage">90%</span> </div> <div class="skill-bar"> <div class="skill-progress"></div> </div> </div> <div class="skill-item" data-skill="88"> <div class="skill-header"> <span class="skill-name">Node.js</span> <span class="skill-percentage">88%</span> </div> <div class="skill-bar"> <div class="skill-progress"></div> </div> </div> <div class="skill-item" data-skill="85"> <div class="skill-header"> <span class="skill-name">Three.js</span> <span class="skill-percentage">85%</span> </div> <div class="skill-bar"> <div class="skill-progress"></div> </div> </div> <div class="skill-item" data-skill="92"> <div class="skill-header"> <span class="skill-name">UI/UX Design</span> <span class="skill-percentage">92%</span> </div> <div class="skill-bar"> <div class="skill-progress"></div> </div> </div> <div class="skill-item" data-skill="80"> <div class="skill-header"> <span class="skill-name">Python</span> <span class="skill-percentage">80%</span> </div> <div class="skill-bar"> <div class="skill-progress"></div> </div> </div> </div> </div> </section> <!-- Projects Section --> <section id="projects" class="projects section"> <div class="container"> <div class="section-header"> <h2 class="section-title">Featured Projects</h2> <div class="section-subtitle">Some of my recent work</div> </div> <div class="projects-grid"> <div class="project-card glass-card"> <div class="project-image"> <img src="https://via.placeholder.com/400x250/0000FF/FFFFFF?text=AI+Dashboard" alt="AI Analytics Dashboard"> <div class="project-overlay"> <div class="project-links"> <a href="#" class="project-link" target="_blank">Live Demo</a> <a href="#" class="project-link" target="_blank">GitHub</a> </div> </div> </div> <div class="project-content"> <h3 class="project-title">AI Analytics Dashboard</h3> <p class="project-description">Enterprise-level dashboard with real-time data visualization and machine learning insights</p> <div class="project-tech"> <span class="tech-tag">React</span> <span class="tech-tag">D3.js</span> <span class="tech-tag">Python</span> <span class="tech-tag">TensorFlow</span> </div> </div> </div> <div class="project-card glass-card"> <div class="project-image"> <img src="https://via.placeholder.com/400x250/FF0000/FFFFFF?text=E-Commerce" alt="E-Commerce Platform"> <div class="project-overlay"> <div class="project-links"> <a href="#" class="project-link" target="_blank">Live Demo</a> <a href="#" class="project-link" target="_blank">GitHub</a> </div> </div> </div> <div class="project-content"> <h3 class="project-title">E-Commerce Platform</h3> <p class="project-description">Full-stack e-commerce solution with advanced payment integration and inventory management</p> <div class="project-tech"> <span class="tech-tag">Next.js</span> <span class="tech-tag">Stripe</span> <span class="tech-tag">PostgreSQL</span> <span class="tech-tag">AWS</span> </div> </div> </div> <div class="project-card glass-card"> <div class="project-image"> <img src="https://via.placeholder.com/400x250/FFD700/000000?text=3D+Portfolio" alt="3D Portfolio Website"> <div class="project-overlay"> <div class="project-links"> <a href="#" class="project-link" target="_blank">Live Demo</a> <a href="#" class="project-link" target="_blank">GitHub</a> </div> </div> </div> <div class="project-content"> <h3 class="project-title">3D Portfolio Website</h3> <p class="project-description">Immersive 3D portfolio showcasing advanced WebGL techniques and particle systems</p> <div class="project-tech"> <span class="tech-tag">Three.js</span> <span class="tech-tag">GSAP</span> <span class="tech-tag">WebGL</span> <span class="tech-tag">Blender</span> </div> </div> </div> </div> </div> </section> <!-- Contact Section --> <section id="contact" class="contact section"> <div class="container"> <div class="section-header"> <h2 class="section-title">Let's Work Together</h2> <div class="section-subtitle">Ready to bring your ideas to life</div> </div> <div class="contact-content"> <div class="contact-info"> <div class="contact-item"> <div class="contact-icon">π§</div> <div class="contact-details"> <h4>Email</h4> <a href="mailto:[email protected]">[email protected]</a> </div> </div> <div class="contact-item"> <div class="contact-icon">π±</div> <div class="contact-details"> <h4>Phone</h4> <a href="tel:+15551234567">+1 (555) 123-4567</a> </div> </div> <div class="contact-item"> <div class="contact-icon">π</div> <div class="contact-details"> <h4>Location</h4> <span>San Francisco, CA</span> </div> </div> <div class="social-links"> <a href="https://github.com/alexportfolio" target="_blank" class="social-link">GitHub</a> <a href="https://linkedin.com/in/alexportfolio" target="_blank" class="social-link">LinkedIn</a> <a href="https://twitter.com/alexportfolio" target="_blank" class="social-link">Twitter</a> </div> </div> <form class="contact-form glass-card" id="contact-form"> <div class="form-group"> <input type="text" id="name" name="name" class="form-control" placeholder="Your Name" required> <label for="name" class="form-label">Name</label> </div> <div class="form-group"> <input type="email" id="email" name="email" class="form-control" placeholder="Your Email" required> <label for="email" class="form-label">Email</label> </div> <div class="form-group"> <input type="text" id="subject" name="subject" class="form-control" placeholder="Subject" required> <label for="subject" class="form-label">Subject</label> </div> <div class="form-group"> <textarea id="message" name="message" class="form-control" placeholder="Your Message" rows="5" required></textarea> <label for="message" class="form-label">Message</label> </div> <button type="submit" class="btn btn-primary btn-full-width"> <span>Send Message</span> <div class="btn-particles"></div> </button> </form> </div> </div> </section> <!-- Footer --> <footer class="footer"> <div class="container"> <div class="footer-content"> <div class="footer-text"> <p>© 2025 Alex Portfolio. Crafted with passion and cutting-edge technology.</p> </div> <div class="footer-links"> <a href="#hero">Back to Top</a> </div> </div> </div> </footer> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> <script src="app.js"></script> </body> </html> ; :root { /* Colors */ --color-background: rgba(252, 252, 249, 1); --color-surface: rgba(255, 255, 253, 1); --color-text: rgba(19, 52, 59, 1); --color-text-secondary: rgba(98, 108, 113, 1); --color-primary: rgba(33, 128, 141, 1); --color-primary-hover: rgba(29, 116, 128, 1); --color-primary-active: rgba(26, 104, 115, 1); --color-secondary: rgba(94, 82, 64, 0.12); --color-secondary-hover: rgba(94, 82, 64, 0.2); --color-secondary-active: rgba(94, 82, 64, 0.25); --color-border: rgba(94, 82, 64, 0.2); --color-btn-primary-text: rgba(252, 252, 249, 1); --color-card-border: rgba(94, 82, 64, 0.12); --color-card-border-inner: rgba(94, 82, 64, 0.12); --color-error: rgba(192, 21, 47, 1); --color-success: rgba(33, 128, 141, 1); --color-warning: rgba(168, 75, 47, 1); --color-info: rgba(98, 108, 113, 1); --color-focus-ring: rgba(33, 128, 141, 0.4); --color-select-caret: rgba(19, 52, 59, 0.8); /* Common style patterns */ --focus-ring: 0 0 0 3px var(--color-focus-ring); --focus-outline: 2px solid var(--color-primary); --status-bg-opacity: 0.15; --status-border-opacity: 0.25; --select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); --select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); /* RGB versions for opacity control */ --color-success-rgb: 33, 128, 141; --color-error-rgb: 192, 21, 47; --color-warning-rgb: 168, 75, 47; --color-info-rgb: 98, 108, 113; /* Typography */ --font-family-base: "FKGroteskNeue", "Geist", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; --font-family-mono: "Berkeley Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; --font-size-xs: 11px; --font-size-sm: 12px; --font-size-base: 14px; --font-size-md: 14px; --font-size-lg: 16px; --font-size-xl: 18px; --font-size-2xl: 20px; --font-size-3xl: 24px; --font-size-4xl: 30px; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 550; --font-weight-bold: 600; --line-height-tight: 1.2; --line-height-normal: 1.5; --letter-spacing-tight: -0.01em; /* Spacing */ --space-0: 0; --space-1: 1px; --space-2: 2px; --space-4: 4px; --space-6: 6px; --space-8: 8px; --space-10: 10px; --space-12: 12px; --space-16: 16px; --space-20: 20px; --space-24: 24px; --space-32: 32px; /* Border Radius */ --radius-sm: 6px; --radius-base: 8px; --radius-md: 10px; --radius-lg: 12px; --radius-full: 9999px; /* Shadows */ --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.02); --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.02); --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.04), 0 2px 4px -1px rgba(0, 0, 0, 0.02); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.04), 0 4px 6px -2px rgba(0, 0, 0, 0.02); --shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.03); /* Animation */ --duration-fast: 150ms; --duration-normal: 250ms; --ease-standard: cubic-bezier(0.16, 1, 0.3, 1); /* Layout */ --container-sm: 640px; --container-md: 768px; --container-lg: 1024px; --container-xl: 1280px; } /* Dark mode colors */
@media
(prefers-color-scheme: dark) { :root { --color-background: rgba(31, 33, 33, 1); --color-surface: rgba(38, 40, 40, 1); --color-text: rgba(245, 245, 245, 1); --color-text-secondary: rgba(167, 169, 169, 0.7); --color-primary: rgba(50, 184, 198, 1); --color-primary-hover: rgba(45, 166, 178, 1); --color-primary-active: rgba(41, 150, 161, 1); --color-secondary: rgba(119, 124, 124, 0.15); --color-secondary-hover: rgba(119, 124, 124, 0.25); --color-secondary-active: rgba(119, 124, 124, 0.3); --color-border: rgba(119, 124, 124, 0.3); --color-error: rgba(255, 84, 89, 1); --color-success: rgba(50, 184, 198, 1); --color-warning: rgba(230, 129, 97, 1); --color-info: rgba(167, 169, 169, 1); --color-focus-ring: rgba(50, 184, 198, 0.4); --color-btn-primary-text: rgba(19, 52, 59, 1); --color-card-border: rgba(119, 124, 124, 0.2); --color-card-border-inner: rgba(119, 124, 124, 0.15); --shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.15); --button-border-secondary: rgba(119, 124, 124, 0.2); --color-border-secondary: rgba(119, 124, 124, 0.2); --color-select-caret: rgba(245, 245, 245, 0.8); /* Common style patterns - updated for dark mode */ --focus-ring: 0 0 0 3px var(--color-focus-ring); --focus-outline: 2px solid var(--color-primary); --status-bg-opacity: 0.15; --status-border-opacity: 0.25; --select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); --select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); /* RGB versions for dark mode */ --color-success-rgb: 50, 184, 198; --color-error-rgb: 255, 84, 89; --color-warning-rgb: 230, 129, 97; --color-info-rgb: 167, 169, 169; } } /* Data attribute for manual theme switching */ [data-color-scheme="dark"] { --color-background: rgba(31, 33, 33, 1); --color-surface: rgba(38, 40, 40, 1); --color-text: rgba(245, 245, 245, 1); --color-text-secondary: rgba(167, 169, 169, 0.7); --color-primary: rgba(50, 184, 198, 1); --color-primary-hover: rgba(45, 166, 178, 1); --color-primary-active: rgba(41, 150, 161, 1); --color-secondary: rgba(119, 124, 124, 0.15); --color-secondary-hover: rgba(119, 124, 124, 0.25); --color-secondary-active: rgba(119, 124, 124, 0.3); --color-border: rgba(119, 124, 124, 0.3); --color-error: rgba(255, 84, 89, 1); --color-success: rgba(50, 184, 198, 1); --color-warning: rgba(230, 129, 97, 1); --color-info: rgba(167, 169, 169, 1); --color-focus-ring: rgba(50, 184, 198, 0.4); --color-btn-primary-text: rgba(19, 52, 59, 1); --color-card-border: rgba(119, 124, 124, 0.15); --color-card-border-inner: rgba(119, 124, 124, 0.15); --shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.15); --color-border-secondary: rgba(119, 124, 124, 0.2); --color-select-caret: rgba(245, 245, 245, 0.8); /* Common style patterns - updated for dark mode */ --focus-ring: 0 0 0 3px var(--color-focus-ring); --focus-outline: 2px solid var(--color-primary); --status-bg-opacity: 0.15; --status-border-opacity: 0.25; --select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); --select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); /* RGB versions for dark mode */ --color-success-rgb: 50, 184, 198; --color-error-rgb: 255, 84, 89; --color-warning-rgb: 230, 129, 97; --color-info-rgb: 167, 169, 169; } [data-color-scheme="light"] { --color-background: rgba(252, 252, 249, 1); --color-surface: rgba(255, 255, 253, 1); --color-text: rgba(19, 52, 59, 1); --color-text-secondary: rgba(98, 108, 113, 1); --color-primary: rgba(33, 128, 141, 1); --color-primary-hover: rgba(29, 116, 128, 1); --color-primary-active: rgba(26, 104, 115, 1); --color-secondary: rgba(94, 82, 64, 0.12); --color-secondary-hover: rgba(94, 82, 64, 0.2); --color-secondary-active: rgba(94, 82, 64, 0.25); --color-border: rgba(94, 82, 64, 0.2); --color-btn-primary-text: rgba(252, 252, 249, 1); --color-card-border: rgba(94, 82, 64, 0.12); --color-card-border-inner: rgba(94, 82, 64, 0.12); --color-error: rgba(192, 21, 47, 1); --color-success: rgba(33, 128, 141, 1); --color-warning: rgba(168, 75, 47, 1); --color-info: rgba(98, 108, 113, 1); --color-focus-ring: rgba(33, 128, 141, 0.4); /* RGB versions for light mode */ --color-success-rgb: 33, 128, 141; --color-error-rgb: 192, 21, 47; --color-warning-rgb: 168, 75, 47; --color-info-rgb: 98, 108, 113; } /* Base styles */ html { font-size: var(--font-size-base); font-family: var(--font-family-base); line-height: var(--line-height-normal); color: var(--color-text); background-color: var(--color-background); -webkit-font-smoothing: antialiased; box-sizing: border-box; } body { margin: 0; padding: 0; } *, *::before, *::after { box-sizing: inherit; } /* Typography */ h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: var(--font-weight-semibold); line-height: var(--line-height-tight); color: var(--color-text); letter-spacing: var(--letter-spacing-tight); } h1 { font-size: var(--font-size-4xl); } h2 { font-size: var(--font-size-3xl); } h3 { font-size: var(--font-size-2xl); } h4 { font-size: var(--font-size-xl); } h5 { font-size: var(--font-size-lg); } h6 { font-size: var(--font-size-md); } p { margin: 0 0 var(--space-16) 0; } a { color: var(--color-primary); text-decoration: none; transition: color var(--duration-fast) var(--ease-standard); } a:hover { color: var(--color-primary-hover); } code, pre { font-family: var(--font-family-mono); font-size: calc(var(--font-size-base) * 0.95); background-color: var(--color-secondary); border-radius: var(--radius-sm); } code { padding: var(--space-1) var(--space-4); } pre { padding: var(--space-16); margin: var(--space-16) 0; overflow: auto; border: 1px solid var(--color-border); } pre code { background: none; padding: 0; } /* Buttons */ .btn { display: inline-flex; align-items: center; justify-content: center; padding: var(--space-8) var(--space-16); border-radius: var(--radius-base); font-size: var(--font-size-base); font-weight: 500; line-height: 1.5; cursor: pointer; transition: all var(--duration-normal) var(--ease-standard); border: none; text-decoration: none; position: relative; } .btn:focus-visible { outline: none; box-shadow: var(--focus-ring); } .btn--primary { background: var(--color-primary); color: var(--color-btn-primary-text); } .btn--primary:hover { background: var(--color-primary-hover); } .btn--primary:active { background: var(--color-primary-active); } .btn--secondary { background: var(--color-secondary); color: var(--color-text); } .btn--secondary:hover { background: var(--color-secondary-hover); } .btn--secondary:active { background: var(--color-secondary-active); } .btn--outline { background: transparent; border: 1px solid var(--color-border); color: var(--color-text); } .btn--outline:hover { background: var(--color-secondary); } .btn--sm { padding: var(--space-4) var(--space-12); font-size: var(--font-size-sm); border-radius: var(--radius-sm); } .btn--lg { padding: var(--space-10) var(--space-20); font-size: var(--font-size-lg); border-radius: var(--radius-md); } .btn--full-width { width: 100%; } .btn:disabled { opacity: 0.5; cursor: not-allowed; } /* Form elements */ .form-control { display: block; width: 100%; padding: var(--space-8) var(--space-12); font-size: var(--font-size-md); line-height: 1.5; color: var(--color-text); background-color: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-base); transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard); } textarea.form-control { font-family: var(--font-family-base); font-size: var(--font-size-base); } select.form-control { padding: var(--space-8) var(--space-12); -webkit-appearance: none; -moz-appearance: none; appearance: none; background-image: var(--select-caret-light); background-repeat: no-repeat; background-position: right var(--space-12) center; background-size: 16px; padding-right: var(--space-32); } /* Add a dark mode specific caret */
@media
(prefers-color-scheme: dark) { select.form-control { background-image: var(--select-caret-dark); } } /* Also handle data-color-scheme */ [data-color-scheme="dark"] select.form-control { background-image: var(--select-caret-dark); } [data-color-scheme="light"] select.form-control { background-image: var(--select-caret-light); } .form-control:focus { border-color: var(--color-primary); outline: var(--focus-outline); } .form-label { display: block; margin-bottom: var(--space-8); font-weight: var(--font-weight-medium); font-size: var(--font-size-sm); } .form-group { margin-bottom: var(--space-16); } /* Card component */ .card { background-color: var(--color-surface); border-radius: var(--radius-lg); border: 1px solid var(--color-card-border); box-shadow: var(--shadow-sm); overflow: hidden; transition: box-shadow var(--duration-normal) var(--ease-standard); } .card:hover { box-shadow: var(--shadow-md); } .card__body { padding: var(--space-16); } .card__header, .card__footer { padding: var(--space-16); border-bottom: 1px solid var(--color-card-border-inner); } /* Status indicators - simplified with CSS variables */ .status { display: inline-flex; align-items: center; padding: var(--space-6) var(--space-12); border-radius: var(--radius-full); font-weight: var(--font-weight-medium); font-size: var(--font-size-sm); } .status--success { background-color: rgba( var(--color-success-rgb, 33, 128, 141), var(--status-bg-opacity) ); color: var(--color-success); border: 1px solid rgba(var(--color-success-rgb, 33, 128, 141), var(--status-border-opacity)); } .status--error { background-color: rgba( var(--color-error-rgb, 192, 21, 47), var(--status-bg-opacity) ); color: var(--color-error); border: 1px solid rgba(var(--color-error-rgb, 192, 21, 47), var(--status-border-opacity)); } .status--warning { background-color: rgba( var(--color-warning-rgb, 168, 75, 47), var(--status-bg-opacity) ); color: var(--color-warning); border: 1px solid rgba(var(--color-warning-rgb, 168, 75, 47), var(--status-border-opacity)); } .status--info { background-color: rgba( var(--color-info-rgb, 98, 108, 113), var(--status-bg-opacity) ); color: var(--color-info); border: 1px solid rgba(var(--color-info-rgb, 98, 108, 113), var(--status-border-opacity)); } /* Container layout */ .container { width: 100%; margin-right: auto; margin-left: auto; padding-right: var(--space-16); padding-left: var(--space-16); }
@media
(min-width: 640px) { .container { max-width: var(--container-sm); } }
@media
(min-width: 768px) { .container { max-width: var(--container-md); } }
@media
(min-width: 1024px) { .container { max-width: var(--container-lg); } }
@media
(min-width: 1280px) { .container { max-width: var(--container-xl); } } /* Utility classes */ .flex { display: flex; } .flex-col { flex-direction: column; } .items-center { align-items: center; } .justify-center { justify-content: center; } .justify-between { justify-content: space-between; } .gap-4 { gap: var(--space-4); } .gap-8 { gap: var(--space-8); } .gap-16 { gap: var(--space-16); } .m-0 { margin: 0; } .mt-8 { margin-top: var(--space-8); } .mb-8 { margin-bottom: var(--space-8); } .mx-8 { margin-left: var(--space-8); margin-right: var(--space-8); } .my-8 { margin-top: var(--space-8); margin-bottom: var(--space-8); } .p-0 { padding: 0; } .py-8 { padding-top: var(--space-8); padding-bottom: var(--space-8); } .px-8 { padding-left: var(--space-8); padding-right: var(--space-8); } .py-16 { padding-top: var(--space-16); padding-bottom: var(--space-16); } .px-16 { padding-left: var(--space-16); padding-right: var(--space-16); } .block { display: block; } .hidden { display: none; } /* Accessibility */ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; } :focus-visible { outline: var(--focus-outline); outline-offset: 2px; } /* Dark mode specifics */ [data-color-scheme="dark"] .btn--outline { border: 1px solid var(--color-border-secondary); } @font-face { font-family: 'FKGroteskNeue'; src: url('https://r2cdn.perplexity.ai/fonts/FKGroteskNeue.woff2') format('woff2'); } :root { /* AMOLED Color Palette */ --amoled-black: #000000; --amoled-black-secondary: #0D0D0D; --amoled-white: #FFFFFF; --amoled-red: #FF0000; --amoled-blue: #0000FF; --amoled-golden: #FFD700; /* Additional colors */ --dark-gray: #1A1A1A; --medium-gray: #333333; --light-gray: #666666; --glass-bg: rgba(255, 255, 255, 0.02); --glass-border: rgba(255, 255, 255, 0.1); /* Typography */ --font-primary: 'Inter', sans-serif; --font-display: 'Orbitron', monospace; /* Spacing */ --section-padding: 100px 0; --container-padding: 0 20px; /* Animations */ --transition-smooth: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); --transition-fast: all 0.2s ease-out; --transition-bounce: all 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--font-primary); background-color: var(--amoled-black); color: var(--amoled-white); line-height: 1.6; overflow-x: hidden; } html { scroll-behavior: smooth; } /* Loading Screen */ .loading-screen { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: linear-gradient(135deg, var(--amoled-black) 0%, var(--amoled-black-secondary) 100%); display: flex; align-items: center; justify-content: center; z-index: 10000; transition: opacity 0.5s ease-out; } .loading-content { text-align: center; color: var(--amoled-white); } .loading-particles { width: 80px; height: 80px; margin: 0 auto 20px; position: relative; } .loading-particles::before { content: ''; position: absolute; width: 20px; height: 20px; background: var(--amoled-golden); border-radius: 50%; animation: loadingParticle 1.5s infinite ease-in-out; }
@keyframes
loadingParticle { 0%, 100% { transform: scale(0) rotate(0deg); opacity: 0; } 50% { transform: scale(1) rotate(180deg); opacity: 1; } } .loading-text { font-size: 18px; font-weight: 300; margin-bottom: 30px; letter-spacing: 2px; } .loading-progress { width: 200px; height: 2px; background: var(--dark-gray); border-radius: 1px; overflow: hidden; margin: 0 auto; } .progress-bar { height: 100%; background: linear-gradient(90deg, var(--amoled-blue), var(--amoled-golden)); width: 0%; transition: width 0.3s ease; } /* Navigation */ .nav { position: fixed; top: 0; left: 0; width: 100%; background: rgba(0, 0, 0, 0.9); backdrop-filter: blur(20px); z-index: 1000; padding: 15px 0; transition: var(--transition-smooth); } .nav.scrolled { background: rgba(0, 0, 0, 0.95); box-shadow: 0 2px 20px rgba(255, 215, 0, 0.1); } .nav-container { max-width: 1200px; margin: 0 auto; padding: var(--container-padding); display: flex; justify-content: space-between; align-items: center; } .nav-logo { font-family: var(--font-display); font-size: 24px; font-weight: 700; text-decoration: none; color: var(--amoled-white); } .logo-text { color: var(--amoled-white); } .logo-accent { color: var(--amoled-golden); margin-left: 5px; } .nav-menu { display: flex; gap: 30px; } .nav-link { color: var(--amoled-white); text-decoration: none; font-weight: 500; position: relative; transition: var(--transition-smooth); } .nav-link::after { content: ''; position: absolute; bottom: -5px; left: 0; width: 0; height: 2px; background: linear-gradient(90deg, var(--amoled-blue), var(--amoled-golden)); transition: var(--transition-smooth); } .nav-link:hover::after, .nav-link.active::after { width: 100%; } .nav-toggle { display: none; flex-direction: column; cursor: pointer; gap: 4px; } .nav-toggle span { width: 25px; height: 2px; background: var(--amoled-white); transition: var(--transition-smooth); } /* Hero Section */ .hero { height: 100vh; position: relative; display: flex; align-items: center; justify-content: center; overflow: hidden; } .particle-canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; } .hero-content { position: relative; z-index: 2; text-align: center; max-width: 800px; padding: var(--container-padding); } .hero-title { font-family: var(--font-display); font-size: clamp(3rem, 8vw, 6rem); font-weight: 900; margin-bottom: 20px; background: linear-gradient(135deg, var(--amoled-white) 0%, var(--amoled-golden) 50%, var(--amoled-blue) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; line-height: 1.1; } .typewriter { display: inline-block; } .cursor { animation: blink 1s infinite; color: var(--amoled-golden); }
@keyframes
blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } } .hero-subtitle { font-size: 24px; font-weight: 300; margin-bottom: 15px; color: var(--amoled-blue); letter-spacing: 1px; } .hero-description { font-size: 18px; color: rgba(255, 255, 255, 0.8); margin-bottom: 40px; max-width: 600px; margin-left: auto; margin-right: auto; } .hero-buttons { display: flex; gap: 20px; justify-content: center; flex-wrap: wrap; } /* Buttons */ .btn { position: relative; display: inline-flex; align-items: center; justify-content: center; padding: 15px 30px; font-size: 16px; font-weight: 600; text-decoration: none; border-radius: 50px; transition: var(--transition-smooth); overflow: hidden; border: none; cursor: pointer; text-transform: uppercase; letter-spacing: 1px; } .btn span { position: relative; z-index: 2; } .btn-primary { background: linear-gradient(135deg, var(--amoled-blue), var(--amoled-golden)); color: var(--amoled-black); box-shadow: 0 10px 30px rgba(0, 0, 255, 0.3); } .btn-primary:hover { transform: translateY(-3px); box-shadow: 0 15px 40px rgba(0, 0, 255, 0.4); } .btn-outline { background: transparent; color: var(--amoled-white); border: 2px solid var(--amoled-golden); } .btn-outline:hover { background: var(--amoled-golden); color: var(--amoled-black); transform: translateY(-3px); } .btn-particles { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } .btn-full-width { width: 100%; } /* Scroll Indicator */ .scroll-indicator { position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; color: rgba(255, 255, 255, 0.6); animation: float 3s ease-in-out infinite; } .scroll-mouse { width: 24px; height: 40px; border: 2px solid var(--amoled-golden); border-radius: 12px; position: relative; margin-bottom: 10px; } .scroll-wheel { width: 3px; height: 6px; background: var(--amoled-golden); border-radius: 2px; position: absolute; top: 8px; left: 50%; transform: translateX(-50%); animation: scroll 2s infinite; }
@keyframes
scroll { 0% { transform: translateX(-50%) translateY(0); opacity: 0; } 50% { opacity: 1; } 100% { transform: translateX(-50%) translateY(10px); opacity: 0; } }
@keyframes
float { 0%, 100% { transform: translateX(-50%) translateY(0px); } 50% { transform: translateX(-50%) translateY(-10px); } } /* Section Styles */ .section { padding: var(--section-padding); position: relative; } .container { max-width: 1200px; margin: 0 auto; padding: var(--container-padding); } .section-header { text-align: center; margin-bottom: 60px; } .section-title { font-family: var(--font-display); font-size: clamp(2.5rem, 5vw, 4rem); font-weight: 700; margin-bottom: 15px; background: linear-gradient(135deg, var(--amoled-white) 0%, var(--amoled-golden) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .section-subtitle { font-size: 18px; color: rgba(255, 255, 255, 0.7); font-weight: 300; letter-spacing: 1px; } /* Glass Card Effect */ .glass-card { background: var(--glass-bg); backdrop-filter: blur(20px); border: 1px solid var(--glass-border); border-radius: 20px; padding: 40px; transition: var(--transition-smooth); } .glass-card:hover { transform: translateY(-5px); box-shadow: 0 20px 40px rgba(255, 215, 0, 0.1); border-color: rgba(255, 215, 0, 0.3); } /* About Section */ .about-content { display: grid; gap: 40px; } .about-text p { font-size: 18px; line-height: 1.8; margin-bottom: 20px; color: rgba(255, 255, 255, 0.9); } .about-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 30px; margin-top: 40px; } .stat-item { text-align: center; } .stat-number { font-size: 3rem; font-weight: 700; color: var(--amoled-golden); display: block; font-family: var(--font-display); } .stat-label { font-size: 14px; color: rgba(255, 255, 255, 0.7); margin-top: 10px; text-transform: uppercase; letter-spacing: 1px; } /* Skills Section */ .skills { background: linear-gradient(135deg, var(--amoled-black-secondary) 0%, var(--dark-gray) 100%); } .skills-grid { display: grid; gap: 30px; max-width: 800px; margin: 0 auto; } .skill-item { background: var(--glass-bg); border: 1px solid var(--glass-border); border-radius: 15px; padding: 25px; transition: var(--transition-smooth); } .skill-item:hover { transform: translateX(10px); border-color: var(--amoled-golden); } .skill-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; } .skill-name { font-size: 18px; font-weight: 600; color: var(--amoled-white); } .skill-percentage { font-size: 16px; color: var(--amoled-golden); font-weight: 700; } .skill-bar { height: 8px; background: var(--dark-gray); border-radius: 4px; overflow: hidden; position: relative; } .skill-progress { height: 100%; background: linear-gradient(90deg, var(--amoled-blue), var(--amoled-golden)); border-radius: 4px; width: 0%; transition: width 1.5s cubic-bezier(0.25, 0.8, 0.25, 1); position: relative; } .skill-progress::after { content: ''; position: absolute; top: 0; right: 0; width: 20px; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4)); animation: shimmer 2s infinite; }
@keyframes
shimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } /* Projects Section */ .projects-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 40px; } .project-card { border-radius: 20px; overflow: hidden; transition: var(--transition-smooth); background: var(--glass-bg); border: 1px solid var(--glass-border); } .project-card:hover { transform: translateY(-10px) scale(1.02); box-shadow: 0 25px 50px rgba(255, 215, 0, 0.2); } .project-image { position: relative; overflow: hidden; height: 250px; } .project-image img { width: 100%; height: 100%; object-fit: cover; transition: var(--transition-smooth); } .project-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); display: flex; align-items: center; justify-content: center; opacity: 0; transition: var(--transition-smooth); } .project-card:hover .project-overlay { opacity: 1; } .project-card:hover .project-image img { transform: scale(1.1); } .project-links { display: flex; gap: 20px; } .project-link { color: var(--amoled-white); text-decoration: none; padding: 10px 20px; border: 1px solid var(--amoled-golden); border-radius: 25px; transition: var(--transition-smooth); } .project-link:hover { background: var(--amoled-golden); color: var(--amoled-black); } .project-content { padding: 30px; } .project-title { font-size: 24px; font-weight: 700; margin-bottom: 15px; color: var(--amoled-white); } .project-description { font-size: 16px; color: rgba(255, 255, 255, 0.8); margin-bottom: 20px; line-height: 1.6; } .project-tech { display: flex; flex-wrap: wrap; gap: 10px; } .tech-tag { background: linear-gradient(135deg, var(--amoled-blue), var(--amoled-golden)); color: var(--amoled-black); padding: 5px 12px; border-radius: 15px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; } /* Contact Section */ .contact { background: linear-gradient(135deg, var(--amoled-black-secondary) 0%, var(--dark-gray) 100%); } .contact-content { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: start; } .contact-info { display: flex; flex-direction: column; gap: 30px; } .contact-item { display: flex; align-items: center; gap: 20px; } .contact-icon { font-size: 24px; width: 50px; height: 50px; background: var(--glass-bg); border: 1px solid var(--glass-border); border-radius: 50%; display: flex; align-items: center; justify-content: center; } .contact-details h4 { font-size: 18px; font-weight: 600; margin-bottom: 5px; color: var(--amoled-white); } .contact-details a, .contact-details span { color: rgba(255, 255, 255, 0.8); text-decoration: none; transition: var(--transition-smooth); } .contact-details a:hover { color: var(--amoled-golden); } .social-links { display: flex; gap: 20px; margin-top: 20px; } .social-link { color: var(--amoled-white); text-decoration: none; padding: 10px 20px; border: 1px solid var(--glass-border); border-radius: 25px; transition: var(--transition-smooth); } .social-link:hover { border-color: var(--amoled-golden); color: var(--amoled-golden); transform: translateY(-2px); } /* Form Styles */ .contact-form { display: flex; flex-direction: column; gap: 25px; } .form-group { position: relative; } .form-control { width: 100%; padding: 15px 20px; background: rgba(255, 255, 255, 0.05); border: 1px solid var(--glass-border); border-radius: 10px; color: var(--amoled-white); font-size: 16px; transition: var(--transition-smooth); } .form-control:focus { outline: none; border-color: var(--amoled-golden); box-shadow: 0 0 0 3px rgba(255, 215, 0, 0.2); } .form-control::placeholder { color: rgba(255, 255, 255, 0.5); } .form-label { position: absolute; top: -10px; left: 15px; background: var(--amoled-black); padding: 0 10px; font-size: 12px; color: var(--amoled-golden); font-weight: 600; text-transform: uppercase; letter-spacing: 1px; } /* Footer */ .footer { background: var(--amoled-black); padding: 40px 0; border-top: 1px solid var(--glass-border); } .footer-content { display: flex; justify-content: space-between; align-items: center; color: rgba(255, 255, 255, 0.6); } .footer-links a { color: var(--amoled-golden); text-decoration: none; transition: var(--transition-smooth); } .footer-links a:hover { color: var(--amoled-white); } /* Responsive Design */
@media
(max-width: 768px) { .nav-menu { position: fixed; top: 70px; left: -100%; width: 100%; height: calc(100vh - 70px); background: rgba(0, 0, 0, 0.95); flex-direction: column; align-items: center; justify-content: center; transition: var(--transition-smooth); } .nav-menu.active { left: 0; } .nav-toggle { display: flex; } .nav-toggle.active span:nth-child(1) { transform: rotate(45deg) translate(5px, 5px); } .nav-toggle.active span:nth-child(2) { opacity: 0; } .nav-toggle.active span:nth-child(3) { transform: rotate(-45deg) translate(7px, -6px); } .hero-buttons { flex-direction: column; align-items: center; } .btn { width: 100%; max-width: 300px; } .contact-content { grid-template-columns: 1fr; gap: 40px; } .projects-grid { grid-template-columns: 1fr; } .about-stats { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); } .footer-content { flex-direction: column; gap: 20px; text-align: center; } }
@media
(max-width: 480px) { .hero-title { font-size: 3rem; } .section-title { font-size: 2.5rem; } .glass-card { padding: 25px; } .project-content { padding: 20px; } } ; // Global variables let scene, camera, renderer, particles, particleSystem; let mouseX = 0, mouseY = 0; let windowHalfX = window.innerWidth / 2; let windowHalfY = window.innerHeight / 2; let isLoaded = false; let threeJSLoaded = false; // Initialize everything when DOM is loaded document.addEventListener('DOMContentLoaded', function() { console.log('DOM loaded, initializing...'); initLoading(); checkThreeJS(); initTypewriter(); initNavigation(); initScrollAnimations(); initFormHandling(); initParticleInteractions(); // Force hide loading screen after maximum time setTimeout(() => { console.log('Force hiding loading screen'); hideLoadingScreen(); }, 4000); }); // Check if Three.js is loaded and initialize function checkThreeJS() { if (typeof THREE !== 'undefined') { console.log('Three.js loaded, initializing particle system...'); threeJSLoaded = true; initThreeJS(); } else { console.log('Three.js not loaded yet, retrying...'); setTimeout(checkThreeJS, 100); } } // Loading Screen function initLoading() { console.log('Initializing loading screen...'); const progressBar = document.querySelector('.progress-bar'); let progress = 0; const loadingInterval = setInterval(() => { progress += Math.random() * 15; if (progress >= 100) { progress = 100; clearInterval(loadingInterval); setTimeout(() => { hideLoadingScreen(); }, 1000); } if (progressBar) { progressBar.style.width = progress + '%'; } }, 200); } function hideLoadingScreen() { console.log('Hiding loading screen...'); const loadingScreen = document.getElementById('loading-screen'); if (loadingScreen) { loadingScreen.style.opacity = '0'; setTimeout(() => { loadingScreen.style.display = 'none'; isLoaded = true; startAnimations(); console.log('Loading screen hidden, starting animations...'); }, 500); } } // Three.js Particle System function initThreeJS() { try { const canvas = document.getElementById('particle-canvas'); if (!canvas) { console.error('Canvas not found'); return; } console.log('Initializing Three.js...'); // Scene setup scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer({ canvas: canvas, alpha: true, antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0x000000, 0); // Create particle system createParticleSystem(); // Position camera camera.position.z = 50; // Start animation loop animate(); // Handle window resize window.addEventListener('resize', onWindowResize); // Mouse movement tracking document.addEventListener('mousemove', onDocumentMouseMove); console.log('Three.js initialized successfully'); } catch (error) { console.error('Error initializing Three.js:', error); // Continue without Three.js if it fails createFallbackBackground(); } } function createFallbackBackground() { console.log('Creating fallback background...'); const canvas = document.getElementById('particle-canvas'); if (canvas) { canvas.style.background = ` radial-gradient(circle at 20% 50%, rgba(0, 0, 255, 0.3) 0%, transparent 50%), radial-gradient(circle at 80% 20%, rgba(255, 215, 0, 0.3) 0%, transparent 50%), radial-gradient(circle at 40% 80%, rgba(255, 0, 0, 0.2) 0%, transparent 50%), linear-gradient(135deg, #000000 0%, #0D0D0D 100%) `; canvas.style.animation = 'fallbackFloat 10s ease-in-out infinite alternate'; } // Add fallback animation const style = document.createElement('style'); style.textContent = `
@keyframes
fallbackFloat { 0% { transform: scale(1) rotate(0deg); } 100% { transform: scale(1.05) rotate(2deg); } } `; document.head.appendChild(style); } function createParticleSystem() { try { const particleCount = 1500; // Reduced for better performance const geometry = new THREE.BufferGeometry(); const positions = new Float32Array(particleCount * 3); const velocities = new Float32Array(particleCount * 3); const colors = new Float32Array(particleCount * 3); // Create sphere of particles for (let i = 0; i < particleCount; i++) { const i3 = i * 3; // Spherical distribution const radius = 15 + Math.random() * 15; const theta = Math.random() * Math.PI * 2; const phi = Math.random() * Math.PI; positions[i3] = radius * Math.sin(phi) * Math.cos(theta); positions[i3 + 1] = radius * Math.sin(phi) * Math.sin(theta); positions[i3 + 2] = radius * Math.cos(phi); // Random 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; // Color variations (golden to blue) const colorChoice = Math.random(); if (colorChoice < 0.6) { // Golden colors[i3] = 1.0; colors[i3 + 1] = 0.84; colors[i3 + 2] = 0.0; } else if (colorChoice < 0.8) { // Blue colors[i3] = 0.0; colors[i3 + 1] = 0.0; colors[i3 + 2] = 1.0; } else { // White colors[i3] = 1.0; colors[i3 + 1] = 1.0; colors[i3 + 2] = 1.0; } } geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geometry.setAttribute('velocity', new THREE.BufferAttribute(velocities, 3)); geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3)); // Particle material const material = new THREE.PointsMaterial({ size: 0.8, vertexColors: true, transparent: true, opacity: 0.8, blending: THREE.AdditiveBlending }); particleSystem = new THREE.Points(geometry, material); scene.add(particleSystem); // Store reference to positions and velocities particles = { positions: positions, velocities: velocities, geometry: geometry }; console.log('Particle system created successfully'); } catch (error) { console.error('Error creating particle system:', error); } } function animate() { if (!threeJSLoaded || !renderer || !scene || !camera) return; requestAnimationFrame(animate); try { if (particleSystem && isLoaded) { // Rotate particle system particleSystem.rotation.y += 0.003; particleSystem.rotation.x += 0.001; // Update particle positions if (particles && particles.positions && particles.velocities) { const positions = particles.positions; const velocities = particles.velocities; for (let i = 0; i < positions.length; i += 3) { // Apply mouse influence const mouseInfluence = 0.00005; velocities[i] += (mouseX - windowHalfX) * mouseInfluence; velocities[i + 1] += -(mouseY - windowHalfY) * mouseInfluence; // Update positions positions[i] += velocities[i]; positions[i + 1] += velocities[i + 1]; positions[i + 2] += velocities[i + 2]; // Boundary constraints (sphere) const distance = Math.sqrt( positions[i] * positions[i] + positions[i + 1] * positions[i + 1] + positions[i + 2] * positions[i + 2] ); if (distance > 30) { const factor = 30 / distance; positions[i] *= factor; positions[i + 1] *= factor; positions[i + 2] *= factor; // Bounce back velocities[i] *= -0.3; velocities[i + 1] *= -0.3; velocities[i + 2] *= -0.3; } // Damping velocities[i] *= 0.995; velocities[i + 1] *= 0.995; velocities[i + 2] *= 0.995; } particles.geometry.attributes.position.needsUpdate = true; } } renderer.render(scene, camera); } catch (error) { console.error('Animation error:', error); } } function onWindowResize() { windowHalfX = window.innerWidth / 2; windowHalfY = window.innerHeight / 2; if (camera && renderer) { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } } function onDocumentMouseMove(event) { mouseX = event.clientX; mouseY = event.clientY; } // Typewriter Effect function initTypewriter() { console.log('Initializing typewriter effect...'); const typewriterElement = document.getElementById('typewriter'); const text = 'ALEX PORTFOLIO'; let i = 0; function typeWriter() { if (i < text.length && typewriterElement) { typewriterElement.innerHTML += text.charAt(i); i++; const delay = Math.random() * 100 + 50; // Variable typing speed setTimeout(typeWriter, delay); } } // Start typewriter effect after loading setTimeout(() => { if (isLoaded) { typeWriter(); } else { // Start anyway after a delay setTimeout(typeWriter, 2000); } }, 1500); } // Navigation function initNavigation() { console.log('Initializing navigation...'); const nav = document.getElementById('nav'); const navToggle = document.getElementById('nav-toggle'); const navMenu = document.getElementById('nav-menu'); const navLinks = document.querySelectorAll('.nav-link'); // Scroll effect window.addEventListener('scroll', () => { if (nav) { if (window.scrollY > 100) { nav.classList.add('scrolled'); } else { nav.classList.remove('scrolled'); } } }); // Mobile menu toggle if (navToggle && navMenu) { navToggle.addEventListener('click', () => { navMenu.classList.toggle('active'); navToggle.classList.toggle('active'); }); } // Close mobile menu when clicking links navLinks.forEach(link => { link.addEventListener('click', () => { if (navMenu && navToggle) { navMenu.classList.remove('active'); navToggle.classList.remove('active'); } }); }); // Active link highlighting window.addEventListener('scroll', () => { let current = ''; const sections = document.querySelectorAll('section'); sections.forEach(section => { const sectionTop = section.offsetTop; if (scrollY >= sectionTop - 200) { current = section.getAttribute('id'); } }); navLinks.forEach(link => { link.classList.remove('active'); if (link.getAttribute('href') === '#' + current) { link.classList.add('active'); } }); }); } // Scroll Animations function initScrollAnimations() { console.log('Initializing scroll animations...'); const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('animate-in'); // Trigger specific animations if (entry.target.classList.contains('skills')) { animateSkills(); } if (entry.target.classList.contains('about')) { animateStats(); } } }); }, observerOptions); // Observe sections const sections = document.querySelectorAll('section'); sections.forEach(section => { observer.observe(section); }); // Add CSS for animations addAnimationStyles(); } function addAnimationStyles() { const style = document.createElement('style'); style.textContent = ` section { opacity: 0; transform: translateY(30px); transition: all 0.8s cubic-bezier(0.25, 0.8, 0.25, 1); } section.animate-in { opacity: 1; transform: translateY(0); } .glass-card { opacity: 0; transform: translateY(30px); transition: all 0.6s cubic-bezier(0.25, 0.8, 0.25, 1); } .animate-in .glass-card { opacity: 1; transform: translateY(0); } .project-card:nth-child(1) { transition-delay: 0.1s; } .project-card:nth-child(2) { transition-delay: 0.2s; } .project-card:nth-child(3) { transition-delay: 0.3s; } .hero { opacity: 1 !important; transform: none !important; } `; document.head.appendChild(style); } // Skills Animation function animateSkills() { console.log('Animating skills...'); const skillItems = document.querySelectorAll('.skill-item'); skillItems.forEach((item, index) => { setTimeout(() => { const progress = item.querySelector('.skill-progress'); const percentage = item.getAttribute('data-skill'); if (progress) { progress.style.width = percentage + '%'; } }, index * 200); }); } // Stats Counter Animation function animateStats() { console.log('Animating stats...'); const statNumbers = document.querySelectorAll('.stat-number'); statNumbers.forEach(stat => { const target = parseInt(stat.getAttribute('data-target')); const increment = target / 100; let current = 0; const timer = setInterval(() => { current += increment; if (current >= target) { current = target; clearInterval(timer); } stat.textContent = Math.floor(current) + (target === 100 ? '%' : '+'); }, 20); }); } // Form Handling function initFormHandling() { console.log('Initializing form handling...'); const form = document.getElementById('contact-form'); if (form) { form.addEventListener('submit', (e) => { e.preventDefault(); console.log('Form submitted'); // Get form data const formData = new FormData(form); const data = { name: formData.get('name'), email: formData.get('email'), subject: formData.get('subject'), message: formData.get('message') }; console.log('Form data:', data); // Simulate form submission const submitButton = form.querySelector('button[type="submit"]'); const originalText = submitButton.querySelector('span').textContent; submitButton.querySelector('span').textContent = 'Sending...'; submitButton.disabled = true; setTimeout(() => { submitButton.querySelector('span').textContent = 'Message Sent!'; createSuccessParticles(submitButton); setTimeout(() => { submitButton.querySelector('span').textContent = originalText; submitButton.disabled = false; form.reset(); }, 2000); }, 1500); }); // Form validation const inputs = form.querySelectorAll('.form-control'); inputs.forEach(input => { input.addEventListener('blur', validateField); input.addEventListener('input', clearValidation); }); } } function validateField(e) { const field = e.target; const value = field.value.trim(); // Remove existing validation clearValidation(e); if (!value) { showValidationError(field, 'This field is required'); return; } if (field.type === 'email' && !isValidEmail(value)) { showValidationError(field, 'Please enter a valid email'); return; } showValidationSuccess(field); } function clearValidation(e) { const field = e.target; const group = field.parentNode; group.classList.remove('error', 'success'); const existingMessage = group.querySelector('.validation-message'); if (existingMessage) { existingMessage.remove(); } } function showValidationError(field, message) { const group = field.parentNode; group.classList.add('error'); const messageEl = document.createElement('div'); messageEl.className = 'validation-message error-message'; messageEl.textContent = message; group.appendChild(messageEl); } function showValidationSuccess(field) { const group = field.parentNode; group.classList.add('success'); } function isValidEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } // Particle Interactions function initParticleInteractions() { console.log('Initializing particle interactions...'); const buttons = document.querySelectorAll('.btn'); buttons.forEach(button => { button.addEventListener('mouseenter', () => { createButtonParticles(button); }); button.addEventListener('click', (e) => { createClickParticles(e); }); }); } function createButtonParticles(button) { const particleContainer = button.querySelector('.btn-particles'); if (!particleContainer) return; for (let i = 0; i < 6; i++) { const particle = document.createElement('div'); particle.style.cssText = ` position: absolute; width: 4px; height: 4px; background: #FFD700; border-radius: 50%; pointer-events: none; animation: buttonParticle 0.6s ease-out forwards; `; particle.style.left = Math.random() * 100 + '%'; particle.style.top = Math.random() * 100 + '%'; particleContainer.appendChild(particle); setTimeout(() => { if (particle.parentNode) { particle.remove(); } }, 600); } } function createClickParticles(e) { const rect = e.target.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; for (let i = 0; i < 8; i++) { const particle = document.createElement('div'); particle.style.cssText = ` position: fixed; left: ${rect.left + x}px; top: ${rect.top + y}px; width: 6px; height: 6px; background: #FFD700; border-radius: 50%; pointer-events: none; z-index: 10000; animation: clickParticle 0.8s ease-out forwards; `; const angle = (i / 8) * Math.PI * 2; const distance = 50 + Math.random() * 30; const endX = Math.cos(angle) * distance; const endY = Math.sin(angle) * distance; particle.style.setProperty('--endX', endX + 'px'); particle.style.setProperty('--endY', endY + 'px'); document.body.appendChild(particle); setTimeout(() => { if (particle.parentNode) { particle.remove(); } }, 800); } } function createSuccessParticles(element) { const rect = element.getBoundingClientRect(); for (let i = 0; i < 15; i++) { const particle = document.createElement('div'); particle.style.cssText = ` position: fixed; left: ${rect.left + rect.width / 2}px; top: ${rect.top + rect.height / 2}px; width: 8px; height: 8px; background: #00FF00; border-radius: 50%; pointer-events: none; z-index: 10000; animation: successParticle 1s ease-out forwards; `; const angle = (i / 15) * Math.PI * 2; const velocity = 40 + Math.random() * 40; const endX = Math.cos(angle) * velocity; const endY = Math.sin(angle) * velocity; particle.style.setProperty('--endX', endX + 'px'); particle.style.setProperty('--endY', endY + 'px'); document.body.appendChild(particle); setTimeout(() => { if (particle.parentNode) { particle.remove(); } }, 1000); } } // Start animations function startAnimations() { console.log('Starting animations...'); // Add animation keyframes const animationStyles = document.createElement('style'); animationStyles.textContent = `
@keyframes
buttonParticle { 0% { transform: scale(0); opacity: 1; } 100% { transform: scale(1) translate(${Math.random() * 40 - 20}px, ${Math.random() * 40 - 20}px); opacity: 0; } }
@keyframes
clickParticle { 0% { transform: scale(0); opacity: 1; } 100% { transform: scale(1) translate(var(--endX), var(--endY)); opacity: 0; } }
@keyframes
successParticle { 0% { transform: scale(0); opacity: 1; } 100% { transform: scale(1) translate(var(--endX), var(--endY)); opacity: 0; } } .form-group.error .form-control { border-color: #FF0000; box-shadow: 0 0 0 3px rgba(255, 0, 0, 0.2); } .form-group.success .form-control { border-color: #00FF00; box-shadow: 0 0 0 3px rgba(0, 255, 0, 0.2); } .validation-message { position: absolute; bottom: -20px; left: 15px; font-size: 12px; font-weight: 500; } .error-message { color: #FF0000; } `; document.head.appendChild(animationStyles); // Trigger initial animations setTimeout(() => { const heroSection = document.querySelector('.hero'); if (heroSection) { heroSection.classList.add('animate-in'); } }, 500); } // Smooth scrolling for navigation links document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); }); // Performance optimization let ticking = false; function updateAnimations() { if (!ticking) { requestAnimationFrame(() => { ticking = false; }); ticking = true; } } window.addEventListener('scroll', updateAnimations); // Preload critical resources window.addEventListener('load', () => { console.log('Window loaded'); document.body.classList.add('loaded'); // Ensure loading screen is hidden if (!isLoaded) { hideLoadingScreen(); } }); - Initial Deployment
b760676
verified