From b1bb6eab5e8768ceec67f3b11a637564da2bf86d Mon Sep 17 00:00:00 2001 From: techmannih Date: Wed, 3 Dec 2025 23:24:38 +0530 Subject: [PATCH 1/2] Add faux board visibility toggle in Appearance menu --- src/CadViewer.tsx | 9 +++-- src/CadViewerJscad.tsx | 24 +++++++++----- src/CadViewerManifold.tsx | 31 ++++++++++++++++- src/components/AppearanceMenu.tsx | 27 +++++++++++++++ src/contexts/FauxBoardContext.tsx | 44 +++++++++++++++++++++++++ src/contexts/LayerVisibilityContext.tsx | 2 ++ 6 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 src/contexts/FauxBoardContext.tsx diff --git a/src/CadViewer.tsx b/src/CadViewer.tsx index f625a85f..3a0e6445 100644 --- a/src/CadViewer.tsx +++ b/src/CadViewer.tsx @@ -19,6 +19,7 @@ import { useCameraController, } from "./contexts/CameraControllerContext" import { ToastProvider, useToast } from "./contexts/ToastContext" +import { FauxBoardProvider } from "./contexts/FauxBoardContext" import { ContextMenu } from "./components/ContextMenu" import { KeyboardShortcutsDialog } from "./components/KeyboardShortcutsDialog" import type { CameraController, CameraPreset } from "./hooks/cameraAnimation" @@ -319,9 +320,11 @@ export const CadViewer = (props: any) => { initialCameraPosition={initialCameraPosition} > - - - + + + + + ) diff --git a/src/CadViewerJscad.tsx b/src/CadViewerJscad.tsx index 4ff4faa8..a2cc0b38 100644 --- a/src/CadViewerJscad.tsx +++ b/src/CadViewerJscad.tsx @@ -20,6 +20,7 @@ import { VisibleSTLModel } from "./three-components/VisibleSTLModel" import { ThreeErrorBoundary } from "./three-components/ThreeErrorBoundary" import { addFauxBoardIfNeeded } from "./utils/preprocess-circuit-json" import { tuple } from "./utils/tuple" +import { useLayerVisibility } from "./contexts/LayerVisibilityContext" interface Props { /** @@ -121,9 +122,13 @@ export const CadViewerJscad = forwardRef< // Use the state `boardGeom` which starts simplified and gets updated const { stls: boardStls, loading } = useStlsFromGeom(boardGeom) + const { visibility } = useLayerVisibility() const cad_components = su(internalCircuitJson).cad_component.list() + // If this is a faux board and faux board visibility is disabled, don't render the board + const shouldRenderBoard = !(isFauxBoard && !visibility.fauxBoard) + return ( - {boardStls.map(({ stlData, color, layerType }, index) => ( - - ))} + {shouldRenderBoard && + boardStls.map(({ stlData, color, layerType }, index) => ( + + ))} {cad_components.map((cad_component) => ( { const { rootObject } = useThree() const { visibility } = useLayerVisibility() @@ -38,6 +41,23 @@ const BoardMeshes = ({ useEffect(() => { if (!rootObject) return + // If this is a faux board and faux board visibility is disabled, don't render anything + // But we still need to clean up any previously added meshes + if (isFauxBoard && !visibility.fauxBoard) { + // Clean up any previously added meshes + geometryMeshes.forEach((mesh) => { + if (mesh.parent === rootObject) { + rootObject.remove(mesh) + } + }) + textureMeshes.forEach((mesh) => { + if (mesh.parent === rootObject) { + rootObject.remove(mesh) + } + }) + return + } + // Filter and add meshes based on visibility settings geometryMeshes.forEach((mesh) => { let shouldShow = true @@ -110,7 +130,7 @@ const BoardMeshes = ({ } }) } - }, [rootObject, geometryMeshes, textureMeshes, visibility]) + }, [rootObject, geometryMeshes, textureMeshes, visibility, isFauxBoard]) return null } @@ -230,8 +250,16 @@ try { error: builderError, isLoading: builderIsLoading, boardData, + isFauxBoard, } = useManifoldBoardBuilder(manifoldJSModule, circuitJson) + const { setIsFauxBoard } = useFauxBoard() + + // Update the context with the faux board state + useEffect(() => { + setIsFauxBoard(isFauxBoard) + }, [isFauxBoard, setIsFauxBoard]) + const geometryMeshes = useMemo(() => createGeometryMeshes(geoms), [geoms]) const textureMeshes = useMemo( () => createTextureMeshes(textures, boardData, pcbThickness), @@ -317,6 +345,7 @@ try { {cadComponents.map((cad_component: CadComponent) => ( { const { visibility, setLayerVisibility } = useLayerVisibility() + const { isFauxBoard } = useFauxBoard() const [appearanceSubOpen, setAppearanceSubOpen] = useState(false) const [hoveredItem, setHoveredItem] = useState(null) @@ -126,6 +128,31 @@ export const AppearanceMenu = () => { + {isFauxBoard && ( + e.preventDefault()} + onPointerDown={(e) => { + e.preventDefault() + setLayerVisibility("fauxBoard", !visibility.fauxBoard) + }} + onMouseEnter={() => setHoveredItem("fauxBoard")} + onMouseLeave={() => setHoveredItem(null)} + onTouchStart={() => setHoveredItem("fauxBoard")} + > + + {visibility.fauxBoard && } + + + Faux Board + + + )} + void +} + +const FauxBoardContext = createContext( + undefined, +) + +export const FauxBoardProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const [isFauxBoard, setIsFauxBoard] = useState(false) + + const value = useMemo( + () => ({ + isFauxBoard, + setIsFauxBoard, + }), + [isFauxBoard], + ) + + return ( + + {children} + + ) +} + +export const useFauxBoard = () => { + const context = useContext(FauxBoardContext) + if (!context) { + throw new Error("useFauxBoard must be used within a FauxBoardProvider") + } + return context +} diff --git a/src/contexts/LayerVisibilityContext.tsx b/src/contexts/LayerVisibilityContext.tsx index c6847759..1e8b6e7b 100644 --- a/src/contexts/LayerVisibilityContext.tsx +++ b/src/contexts/LayerVisibilityContext.tsx @@ -26,6 +26,7 @@ export interface LayerVisibilityState { threedAxis: boolean backgroundStart: boolean backgroundEnd: boolean + fauxBoard: boolean } interface LayerVisibilityContextType { @@ -56,6 +57,7 @@ const defaultVisibility: LayerVisibilityState = { threedAxis: false, backgroundStart: true, backgroundEnd: true, + fauxBoard: true, } const LayerVisibilityContext = createContext< From d4fbf8fbab3a38fa53d8af66efcca307060ce843 Mon Sep 17 00:00:00 2001 From: techmannih Date: Fri, 5 Dec 2025 19:01:56 +0530 Subject: [PATCH 2/2] clean up --- src/CadViewer.tsx | 9 ++---- src/CadViewerManifold.tsx | 8 ------ src/components/AppearanceMenu.tsx | 48 ++++++++++++++----------------- src/contexts/FauxBoardContext.tsx | 44 ---------------------------- 4 files changed, 25 insertions(+), 84 deletions(-) delete mode 100644 src/contexts/FauxBoardContext.tsx diff --git a/src/CadViewer.tsx b/src/CadViewer.tsx index 3a0e6445..f625a85f 100644 --- a/src/CadViewer.tsx +++ b/src/CadViewer.tsx @@ -19,7 +19,6 @@ import { useCameraController, } from "./contexts/CameraControllerContext" import { ToastProvider, useToast } from "./contexts/ToastContext" -import { FauxBoardProvider } from "./contexts/FauxBoardContext" import { ContextMenu } from "./components/ContextMenu" import { KeyboardShortcutsDialog } from "./components/KeyboardShortcutsDialog" import type { CameraController, CameraPreset } from "./hooks/cameraAnimation" @@ -320,11 +319,9 @@ export const CadViewer = (props: any) => { initialCameraPosition={initialCameraPosition} > - - - - - + + + ) diff --git a/src/CadViewerManifold.tsx b/src/CadViewerManifold.tsx index 04a1bb1e..27b7e7b0 100644 --- a/src/CadViewerManifold.tsx +++ b/src/CadViewerManifold.tsx @@ -16,7 +16,6 @@ import { ThreeErrorBoundary } from "./three-components/ThreeErrorBoundary" import { createGeometryMeshes } from "./utils/manifold/create-three-geometry-meshes" import { createTextureMeshes } from "./utils/manifold/create-three-texture-meshes" import { useLayerVisibility } from "./contexts/LayerVisibilityContext" -import { useFauxBoard } from "./contexts/FauxBoardContext" declare global { interface Window { @@ -261,13 +260,6 @@ try { isFauxBoard, } = useManifoldBoardBuilder(manifoldJSModule, circuitJson) - const { setIsFauxBoard } = useFauxBoard() - - // Update the context with the faux board state - useEffect(() => { - setIsFauxBoard(isFauxBoard) - }, [isFauxBoard, setIsFauxBoard]) - const geometryMeshes = useMemo(() => createGeometryMeshes(geoms), [geoms]) const textureMeshes = useMemo( () => createTextureMeshes(textures, boardData, pcbThickness), diff --git a/src/components/AppearanceMenu.tsx b/src/components/AppearanceMenu.tsx index 6eaae995..0c550413 100644 --- a/src/components/AppearanceMenu.tsx +++ b/src/components/AppearanceMenu.tsx @@ -1,6 +1,5 @@ import { useState } from "react" import { useLayerVisibility } from "../contexts/LayerVisibilityContext" -import { useFauxBoard } from "../contexts/FauxBoardContext" import type React from "react" import * as DropdownMenu from "@radix-ui/react-dropdown-menu" import { CheckIcon, ChevronRightIcon } from "./Icons" @@ -62,7 +61,6 @@ const iconContainerStyles: React.CSSProperties = { export const AppearanceMenu = () => { const { visibility, setLayerVisibility } = useLayerVisibility() - const { isFauxBoard } = useFauxBoard() const [appearanceSubOpen, setAppearanceSubOpen] = useState(false) const [hoveredItem, setHoveredItem] = useState(null) @@ -128,30 +126,28 @@ export const AppearanceMenu = () => { - {isFauxBoard && ( - e.preventDefault()} - onPointerDown={(e) => { - e.preventDefault() - setLayerVisibility("fauxBoard", !visibility.fauxBoard) - }} - onMouseEnter={() => setHoveredItem("fauxBoard")} - onMouseLeave={() => setHoveredItem(null)} - onTouchStart={() => setHoveredItem("fauxBoard")} - > - - {visibility.fauxBoard && } - - - Faux Board - - - )} + e.preventDefault()} + onPointerDown={(e) => { + e.preventDefault() + setLayerVisibility("fauxBoard", !visibility.fauxBoard) + }} + onMouseEnter={() => setHoveredItem("fauxBoard")} + onMouseLeave={() => setHoveredItem(null)} + onTouchStart={() => setHoveredItem("fauxBoard")} + > + + {visibility.fauxBoard && } + + + Faux Board + + void -} - -const FauxBoardContext = createContext( - undefined, -) - -export const FauxBoardProvider: React.FC<{ children: React.ReactNode }> = ({ - children, -}) => { - const [isFauxBoard, setIsFauxBoard] = useState(false) - - const value = useMemo( - () => ({ - isFauxBoard, - setIsFauxBoard, - }), - [isFauxBoard], - ) - - return ( - - {children} - - ) -} - -export const useFauxBoard = () => { - const context = useContext(FauxBoardContext) - if (!context) { - throw new Error("useFauxBoard must be used within a FauxBoardProvider") - } - return context -}