Spaces:
Sleeping
Sleeping
| /** | |
| * Global scroll progress, kept OUTSIDE React state so the R3F render loop can | |
| * read it every frame (via getScroll()) without triggering re-renders. Lenis | |
| * writes to it; the 3D scene and any rAF consumer read from it. | |
| */ | |
| export interface ScrollState { | |
| /** 0–1 progress across the entire page. */ | |
| progress: number | |
| /** Raw scroll offset in px. */ | |
| scrollY: number | |
| /** Total scrollable height in px. */ | |
| limit: number | |
| /** Viewport height in px. */ | |
| viewport: number | |
| } | |
| const state: ScrollState = { | |
| progress: 0, | |
| scrollY: 0, | |
| limit: 1, | |
| viewport: typeof window !== 'undefined' ? window.innerHeight : 1, | |
| } | |
| export function setScroll(scrollY: number, limit: number) { | |
| state.scrollY = scrollY | |
| state.limit = Math.max(1, limit) | |
| state.progress = Math.min(1, Math.max(0, scrollY / state.limit)) | |
| state.viewport = window.innerHeight | |
| } | |
| export function getScroll(): ScrollState { | |
| return state | |
| } | |
| /** | |
| * Progress (0–1) of a single section, given its index and the total number of | |
| * full-viewport sections. Lets the 3D scene know "how far through the hero / the | |
| * descent are we" independent of total page height. | |
| */ | |
| export function sectionProgress( | |
| sectionIndex: number, | |
| totalSections: number, | |
| ): number { | |
| const per = 1 / totalSections | |
| const start = sectionIndex * per | |
| const local = (state.progress - start) / per | |
| return Math.min(1, Math.max(0, local)) | |
| } | |