|
1 | | -import { lazy, Suspense, useState, useEffect, useRef } from 'react' |
| 1 | +import Hero from '../Hero/Hero.jsx' |
2 | 2 | import ScrollVelocity from '../ScrollVelocity/ScrollVelocity.jsx' |
3 | 3 | import ScrollReveal from '../ScrollReveal/ScrollReveal.jsx' |
4 | 4 | import ScrollStack, { ScrollStackItem } from '../ScrollStack/ScrollStack.jsx' |
5 | 5 | import LogoLoop from '../LogoLoop/LogoLoop.jsx' |
6 | 6 | import TrueFocus from '../TrueFocus/TrueFocus.jsx' |
| 7 | +import FlyingPostersSection from '../FlyingPosters/FlyingPostersSection.jsx' |
| 8 | +import FlowingMenu from '../FlowingMenu/FlowingMenu.jsx' |
| 9 | +import LensesShowcase from '../LensesShowcase/LensesShowcase.jsx' |
| 10 | +import ContactShowcase from '../ContactShowcase/ContactShowcase.jsx' |
7 | 11 | import ErrorBoundary from '../ErrorBoundary.jsx' |
8 | 12 |
|
9 | | -const Hero = lazy(() => import('../Hero/Hero.jsx')) |
10 | | -const FlyingPostersSection = lazy(() => import('../FlyingPosters/FlyingPostersSection.jsx')) |
11 | | -const FlowingMenu = lazy(() => import('../FlowingMenu/FlowingMenu.jsx')) |
12 | | -const LensesShowcase = lazy(() => import('../LensesShowcase/LensesShowcase.jsx')) |
13 | | -const ContactShowcase = lazy(() => import('../ContactShowcase/ContactShowcase.jsx')) |
14 | | - |
15 | 13 | // FlowingMenu images (specific photography picks from subfolders) |
16 | 14 | import parisImg from '/Photography/Paris/IMG_1598.jpg' |
17 | 15 | import chaoshanImg from '/Photography/Chaoshan/A395CF89-F602-44F6-97F0-747AD556F2C4_1_105_c.jpeg' |
@@ -95,39 +93,10 @@ const posterImages = Object.values( |
95 | 93 | import.meta.glob('/Photography/*.{jpeg,jpg,png}', { eager: true, query: '?url', import: 'default' }) |
96 | 94 | ) |
97 | 95 |
|
98 | | -// Defers mounting of heavy off-screen sections (Hyperspeed, ASCIIText, |
99 | | -// TextPressure, FluidGlass) until they approach the viewport. Without this, |
100 | | -// the Home page initializes ~6 WebGL contexts on load — most far below the |
101 | | -// fold — causing a large initial GPU/CPU spike. The wrapper stays in the |
102 | | -// document flow (0-height until mounted) so IntersectionObserver can fire; it |
103 | | -// grows once children mount, naturally re-triggering observers of sections |
104 | | -// below it. rootMargin '400px' mounts + renders content before the user sees |
105 | | -// it, avoiding visible layout shift. |
106 | | -function DeferredMount({ children, rootMargin = '400px' }) { |
107 | | - const [shouldMount, setShouldMount] = useState(false) |
108 | | - const ref = useRef(null) |
109 | | - useEffect(() => { |
110 | | - const el = ref.current |
111 | | - if (!el) return |
112 | | - if (typeof IntersectionObserver === 'undefined') { setShouldMount(true); return } |
113 | | - const io = new IntersectionObserver((entries) => { |
114 | | - if (entries[0].isIntersecting) { |
115 | | - setShouldMount(true) |
116 | | - io.disconnect() |
117 | | - } |
118 | | - }, { rootMargin }) |
119 | | - io.observe(el) |
120 | | - return () => io.disconnect() |
121 | | - }, [rootMargin]) |
122 | | - return <div ref={ref}>{shouldMount ? children : null}</div> |
123 | | -} |
124 | | - |
125 | 96 | export default function Home() { |
126 | 97 | return ( |
127 | 98 | <> |
128 | | - <Suspense fallback={<div className="hero hero-loading" aria-hidden="true" />}> |
129 | | - <Hero /> |
130 | | - </Suspense> |
| 99 | + <Hero /> |
131 | 100 | <section className="scroll-velocity-section" aria-label="Interests marquee"> |
132 | 101 | <ScrollVelocity |
133 | 102 | texts={[ |
@@ -288,33 +257,17 @@ export default function Home() { |
288 | 257 | /> |
289 | 258 | </section> |
290 | 259 |
|
291 | | - <DeferredMount rootMargin="600px"> |
292 | | - <Suspense fallback={null}> |
293 | | - <ErrorBoundary> |
294 | | - <FlyingPostersSection items={posterImages} /> |
295 | | - </ErrorBoundary> |
296 | | - </Suspense> |
297 | | - </DeferredMount> |
| 260 | + <ErrorBoundary> |
| 261 | + <FlyingPostersSection items={posterImages} /> |
| 262 | + </ErrorBoundary> |
298 | 263 |
|
299 | | - <DeferredMount rootMargin="600px"> |
300 | | - <Suspense fallback={<div style={{ height: '600px' }} aria-hidden="true" />}> |
301 | | - <div style={{ height: '600px', position: 'relative' }}> |
302 | | - <FlowingMenu items={flowingMenuItems} /> |
303 | | - </div> |
304 | | - </Suspense> |
305 | | - </DeferredMount> |
| 264 | + <div style={{ height: '600px', position: 'relative' }}> |
| 265 | + <FlowingMenu items={flowingMenuItems} /> |
| 266 | + </div> |
306 | 267 |
|
307 | | - <DeferredMount> |
308 | | - <Suspense fallback={null}> |
309 | | - <LensesShowcase /> |
310 | | - </Suspense> |
311 | | - </DeferredMount> |
| 268 | + <LensesShowcase /> |
312 | 269 |
|
313 | | - <DeferredMount> |
314 | | - <Suspense fallback={null}> |
315 | | - <ContactShowcase /> |
316 | | - </Suspense> |
317 | | - </DeferredMount> |
| 270 | + <ContactShowcase /> |
318 | 271 | </> |
319 | 272 | ) |
320 | 273 | } |
0 commit comments