2ppp / index.html
Marv12's picture
Add 2 files
add0a59 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Luminous Portfolio</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.11.4/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700&family=Inter:wght@300;400;600&display=swap');
:root {
--primary-bg: linear-gradient(135deg, #fff9f0 0%, #f0fff9 100%);
--text-primary: #333;
--text-secondary: #555;
}
body {
font-family: 'Inter', sans-serif;
background: var(--primary-bg);
color: var(--text-primary);
margin: 0;
padding: 0;
overflow-x: hidden;
cursor: default;
min-height: 100vh;
}
.hero-text {
font-family: 'Playfair Display', serif;
text-shadow: 0 2px 10px rgba(0,0,0,0.1);
font-size: clamp(2.5rem, 8vw, 4.5rem);
line-height: 1.2;
}
.glass-card {
backdrop-filter: blur(16px);
background: rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.1);
border: 1px solid rgba(255, 255, 255, 0.18);
}
.floating {
animation: floating 6s ease-in-out infinite;
}
@keyframes floating {
0% { transform: translateY(0px); }
50% { transform: translateY(-15px); }
100% { transform: translateY(0px); }
}
#canvas-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
pointer-events: none;
}
.project-tile {
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transform-style: preserve-3d;
}
.project-tile:hover {
transform: translateY(-10px) rotateX(5deg);
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
}
.nav-sphere {
transition: all 0.3s ease;
box-shadow: 0 0 0 0 rgba(255,255,255,0.7);
}
.nav-sphere:hover {
transform: scale(1.1);
box-shadow: 0 0 0 8px rgba(255,255,255,0.3);
}
.btn-spring {
transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.btn-spring:hover {
transform: translateY(-3px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.ribbon-text {
background: linear-gradient(90deg, #ffd6e0 0%, #c8f7f4 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.nav-spheres {
bottom: 20px;
right: 50%;
transform: translateX(50%);
flex-direction: row;
gap: 12px;
}
.nav-sphere {
width: 10vw;
height: 10vw;
min-width: 40px;
min-height: 40px;
}
.project-tile {
max-width: 100%;
}
#hero {
padding-top: 20vh;
padding-bottom: 20vh;
}
.hero-subtext {
font-size: clamp(1rem, 4vw, 1.5rem);
}
.section-padding {
padding: 5rem 1.5rem;
}
.contact-form {
padding: 1.5rem;
}
}
@media (max-width: 480px) {
.keyword-tag {
font-size: 0.8rem;
padding: 0.4rem 0.8rem;
}
.project-tile h3 {
font-size: 1.2rem;
}
.project-tile p {
font-size: 0.9rem;
}
}
/* Fluid typography */
html {
font-size: 16px;
}
@media (min-width: 600px) {
html {
font-size: 18px;
}
}
@media (min-width: 900px) {
html {
font-size: 20px;
}
}
/* Touch device optimizations */
@media (hover: none) {
.project-tile:hover {
transform: none;
}
.btn-spring:hover {
transform: none;
}
}
</style>
</head>
<body>
<!-- 3D Canvas Container -->
<div id="canvas-container"></div>
<!-- Navigation Spheres - Positioned differently for mobile -->
<div class="fixed right-8 top-1/2 transform -translate-y-1/2 flex flex-col space-y-4 z-50 nav-spheres md:flex">
<div class="nav-sphere w-12 h-12 rounded-full bg-gradient-to-br from-pink-100 to-teal-100 border border-white cursor-pointer flex items-center justify-center shadow-lg" data-section="hero"></div>
<div class="nav-sphere w-12 h-12 rounded-full bg-gradient-to-br from-yellow-100 to-blue-100 border border-white cursor-pointer flex items-center justify-center shadow-lg" data-section="projects"></div>
<div class="nav-sphere w-12 h-12 rounded-full bg-gradient-to-br from-purple-100 to-green-100 border border-white cursor-pointer flex items-center justify-center shadow-lg" data-section="gallery"></div>
<div class="nav-sphere w-12 h-12 rounded-full bg-gradient-to-br from-red-100 to-indigo-100 border border-white cursor-pointer flex items-center justify-center shadow-lg" data-section="contact"></div>
</div>
<!-- Hero Section -->
<section id="hero" class="min-h-screen flex flex-col justify-center items-center px-4 sm:px-8 relative overflow-hidden section-padding">
<div class="max-w-4xl mx-auto text-center z-10">
<h1 class="hero-text text-5xl md:text-7xl font-bold mb-4 md:mb-6 text-gray-800">Hello, I'm <span class="ribbon-text">Alex</span></h1>
<p class="hero-subtext text-xl md:text-2xl text-gray-600 mb-8 md:mb-12 max-w-2xl mx-auto">Creating digital experiences with <span class="font-semibold">trust</span>, <span class="font-semibold">understanding</span>, and <span class="font-semibold">creativity</span></p>
<div class="flex flex-wrap justify-center gap-3 mb-8 md:mb-16">
<div class="px-4 py-2 md:px-6 md:py-3 glass-card rounded-full text-gray-700 font-medium keyword-tag">Hardworking</div>
<div class="px-4 py-2 md:px-6 md:py-3 glass-card rounded-full text-gray-700 font-medium keyword-tag">Willingness</div>
<div class="px-4 py-2 md:px-6 md:py-3 glass-card rounded-full text-gray-700 font-medium keyword-tag">Dedication</div>
</div>
<button class="btn-spring px-6 py-3 md:px-8 md:py-4 bg-white rounded-full text-gray-800 font-semibold shadow-lg flex items-center mx-auto">
<span class="text-sm md:text-base">Explore My Work</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 md:h-5 md:w-5 ml-2" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L12.586 11H5a1 1 0 110-2h7.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
<!-- Floating keywords -->
<div id="keywords-container" class="absolute inset-0 pointer-events-none"></div>
</section>
<!-- Projects Section -->
<section id="projects" class="min-h-screen py-12 md:py-20 px-4 sm:px-8 relative section-padding">
<div class="max-w-6xl mx-auto">
<h2 class="text-3xl md:text-4xl font-bold text-center mb-8 md:mb-16 text-gray-800">Featured Projects</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 md:gap-8">
<!-- Project Tile 1 -->
<div class="project-tile bg-white rounded-xl md:rounded-2xl overflow-hidden shadow-lg md:shadow-xl">
<div class="h-40 md:h-48 bg-gradient-to-r from-pink-100 to-purple-100 flex items-center justify-center">
<div class="text-4xl md:text-5xl">🌐</div>
</div>
<div class="p-4 md:p-6">
<h3 class="text-lg md:text-xl font-bold mb-2">Interactive Web Portal</h3>
<p class="text-sm md:text-base text-gray-600 mb-3 md:mb-4">A responsive platform with real-time data visualization and user engagement features.</p>
<div class="flex flex-wrap gap-1 md:gap-2 mb-3 md:mb-4">
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-pink-100 text-pink-800 rounded-full">React</span>
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-blue-100 text-blue-800 rounded-full">Three.js</span>
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-green-100 text-green-800 rounded-full">Node.js</span>
</div>
<button class="text-xs md:text-sm font-medium text-pink-600 hover:text-pink-800">View Case Study →</button>
</div>
</div>
<!-- Project Tile 2 -->
<div class="project-tile bg-white rounded-xl md:rounded-2xl overflow-hidden shadow-lg md:shadow-xl">
<div class="h-40 md:h-48 bg-gradient-to-r from-blue-100 to-teal-100 flex items-center justify-center">
<div class="text-4xl md:text-5xl">📱</div>
</div>
<div class="p-4 md:p-6">
<h3 class="text-lg md:text-xl font-bold mb-2">Mobile Experience</h3>
<p class="text-sm md:text-base text-gray-600 mb-3 md:mb-4">An award-winning mobile app with gesture-based navigation and AR features.</p>
<div class="flex flex-wrap gap-1 md:gap-2 mb-3 md:mb-4">
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-purple-100 text-purple-800 rounded-full">Swift</span>
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-yellow-100 text-yellow-800 rounded-full">ARKit</span>
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-red-100 text-red-800 rounded-full">Firebase</span>
</div>
<button class="text-xs md:text-sm font-medium text-blue-600 hover:text-blue-800">View Case Study →</button>
</div>
</div>
<!-- Project Tile 3 -->
<div class="project-tile bg-white rounded-xl md:rounded-2xl overflow-hidden shadow-lg md:shadow-xl">
<div class="h-40 md:h-48 bg-gradient-to-r from-yellow-100 to-orange-100 flex items-center justify-center">
<div class="text-4xl md:text-5xl">🎨</div>
</div>
<div class="p-4 md:p-6">
<h3 class="text-lg md:text-xl font-bold mb-2">Generative Art</h3>
<p class="text-sm md:text-base text-gray-600 mb-3 md:mb-4">An interactive installation that creates unique visual patterns based on user input.</p>
<div class="flex flex-wrap gap-1 md:gap-2 mb-3 md:mb-4">
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-indigo-100 text-indigo-800 rounded-full">p5.js</span>
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-green-100 text-green-800 rounded-full">WebGL</span>
<span class="text-xs px-2 py-1 md:px-3 md:py-1 bg-pink-100 text-pink-800 rounded-full">GSAP</span>
</div>
<button class="text-xs md:text-sm font-medium text-orange-600 hover:text-orange-800">View Case Study →</button>
</div>
</div>
</div>
</div>
</section>
<!-- Gallery Section -->
<section id="gallery" class="min-h-screen py-12 md:py-20 px-4 sm:px-8 bg-white bg-opacity-50 relative section-padding">
<div class="max-w-6xl mx-auto">
<h2 class="text-3xl md:text-4xl font-bold text-center mb-8 md:mb-16 text-gray-800">Creative Explorations</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 md:gap-8 mb-8 md:mb-12">
<div class="glass-card rounded-2xl md:rounded-3xl p-4 md:p-8">
<h3 class="text-xl md:text-2xl font-bold mb-3 md:mb-4 text-gray-800">Sculpture Garden</h3>
<p class="text-sm md:text-base text-gray-600 mb-4 md:mb-6">Interactive 3D frames that reveal layered illustrations when manipulated. Each piece responds to user interaction with subtle physics and sound.</p>
<div class="h-48 md:h-64 bg-gradient-to-r from-green-100 to-blue-100 rounded-xl md:rounded-2xl flex items-center justify-center">
<div class="text-3xl md:text-4xl">🖼️</div>
</div>
</div>
<div class="glass-card rounded-2xl md:rounded-3xl p-4 md:p-8">
<h3 class="text-xl md:text-2xl font-bold mb-3 md:mb-4 text-gray-800">Generative Systems</h3>
<p class="text-sm md:text-base text-gray-600 mb-4 md:mb-6">Algorithmic compositions that evolve over time, creating unique visual and auditory experiences based on mathematical patterns.</p>
<div class="h-48 md:h-64 bg-gradient-to-r from-purple-100 to-pink-100 rounded-xl md:rounded-2xl flex items-center justify-center">
<div class="text-3xl md:text-4xl">🌀</div>
</div>
</div>
</div>
<div class="text-center mt-8 md:mt-12">
<button class="btn-spring px-6 py-3 md:px-8 md:py-4 bg-white rounded-full text-gray-800 font-semibold shadow-lg flex items-center mx-auto">
<span class="text-sm md:text-base">View Full Gallery</span>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 md:h-5 md:w-5 ml-2" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L12.586 11H5a1 1 0 110-2h7.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
</div>
</section>
<!-- Contact Section -->
<section id="contact" class="min-h-screen py-12 md:py-20 px-4 sm:px-8 relative section-padding">
<div class="max-w-4xl mx-auto text-center">
<h2 class="text-3xl md:text-4xl font-bold mb-4 md:mb-6 text-gray-800">Let's Build <span class="ribbon-text">Together</span></h2>
<p class="text-lg md:text-xl text-gray-600 mb-8 md:mb-12 max-w-2xl mx-auto">I'm always excited to collaborate on meaningful projects that push creative boundaries.</p>
<div class="glass-card rounded-2xl md:rounded-3xl p-4 md:p-8 lg:p-12 max-w-2xl mx-auto contact-form">
<form class="space-y-4 md:space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6">
<div>
<label for="name" class="block text-left text-sm md:text-base text-gray-700 mb-1 md:mb-2">Name</label>
<input type="text" id="name" class="w-full px-3 py-2 md:px-4 md:py-3 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-pink-200 text-sm md:text-base">
</div>
<div>
<label for="email" class="block text-left text-sm md:text-base text-gray-700 mb-1 md:mb-2">Email</label>
<input type="email" id="email" class="w-full px-3 py-2 md:px-4 md:py-3 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-blue-200 text-sm md:text-base">
</div>
</div>
<div>
<label for="message" class="block text-left text-sm md:text-base text-gray-700 mb-1 md:mb-2">Message</label>
<textarea id="message" rows="4" class="w-full px-3 py-2 md:px-4 md:py-3 rounded-lg border border-gray-200 focus:outline-none focus:ring-2 focus:ring-teal-200 text-sm md:text-base"></textarea>
</div>
<button type="submit" class="btn-spring w-full md:w-auto px-6 py-3 md:px-8 md:py-4 bg-gradient-to-r from-pink-400 to-blue-400 text-white font-semibold rounded-full shadow-lg text-sm md:text-base">
Send Message
</button>
</form>
</div>
<div class="mt-8 md:mt-16 flex justify-center space-x-4 md:space-x-6">
<a href="#" class="text-gray-600 hover:text-pink-500">
<svg class="w-5 h-5 md:w-6 md:h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" />
</svg>
</a>
<a href="#" class="text-gray-600 hover:text-blue-500">
<svg class="w-5 h-5 md:w-6 md:h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
</svg>
</a>
<a href="#" class="text-gray-600 hover:text-orange-500">
<svg class="w-5 h-5 md:w-6 md:h-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
<path fill-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10c5.51 0 10-4.48 10-10S17.51 2 12 2zm6.605 4.61a8.502 8.502 0 011.93 5.314c-.281-.054-3.101-.629-5.943-.271-.065-.141-.12-.293-.184-.445a25.416 25.416 0 00-.564-1.236c3.145-1.28 4.577-3.124 4.761-3.362zM12 3.475c2.17 0 4.154.813 5.662 2.148-.152.216-1.443 1.941-4.48 3.08-1.399-2.57-2.95-4.675-3.189-5A8.687 8.687 0 0112 3.475zm-3.633.803a53.896 53.896 0 013.167 4.935c-3.992 1.063-7.517 1.04-7.896 1.04a8.581 8.581 0 014.729-5.975zM3.453 12.01v-.26c.37.01 4.512.065 8.775-1.215.25.477.477.965.694 1.453-.109.033-.228.065-.336.098-4.404 1.42-6.747 5.303-6.942 5.629a8.522 8.522 0 01-2.19-5.705zM12 20.547a8.482 8.482 0 01-5.239-1.8c.152-.315 1.888-3.656 6.703-5.337.022-.01.033-.01.054-.022a35.318 35.318 0 011.823 6.475 8.4 8.4 0 01-3.341.684zm4.761-1.465c-.086-.52-.542-3.015-1.659-6.084 2.679-.423 5.022.271 5.314.369a8.468 8.468 0 01-3.655 5.715z" clip-rule="evenodd" />
</svg>
</a>
</div>
</div>
<!-- Floating lanterns -->
<div class="absolute bottom-8 left-0 right-0 flex justify-center space-x-8 md:space-x-12 pointer-events-none">
<div class="w-6 h-10 md:w-8 md:h-12 bg-gradient-to-b from-yellow-100 to-yellow-300 rounded-full opacity-80 floating" style="animation-delay: 0s;"></div>
<div class="w-6 h-10 md:w-8 md:h-12 bg-gradient-to-b from-pink-100 to-pink-300 rounded-full opacity-80 floating" style="animation-delay: 1s;"></div>
<div class="w-6 h-10 md:w-8 md:h-12 bg-gradient-to-b from-blue-100 to-blue-300 rounded-full opacity-80 floating" style="animation-delay: 2s;"></div>
</div>
</section>
<script>
// Initialize Three.js scene
let scene, camera, renderer, objects = [];
let isMobile = window.matchMedia("(max-width: 768px)").matches;
function initThreeJS() {
// Scene setup
scene = new THREE.Scene();
scene.background = new THREE.Color(0xf9f9f9);
// Camera setup - adjust for mobile
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = isMobile ? 40 : 30;
// Renderer setup
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
powerPreference: "high-performance"
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); // Limit pixel ratio for performance
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Lights - simplified for mobile
const ambientLight = new THREE.AmbientLight(0xffffff, isMobile ? 0.8 : 0.6);
scene.add(ambientLight);
if (!isMobile) {
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(1, 1, 1);
scene.add(directionalLight);
}
// Create floating objects - fewer on mobile
createFloatingObjects();
// Handle window resize with debounce
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(onWindowResize, 200);
});
// Start animation loop
animate();
}
function createFloatingObjects() {
const count = isMobile ? 4 : 8; // Fewer objects on mobile
const geometry = new THREE.SphereGeometry(1, isMobile ? 16 : 32, isMobile ? 16 : 32);
const material = new THREE.MeshPhongMaterial({
color: 0xffd6e0,
transparent: true,
opacity: 0.8,
shininess: 100,
refractionRatio: 0.8
});
// Create glass orbs
for (let i = 0; i < count; i++) {
const sphere = new THREE.Mesh(geometry, material.clone());
sphere.position.x = (Math.random() - 0.5) * (isMobile ? 30 : 40);
sphere.position.y = (Math.random() - 0.5) * (isMobile ? 15 : 20);
sphere.position.z = (Math.random() - 0.5) * (isMobile ? 15 : 20);
sphere.scale.setScalar(0.6 + Math.random() * (isMobile ? 0.4 : 0.5));
// Add slight color variation
sphere.material.color.setHSL(
0.6 + Math.random() * 0.1,
0.3 + Math.random() * 0.2,
0.8 + Math.random() * 0.2
);
// Store original position for floating animation
sphere.userData = {
originalY: sphere.position.y,
speed: 0.1 + Math.random() * 0.1,
angle: Math.random() * Math.PI * 2
};
scene.add(sphere);
objects.push(sphere);
}
// Create keywords inside the orbs (only on desktop)
if (!isMobile) {
const keywords = ['Trust', 'Understanding', 'Hardworking', 'Creativity', 'Willingness'];
const container = document.getElementById('keywords-container');
keywords.forEach((word, i) => {
const el = document.createElement('div');
el.className = 'absolute text-lg md:text-xl font-bold text-gray-700 opacity-70';
el.style.top = `${30 + Math.random() * 40}%`;
el.style.left = `${20 + Math.random() * 60}%`;
el.textContent = word;
container.appendChild(el);
});
}
}
function onWindowResize() {
isMobile = window.matchMedia("(max-width: 768px)").matches;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
// Adjust camera position for mobile
camera.position.z = isMobile ? 40 : 30;
}
function animate() {
requestAnimationFrame(animate);
// Animate floating objects with reduced motion on mobile
objects.forEach(obj => {
obj.userData.angle += obj.userData.speed * (isMobile ? 0.005 : 0.01);
obj.position.y = obj.userData.originalY + Math.sin(obj.userData.angle) * (isMobile ? 1 : 2);
obj.rotation.x += isMobile ? 0.002 : 0.005;
obj.rotation.y += isMobile ? 0.002 : 0.005;
});
renderer.render(scene, camera);
}
// Navigation sphere click handlers
document.querySelectorAll('.nav-sphere').forEach(sphere => {
sphere.addEventListener('click', () => {
const section = document.getElementById(sphere.dataset.section);
section.scrollIntoView({ behavior: 'smooth' });
// Add animation to clicked sphere
gsap.to(sphere, {
scale: 1.3,
boxShadow: '0 0 0 12px rgba(255,255,255,0.5)',
duration: 0.3,
ease: 'power2.out',
onComplete: () => {
gsap.to(sphere, {
scale: 1,
boxShadow: '0 0 0 0 rgba(255,255,255,0.7)',
duration: 0.5,
ease: 'elastic.out(1, 0.5)'
});
}
});
});
});
// Initialize everything when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
// Only initialize Three.js on desktop
if (!isMobile) {
initThreeJS();
}
// Add GSAP animations for page elements
gsap.from('.hero-text', {
duration: 1.5,
y: 50,
opacity: 0,
ease: 'power3.out'
});
gsap.from('.project-tile', {
duration: 1,
y: 50,
opacity: 0,
stagger: 0.1,
ease: 'back.out(1.7)',
scrollTrigger: {
trigger: '#projects',
start: 'top 80%'
}
});
// Mobile navigation spheres repositioning
if (isMobile) {
const navSpheres = document.querySelector('.nav-spheres');
navSpheres.classList.remove('right-8', 'top-1/2', 'transform', '-translate-y-1/2', 'flex-col', 'space-y-4');
navSpheres.classList.add('bottom-8', 'right-1/2', 'transform', 'translate-x-1/2', 'flex-row', 'space-x-4');
}
});
// Touch device optimizations
if ('ontouchstart' in window) {
document.body.classList.add('touch-device');
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Marv12/2ppp" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>