-
Notifications
You must be signed in to change notification settings - Fork 0
Emit LOD visibility event after GLB render #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,19 @@ | ||
| 'use client'; | ||
|
|
||
| import React, { Suspense, useMemo } from 'react'; | ||
| import React, { Suspense, useEffect, useMemo } from 'react'; | ||
| import { Canvas } from '@react-three/fiber'; | ||
| import { Environment, OrbitControls, useGLTF } from '@react-three/drei'; | ||
|
|
||
| type Viewer3DProps = { | ||
| modelUrl: string; | ||
| }; | ||
|
|
||
| declare global { | ||
| interface Window { | ||
| __lod0VisibleAt?: number; | ||
| } | ||
| } | ||
|
|
||
| function Model({ modelUrl }: { modelUrl: string }) { | ||
| // Resolve absolute URL to avoid base path issues | ||
| const src = useMemo(() => { | ||
|
|
@@ -19,6 +25,33 @@ function Model({ modelUrl }: { modelUrl: string }) { | |
|
|
||
| // Load GLB (no extra params to avoid signature mismatches) | ||
| const gltf = useGLTF(src); | ||
|
|
||
| useEffect(() => { | ||
| if (typeof window === 'undefined') { | ||
| return undefined; | ||
| } | ||
|
|
||
| if (!gltf?.scene) { | ||
| return undefined; | ||
| } | ||
|
|
||
| let cancelled = false; | ||
| const rafId = window.requestAnimationFrame(() => { | ||
| if (cancelled) { | ||
| return; | ||
| } | ||
|
|
||
| const ts = performance.now(); | ||
| window.__lod0VisibleAt = ts; | ||
| window.dispatchEvent(new CustomEvent('lod0:visible', { detail: { ts } })); | ||
|
Comment on lines
+39
to
+46
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major 🧩 Analysis chainVerify: The RAF callback runs before the next paint, not after the frame is painted to the screen. This means If the goal is to track when LOD0 is truly visible (painted), consider these options:
To confirm the timing behavior, you can test with this approach: // Nested RAF ensures one paint cycle
const rafId = window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
if (cancelled) return;
const ts = performance.now();
window.__lod0VisibleAt = ts;
window.dispatchEvent(new CustomEvent('lod0:visible', { detail: { ts } }));
});
});🏁 Script executed: #!/bin/bash
# Display the first 200 lines of viewer3d.tsx to inspect the useEffect implementation
sed -n '1,200p' frontend/src/app/components/viewer3d.tsxLength of output: 1767 Ensure visibility timestamp after paint const rafId = window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => {
if (cancelled) return;
const ts = performance.now();
window.__lod0VisibleAt = ts;
window.dispatchEvent(new CustomEvent('lod0:visible', { detail: { ts } }));
});
});🤖 Prompt for AI Agents
Comment on lines
+44
to
+46
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial 🧩 Analysis chainMultiple Model instances will overwrite If multiple Consider one of these approaches:
🏁 Script executed: #!/bin/bash
echo "Occurrences of __lod0VisibleAt:"
rg -n "__lod0VisibleAt"
echo -e "\nOccurrences of 'lod0:visible':"
rg -n "lod0:visible"Length of output: 341 🏁 Script executed: sed -n '1,30p' frontend/src/app/components/viewer3d.tsxLength of output: 758 Avoid overwriting a single global timestamp across multiple If more than one
🤖 Prompt for AI Agents |
||
| }); | ||
|
|
||
| return () => { | ||
| cancelled = true; | ||
| window.cancelAnimationFrame(rafId); | ||
| }; | ||
| }, [gltf?.scene, src]); | ||
|
|
||
| return <primitive object={gltf.scene} />; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider moving global augmentation to a dedicated types file.
While the Window interface augmentation is functionally correct, global type declarations are conventionally placed in dedicated type definition files (e.g.,
globals.d.tsorwindow.d.ts) rather than component files. This improves maintainability and separates type definitions from component logic.🤖 Prompt for AI Agents