From 79e9d151e70e4244744e28f5f64865796e22f684 Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 14 Aug 2026 09:54:27 +0200 Subject: [PATCH 1/3] feat: add per-object hide and show-all-objects Adds a "Hide" action for the currently selected object next to its backend-driven FUNCTIONS buttons, and a toolbar button to restore every object hidden this way. Hidden objects are also excluded from picking, since the raycast already only considers currently-visible geometry. Co-Authored-By: Claude Sonnet 5 --- src/components/layout/ObjectInfo.vue | 17 +++++++++-- src/components/tools/display/DisplayGroup.vue | 2 ++ .../tools/display/ShowAllObjectsButton.vue | 27 +++++++++++++++++ src/components/tools/display/index.ts | 1 + src/viewer/viewer_runtime.ts | 29 ++++++++++++++++++- src/viewer/viewer_store.ts | 2 ++ 6 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 src/components/tools/display/ShowAllObjectsButton.vue diff --git a/src/components/layout/ObjectInfo.vue b/src/components/layout/ObjectInfo.vue index d69a6cd..d55c957 100644 --- a/src/components/layout/ObjectInfo.vue +++ b/src/components/layout/ObjectInfo.vue @@ -33,6 +33,12 @@ > FUNCTIONS +
+ +
runtime.handleObjectAction({ ...action }, value); const infoPanel = ref(null); +function handleHide() { + if (!selectedObjectGuid.value) return; + runtime.hideObjectByGuid(selectedObjectGuid.value); + runtime.deselectObject(); +} + const { isHovered } = useHover(infoPanel); watchEffect(() => { diff --git a/src/components/tools/display/DisplayGroup.vue b/src/components/tools/display/DisplayGroup.vue index 5182d46..e38797d 100644 --- a/src/components/tools/display/DisplayGroup.vue +++ b/src/components/tools/display/DisplayGroup.vue @@ -12,6 +12,7 @@ @delete="deleteSavedView" /> +
@@ -25,6 +26,7 @@ import { SaveViewButton, SavedViewsButton, SaveScreenshotButton, + ShowAllObjectsButton, } from "./index"; const SAVED_VIEWS_STORAGE_KEY = "compas_threejs_saved_views"; diff --git a/src/components/tools/display/ShowAllObjectsButton.vue b/src/components/tools/display/ShowAllObjectsButton.vue new file mode 100644 index 0000000..8212306 --- /dev/null +++ b/src/components/tools/display/ShowAllObjectsButton.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/components/tools/display/index.ts b/src/components/tools/display/index.ts index b8a1e4c..d1299f5 100644 --- a/src/components/tools/display/index.ts +++ b/src/components/tools/display/index.ts @@ -1,3 +1,4 @@ export { default as SaveViewButton } from "./SaveViewButton.vue"; export { default as SavedViewsButton } from "./SavedViewsButton.vue"; export { default as SaveScreenshotButton } from "./SaveScreenshotButton.vue"; +export { default as ShowAllObjectsButton } from "./ShowAllObjectsButton.vue"; diff --git a/src/viewer/viewer_runtime.ts b/src/viewer/viewer_runtime.ts index b62e953..4a7b736 100644 --- a/src/viewer/viewer_runtime.ts +++ b/src/viewer/viewer_runtime.ts @@ -122,6 +122,7 @@ export class ViewerRuntime { private disposed = false; private pickedObject: THREE.Object3D | null = null; private pickedMaterial: THREE.Material | THREE.Material[] | null = null; + private readonly hiddenGuids = new Set(); private readonly highlightMaterial = new THREE.MeshStandardMaterial({ color: "orange", emissive: "yellow", @@ -275,6 +276,25 @@ export class ViewerRuntime { this.store.objectBarData.isVisible = false; } + hideObjectByGuid(guid: string): void { + const object = this.geometries.get(guid); + if (!object) return; + object.visible = false; + this.hiddenGuids.add(guid); + } + + showAllObjects(): void { + for (const guid of this.hiddenGuids) { + const object = this.geometries.get(guid); + if (object) object.visible = true; + } + this.hiddenGuids.clear(); + } + + deselectObject(): void { + this.clearPickedObject(); + } + setTransformMode(mode: "translate" | "rotate" | "scale"): void { this.store.pickerMode.value = mode; this.transformControls.setMode(mode); @@ -356,6 +376,7 @@ export class ViewerRuntime { this.disposeObject(object); } this.geometries.clear(); + this.hiddenGuids.clear(); this.clearLights(); for (const entry of this.materials.values()) entry.material.dispose(); this.materials.clear(); @@ -687,7 +708,10 @@ export class ViewerRuntime { } this.transformControls.attach(picked); const guid = this.findGeometryGuid(picked); - if (guid) this.sendData({ dispatch: "object_picked", guid }); + if (guid) { + this.store.selectedObjectGuid.value = guid; + this.sendData({ dispatch: "object_picked", guid }); + } } private clearPickedObject(): void { @@ -703,6 +727,7 @@ export class ViewerRuntime { this.transformControls.detach(); this.store.objectBarData.data = null; this.store.objectActionsState.splice(0); + this.store.selectedObjectGuid.value = null; } private findGeometryGuid(object: THREE.Object3D): string | undefined { @@ -803,6 +828,7 @@ export class ViewerRuntime { this.disposeObject(object); this.geometries.delete(guid); this.geometryMaterials.delete(guid); + this.hiddenGuids.delete(guid); } else if (data.type === "set_visibility") { object.visible = data.visible; } else if (data.type === "toggle_visibility") { @@ -1011,6 +1037,7 @@ export class ViewerRuntime { private resetAfterDispose(): void { for (const object of this.geometries.values()) this.disposeObject(object); this.geometries.clear(); + this.hiddenGuids.clear(); this.clearLights(); for (const entry of this.materials.values()) entry.material.dispose(); this.materials.clear(); diff --git a/src/viewer/viewer_store.ts b/src/viewer/viewer_store.ts index 26e0ea7..bd1384d 100644 --- a/src/viewer/viewer_store.ts +++ b/src/viewer/viewer_store.ts @@ -85,6 +85,7 @@ export interface ViewerStore { blockPicker: { value: boolean }; showEdges: { value: boolean }; theme: { value: "light" | "dark" }; + selectedObjectGuid: { value: string | null }; } export function createViewerStore(): ViewerStore { @@ -106,5 +107,6 @@ export function createViewerStore(): ViewerStore { blockPicker: reactive({ value: false }), showEdges: reactive({ value: false }), theme: reactive({ value: "light" as const }), + selectedObjectGuid: reactive({ value: null as string | null }), }; } From da1f34deab5d415e1abb7a6c6c074889fd78244e Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 14 Aug 2026 15:16:30 +0200 Subject: [PATCH 2/3] docs: note per-object hide/show-all in the changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0940f0..de8de83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog + +## Unreleased + +### Added + +- Added per-object hide and a show-all-objects control. + ## [1.0.1](https://github.com/compas-dev/compas_threejs_ts/compare/v1.0.0...v1.0.1) (2026-08-13) ### Bug Fixes From 6fc94a88b4161ff314d3445acadf47fecd7d569c Mon Sep 17 00:00:00 2001 From: Eric Date: Fri, 14 Aug 2026 15:28:22 +0200 Subject: [PATCH 3/3] prettier --- src/components/layout/ObjectInfo.vue | 9 +++++++-- .../tools/display/ShowAllObjectsButton.vue | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/components/layout/ObjectInfo.vue b/src/components/layout/ObjectInfo.vue index d55c957..4a076f6 100644 --- a/src/components/layout/ObjectInfo.vue +++ b/src/components/layout/ObjectInfo.vue @@ -121,8 +121,13 @@ import { useViewerRuntime } from "@/viewer/viewer_context"; import type { ObjectAction } from "@/viewer/viewer_store"; const runtime = useViewerRuntime(); -const { objectActionsState, objectBarData, blockPicker, theme, selectedObjectGuid } = - runtime.store; +const { + objectActionsState, + objectBarData, + blockPicker, + theme, + selectedObjectGuid, +} = runtime.store; const handleObjectAction = (action: ObjectAction, value?: unknown) => runtime.handleObjectAction({ ...action }, value); const infoPanel = ref(null); diff --git a/src/components/tools/display/ShowAllObjectsButton.vue b/src/components/tools/display/ShowAllObjectsButton.vue index 8212306..8e7ab87 100644 --- a/src/components/tools/display/ShowAllObjectsButton.vue +++ b/src/components/tools/display/ShowAllObjectsButton.vue @@ -2,7 +2,12 @@ - @@ -16,7 +21,12 @@