Skip to content

Commit da8388b

Browse files
committed
Add varied 3D materials and fix WebXR polyfill errors
- Added 5 different material types for floating shapes (glass, metal, neon, hologram, crystal) - Simplified material properties to avoid Three.js uniform errors - Improved Canvas configuration for better WebXR compatibility - Added proper fallback component for loading states - Enhanced error handling for 3D rendering context
1 parent 5d5d4dc commit da8388b

5 files changed

Lines changed: 852 additions & 344 deletions

File tree

116 KB
Binary file not shown.

src/components/FloatingShapes.jsx

Lines changed: 67 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ const FloatingShapes = () => {
2828
const shapes = useMemo(() => {
2929
const shapeArray = []
3030
const shapeTypes = ['sphere', 'cube']
31+
const materialTypes = ['glass', 'metal', 'neon', 'hologram', 'crystal']
3132

3233
for (let i = 0; i < 200; i++) { // Doubled from 100 to 200 balls
3334
shapeArray.push({
3435
id: i,
3536
type: shapeTypes[Math.floor(Math.random() * shapeTypes.length)], // Random sphere or cube
37+
materialType: materialTypes[Math.floor(Math.random() * materialTypes.length)], // Random material
3638
position: [
3739
(Math.random() - 0.5) * 30, // Even wider spread for more balls
3840
(Math.random() - 0.5) * 20, // Higher spread
@@ -71,8 +73,8 @@ const FloatingShapes = () => {
7173
child.position.y += shape.direction[1] * delta * 0.15 // Reduced from 0.3
7274
child.position.z += shape.direction[2] * delta * 0.2 // Reduced from 0.4
7375

74-
// Add upward movement based on scroll
75-
child.position.y += scrollYRef.current * 0.01 * delta // Use ref instead of state
76+
// Add upward movement based on scroll - reduced to 1/4 speed
77+
child.position.y += scrollYRef.current * 0.0025 * delta // Reduced from 0.01 to 0.0025
7678

7779
// Gentle sinusoidal movement for organic feel - reduced intensity
7880
child.position.x += Math.sin(time * 0.5) * delta * 0.1 // Reduced from 0.2
@@ -114,6 +116,68 @@ const FloatingShapes = () => {
114116
}
115117
}, [shape.type])
116118

119+
// Different material types for variety
120+
const material = useMemo(() => {
121+
switch (shape.materialType) {
122+
case 'glass':
123+
return (
124+
<meshPhysicalMaterial
125+
color={shape.color}
126+
metalness={0.0}
127+
roughness={0.0}
128+
transmission={0.9}
129+
transparent={true}
130+
opacity={0.6}
131+
/>
132+
)
133+
case 'metal':
134+
return (
135+
<meshStandardMaterial
136+
color={shape.color}
137+
metalness={1.0}
138+
roughness={0.2}
139+
/>
140+
)
141+
case 'neon':
142+
return (
143+
<meshBasicMaterial
144+
color={shape.color}
145+
transparent={true}
146+
opacity={0.8}
147+
/>
148+
)
149+
case 'hologram':
150+
return (
151+
<meshPhongMaterial
152+
color={shape.color}
153+
transparent={true}
154+
opacity={0.4}
155+
shininess={100}
156+
/>
157+
)
158+
case 'crystal':
159+
return (
160+
<meshPhysicalMaterial
161+
color={shape.color}
162+
metalness={0.1}
163+
roughness={0.0}
164+
transparent={true}
165+
opacity={0.7}
166+
/>
167+
)
168+
default:
169+
return (
170+
<meshStandardMaterial
171+
color={shape.color}
172+
metalness={0.2}
173+
roughness={0.1}
174+
transparent={true}
175+
opacity={0.8}
176+
/>
177+
)
178+
}
179+
}, [shape.materialType, shape.color])
180+
117181
return (
118182
<mesh
119183
ref={meshRef}
@@ -122,17 +186,7 @@ const FloatingShapes = () => {
122186
scale={shape.scale}
123187
>
124188
{geometry}
125-
<meshPhysicalMaterial
126-
color={shape.color}
127-
metalness={0.2}
128-
roughness={0.1}
129-
clearcoat={0.8}
130-
clearcoatRoughness={0.1}
131-
transparent
132-
opacity={0.8}
133-
emissive={shape.color}
134-
emissiveIntensity={0.05}
135-
/>
189+
{material}
136190
</mesh>
137191
)
138192
}

src/components/HeroSection.jsx

Lines changed: 97 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@ const Scene = () => {
1111
useCursorInteraction()
1212

1313
return (
14-
<MouseCameraController>
15-
<GradientSkybox />
16-
<SceneLighting />
17-
18-
{/* Futuristic Platform */}
19-
<Platform />
20-
21-
{/* Minimal floating shapes */}
22-
<FloatingShapes />
23-
</MouseCameraController>
14+
<>
15+
<MouseCameraController>
16+
<GradientSkybox />
17+
<SceneLighting />
18+
19+
{/* Futuristic Platform - Hidden for now */}
20+
{/* <Platform /> */}
21+
22+
{/* Minimal floating shapes */}
23+
<FloatingShapes />
24+
</MouseCameraController>
25+
</>
2426
)
2527
}
2628

@@ -46,14 +48,24 @@ const HeroSection = () => {
4648
{/* Navbar */}
4749
<nav className="navbar">
4850
<div className="navbar__content">
49-
<a href="mailto:austinthemichaud@gmail.com" className="navbar__link">
50-
austinthemichaud@gmail.com
51-
</a>
52-
<a href="https://www.linkedin.com/in/austin-michaud-9b25aa141/" target="_blank" rel="noopener noreferrer" className="navbar__link">
53-
LinkedIn
54-
</a>
55-
<a href="https://github.com/foobar404" target="_blank" rel="noopener noreferrer" className="navbar__link">
56-
GitHub
51+
<div className="navbar__links">
52+
<a href="mailto:austinthemichaud@gmail.com" className="navbar__link">
53+
austinthemichaud@gmail.com
54+
</a>
55+
<a href="https://www.linkedin.com/in/austin-michaud-9b25aa141/" target="_blank" rel="noopener noreferrer" className="navbar__link">
56+
LinkedIn
57+
</a>
58+
<a href="https://github.com/foobar404" target="_blank" rel="noopener noreferrer" className="navbar__link">
59+
GitHub
60+
</a>
61+
</div>
62+
<a href="/assets/resume.pdf" download="Austin_Michaud_Resume.pdf" className="navbar__resume-btn">
63+
<span>Download Resume</span>
64+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
65+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
66+
<polyline points="7,10 12,15 17,10"></polyline>
67+
<line x1="12" y1="15" x2="12" y2="3"></line>
68+
</svg>
5769
</a>
5870
</div>
5971
</nav>
@@ -68,11 +80,16 @@ const HeroSection = () => {
6880
gl={{
6981
antialias: false,
7082
alpha: true,
71-
powerPreference: "default"
83+
powerPreference: "high-performance",
84+
preserveDrawingBuffer: false,
85+
failIfMajorPerformanceCaveat: false
86+
}}
87+
dpr={[1, 2]}
88+
onCreated={({ gl }) => {
89+
gl.setClearColor('#000000', 0)
7290
}}
73-
dpr={1}
7491
>
75-
<Suspense fallback={null}>
92+
<Suspense fallback={<LoadingFallback />}>
7693
<Scene />
7794
</Suspense>
7895
</Canvas>
@@ -105,14 +122,72 @@ const HeroSection = () => {
105122
<h1 className="hero__title">
106123
Austin Michaud
107124
</h1>
108-
<div className="flex justify-center items-center mt-8">
125+
126+
127+
{/* Floating Tech Bubbles */}
128+
<div className="tech-bubbles">
129+
<div className="tech-bubble">
130+
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/blender/blender-original.svg" alt="Blender" />
131+
<span className="tooltip">Blender - 3D modeling and animation for XR assets</span>
132+
</div>
133+
<div className="tech-bubble">
134+
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/godot/godot-original.svg" alt="Godot" />
135+
<span className="tooltip">Godot Engine - Open-source game engine for XR development</span>
136+
</div>
137+
<div className="tech-bubble">
138+
<svg width="32" height="32" viewBox="0 0 100 100" fill="none">
139+
<circle cx="50" cy="50" r="50" fill="#DC2626"/>
140+
<text x="50" y="70" textAnchor="middle" fontSize="45" fill="white" fontWeight="bold">XR</text>
141+
</svg>
142+
<span className="tooltip">WebXR - Web-based extended reality experiences</span>
143+
</div>
144+
<div className="tech-bubble">
145+
<svg width="32" height="32" viewBox="0 0 100 100" fill="none">
146+
<path d="M50 10L80 80H20L50 10Z" fill="#EF2D5E"/>
147+
<path d="M35 65L50 35L65 65H35Z" fill="#FFF"/>
148+
</svg>
149+
<span className="tooltip">A-Frame - Web framework for building VR experiences</span>
150+
</div>
151+
<div className="tech-bubble">
152+
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/threejs/threejs-original.svg" alt="Three.js" />
153+
<span className="tooltip">Three.js - JavaScript 3D library for interactive graphics</span>
154+
</div>
155+
<div className="tech-bubble">
156+
<svg width="32" height="32" viewBox="0 0 100 100" fill="none">
157+
<circle cx="30" cy="30" r="15" fill="#4A90E2" opacity="0.8"/>
158+
<rect x="55" y="15" width="30" height="30" rx="5" fill="#7B68EE" opacity="0.8"/>
159+
<polygon points="20,85 35,60 50,85" fill="#FF6B9D" opacity="0.8"/>
160+
<path d="M65 85L85 65L85 85Z" fill="#50E3C2" opacity="0.8"/>
161+
</svg>
162+
<span className="tooltip">ShapesXR - Professional XR creation platform</span>
163+
</div>
164+
<div className="tech-bubble">
165+
<svg width="32" height="32" viewBox="0 0 100 100" fill="none">
166+
<defs>
167+
<linearGradient id="gravityGrad" x1="0%" y1="0%" x2="100%" y2="100%">
168+
<stop offset="0%" stopColor="#FF4081"/>
169+
<stop offset="50%" stopColor="#9C27B0"/>
170+
<stop offset="100%" stopColor="#3F51B5"/>
171+
</linearGradient>
172+
</defs>
173+
<circle cx="50" cy="50" r="45" fill="url(#gravityGrad)" opacity="0.9"/>
174+
<path d="M30 30Q50 15 70 30Q70 50 70 70Q50 85 30 70Q30 50 30 30Z" fill="#FFF" opacity="0.9"/>
175+
<circle cx="50" cy="40" r="8" fill="url(#gravityGrad)"/>
176+
<path d="M40 55L50 65L60 55" stroke="url(#gravityGrad)" strokeWidth="3" fill="none" strokeLinecap="round"/>
177+
</svg>
178+
<span className="tooltip">Gravity Sketch - VR design and modeling tool for 3D creation</span>
179+
</div>
180+
</div>
181+
182+
<div className="flex justify-center items-center mt-14">
109183
<button
110184
className="btn btn--secondary"
111185
onClick={handleScrollToNext}
112186
>
113187
Scroll
114188
</button>
115189
</div>
190+
116191
</div>
117192
</section>
118193

src/components/MouseCameraController.jsx

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,67 @@
1-
import React, { useRef, useEffect, useState } from 'react'
2-
import { useFrame } from '@react-three/fiber'
3-
import { useMouseParallax } from '../utils/useInteractions'
1+
import React, { useRef, useEffect } from 'react'
2+
import { useFrame, useThree } from '@react-three/fiber'
43

54
const MouseCameraController = ({ children }) => {
65
const groupRef = useRef()
7-
const mousePosition = useMouseParallax(1.2) // Increased intensity for more responsiveness
8-
const [scrollY, setScrollY] = useState(0)
6+
const { camera } = useThree()
7+
const mouseRef = useRef({ x: 0, y: 0 })
8+
const scrollYRef = useRef(0)
9+
const targetRotation = useRef({ x: 0, y: 0 })
10+
const currentRotation = useRef({ x: 0, y: 0 })
911

10-
// Listen to scroll events
12+
// Mouse tracking
1113
useEffect(() => {
14+
const handleMouseMove = (event) => {
15+
mouseRef.current.x = (event.clientX / window.innerWidth) * 2 - 1
16+
mouseRef.current.y = -(event.clientY / window.innerHeight) * 2 + 1
17+
}
18+
19+
window.addEventListener('mousemove', handleMouseMove, { passive: true })
20+
return () => window.removeEventListener('mousemove', handleMouseMove)
21+
}, [])
22+
23+
// Scroll tracking
24+
useEffect(() => {
25+
let ticking = false
26+
1227
const handleScroll = () => {
13-
setScrollY(window.scrollY)
28+
if (!ticking) {
29+
requestAnimationFrame(() => {
30+
scrollYRef.current = window.scrollY
31+
ticking = false
32+
})
33+
ticking = true
34+
}
1435
}
1536

16-
window.addEventListener('scroll', handleScroll)
37+
window.addEventListener('scroll', handleScroll, { passive: true })
1738
return () => window.removeEventListener('scroll', handleScroll)
1839
}, [])
1940

2041
useFrame((state, delta) => {
21-
if (groupRef.current) {
22-
// Much more responsive mouse movement
23-
const targetX = mousePosition.x * 1.5 // Increased from 0.5 to 1.5
24-
const targetY = mousePosition.y * 0.8 // Increased from 0.3 to 0.8
42+
if (groupRef.current && camera) {
43+
const mouse = mouseRef.current
44+
const scrollInfluence = scrollYRef.current * 0.0002
45+
46+
// Calculate target rotations based on mouse position
47+
targetRotation.current.x = mouse.y * 0.3 // Vertical mouse movement
48+
targetRotation.current.y = mouse.x * 0.5 // Horizontal mouse movement
2549

26-
// Reduced scroll influence for focus on mouse control
27-
const scrollInfluence = scrollY * 0.0002 // Reduced from 0.0005
50+
// Smooth interpolation for camera panning
51+
const lerpSpeed = delta * 3
52+
currentRotation.current.x += (targetRotation.current.x - currentRotation.current.x) * lerpSpeed
53+
currentRotation.current.y += (targetRotation.current.y - currentRotation.current.y) * lerpSpeed
2854

29-
// Much faster, snappier interpolation
30-
groupRef.current.rotation.y += (targetX - groupRef.current.rotation.y + scrollInfluence) * delta * 8 // Increased from 1.5 to 8
31-
groupRef.current.rotation.x += (targetY - groupRef.current.rotation.x + scrollInfluence * 0.2) * delta * 8 // Increased from 1.5 to 8
55+
// Apply rotation to the group (which contains all 3D objects)
56+
groupRef.current.rotation.x = currentRotation.current.x + scrollInfluence * 0.1
57+
groupRef.current.rotation.y = currentRotation.current.y + scrollInfluence
3258

33-
// Minimal continuous rotation so mouse control is primary
34-
groupRef.current.rotation.y += delta * (0.01 - scrollInfluence * 0.005) // Reduced base rotation
59+
// Add gentle continuous rotation
60+
groupRef.current.rotation.y += delta * 0.008
3561

36-
// More responsive position shift
37-
groupRef.current.position.z = Math.sin(scrollInfluence) * 0.3 // Reduced from 0.5
62+
// Optional: Subtle camera position shift for additional parallax
63+
camera.position.x = mouse.x * 0.2
64+
camera.position.y = mouse.y * 0.1
3865
}
3966
})
4067

0 commit comments

Comments
 (0)