I’m sorry I completely forgot to paste my code:
A bit about what happens: when the viewer scrolls, it triggers an animation based from the experience. All of that works, it’s just getting the viewer width to position the camera is driving me nutz.
——————————————-
import { Canvas, useThree } from “@react-three/fiber”;
import “./App.css”;
import Experience from “./components/Experience”;
import { Suspense, useState,useEffect } from “react”;
import { LoadingScreen } from “./components/LoadingScreen”;
import ‘./components/ButtonsOverlay.css’
function ResponsiveCamera() {
const { camera, viewport } = useThree();
const { getCurrentViewport } = useThree(state => state.viewport)
const { width, height } = getCurrentViewport()
useEffect(() => {
// Adjust camera position or other properties based on viewport dimensions
console.log('Viewport:', viewport.width);
if (viewport.width < 14.01) {
// Example: For smaller screens, move camera closer
camera.position.set(0, 0.5, 35);
camera.fov = 50;
}
else {
// Example: For larger screens, move camera further away
camera.position.set(0, 0.5, 20);
camera.fov = 50;
}
camera.updateProjectionMatrix();// Important to update after changing camera properties
console.log("camera x: "+camera.position.x +" y:" +camera.position.y +" z:"+ camera.position.z );
}, \[viewport.width, camera\],\[camera.position\]); // Re-run effect when viewport width changes
return null; // This component doesn't render anything visually
}
function App() {
const [activeButton, setActiveButton] = useState(null);
const [start, setStart] = useState(false); // ← bring this back
const [hasScrolled, setHasScrolled] = useState(false);
const handleScroll = (offset) => {
if (offset > 0.01 && !hasScrolled) setHasScrolled(true);
if (offset <= 0.01 && hasScrolled) setHasScrolled(false);
};
//
Map button labels to URLs
const buttonLinks = {
"Video Production": "https://your-site.com/contact/videoproduction/",
"Design": "https://your-site.com/contact/branding/",
"Social Campaigns": "https://your-site.com/social",
"Interactive": "https://your-site.com/interactive",
"Contact": "https://your-site.com/contact"
};
return (
<>
<LoadingScreen started={start} onStarted={() => setStart(true)} />
<div style={{ pointerEvents: 'none' }}>
<div className= "stage" style={{ minWidth: "300px", width: "100%", height: "100vh" }}>
<Canvas style={{ touchAction: 'pan-y'}} >
<ResponsiveCamera />
<Suspense fallback={null}>
<Experience onActiveButtonChange={setActiveButton}
onScrollChange={handleScroll} />
</Suspense>
</Canvas>
{/\* ✅ Pass state so loading screen button can hide itself \*/}
{/\* === HTML Overlay OUTSIDE the Canvas === \*/}
{!hasScrolled && <ScrollDownIndicator />}
{/\* Overlay outside Canvas \*/}
<div >
{activeButton && (
<button className= "homeBut"
onClick={() => {
const link = buttonLinks\[activeButton\];
if (link) {
window.open(link, "\_blank"); // new tab
}
}}
>
{activeButton}
</button>
)}
</div>
</div>
</>
);
}
function ScrollDownIndicator( ) {
return (
<div className= "scrollDown" >
↓ Scroll Down ↓
<style>
{\`
@keyframes scrollPulse {
0% { opacity: 0.4; transform: translateY(0); }
50% { opacity: 1; transform: translateY(-10px); }
100% { opacity: 0.4; transform: translateY(0); }
}
\`}
</style>
</div>
);
}
export default App;