diff --git a/.changeset/cylinder-stock.md b/.changeset/cylinder-stock.md new file mode 100644 index 0000000..676cdd4 --- /dev/null +++ b/.changeset/cylinder-stock.md @@ -0,0 +1,9 @@ +--- +'@toolpath/viewer': major +--- + +Consolidate stock rendering into `Stock`, accepting exactly one of `geometry`, `glb`, `box`, or `cylinder`. Box and cylinder inputs accept either resolved placement or part-relative preview options, with placement calculated internally. Resolved box figures support optional setup frames; resolved cylinder figures support arbitrary axes. Fetching, caching and artifact storage remain caller-owned. Stock outlines are built only when shown. + +Remove `BoxStock` and `BoxStockProps`. Replace `` with ``; for explicit dimensions use ``. Preview builders are internal, and inline options do not cause repeated part scans on ordinary renders. Existing `` usage is unchanged. + +`StockProps` is now a union type alias rather than an interface, so `interface X extends StockProps` no longer compiles; write `type X = StockProps & { … }` instead. Use `StockAppearanceProps` for the shared appearance props alone. diff --git a/.changeset/stock-mesh-transitions.md b/.changeset/stock-mesh-transitions.md new file mode 100644 index 0000000..774c4f7 --- /dev/null +++ b/.changeset/stock-mesh-transitions.md @@ -0,0 +1,5 @@ +--- +'@toolpath/viewer': minor +--- + +Add optional `Stock` `retainPrevious` behavior to keep the current GLB visible until its replacement finishes decoding. Dispose replaced geometry after the swap, and discard cancelled decode results. diff --git a/.changeset/stock-workpiece-shading.md b/.changeset/stock-workpiece-shading.md new file mode 100644 index 0000000..7ae366b --- /dev/null +++ b/.changeset/stock-workpiece-shading.md @@ -0,0 +1,5 @@ +--- +'@toolpath/viewer': minor +--- + +Add a `legacy-workpiece` render style to `Stock`, reproducing legacy white/emissive shading, 20% opacity, two surface passes and edges drawn before surfaces. Add optional `emissive` and `flatShading` appearance props. Existing overlay defaults and source geometry remain unchanged. diff --git a/examples/react-viewer/src/main.tsx b/examples/react-viewer/src/main.tsx index 9264763..f87a20d 100644 --- a/examples/react-viewer/src/main.tsx +++ b/examples/react-viewer/src/main.tsx @@ -5,7 +5,7 @@ import * as THREE from 'three' import { Axes, Banana, - BoxStock, + Stock, fixedBoxStockBounds, directionHighlights, directionLabel, @@ -36,6 +36,7 @@ import { } from '@toolpath/viewer' import { AnalysisOptions } from './analysis-options' import { MODELS, modelFromQuery } from './models' +import stockMeshFixture from '../../../packages/viewer/fixtures/mesh/stock-box.json' import './style.css' /** @@ -55,6 +56,14 @@ const params = new URLSearchParams(window.location.search) const projection: Projection = params.get('projection') === 'orthographic' ? 'orthographic' : 'perspective' const showOrbitTarget = params.get('orbitTarget') === 'on' +const STOCK_GLB_BYTES = Uint8Array.from(atob(stockMeshFixture.base64), (char) => + char.charCodeAt(0), +).buffer +const LARGE_STOCK_GLB_BYTES = Uint8Array.from(atob(stockMeshFixture.largeBase64), (char) => + char.charCodeAt(0), +).buffer +type StockShape = 'box' | 'cylinder' +type StockSource = 'geometry' | 'glb' const requestedControls = params.get('controls') const initialControls: ControlScheme = CONTROL_SCHEME_OPTIONS.some( (option) => option.value === requestedControls, @@ -215,7 +224,15 @@ const App = () => { const [showDirections, setShowDirections] = useState(false) const [focus, setFocus] = useState(false) const [wireframe, setWireframe] = useState(false) + const [stockShape, setStockShape] = useState( + params.get('stockShape') === 'cylinder' ? 'cylinder' : 'box', + ) + const [stockSource, setStockSource] = useState( + params.get('stockSource') === 'glb' ? 'glb' : 'geometry', + ) const [stockDimensions, setStockDimensions] = useState({ x: 25.908, y: 25.908, z: 25.908 }) + const [stockCylinder, setStockCylinder] = useState({ diameter: 38.1, length: 25.908 }) + const [stockMeshSize, setStockMeshSize] = useState('40') const [stockPosition, setStockPosition] = useState('model_centered') const [stockPositionOffset, setStockPositionOffset] = useState(0) const stockSize = useMemo( @@ -346,69 +363,146 @@ const App = () => {

{part.hint}

Stock:{' '} - {stockSize - .toArray() - .map((value) => value.toFixed(2)) - .join(' × ')}{' '} - mm (X × Y × Z) + {stockSource === 'glb' + ? `${stockMeshSize}.00 × ${stockMeshSize}.00 × ${stockMeshSize}.00 mm (services-encoded GLB blank)` + : stockShape === 'cylinder' + ? `⌀${stockCylinder.diameter.toFixed(2)} × ${stockCylinder.length.toFixed(2)} mm (diameter × length)` + : `${stockSize + .toArray() + .map((value) => value.toFixed(2)) + .join(' × ')} mm (X × Y × Z)`}

- - - - {stockPosition !== 'model_centered' ? ( + {stockSource === 'geometry' ? ( + + ) : null} + {stockSource === 'glb' ? ( + + ) : null} + {stockSource === 'geometry' && stockShape === 'cylinder' ? ( + <> + + + + ) : null} + {stockSource === 'geometry' && stockShape === 'box' ? ( + <> + + + + + ) : null} + {stockSource === 'geometry' ? ( + + ) : null} + {stockSource === 'geometry' && stockPosition !== 'model_centered' ? ( ) : null}

- Fixed box stock dimensions and position. Values are millimetres. + {stockSource === 'glb' + ? 'Synthetic initial stock encoded by the services GLB writer, in part coordinates.' + : 'Fixed stock shape, dimensions and position. Values are millimetres.'}