Skip to content

Commit ad89c22

Browse files
authored
Emit LOD visibility event after GLB render (#15)
1 parent 08a516c commit ad89c22

File tree

1 file changed

+34
-1
lines changed

1 file changed

+34
-1
lines changed

frontend/src/app/components/viewer3d.tsx

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
'use client';
22

3-
import React, { Suspense, useMemo } from 'react';
3+
import React, { Suspense, useEffect, useMemo } from 'react';
44
import { Canvas } from '@react-three/fiber';
55
import { Environment, OrbitControls, useGLTF } from '@react-three/drei';
66

77
type Viewer3DProps = {
88
modelUrl: string;
99
};
1010

11+
declare global {
12+
interface Window {
13+
__lod0VisibleAt?: number;
14+
}
15+
}
16+
1117
function Model({ modelUrl }: { modelUrl: string }) {
1218
// Resolve absolute URL to avoid base path issues
1319
const src = useMemo(() => {
@@ -19,6 +25,33 @@ function Model({ modelUrl }: { modelUrl: string }) {
1925

2026
// Load GLB (no extra params to avoid signature mismatches)
2127
const gltf = useGLTF(src);
28+
29+
useEffect(() => {
30+
if (typeof window === 'undefined') {
31+
return undefined;
32+
}
33+
34+
if (!gltf?.scene) {
35+
return undefined;
36+
}
37+
38+
let cancelled = false;
39+
const rafId = window.requestAnimationFrame(() => {
40+
if (cancelled) {
41+
return;
42+
}
43+
44+
const ts = performance.now();
45+
window.__lod0VisibleAt = ts;
46+
window.dispatchEvent(new CustomEvent('lod0:visible', { detail: { ts } }));
47+
});
48+
49+
return () => {
50+
cancelled = true;
51+
window.cancelAnimationFrame(rafId);
52+
};
53+
}, [gltf?.scene, src]);
54+
2255
return <primitive object={gltf.scene} />;
2356
}
2457

0 commit comments

Comments
 (0)