@@ -76,21 +76,27 @@ export const StatusBar: React.FC<IStatusBarProps> = ({
7676 const [ isMobile , setIsMobile ] = React . useState ( false ) ;
7777 const selectedIds = useEditorStore ( ( state ) => state . selectedIds ) ;
7878
79+ // Detect if mobile (only once on mount)
7980 React . useEffect ( ( ) => {
80- // Detect if mobile
8181 const checkMobile = / A n d r o i d | w e b O S | i P h o n e | i P a d | i P o d | B l a c k B e r r y | I E M o b i l e | O p e r a M i n i / i. test (
8282 navigator . userAgent ,
8383 ) ;
8484 setIsMobile ( checkMobile ) ;
85+ } , [ ] ) ;
8586
87+ // Triangle counting with startup delay (only once on mount)
88+ React . useEffect ( ( ) => {
8689 const countTriangles = ( ) => {
8790 try {
8891 const scene = ( window as any ) . __r3fScene ;
8992 if ( ! scene ) return { total : 0 , selected : 0 } ;
9093
9194 let totalCount = 0 ;
9295 let selectedCount = 0 ;
93- const selectedIdsSet = new Set ( selectedIds ) ;
96+
97+ // Get latest selectedIds from store
98+ const currentSelectedIds = useEditorStore . getState ( ) . selectedIds ;
99+ const selectedIdsSet = new Set ( currentSelectedIds ) ;
94100
95101 scene . traverse ( ( obj : any ) => {
96102 if ( obj . geometry ) {
@@ -106,7 +112,17 @@ export const StatusBar: React.FC<IStatusBarProps> = ({
106112 totalCount += triangles ;
107113
108114 // Count triangles for selected entities
109- if ( obj . userData ?. entityId && selectedIdsSet . has ( obj . userData . entityId ) ) {
115+ // Check this object and traverse up parent hierarchy for entityId
116+ let entityId = obj . userData ?. entityId ;
117+ if ( ! entityId ) {
118+ let parent = obj . parent ;
119+ while ( parent && ! entityId ) {
120+ entityId = parent . userData ?. entityId ;
121+ parent = parent . parent ;
122+ }
123+ }
124+
125+ if ( entityId && selectedIdsSet . has ( entityId ) ) {
110126 selectedCount += triangles ;
111127 }
112128 }
@@ -118,14 +134,29 @@ export const StatusBar: React.FC<IStatusBarProps> = ({
118134 }
119135 } ;
120136
121- const interval = setInterval ( ( ) => {
137+ // Wait 500ms for initial geometry to stabilize (terrain async loading, etc.)
138+ const startupDelay = setTimeout ( ( ) => {
139+ // Do initial count
122140 const { total, selected } = countTriangles ( ) ;
123141 setTriangleCount ( total ) ;
124142 setSelectedTriangleCount ( selected ) ;
125- } , 1000 ) ;
126143
127- return ( ) => clearInterval ( interval ) ;
128- } , [ selectedIds ] ) ;
144+ // Then start interval - reads latest selectedIds on each tick
145+ const interval = setInterval ( ( ) => {
146+ const { total, selected } = countTriangles ( ) ;
147+ setTriangleCount ( total ) ;
148+ setSelectedTriangleCount ( selected ) ;
149+ } , 1000 ) ;
150+
151+ // Cleanup function returned from timeout
152+ return ( ) => clearInterval ( interval ) ;
153+ } , 500 ) ;
154+
155+ // Cleanup: clear the timeout and its returned interval cleanup
156+ return ( ) => {
157+ clearTimeout ( startupDelay ) ;
158+ } ;
159+ } , [ ] ) ; // Only run once on mount
129160
130161 // Calculate budget status
131162 const mobileBudget = 500000 ; // 500k triangles for mobile
0 commit comments