Fix scan/guide visibility with per-project preferences

- Store showScans/showGuides preferences per project so toggling
  persists when switching between projects
- Apply showGuides/showScans directly on guide and scan renderer groups
- Set projectId in both editor and viewer pages on mount

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Aymeric Rabot
2026-02-27 01:38:10 -05:00
co-authored by Claude Opus 4.6
parent d0e0fe7e1e
commit 31c09bacdd
5 changed files with 58 additions and 5 deletions
+4
View File
@@ -28,6 +28,10 @@ export default function ViewerPage() {
const [canShowGuides, setCanShowGuides] = useState(true) const [canShowGuides, setCanShowGuides] = useState(true)
const setScene = useScene((state) => state.setScene) const setScene = useScene((state) => state.setScene)
useEffect(() => {
useViewer.getState().setProjectId(projectId)
}, [projectId])
useEffect(() => { useEffect(() => {
const loadContent = async () => { const loadContent = async () => {
try { try {
+8
View File
@@ -71,6 +71,14 @@ export default function Editor({ projectId }: EditorProps) {
const isSceneLoading = useProjectStore((state) => state.isSceneLoading) const isSceneLoading = useProjectStore((state) => state.isSceneLoading)
const isLoading = isProjectLoading || isSceneLoading const isLoading = isProjectLoading || isSceneLoading
useEffect(() => {
if (projectId) {
useViewer.getState().setProjectId(projectId)
} else {
useViewer.getState().setProjectId(null)
}
}, [projectId])
useEffect(() => { useEffect(() => {
document.body.classList.add('dark') document.body.classList.add('dark')
return () => { return () => {
@@ -5,15 +5,17 @@ import { DoubleSide, type Group, type Texture, TextureLoader } from 'three'
import { float, texture } from 'three/tsl' import { float, texture } from 'three/tsl'
import { MeshBasicNodeMaterial } from 'three/webgpu' import { MeshBasicNodeMaterial } from 'three/webgpu'
import { useAssetUrl } from '../../../hooks/use-asset-url' import { useAssetUrl } from '../../../hooks/use-asset-url'
import useViewer from '../../../store/use-viewer'
export const GuideRenderer = ({ node }: { node: GuideNode }) => { export const GuideRenderer = ({ node }: { node: GuideNode }) => {
const showGuides = useViewer((s) => s.showGuides)
const ref = useRef<Group>(null!) const ref = useRef<Group>(null!)
useRegistry(node.id, 'guide', ref) useRegistry(node.id, 'guide', ref)
const resolvedUrl = useAssetUrl(node.url) const resolvedUrl = useAssetUrl(node.url)
return ( return (
<group ref={ref} position={node.position} rotation={[0, node.rotation[1], 0]}> <group ref={ref} visible={showGuides} position={node.position} rotation={[0, node.rotation[1], 0]}>
{resolvedUrl && ( {resolvedUrl && (
<Suspense> <Suspense>
<GuidePlane url={resolvedUrl} scale={node.scale} opacity={node.opacity} /> <GuidePlane url={resolvedUrl} scale={node.scale} opacity={node.opacity} />
@@ -3,8 +3,10 @@ import { Suspense, useMemo, useRef } from 'react'
import type { Group, Material, Mesh } from 'three' import type { Group, Material, Mesh } from 'three'
import { useAssetUrl } from '../../../hooks/use-asset-url' import { useAssetUrl } from '../../../hooks/use-asset-url'
import { useGLTFKTX2 } from '../../../hooks/use-gltf-ktx2' import { useGLTFKTX2 } from '../../../hooks/use-gltf-ktx2'
import useViewer from '../../../store/use-viewer'
export const ScanRenderer = ({ node }: { node: ScanNode }) => { export const ScanRenderer = ({ node }: { node: ScanNode }) => {
const showScans = useViewer((s) => s.showScans)
const ref = useRef<Group>(null!) const ref = useRef<Group>(null!)
useRegistry(node.id, 'scan', ref) useRegistry(node.id, 'scan', ref)
@@ -13,6 +15,7 @@ export const ScanRenderer = ({ node }: { node: ScanNode }) => {
return ( return (
<group <group
ref={ref} ref={ref}
visible={showScans}
position={node.position} position={node.position}
rotation={node.rotation} rotation={node.rotation}
scale={[node.scale, node.scale, node.scale]} scale={[node.scale, node.scale, node.scale]}
+40 -4
View File
@@ -47,6 +47,10 @@ type ViewerState = {
showGuides: boolean showGuides: boolean
setShowGuides: (show: boolean) => void setShowGuides: (show: boolean) => void
projectId: string | null
setProjectId: (id: string | null) => void
projectPreferences: Record<string, { showScans?: boolean, showGuides?: boolean }>
// Smart selection update // Smart selection update
setSelection: (updates: Partial<SelectionPath>) => void setSelection: (updates: Partial<SelectionPath>) => void
resetSelection: () => void resetSelection: () => void
@@ -80,10 +84,43 @@ const useViewer = create<ViewerState>()(
setWallMode: (mode) => set({ wallMode: mode }), setWallMode: (mode) => set({ wallMode: mode }),
showScans: true, showScans: true,
setShowScans: (show) => set({ showScans: show }), setShowScans: (show) =>
set((state) => {
const projectPreferences = { ...(state.projectPreferences || {}) };
if (state.projectId) {
projectPreferences[state.projectId] = {
...(projectPreferences[state.projectId] || {}),
showScans: show,
};
}
return { showScans: show, projectPreferences };
}),
showGuides: true, showGuides: true,
setShowGuides: (show) => set({ showGuides: show }), setShowGuides: (show) =>
set((state) => {
const projectPreferences = { ...(state.projectPreferences || {}) };
if (state.projectId) {
projectPreferences[state.projectId] = {
...(projectPreferences[state.projectId] || {}),
showGuides: show,
};
}
return { showGuides: show, projectPreferences };
}),
projectId: null,
setProjectId: (id) =>
set((state) => {
if (!id) return { projectId: id };
const prefs = state.projectPreferences?.[id] || {};
return {
projectId: id,
showScans: prefs.showScans ?? true,
showGuides: prefs.showGuides ?? true,
};
}),
projectPreferences: {},
setSelection: (updates) => setSelection: (updates) =>
set((state) => { set((state) => {
@@ -130,8 +167,7 @@ const useViewer = create<ViewerState>()(
cameraMode: state.cameraMode, cameraMode: state.cameraMode,
levelMode: state.levelMode, levelMode: state.levelMode,
wallMode: state.wallMode, wallMode: state.wallMode,
showScans: state.showScans, projectPreferences: state.projectPreferences,
showGuides: state.showGuides,
}), }),
}, },
), ),