Skip to content

Conversation

@PythonFZ
Copy link
Member

@PythonFZ PythonFZ commented Jan 18, 2026

  • Create usePathtracingMesh hook to encapsulate pathtracing mesh conversion logic, eliminating ~40 lines of duplicate code from 6 geometry components
  • Refactor Particles, Bonds, Arrow, Box, Plane, Shape to use the new hook
  • Fix type error in Bonds.tsx (hoverMeshRef was Mesh instead of InstancedMesh)
  • Optimize Zustand store access by using individual selectors instead of object destructuring to prevent unnecessary re-renders
  • Improve convertInstancedMesh utility with better bounding box computation

Summary by CodeRabbit

  • Performance

    • Faster geometry merging and more efficient pathtracing mesh updates for smoother frame rates.
    • More granular state subscriptions to reduce unnecessary re-renders.
  • Bug Fixes

    • More consistent behavior when pathtracing is enabled — visuals route or hide appropriately and cleanup is improved.
    • Reduced spurious update calls by batching pathtracer updates to the render loop.
  • Refactor

    • Rendering plumbing and pathtracing integration reworked for more stable updates and lifecycle handling.

✏️ Tip: You can customize this high-level summary in your review settings.

PythonFZ and others added 2 commits January 18, 2026 23:39
- Create usePathtracingMesh hook to encapsulate pathtracing mesh conversion
  logic, eliminating ~40 lines of duplicate code from 6 geometry components
- Refactor Particles, Bonds, Arrow, Box, Plane, Shape to use the new hook
- Fix type error in Bonds.tsx (hoverMeshRef was Mesh instead of InstancedMesh)
- Optimize Zustand store access by using individual selectors instead of
  object destructuring to prevent unnecessary re-renders
- Improve convertInstancedMesh utility with better bounding box computation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 18, 2026

📝 Walkthrough

Walkthrough

Refactors pathtracing merged-mesh workflow into a new hook, reorganizes Canvas component categories (adds data+pathtracing and data-only sets, moves Curve/Cell/Floor), adds pathtracing guards and memoization to geometry components, replaces bulk store destructurings with per-property selectors, and defers pathtracer.update to useFrame.

Changes

Cohort / File(s) Summary
Pathtracing hook & mesh util
app/src/hooks/usePathtracingMesh.ts, app/src/utils/convertInstancedMesh.ts
New usePathtracingMesh(parentGroupRef, mainMeshRef, pathtracingEnabled) that returns updateMergedMesh(geometry) to imperatively create/dispose merged meshes and trigger pathtracing updates; convertInstancedMeshToMerged rewritten to single-pass merge and added disposeMesh.
Canvas routing & component maps
app/src/components/Canvas.tsx
Introduced DATA_PATHTRACING_GEOMETRY_COMPONENTS and DATA_ONLY_GEOMETRY_COMPONENTS; moved Curve to pathtracing set, Cell to data+pathtracing, Floor to data-only; rendering order adjusted to pathtracing, data+pathtracing, then data-only.
Geometry components — hook integration
app/src/components/three/* (e.g. Arrow.tsx, Bonds.tsx, Box.tsx, Particles.tsx, Plane.tsx, Shape.tsx)
Replaced prior instanced→merged JSX lifecycle with usePathtracingMesh + parentGroupRef; compute fullData via useMemo; call updateMergedMesh when pathtracingEnabled; removed inline merged-mesh JSX branches and related disposal effects.
Geometry components — pathtracing guards & API
app/src/components/three/Cell.tsx, app/src/components/three/Curve.tsx, app/src/components/three/Box.tsx, Plane.tsx
Added optional pathtracingEnabled?: boolean prop (default false) where applicable and guards that hide unsupported Line-based components when pathtracing is active; included prop in effect dependencies.
Pathtracing update scheduling
app/src/components/PathtracingUpdater.tsx
Deferred pathtracer.update() by batching updates via a pendingUpdate flag and running updates inside useFrame instead of invoking immediately from effects.
Store access refactor — components
app/src/components/ProgressBar.tsx, SelectionGroupsPanel.tsx, HoverInfoBox.tsx, KeyboardShortcutsHandler.tsx, MultiGeometryTransformControls.tsx, StaticInfoBox.tsx, Camera.tsx
Replaced bulk useAppStore() destructuring with multiple per-property useAppStore(state => state.x) selectors to narrow subscriptions.
Store access refactor — hooks & managers
app/src/hooks/*, app/src/hooks/useRestManager.ts, app/src/hooks/useSocketManager.ts
Same selector-granularity refactor across hooks/managers (e.g., useFrameEditing, useGeometryEditing, useKeyboardShortcuts, useRestManager, useSocketManager).
Misc. component API & memoization
app/src/components/three/* (Cell/Curve/Box/...)
Added memoization for fullData via useMemo, moved some components to accept pathtracingEnabled prop, and updated effect dependencies accordingly.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Component as Geometry Component
participant Hook as usePathtracingMesh
participant Convert as convertInstancedMeshToMerged
participant Group as ParentGroup
participant Pathtracer as Pathtracer

Component->>Hook: call usePathtracingMesh(parentGroupRef, mainMeshRef, pathtracingEnabled)
Note right of Hook: returns updateMergedMesh(geometry)
Component->>Hook: updateMergedMesh(geometry) when mesh updated && pathtracingEnabled
Hook->>Convert: convert instanced mesh using supplied geometry
Convert-->>Hook: merged THREE.Mesh
Hook->>Group: attach merged mesh (imperative)
Hook->>Pathtracer: requestPathtracingUpdate()
Pathtracer-->>Component: pathtracer.update() (deferred via pending flag / useFrame)

style Component fill:rgba(99,102,241,0.5)
style Hook fill:rgba(16,185,129,0.5)
style Convert fill:rgba(239,68,68,0.5)
style Group fill:rgba(234,179,8,0.5)
style Pathtracer fill:rgba(14,165,233,0.5)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • refactor: apply React best practices to Canvas and App #862: Modifies Canvas.tsx geometry component maps; directly related to the Canvas category and render-order changes in this PR.
  • dev #803: Alters multiple geometry components and their pathtracing handling (Curve, Cell, Box/Plane/Shape) and hooks like usePathtracingMesh; closely related at code level.

Poem

🐰 I hop through scenes and stitch each mesh,

Hooks weave merges, tidy and fresh,
Selectors sliced, updates delayed,
Curves hide while pathtracing's played,
A rabbit’s refactor—swiftly sketched!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: extract usePathtracingMesh hook and optimize Zustand selectors' directly reflects the two main refactoring objectives of the PR: extracting a new hook and optimizing store access patterns.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app/src/utils/convertInstancedMesh.ts`:
- Around line 51-67: The merged index buffer currently chooses Uint16Array vs
Uint32Array based only on baseIndices.array type; change the logic in
convertInstancedMesh (around variables baseIndexCount/totalVertexCount and
mergedIndices) to also promote to Uint32Array when totalVertexCount > 65535 (or
totalVertexCount + base vertex offset could exceed 65535) so indices won't
overflow; ensure the condition checks (baseIndices?.array instanceof
Uint32Array) || totalVertexCount > 65535 and use Uint32Array in that case,
otherwise use Uint16Array, keeping mergedIndices creation consistent with
existing baseIndices handling.
🧹 Nitpick comments (8)
app/src/components/three/MultiGeometryTransformControls.tsx (1)

129-131: The eslint-disable is justified, but consider a more targeted disable.

The comment correctly explains that showSnackbar and updateSelectionForGeometry are stable Zustand actions. However, a more targeted disable would be clearer:

-		// Note: showSnackbar and updateSelectionForGeometry are stable Zustand actions, omit from deps
-		// eslint-disable-next-line react-hooks/exhaustive-deps
-	}, [mode, geometries, selections, loadedPositionsMap]);
+	}, [
+		mode,
+		geometries,
+		selections,
+		loadedPositionsMap,
+		// showSnackbar and updateSelectionForGeometry are stable Zustand actions
+		// eslint-disable-next-line react-hooks/exhaustive-deps
+	]);

Alternatively, you could include them in the dependency array since they're stable anyway—it would satisfy the linter without causing additional re-renders.

app/src/hooks/useSocketManager.ts (1)

873-904: Dependency array is correct but extensive.

All setters listed are stable Zustand references, so this large dependency array won't trigger spurious re-runs. However, consider extracting the socket event handlers into a custom hook or grouping related setters if this file grows further to improve maintainability.

app/src/components/three/Plane.tsx (1)

509-513: Consider adding updateMergedMesh to the dependency array.

While updateMergedMesh is a useCallback-memoized function, the ESLint react-hooks/exhaustive-deps rule typically expects all referenced functions to be included in the dependency array for correctness. Since it's stable, adding it won't cause extra re-runs but ensures compliance with React best practices.

♻️ Suggested change
 	], [
 		frameCount, // Watch frameCount to clear planes when it becomes 0
 		isFetching,
 		hasQueryError,
 		positionData,
 		sizeData,
 		colorData,
 		rotationData,
 		scaleData, // Add scaleData
 		positionProp,
 		sizeProp,
 		colorProp,
 		rotationProp,
 		scale, // Add scale
 		instanceCount,
 		validSelectedIndices,
 		selecting,
 		geometryKey,
 		pathtracingEnabled,
 		material,
 		opacity,
 		data,
+		updateMergedMesh,
 	]);
app/src/components/three/Box.tsx (1)

505-509: Same optional suggestion: consider adding updateMergedMesh to dependencies.

For consistency and React lint compliance, consider adding updateMergedMesh to the dependency array as noted in Plane.tsx.

app/src/components/three/Shape.tsx (1)

456-459: Same optional suggestion: consider adding updateMergedMesh to dependencies.

app/src/components/three/Bonds.tsx (1)

655-661: Same optional suggestion: consider adding updateMergedMesh to dependencies.

For consistency with React hooks best practices, consider adding updateMergedMesh to the dependency array.

app/src/components/three/Particles.tsx (1)

685-709: Dependency array includes unused variables.

The dependencies particleResolution, material, opacity, and data are added but none of these are directly used within the effect body. The effect processes data through fullData (already in scope via destructuring), not these raw props.

  • particleResolution → derived from fullData.resolution (line 179)
  • material, opacity → destructured from fullData (lines 113-119)
  • data → already covered by fullData which is memoized with data as dependency

If the intent is to re-trigger the effect when these change for pathtracing mesh updates, fullData should be added as a dependency instead, or document why these specific raw props are needed.

Consider this adjustment
 	], [
 		frameCount, // Watch frameCount to clear particles when it becomes 0
 		isFetching,
 		hasQueryError,
 		positionData,
 		colorData,
 		radiusData,
 		scaleData,
 		transformData,
 		positionProp,
 		colorProp,
 		radiusProp,
 		scale,
 		positionIsTransform,
 		radiusIsTransform,
 		colorIsTransform,
 		instanceCount,
 		validSelectedIndices,
 		selecting,
 		pathtracingEnabled,
-		particleResolution,
-		material,
-		opacity,
-		data,
+		updateMergedMesh,
+		setInstanceCount,
+		setParticleCount,
 	]);
app/src/components/three/Arrow.tsx (1)

496-518: Same dependency array concern as Particles.tsx.

The dependencies resolution, material, opacity, and data are added but not directly used in the effect body:

  • resolution → used via geometry which is memoized separately (line 555)
  • material, opacity → used in JSX render, not in this effect
  • data → already covered by destructured props from fullData

If these are intended to trigger pathtracing mesh rebuilds when visual properties change, consider adding updateMergedMesh to dependencies instead for clarity, or document the intent.

Consider this adjustment
 	], [
 		frameCount, // Watch frameCount to clear arrows when it becomes 0
 		isFetching,
 		positionData,
 		directionData,
 		colorData,
 		radiusData,
 		scaleData,
 		positionProp,
 		directionProp,
 		color,
 		radius,
 		scale,
 		instanceCount,
 		validSelectedIndices,
 		selecting,
 		geometryKey,
 		pathtracingEnabled,
-		resolution,
-		material,
-		opacity,
-		data,
+		updateMergedMesh,
+		setInstanceCount,
 	]);

@PythonFZ
Copy link
Member Author

Issue with BMIM FILE that with resolution larger 10, BF4 is not rendered. Changing resolution requires step update?

@codecov-commenter
Copy link

codecov-commenter commented Jan 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79.78%. Comparing base (f237fba) to head (e5c4545).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #865      +/-   ##
==========================================
- Coverage   79.81%   79.78%   -0.03%     
==========================================
  Files         165      165              
  Lines       20213    20213              
==========================================
- Hits        16133    16127       -6     
- Misses       4080     4086       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

PythonFZ and others added 3 commits January 19, 2026 08:38
- Add updateMergedMesh to useEffect dependencies in all geometry components
- Memoize fullData in Cell.tsx for consistency with other components
- Remove unused BufferGeometryUtils import from convertInstancedMesh.ts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@app/src/utils/convertInstancedMesh.ts`:
- Around line 111-124: The current code in convertInstancedMesh.ts transforms
normals using only the rotation part of the instance matrix (e/e[0..10]) which
breaks for non-uniform scale; replace that with an inverse-transpose normal
matrix: compute a Matrix3 normalMatrix from the instance Matrix4 (use
Matrix3.getNormalMatrix(instanceMatrix) or equivalent), apply that normalMatrix
to the base normal (nx,ny,nz) to get the transformed normal, then renormalize
the resulting vector before writing into mergedNormals[targetIdx..+2]; update
the code paths that reference mergedNormals, baseNormals and targetIdx to use
this normal-matrix + normalize flow.

@PythonFZ PythonFZ merged commit 731ce39 into main Jan 19, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants