diff --git a/package.json b/package.json index 16904dc..a533e0f 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,13 @@ "@remotion/player": "^4.0.79", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.22.0" + "react-router-dom": "^6.22.0", + "framer-motion": "^11.0.3", + "pts": "^0.11.4" }, "devDependencies": { "vite": "^5.4.2", - "@vitejs/plugin-react": "^4.2.1" + "@vitejs/plugin-react": "^4.2.1", + "@types/three": "^0.161.2" } } \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index c21a499..ecc767b 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,65 +1,81 @@ -import React, { useEffect, useState } from 'react'; -import { createRoot } from 'react-dom/client'; -import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; -import Home from './pages/Home'; -import Manifesto from './pages/Manifesto'; -import { Scene } from './three/Scene'; -import { CardEffects } from './ui/CardEffects'; -import { ScrollEffects } from './ui/ScrollEffects'; -import { RemotionVideo } from './Video'; +import React, { Suspense, lazy, useEffect, useState } from 'react'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import LoadingState from './components/LoadingState'; + +// Lazy load components +const Home = lazy(() => import('./pages/Home')); +const Manifesto = lazy(() => import('./pages/Manifesto')); +const Scene = lazy(() => import('./three/Scene').then(module => ({ default: module.Scene }))); function App() { const [scene, setScene] = useState(null); - const [effects, setEffects] = useState({ card: null, scroll: null }); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { - // Initialize Three.js scene - const newScene = new Scene(); - newScene.animate(); - setScene(newScene); - - // Initialize UI effects - const cardEffects = new CardEffects(); - const scrollEffects = new ScrollEffects(); - setEffects({ card: cardEffects, scroll: scrollEffects }); - - // Initialize Remotion video - const videoContainer = document.createElement('div'); - videoContainer.id = 'remotion-video'; - document.body.appendChild(videoContainer); + // Preload critical assets + const preloadAssets = async () => { + try { + // Initialize Three.js scene + const newScene = new Scene(); + await newScene.init(); // Assuming we make init async + setScene(newScene); + + // Simulate minimum loading time for smooth transition + await new Promise(resolve => setTimeout(resolve, 1000)); + + setIsLoading(false); + } catch (error) { + console.error('Error loading assets:', error); + setIsLoading(false); + } + }; - const root = document.createElement('div'); - root.id = 'remotion-root'; - videoContainer.appendChild(root); - - const videoRoot = createRoot(root); - videoRoot.render(); + preloadAssets(); return () => { - // Cleanup if (scene) { scene.dispose(); } - if (videoContainer.parentNode) { - videoContainer.parentNode.removeChild(videoContainer); - } }; }, []); - // Reinitialize effects on route change - const handleRouteChange = () => { - if (effects.card) effects.card.init(); - if (effects.scroll) effects.scroll.init(); - }; + // Debounced resize handler + useEffect(() => { + let resizeTimeout; + const handleResize = () => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(() => { + if (scene) { + scene.handleResize(); + } + }, 250); + }; + + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + clearTimeout(resizeTimeout); + }; + }, [scene]); + + if (isLoading) { + return ; + } return ( - - - } /> - } /> - } /> - + }> + + scene?.animate()} />} + /> + scene?.animate()} />} + /> + + ); } diff --git a/src/Video.jsx b/src/Video.jsx index 5d354c7..a756429 100644 --- a/src/Video.jsx +++ b/src/Video.jsx @@ -28,58 +28,82 @@ const BackgroundAnimation = () => { const ctx = canvas.getContext('2d'); let animationFrame; - let particles = Array.from({ length: 100 }, () => ({ + + // Increase number of particles and add variation + const particles = Array.from({ length: 150 }, () => ({ x: Math.random() * dimensions.width, y: Math.random() * dimensions.height, - size: Math.random() * 2 + 1, - speedX: (Math.random() - 0.5) * 0.5, - speedY: (Math.random() - 0.5) * 0.5 + size: Math.random() * 3 + 0.5, + speedX: (Math.random() - 0.5) * 0.3, + speedY: (Math.random() - 0.5) * 0.3, + opacity: Math.random() * 0.5 + 0.1 })); const animate = (time) => { canvas.width = dimensions.width; canvas.height = dimensions.height; - // Create gradient background - const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height); - gradient.addColorStop(0, 'rgba(122, 158, 159, 0.05)'); - gradient.addColorStop(1, 'rgba(80, 108, 127, 0.05)'); + // Enhanced gradient background + const gradient = ctx.createRadialGradient( + dimensions.width / 2, + dimensions.height / 2, + 0, + dimensions.width / 2, + dimensions.height / 2, + dimensions.width * 0.7 + ); + gradient.addColorStop(0, 'rgba(122, 158, 159, 0.03)'); + gradient.addColorStop(0.5, 'rgba(80, 108, 127, 0.02)'); + gradient.addColorStop(1, 'rgba(0, 0, 0, 0)'); ctx.fillStyle = gradient; ctx.fillRect(0, 0, canvas.width, canvas.height); - // Update and draw particles + // Update and draw particles with enhanced effects particles.forEach(particle => { - const noiseX = noise4D(particle.x * 0.001, particle.y * 0.001, time * 0.0001, 0); - const noiseY = noise4D(particle.x * 0.001, particle.y * 0.001, 0, time * 0.0001); + const noiseX = noise4D(particle.x * 0.001, particle.y * 0.001, time * 0.0001, 0) * 2; + const noiseY = noise4D(particle.x * 0.001, particle.y * 0.001, 0, time * 0.0001) * 2; particle.x += particle.speedX + noiseX; particle.y += particle.speedY + noiseY; - // Wrap around screen - if (particle.x < 0) particle.x = canvas.width; - if (particle.x > canvas.width) particle.x = 0; - if (particle.y < 0) particle.y = canvas.height; - if (particle.y > canvas.height) particle.y = 0; - - // Draw particle + // Improved wrapping logic + if (particle.x < -50) particle.x = canvas.width + 50; + if (particle.x > canvas.width + 50) particle.x = -50; + if (particle.y < -50) particle.y = canvas.height + 50; + if (particle.y > canvas.height + 50) particle.y = -50; + + // Draw particle with glow effect + const glow = ctx.createRadialGradient( + particle.x, + particle.y, + 0, + particle.x, + particle.y, + particle.size * 2 + ); + glow.addColorStop(0, `rgba(122, 158, 159, ${particle.opacity})`); + glow.addColorStop(1, 'rgba(122, 158, 159, 0)'); + ctx.beginPath(); - ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2); - ctx.fillStyle = `rgba(122, 158, 159, ${0.1 + Math.abs(noiseX) * 0.5})`; + ctx.arc(particle.x, particle.y, particle.size * 2, 0, Math.PI * 2); + ctx.fillStyle = glow; ctx.fill(); }); - // Draw flowing lines + // Draw flowing lines with enhanced effect ctx.beginPath(); - ctx.strokeStyle = 'rgba(122, 158, 159, 0.1)'; - ctx.lineWidth = 1; + ctx.strokeStyle = 'rgba(122, 158, 159, 0.05)'; + ctx.lineWidth = 0.5; - for (let i = 0; i < canvas.width; i += 50) { + for (let i = 0; i < canvas.width; i += 30) { const startY = canvas.height / 2; ctx.moveTo(i, startY); - for (let x = 0; x < canvas.width; x += 10) { - const y = startY + Math.sin(x * 0.01 + time * 0.001) * 50 + - noise4D(x * 0.001, startY * 0.001, time * 0.0001, 0) * 30; + for (let x = 0; x < canvas.width; x += 5) { + const noise = noise4D(x * 0.002, startY * 0.002, time * 0.0001, 0); + const y = startY + + Math.sin(x * 0.01 + time * 0.001) * 30 + + noise * 50; ctx.lineTo(x, y); } } @@ -104,7 +128,7 @@ const BackgroundAnimation = () => { style={{ width: '100%', height: '100%', - opacity: 0.6, + opacity: 0.8, mixBlendMode: 'screen' }} /> diff --git a/src/components/LoadingState.jsx b/src/components/LoadingState.jsx new file mode 100644 index 0000000..e74d3e7 --- /dev/null +++ b/src/components/LoadingState.jsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { motion } from 'framer-motion'; + +const LoadingState = () => { + return ( + +
+ + + {/* Add your logo SVG path here */} + + + + + + {[0, 1, 2].map((_, i) => ( + + ))} + +
+
+ ); +}; + +export default LoadingState; \ No newline at end of file diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 1bffa2e..b45fdc0 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,55 +1,80 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; +import { motion } from 'framer-motion'; function Home({ onMount }) { + const [isLoaded, setIsLoaded] = useState(false); + useEffect(() => { - onMount(); + onMount?.(); + setIsLoaded(true); }, [onMount]); - return ( -
- -
-

Intuition Labs

-

Pioneering the future of AI through research and strategic innovation

-
+ const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.1, + delayChildren: 0.2 + } + } + }; -
-
- {/* First set */} - terminals - radical - pathfinder - wuji - boom - journey - {/* Duplicate set for seamless loop */} - terminals - radical - pathfinder - wuji - boom - journey -
-
+ const itemVariants = { + hidden: { y: 20, opacity: 0 }, + visible: { + y: 0, + opacity: 1, + transition: { duration: 0.6, ease: [0.23, 1, 0.32, 1] } + } + }; -
-

Our Vision

-

Transforming enterprises through cutting-edge AI solutions and polymathic expertise

+ return ( + + +

Intuition Labs

+

Pioneering the future of AI through intuitive design

- Schedule Consultation - Read Our Manifesto + + Schedule Consultation + + + + Read Our Manifesto + +
-
+ -
+

Featured Solutions

-
+

Enterprise AI Strategy

Comprehensive AI implementation and transformation roadmaps

- Learn More → -
+
  • Enterprise AI Implementation Strategy
  • LLM & Agent System Architecture
  • @@ -57,12 +82,16 @@ function Home({ onMount }) {
  • Complex System Integration
-
-
+ + +

LLM Systems

Custom language model development and integration

- Learn More → -
+
  • Custom AI Agent Development
  • Advanced Prompt Engineering
  • @@ -70,32 +99,29 @@ function Home({ onMount }) {
  • Process Automation & Optimization
-
-
-

AI Agents

-

Autonomous agent systems for process automation

- Learn More → -
-
    -
  • 30k+ hours annual productivity improvement
  • -
  • Enterprise systems architecture across industries
  • -
  • Performance management for mega-cap enterprises
  • -
  • Cloud-wide tech stack transformation
  • -
-
-
+
-
+ - -
+ + ); } diff --git a/src/three/FlowField.js b/src/three/FlowField.js index 6802193..a766d72 100644 --- a/src/three/FlowField.js +++ b/src/three/FlowField.js @@ -5,60 +5,90 @@ export class FlowField { constructor() { this.noise4D = createNoise4D(); this.group = new THREE.Group(); - this.geometry = new THREE.BufferGeometry(); + this.lines = []; + this.particleCount = 150; + this.segmentCount = 100; + this.material = new THREE.LineBasicMaterial({ color: 0x7A9E9F, transparent: true, - opacity: 0.3 + opacity: 0.3, + blending: THREE.AdditiveBlending }); this.init(); } - init() { + createFlowLine() { const points = []; - const numLines = 100; - const segments = 75; - - for (let i = 0; i < numLines; i++) { - let x = (Math.random() - 0.5) * 100; - let y = (Math.random() - 0.5) * 100; - let z = (Math.random() - 0.5) * 100; - - for (let j = 0; j < segments; j++) { - points.push(new THREE.Vector3(x, y, z)); - - const scale = 0.015; - const noise = this.noise4D(x * scale, y * scale, z * scale, Date.now() * 0.00003); - - x += Math.cos(noise * Math.PI * 2) * 0.4; - y += Math.sin(noise * Math.PI * 2) * 0.4; - z += (Math.cos(noise * Math.PI) + Math.sin(noise * Math.PI)) * 0.2; - } + const geometry = new THREE.BufferGeometry(); + + // Random starting position + const startPos = new THREE.Vector3( + (Math.random() - 0.5) * 100, + (Math.random() - 0.5) * 100, + (Math.random() - 0.5) * 100 + ); + + points.push(startPos.clone()); + + // Generate flow line points + for (let i = 1; i < this.segmentCount; i++) { + const prevPoint = points[i - 1].clone(); + const noise = this.noise4D( + prevPoint.x * 0.02, + prevPoint.y * 0.02, + prevPoint.z * 0.02, + i * 0.1 + ); + + const angle = noise * Math.PI * 2; + const dx = Math.cos(angle) * 0.5; + const dy = Math.sin(angle) * 0.5; + const dz = (Math.cos(angle) + Math.sin(angle)) * 0.25; + + points.push(new THREE.Vector3( + prevPoint.x + dx, + prevPoint.y + dy, + prevPoint.z + dz + )); } + + geometry.setFromPoints(points); + const line = new THREE.Line(geometry, this.material); + return { line, points: points.map(p => p.clone()) }; + } - this.geometry.setFromPoints(points); - const flowLines = new THREE.LineSegments(this.geometry, this.material); - this.group.add(flowLines); + init() { + for (let i = 0; i < this.particleCount; i++) { + const flowLine = this.createFlowLine(); + this.lines.push(flowLine); + this.group.add(flowLine.line); + } } update(time) { + this.lines.forEach((flowLine, lineIndex) => { + const points = flowLine.points.map((point, i) => { + const noise = this.noise4D( + point.x * 0.02, + point.y * 0.02, + point.z * 0.02, + time + lineIndex * 0.1 + ); + + return new THREE.Vector3( + point.x + Math.cos(noise * Math.PI * 2) * 0.1, + point.y + Math.sin(noise * Math.PI * 2) * 0.1, + point.z + (Math.cos(noise * Math.PI) + Math.sin(noise * Math.PI)) * 0.05 + ); + }); + + flowLine.line.geometry.setFromPoints(points); + flowLine.line.geometry.computeBoundingSphere(); + }); + this.group.rotation.x += 0.0001; this.group.rotation.y += 0.0001; - - const positions = this.geometry.attributes.position.array; - for (let i = 0; i < positions.length; i += 3) { - const x = positions[i]; - const y = positions[i + 1]; - const z = positions[i + 2]; - - const scale = 0.015; - const noise = this.noise4D(x * scale, y * scale, z * scale, time); - - positions[i] += Math.cos(noise * Math.PI * 2) * 0.015; - positions[i + 1] += Math.sin(noise * Math.PI * 2) * 0.015; - positions[i + 2] += Math.cos(noise * Math.PI) * 0.015; - } - this.geometry.attributes.position.needsUpdate = true; } } \ No newline at end of file diff --git a/src/three/Scene.js b/src/three/Scene.js index a9e4563..72f44f1 100644 --- a/src/three/Scene.js +++ b/src/three/Scene.js @@ -1,6 +1,9 @@ import * as THREE from 'three'; import { FlowField } from './FlowField'; import { Spheres } from './Spheres'; +import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'; +import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; +import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass'; export class Scene { constructor() { @@ -12,31 +15,56 @@ export class Scene { alpha: true }); + this.composer = null; this.flowField = new FlowField(); this.spheres = new Spheres(); this.time = 0; + this.mouse = new THREE.Vector2(); + this.targetRotation = new THREE.Vector2(); this.init(); this.setupLights(); + this.setupPostProcessing(); this.setupEventListeners(); } init() { - this.renderer.setPixelRatio(window.devicePixelRatio); + this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); this.renderer.setSize(window.innerWidth, window.innerHeight); + this.renderer.toneMapping = THREE.ACESFilmicToneMapping; + this.renderer.toneMappingExposure = 1; + this.camera.position.setZ(30); + this.camera.position.setY(5); + this.scene.fog = new THREE.FogExp2(0x000000, 0.01); this.scene.add(this.flowField.group); this.spheres.spheres.forEach(sphere => this.scene.add(sphere)); } + setupPostProcessing() { + this.composer = new EffectComposer(this.renderer); + const renderPass = new RenderPass(this.scene, this.camera); + this.composer.addPass(renderPass); + + const bloomPass = new UnrealBloomPass( + new THREE.Vector2(window.innerWidth, window.innerHeight), + 0.5, // strength + 0.4, // radius + 0.85 // threshold + ); + this.composer.addPass(bloomPass); + } + setupLights() { const ambientLight = new THREE.AmbientLight(0x404040, 0.8); - const pointLight = new THREE.PointLight(0x7A9E9F, 1.0); + const pointLight = new THREE.PointLight(0x7A9E9F, 2.0); pointLight.position.set(10, 10, 10); - this.scene.add(ambientLight); - this.scene.add(pointLight); + const pointLight2 = new THREE.PointLight(0x506C7F, 1.5); + pointLight2.position.set(-10, -10, -10); + + this.scene.add(ambientLight, pointLight, pointLight2); } setupEventListeners() { @@ -44,33 +72,36 @@ export class Scene { this.camera.aspect = window.innerWidth / window.innerHeight; this.camera.updateProjectionMatrix(); this.renderer.setSize(window.innerWidth, window.innerHeight); + this.composer.setSize(window.innerWidth, window.innerHeight); }); document.addEventListener('mousemove', (event) => { - const mouseX = (event.clientX - window.innerWidth / 2) * 0.00004; - const mouseY = (event.clientY - window.innerHeight / 2) * 0.00004; + this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; - this.flowField.group.rotation.y += mouseX; - this.flowField.group.rotation.x += mouseY; + this.targetRotation.x = this.mouse.y * 0.1; + this.targetRotation.y = this.mouse.x * 0.1; }); } animate() { - requestAnimationFrame(() => this.animate()); - - this.time += 0.0003; + requestAnimationFrame(this.animate.bind(this)); + this.time += 0.001; + + // Smooth camera rotation + this.camera.rotation.x += (this.targetRotation.x - this.camera.rotation.x) * 0.05; + this.camera.rotation.y += (this.targetRotation.y - this.camera.rotation.y) * 0.05; + + // Update components this.flowField.update(this.time); this.spheres.update(this.time); - - this.renderer.render(this.scene, this.camera); + + // Render with post-processing + this.composer.render(); } dispose() { - // Remove event listeners - window.removeEventListener('resize', this.handleResize); - document.removeEventListener('mousemove', this.handleMouseMove); - - // Dispose of Three.js resources + this.renderer.dispose(); this.scene.traverse((object) => { if (object.geometry) object.geometry.dispose(); if (object.material) { @@ -81,7 +112,5 @@ export class Scene { } } }); - - this.renderer.dispose(); } } \ No newline at end of file diff --git a/src/three/Spheres.js b/src/three/Spheres.js index ff905fc..84586cc 100644 --- a/src/three/Spheres.js +++ b/src/three/Spheres.js @@ -1,38 +1,98 @@ import * as THREE from 'three'; +import { createNoise4D } from 'simplex-noise'; export class Spheres { constructor() { + this.noise4D = createNoise4D(); this.spheres = []; - this.geometry = new THREE.IcosahedronGeometry(1, 3); - this.material = new THREE.MeshPhongMaterial({ - color: 0x506C7F, - transparent: true, - opacity: 0.2, - shininess: 100, - specular: 0x7A9E9F - }); - + this.materials = []; + this.baseGeometry = new THREE.IcosahedronGeometry(1, 3); + + // Create multiple materials for variety + this.createMaterials(); this.init(); } + createMaterials() { + const colors = [0x506C7F, 0x7A9E9F, 0x405C6F]; + colors.forEach(color => { + this.materials.push( + new THREE.MeshPhongMaterial({ + color, + transparent: true, + opacity: 0.2, + shininess: 100, + specular: 0x7A9E9F, + side: THREE.DoubleSide, + wireframe: Math.random() > 0.7 + }) + ); + }); + } + init() { - for (let i = 0; i < 15; i++) { - const sphere = new THREE.Mesh(this.geometry, this.material); + for (let i = 0; i < 20; i++) { + const sphere = new THREE.Mesh( + this.baseGeometry, + this.materials[Math.floor(Math.random() * this.materials.length)] + ); + + // Position spheres in a more interesting pattern + const radius = 30 + Math.random() * 30; + const theta = Math.random() * Math.PI * 2; + const phi = Math.random() * Math.PI; + sphere.position.set( - (Math.random() - 0.5) * 60, - (Math.random() - 0.5) * 60, - (Math.random() - 0.5) * 60 + radius * Math.sin(phi) * Math.cos(theta), + radius * Math.sin(phi) * Math.sin(theta), + radius * Math.cos(phi) ); - sphere.scale.setScalar(Math.random() * 2 + 1); + + sphere.scale.setScalar(Math.random() * 2 + 0.5); + sphere.userData = { + originalPosition: sphere.position.clone(), + rotationSpeed: (Math.random() - 0.5) * 0.002, + pulseSpeed: Math.random() * 0.002 + 0.001, + pulseOffset: Math.random() * Math.PI * 2 + }; + this.spheres.push(sphere); } } update(time) { this.spheres.forEach((sphere, i) => { - sphere.position.y += Math.sin(time + i) * 0.004; - sphere.rotation.x += 0.001; - sphere.rotation.y += 0.001; + // Smooth floating motion + const noise = this.noise4D( + sphere.position.x * 0.02, + sphere.position.y * 0.02, + sphere.position.z * 0.02, + time + ); + + const originalPos = sphere.userData.originalPosition; + sphere.position.x = originalPos.x + Math.cos(time + i) * 2 * noise; + sphere.position.y = originalPos.y + Math.sin(time + i) * 2 * noise; + sphere.position.z = originalPos.z + Math.cos(time * 0.5 + i) * 2 * noise; + + // Rotation + sphere.rotation.x += sphere.userData.rotationSpeed; + sphere.rotation.y += sphere.userData.rotationSpeed * 1.2; + + // Pulsing scale effect + const pulse = Math.sin(time * sphere.userData.pulseSpeed + sphere.userData.pulseOffset) * 0.1 + 1; + const baseScale = sphere.userData.originalScale || 1; + sphere.scale.setScalar(baseScale * pulse); + + // Update material opacity + if (sphere.material.transparent) { + sphere.material.opacity = 0.2 + Math.sin(time * 2 + i) * 0.1; + } }); } + + dispose() { + this.baseGeometry.dispose(); + this.materials.forEach(material => material.dispose()); + } } \ No newline at end of file diff --git a/src/ui/CardEffects.js b/src/ui/CardEffects.js index f7b851c..52a1dd8 100644 --- a/src/ui/CardEffects.js +++ b/src/ui/CardEffects.js @@ -7,19 +7,33 @@ export class CardEffects { const cards = document.querySelectorAll('.card'); cards.forEach(card => { - // Mouse move effect for gradient + // Enhanced mouse move effect card.addEventListener('mousemove', (e) => { const rect = card.getBoundingClientRect(); const x = ((e.clientX - rect.left) / rect.width) * 100; const y = ((e.clientY - rect.top) / rect.height) * 100; + + // Update gradient position card.style.setProperty('--x', `${x}%`); card.style.setProperty('--y', `${y}%`); + + // Add subtle rotation effect + const rotateX = (y - 50) * 0.1; + const rotateY = (x - 50) * -0.1; + card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(1.02)`; }); - // Stagger animation for list items on hover + // Reset transform on mouse leave + card.addEventListener('mouseleave', () => { + card.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale(1)'; + }); + + // Enhanced stagger animation for list items const listItems = card.querySelectorAll('.learn-more-content li'); listItems.forEach((item, index) => { - item.style.transitionDelay = `${index * 50}ms`; + item.style.transitionDelay = `${index * 75}ms`; + item.style.transform = 'translateY(10px)'; + item.style.opacity = '0'; }); }); } diff --git a/src/ui/ScrollEffects.js b/src/ui/ScrollEffects.js index c5ea04a..c391bf4 100644 --- a/src/ui/ScrollEffects.js +++ b/src/ui/ScrollEffects.js @@ -1,18 +1,65 @@ export class ScrollEffects { constructor() { this.init(); + this.setupParallax(); } init() { const sections = document.querySelectorAll('.section'); + const options = { + root: null, + rootMargin: '0px', + threshold: buildThresholdList() + }; + const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { - entry.target.classList.add('visible'); + const ratio = entry.intersectionRatio; + entry.target.style.opacity = Math.min(ratio * 1.5, 1); + entry.target.style.transform = `translateY(${(1 - ratio) * 20}px)`; + + // Animate children with stagger + const children = entry.target.children; + Array.from(children).forEach((child, index) => { + child.style.transitionDelay = `${index * 100}ms`; + child.classList.add('visible'); + }); } }); - }, { threshold: 0.1 }); + }, options); + + sections.forEach(section => { + section.style.opacity = '0'; + section.style.transform = 'translateY(20px)'; + section.style.transition = 'opacity 0.6s ease-out, transform 0.6s ease-out'; + observer.observe(section); + }); + } + + setupParallax() { + const parallaxElements = document.querySelectorAll('[data-parallax]'); + + window.addEventListener('scroll', () => { + const scrolled = window.pageYOffset; + + parallaxElements.forEach(element => { + const speed = element.dataset.parallax || 0.5; + const offset = scrolled * speed; + element.style.transform = `translateY(${offset}px)`; + }); + }); + } +} - sections.forEach(section => observer.observe(section)); +function buildThresholdList() { + let thresholds = []; + let numSteps = 20; + + for (let i = 1; i <= numSteps; i++) { + let ratio = i / numSteps; + thresholds.push(ratio); } + + return thresholds; } \ No newline at end of file diff --git a/style.css b/style.css index 4cb83e1..f6b9543 100644 --- a/style.css +++ b/style.css @@ -303,7 +303,10 @@ h2::before { padding: 2.5rem; border-radius: 2px; border: 1px solid rgba(255, 255, 255, .03); - transition: all .6s cubic-bezier(.23, 1, .32, 1); + transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1), + box-shadow 0.6s cubic-bezier(0.23, 1, 0.32, 1); + transform-style: preserve-3d; + will-change: transform; position: relative; overflow: hidden; } @@ -561,13 +564,15 @@ footer { background: var(--card-bg); border: 1px solid rgba(255, 255, 255, 0.03); border-radius: 2px; - transition: all 0.6s cubic-bezier(0.23, 1, 0.32, 1); + transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1), + background 0.3s ease, + border-color 0.3s ease; + transform-style: preserve-3d; } .manifesto-item:hover { - transform: translateY(-3px); + transform: translateY(-5px) scale(1.02); background: var(--hover); - border-color: var(--glow); } .manifesto-item h2 { @@ -615,6 +620,10 @@ footer { } @keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } to { opacity: 1; transform: translateY(0); @@ -639,4 +648,122 @@ footer { align-items: flex-start; gap: 1.5rem; } +} + +.platforms-track { + animation: scroll 40s linear infinite; + filter: blur(0); + transition: filter 0.3s ease; +} + +.platforms-track:hover { + animation-play-state: paused; + filter: blur(0); +} + +.platform-name { + transition: transform 0.3s ease, + opacity 0.3s ease, + color 0.3s ease; +} + +.platform-name:hover { + transform: scale(1.1); + opacity: 1; + color: var(--glow); +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.section { + animation: fadeIn 0.8s ease-out forwards; + animation-play-state: paused; +} + +.section.visible { + animation-play-state: running; +} + +/* Loading State Styles */ +.loading-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #000000; + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.loading-content { + display: flex; + flex-direction: column; + align-items: center; + gap: 2rem; +} + +.loading-logo { + color: #7A9E9F; + width: 50px; + height: 50px; +} + +.loading-dots { + display: flex; + gap: 0.5rem; +} + +.dot { + width: 8px; + height: 8px; + background-color: #7A9E9F; + border-radius: 50%; + display: inline-block; +} + +/* Enhanced Homepage Styles */ +.gradient-text { + background: linear-gradient(135deg, #7A9E9F 0%, #506C7F 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.hero-section { + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + padding: 2rem; +} + +.solutions-grid { + padding: 4rem 2rem; +} + +.vision-section { + padding: 6rem 2rem; + background: linear-gradient(to bottom, transparent, rgba(122, 158, 159, 0.1)); +} + +.tech-stack { + display: flex; + gap: 2rem; + flex-wrap: wrap; + justify-content: center; + margin-top: 2rem; } \ No newline at end of file diff --git a/vite.config.js b/vite.config.js index cf567d4..6b09cb9 100644 --- a/vite.config.js +++ b/vite.config.js @@ -5,9 +5,30 @@ export default defineConfig({ base: '/', plugins: [react()], build: { - outDir: 'dist' + outDir: 'dist', + rollupOptions: { + output: { + manualChunks: { + 'vendor': ['react', 'react-dom', 'react-router-dom'], + 'three': ['three'], + 'animation': ['framer-motion', 'pts'] + } + } + }, + chunkSizeWarningLimit: 1000, + sourcemap: false, + minify: 'terser', + terserOptions: { + compress: { + drop_console: true, + drop_debugger: true + } + } }, resolve: { extensions: ['.js', '.jsx'] + }, + optimizeDeps: { + include: ['three', 'framer-motion', 'pts'] } }); \ No newline at end of file