@tscircuit/3d-viewer 0.0.641 → 0.0.643

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -60,7 +60,10 @@ type CadViewerProps = Omit<React.ComponentProps<typeof CadViewerJscad>, "circuit
60
60
  circuitJson?: any[];
61
61
  /** Settled circuit retaining authored assembly.explosion stages. */
62
62
  circuit?: RootCircuit;
63
- /** Pre-rendered circuit-json-to-gltf GLB URL. Bypasses geometry/model generation. */
63
+ /**
64
+ * Pre-rendered circuit-json-to-gltf GLB URL. Bypasses geometry/model generation.
65
+ * Changing the GLB preserves the camera. Change the viewer key to frame a different board.
66
+ */
64
67
  glbUrl?: string;
65
68
  /** In-memory alternative to glbUrl. Supply only one GLB source. */
66
69
  glbData?: ArrayBuffer;
package/dist/index.js CHANGED
@@ -19115,7 +19115,8 @@ function getGlbComponentMetadata(object) {
19115
19115
  "cad_component_id",
19116
19116
  "source_component_id",
19117
19117
  "pcb_component_id",
19118
- "componentName"
19118
+ "componentName",
19119
+ "pcb_board_id"
19119
19120
  ]) {
19120
19121
  if (typeof metadata[key] === "string") result[key] = metadata[key];
19121
19122
  }
@@ -22344,7 +22345,7 @@ import * as THREE31 from "three";
22344
22345
  // package.json
22345
22346
  var package_default = {
22346
22347
  name: "@tscircuit/3d-viewer",
22347
- version: "0.0.640",
22348
+ version: "0.0.642",
22348
22349
  repository: {
22349
22350
  type: "git",
22350
22351
  url: "https://github.com/tscircuit/3d-viewer"
@@ -32042,33 +32043,51 @@ var CadViewerManifold = ({
32042
32043
  var CadViewerManifold_default = CadViewerManifold;
32043
32044
 
32044
32045
  // src/CadViewerGlb.tsx
32045
- import { useEffect as useEffect37, useMemo as useMemo31, useState as useState23 } from "react";
32046
+ import {
32047
+ useEffect as useEffect37,
32048
+ useLayoutEffect as useLayoutEffect2,
32049
+ useState as useState23
32050
+ } from "react";
32046
32051
 
32047
32052
  // src/hooks/useGlbModel.ts
32048
- import { useEffect as useEffect36, useMemo as useMemo30, useState as useState22 } from "react";
32053
+ import { useEffect as useEffect36, useLayoutEffect, useMemo as useMemo30, useState as useState22 } from "react";
32049
32054
  function useGlbModel(source) {
32050
32055
  const request = useMemo30(() => ({ source }), [source]);
32051
32056
  const [result, setResult] = useState22();
32057
+ const displayedGlb = result?.loadedGlb;
32052
32058
  useEffect36(() => {
32053
32059
  const controller = new AbortController();
32054
- let model;
32055
- loadGlbScene(request.source, controller.signal).then((loaded) => {
32056
- model = loaded;
32057
- if (controller.signal.aborted) disposeGlbScene(loaded);
32058
- else setResult({ request, model: loaded });
32060
+ let loadedGlb;
32061
+ loadGlbScene(request.source, controller.signal).then((model) => {
32062
+ if (controller.signal.aborted) {
32063
+ disposeGlbScene(model);
32064
+ return;
32065
+ }
32066
+ loadedGlb = { model, wasDisplayed: false };
32067
+ setResult({ request, loadedGlb });
32059
32068
  }).catch((error) => {
32060
- if (!controller.signal.aborted)
32061
- setResult({
32062
- request,
32063
- error: error instanceof Error ? error.message : String(error)
32064
- });
32069
+ if (controller.signal.aborted) return;
32070
+ setResult((previous) => ({
32071
+ request,
32072
+ loadedGlb: previous?.loadedGlb,
32073
+ error: error instanceof Error ? error.message : String(error)
32074
+ }));
32065
32075
  });
32066
32076
  return () => {
32067
32077
  controller.abort();
32068
- if (model) disposeGlbScene(model);
32078
+ if (loadedGlb && !loadedGlb.wasDisplayed) disposeGlbScene(loadedGlb.model);
32069
32079
  };
32070
32080
  }, [request]);
32071
- return result?.request === request ? result : void 0;
32081
+ useLayoutEffect(() => {
32082
+ if (!displayedGlb) return;
32083
+ displayedGlb.wasDisplayed = true;
32084
+ return () => disposeGlbScene(displayedGlb.model);
32085
+ }, [displayedGlb]);
32086
+ return {
32087
+ model: displayedGlb?.model,
32088
+ isLoading: result?.request !== request,
32089
+ error: result?.request === request ? result.error : void 0
32090
+ };
32072
32091
  }
32073
32092
 
32074
32093
  // src/CadViewerGlb.tsx
@@ -32081,19 +32100,7 @@ function GlbScene({
32081
32100
  const { rootObject } = useThree();
32082
32101
  const { addHoverable, removeHoverable } = useHover();
32083
32102
  const [hover, setHover] = useState23();
32084
- const bounds = useMemo31(() => {
32085
- const box = new THREE62.Box3().setFromObject(model);
32086
- if (box.isEmpty()) return;
32087
- return {
32088
- minX: box.min.x,
32089
- maxX: box.max.x,
32090
- minY: box.min.y,
32091
- maxY: box.max.y,
32092
- minZ: box.min.z,
32093
- maxZ: box.max.z
32094
- };
32095
- }, [model]);
32096
- useEffect37(() => {
32103
+ useLayoutEffect2(() => {
32097
32104
  rootObject.add(model);
32098
32105
  return () => {
32099
32106
  rootObject.remove(model);
@@ -32101,14 +32108,14 @@ function GlbScene({
32101
32108
  }, [rootObject, model]);
32102
32109
  useEffect37(() => {
32103
32110
  setHover(void 0);
32104
- const applyVisibility = (object, inComponent) => {
32105
- const id = object.userData.cad_component_id;
32111
+ const applyVisibility = (object, inObject) => {
32112
+ const id = object.userData.cad_component_id ?? object.userData.pcb_board_id;
32106
32113
  if (typeof id === "string")
32107
32114
  object.visible = !isObjectHidden(objectVisibility, id);
32108
- else if (!inComponent && object instanceof THREE62.Mesh)
32115
+ else if (!inObject && object instanceof THREE62.Mesh)
32109
32116
  object.visible = !isObjectHidden(objectVisibility, void 0);
32110
32117
  for (const child of object.children)
32111
- applyVisibility(child, inComponent || typeof id === "string");
32118
+ applyVisibility(child, inObject || typeof id === "string");
32112
32119
  };
32113
32120
  applyVisibility(model, false);
32114
32121
  }, [model, objectVisibility]);
@@ -32144,54 +32151,88 @@ function GlbScene({
32144
32151
  for (const mesh of meshes) removeHoverable(mesh);
32145
32152
  };
32146
32153
  }, [model, objectVisibility, addHoverable, removeHoverable]);
32154
+ return /* @__PURE__ */ jsx24(Fragment5, { children: hover && /* @__PURE__ */ jsx24(
32155
+ Html,
32156
+ {
32157
+ position: hover.position,
32158
+ style: {
32159
+ background: "white",
32160
+ color: "black",
32161
+ padding: "5px",
32162
+ borderRadius: "3px",
32163
+ fontFamily: "sans-serif",
32164
+ transform: "translate(1rem, 1rem)"
32165
+ },
32166
+ children: hover.name
32167
+ }
32168
+ ) });
32169
+ }
32170
+ function CadViewerGlb({
32171
+ source,
32172
+ objectVisibility,
32173
+ ...containerProps
32174
+ }) {
32175
+ const { model, isLoading, error } = useGlbModel(source);
32176
+ const message = error ? `Unable to load 3D view: ${error}` : "Loading 3D view...";
32177
+ const role = error ? "alert" : "status";
32178
+ if (!model) return /* @__PURE__ */ jsx24("div", { role, children: message });
32147
32179
  return /* @__PURE__ */ jsxs8(Fragment5, { children: [
32148
- bounds && /* @__PURE__ */ jsx24(FitCameraToComparison, { bounds }),
32149
- hover && /* @__PURE__ */ jsx24(
32150
- Html,
32180
+ /* @__PURE__ */ jsx24(
32181
+ GlbViewport,
32151
32182
  {
32152
- position: hover.position,
32153
- style: {
32154
- background: "white",
32155
- color: "black",
32156
- padding: "5px",
32157
- borderRadius: "3px",
32158
- fontFamily: "sans-serif",
32159
- transform: "translate(1rem, 1rem)"
32160
- },
32161
- children: hover.name
32183
+ model,
32184
+ objectVisibility,
32185
+ ...containerProps
32162
32186
  }
32163
- )
32187
+ ),
32188
+ (isLoading || error) && /* @__PURE__ */ jsx24("div", { role, style: { position: "absolute", top: 12, left: 12 }, children: message })
32164
32189
  ] });
32165
32190
  }
32166
- function CadViewerGlb({
32167
- source,
32191
+ function GlbViewport({
32192
+ model,
32168
32193
  objectVisibility,
32169
32194
  ...containerProps
32170
32195
  }) {
32171
- const result = useGlbModel(source);
32172
- const framing = useMemo31(() => {
32173
- if (!result?.model) return void 0;
32174
- const bounds = new THREE62.Box3().setFromObject(result.model);
32175
- if (bounds.isEmpty()) return void 0;
32176
- return {
32177
- boardDimensions: {
32178
- width: bounds.max.x - bounds.min.x,
32179
- height: bounds.max.y - bounds.min.y
32180
- },
32181
- boardCenter: {
32182
- x: (bounds.min.x + bounds.max.x) / 2,
32183
- y: (bounds.min.y + bounds.max.y) / 2
32184
- }
32185
- };
32186
- }, [result, source]);
32187
- if (!result) return /* @__PURE__ */ jsx24("div", { role: "status", children: "Loading 3D view..." });
32188
- if (result.error)
32189
- return /* @__PURE__ */ jsxs8("div", { role: "alert", children: [
32190
- "Unable to load 3D view: ",
32191
- result.error
32192
- ] });
32193
- if (!result.model) return null;
32194
- return /* @__PURE__ */ jsx24(CadViewerContainer, { ...containerProps, ...framing, children: /* @__PURE__ */ jsx24(GlbScene, { model: result.model, objectVisibility }) });
32196
+ const [framing, setFraming] = useState23(() => getGlbFraming(model));
32197
+ useEffect37(() => {
32198
+ if (framing) return;
32199
+ const nextFraming = getGlbFraming(model);
32200
+ if (nextFraming) setFraming(nextFraming);
32201
+ }, [framing, model]);
32202
+ return /* @__PURE__ */ jsxs8(
32203
+ CadViewerContainer,
32204
+ {
32205
+ ...containerProps,
32206
+ boardDimensions: framing?.boardDimensions,
32207
+ boardCenter: framing?.boardCenter,
32208
+ children: [
32209
+ framing && /* @__PURE__ */ jsx24(FitCameraToComparison, { bounds: framing.bounds }),
32210
+ /* @__PURE__ */ jsx24(GlbScene, { model, objectVisibility })
32211
+ ]
32212
+ }
32213
+ );
32214
+ }
32215
+ function getGlbFraming(model) {
32216
+ const box = new THREE62.Box3().setFromObject(model);
32217
+ if (box.isEmpty()) return void 0;
32218
+ return {
32219
+ bounds: {
32220
+ minX: box.min.x,
32221
+ maxX: box.max.x,
32222
+ minY: box.min.y,
32223
+ maxY: box.max.y,
32224
+ minZ: box.min.z,
32225
+ maxZ: box.max.z
32226
+ },
32227
+ boardDimensions: {
32228
+ width: box.max.x - box.min.x,
32229
+ height: box.max.y - box.min.y
32230
+ },
32231
+ boardCenter: {
32232
+ x: (box.min.x + box.max.x) / 2,
32233
+ y: (box.min.y + box.max.y) / 2
32234
+ }
32235
+ };
32195
32236
  }
32196
32237
 
32197
32238
  // node_modules/@radix-ui/react-dropdown-menu/dist/index.mjs
@@ -32392,7 +32433,7 @@ var IS_DEVELOPMENT = false;
32392
32433
 
32393
32434
  // node_modules/@radix-ui/react-use-layout-effect/dist/index.mjs
32394
32435
  import * as React13 from "react";
32395
- var useLayoutEffect2 = globalThis?.document ? React13.useLayoutEffect : () => {
32436
+ var useLayoutEffect22 = globalThis?.document ? React13.useLayoutEffect : () => {
32396
32437
  };
32397
32438
 
32398
32439
  // node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs
@@ -32416,7 +32457,7 @@ function useEffectEvent(callback) {
32416
32457
  ref.current = callback;
32417
32458
  });
32418
32459
  } else {
32419
- useLayoutEffect2(() => {
32460
+ useLayoutEffect22(() => {
32420
32461
  ref.current = callback;
32421
32462
  });
32422
32463
  }
@@ -32427,7 +32468,7 @@ __name4(useEffectEvent, "useEffectEvent");
32427
32468
  // node_modules/@radix-ui/react-use-controllable-state/dist/index.mjs
32428
32469
  var __defProp6 = Object.defineProperty;
32429
32470
  var __name5 = (target, value) => __defProp6(target, "name", { value, configurable: true });
32430
- var useInsertionEffect = React15[" useInsertionEffect ".trim().toString()] || useLayoutEffect2;
32471
+ var useInsertionEffect = React15[" useInsertionEffect ".trim().toString()] || useLayoutEffect22;
32431
32472
  function useControllableState({
32432
32473
  prop,
32433
32474
  defaultProp,
@@ -33267,7 +33308,7 @@ function createCollection2(name) {
33267
33308
  [registryRef]
33268
33309
  );
33269
33310
  const composedRefs = useComposedRefs(forwardedRef, registerElement, ref);
33270
- useLayoutEffect2(() => {
33311
+ useLayoutEffect22(() => {
33271
33312
  const node = ref.current;
33272
33313
  const registry = registryRef.current;
33273
33314
  if (node && registry.has(node)) {
@@ -33420,7 +33461,7 @@ function useCallbackRef(callback) {
33420
33461
  callbackRef.current = callback;
33421
33462
  });
33422
33463
  } else {
33423
- useLayoutEffect2(() => {
33464
+ useLayoutEffect22(() => {
33424
33465
  callbackRef.current = callback;
33425
33466
  });
33426
33467
  }
@@ -34089,7 +34130,7 @@ var useReactId = React26[" useId ".trim().toString()] || (() => void 0);
34089
34130
  var count2 = 0;
34090
34131
  function useId2(deterministicId) {
34091
34132
  const [id, setId] = React26.useState(useReactId());
34092
- useLayoutEffect2(() => {
34133
+ useLayoutEffect22(() => {
34093
34134
  if (!deterministicId) setId((reactId) => reactId ?? String(count2++));
34094
34135
  }, [deterministicId]);
34095
34136
  return deterministicId || (id ? `radix-${id}` : "");
@@ -35693,12 +35734,12 @@ var computePosition2 = (reference, floating, options) => {
35693
35734
 
35694
35735
  // node_modules/@floating-ui/react-dom/dist/floating-ui.react-dom.mjs
35695
35736
  import * as React27 from "react";
35696
- import { useLayoutEffect as useLayoutEffect3 } from "react";
35737
+ import { useLayoutEffect as useLayoutEffect4 } from "react";
35697
35738
  import * as ReactDOM3 from "react-dom";
35698
35739
  var isClient = typeof document !== "undefined";
35699
35740
  var noop = function noop2() {
35700
35741
  };
35701
- var index = isClient ? useLayoutEffect3 : noop;
35742
+ var index = isClient ? useLayoutEffect4 : noop;
35702
35743
  function deepEqual(a, b) {
35703
35744
  if (a === b) {
35704
35745
  return true;
@@ -36008,7 +36049,7 @@ var __defProp16 = Object.defineProperty;
36008
36049
  var __name15 = (target, value) => __defProp16(target, "name", { value, configurable: true });
36009
36050
  function useSize(element) {
36010
36051
  const [size4, setSize] = React28.useState(void 0);
36011
- useLayoutEffect2(() => {
36052
+ useLayoutEffect22(() => {
36012
36053
  if (element) {
36013
36054
  setSize({ width: element.offsetWidth, height: element.offsetHeight });
36014
36055
  let rAF = 0;
@@ -36215,7 +36256,7 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
36215
36256
  ]
36216
36257
  });
36217
36258
  const setPlacementState = context.setPlacementState;
36218
- useLayoutEffect2(() => {
36259
+ useLayoutEffect22(() => {
36219
36260
  setPlacementState(placement);
36220
36261
  return () => {
36221
36262
  setPlacementState(void 0);
@@ -36223,7 +36264,7 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
36223
36264
  }, [placement, setPlacementState]);
36224
36265
  const [placedSide, placedAlign] = getSideAndAlignFromPlacement(placement);
36225
36266
  const handlePlaced = useCallbackRef(onPlaced);
36226
- useLayoutEffect2(() => {
36267
+ useLayoutEffect22(() => {
36227
36268
  if (isPositioned) {
36228
36269
  handlePlaced?.();
36229
36270
  }
@@ -36232,7 +36273,7 @@ var PopperContent = /* @__PURE__ */ React29.forwardRef(
36232
36273
  const arrowY = middlewareData.arrow?.y;
36233
36274
  const cannotCenterArrow = middlewareData.arrow?.centerOffset !== 0;
36234
36275
  const [contentZIndex, setContentZIndex] = React29.useState();
36235
- useLayoutEffect2(() => {
36276
+ useLayoutEffect22(() => {
36236
36277
  if (content) setContentZIndex(window.getComputedStyle(content).zIndex);
36237
36278
  }, [content]);
36238
36279
  return /* @__PURE__ */ jsx32(
@@ -36342,7 +36383,7 @@ var Portal = /* @__PURE__ */ React30.forwardRef(
36342
36383
  /* @__PURE__ */ __name17(function Portal2(props, forwardedRef) {
36343
36384
  const { container: containerProp, ...portalProps } = props;
36344
36385
  const [mounted, setMounted] = React30.useState(false);
36345
- useLayoutEffect2(() => setMounted(true), []);
36386
+ useLayoutEffect22(() => setMounted(true), []);
36346
36387
  const container = containerProp || mounted && globalThis?.document?.body;
36347
36388
  return container ? ReactDOM4.createPortal(/* @__PURE__ */ jsx33(Primitive.div, { ...portalProps, ref: forwardedRef }), container) : null;
36348
36389
  }, "Portal")
@@ -36396,7 +36437,7 @@ function usePresence(present) {
36396
36437
  prevAnimationNameRef.current = "none";
36397
36438
  }
36398
36439
  }, [state]);
36399
- useLayoutEffect2(() => {
36440
+ useLayoutEffect22(() => {
36400
36441
  const styles = stylesRef.current;
36401
36442
  const wasPresent = prevPresentRef.current;
36402
36443
  const hasPresentChanged = wasPresent !== present;
@@ -36419,7 +36460,7 @@ function usePresence(present) {
36419
36460
  prevPresentRef.current = present;
36420
36461
  }
36421
36462
  }, [present, send]);
36422
- useLayoutEffect2(() => {
36463
+ useLayoutEffect22(() => {
36423
36464
  if (node) {
36424
36465
  let timeoutId;
36425
36466
  const ownerWindow = node.ownerDocument.defaultView ?? window;
@@ -36699,7 +36740,7 @@ var RovingFocusGroupItem = /* @__PURE__ */ React33.forwardRef(
36699
36740
  const getItems = useCollection(__scopeRovingFocusGroup);
36700
36741
  const { onFocusableItemAdd, onFocusableItemRemove, currentTabStopId } = context;
36701
36742
  const isHydrated = useIsHydrated2();
36702
- useLayoutEffect2(() => {
36743
+ useLayoutEffect22(() => {
36703
36744
  if (!isHydrated || !focusable) {
36704
36745
  return;
36705
36746
  }
@@ -38593,12 +38634,12 @@ var DropdownMenuSubContent = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */
38593
38634
  }, "DropdownMenuSubContent"));
38594
38635
 
38595
38636
  // src/components/ViewportSubContent.tsx
38596
- import { useLayoutEffect as useLayoutEffect5, useState as useState40 } from "react";
38637
+ import { useLayoutEffect as useLayoutEffect6, useState as useState40 } from "react";
38597
38638
  import { jsx as jsx37 } from "react/jsx-runtime";
38598
38639
  var ViewportSubContent = (props) => {
38599
38640
  const [content, setContent] = useState40(null);
38600
38641
  const [overlapWidth, setOverlapWidth] = useState40();
38601
- useLayoutEffect5(() => {
38642
+ useLayoutEffect6(() => {
38602
38643
  if (!content) return;
38603
38644
  const trigger = document.getElementById(
38604
38645
  content.getAttribute("aria-labelledby") ?? ""
@@ -39741,10 +39782,10 @@ var ContextMenu = ({
39741
39782
  };
39742
39783
 
39743
39784
  // src/components/KeyboardShortcutsDialog.tsx
39744
- import { useEffect as useEffect55, useMemo as useMemo41, useRef as useRef28, useState as useState44 } from "react";
39785
+ import { useEffect as useEffect55, useMemo as useMemo40, useRef as useRef28, useState as useState44 } from "react";
39745
39786
 
39746
39787
  // src/hooks/useRegisteredHotkey.ts
39747
- import { useEffect as useEffect54, useMemo as useMemo40, useRef as useRef27, useState as useState43 } from "react";
39788
+ import { useEffect as useEffect54, useMemo as useMemo39, useRef as useRef27, useState as useState43 } from "react";
39748
39789
  var hotkeyRegistry = /* @__PURE__ */ new Map();
39749
39790
  var subscribers = /* @__PURE__ */ new Set();
39750
39791
  var isListenerAttached = false;
@@ -39868,7 +39909,7 @@ var subscribeToRegistry = (subscriber) => {
39868
39909
  var useRegisteredHotkey = (id, handler, metadata) => {
39869
39910
  const handlerRef = useRef27(handler);
39870
39911
  handlerRef.current = handler;
39871
- const normalizedMetadata = useMemo40(
39912
+ const normalizedMetadata = useMemo39(
39872
39913
  () => ({
39873
39914
  shortcut: metadata.shortcut,
39874
39915
  description: metadata.description
@@ -39926,7 +39967,7 @@ var KeyboardShortcutsDialog = ({
39926
39967
  }, 0);
39927
39968
  }
39928
39969
  }, [open]);
39929
- const filteredHotkeys = useMemo41(() => {
39970
+ const filteredHotkeys = useMemo40(() => {
39930
39971
  const normalizedQuery = query.trim().toLowerCase();
39931
39972
  if (!normalizedQuery) {
39932
39973
  return hotkeys;
@@ -41153,10 +41194,10 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
41153
41194
  import {
41154
41195
  GLTFExporter as GLTFExporter3
41155
41196
  } from "three/examples/jsm/exporters/GLTFExporter.js";
41156
- import { useEffect as useEffect58, useState as useState47, useMemo as useMemo42, useCallback as useCallback26 } from "react";
41197
+ import { useEffect as useEffect58, useState as useState47, useMemo as useMemo41, useCallback as useCallback26 } from "react";
41157
41198
  function useSaveGltfAs(options = {}) {
41158
41199
  const parse2 = useParser(options);
41159
- const link = useMemo42(() => document.createElement("a"), []);
41200
+ const link = useMemo41(() => document.createElement("a"), []);
41160
41201
  const saveAs = async (filename) => {
41161
41202
  const name = filename ?? options.filename ?? "";
41162
41203
  if (options.binary == null) options.binary = name.endsWith(".glb");
@@ -41191,7 +41232,7 @@ function useExportGltfUrl(options = {}) {
41191
41232
  return [ref, url, error];
41192
41233
  }
41193
41234
  function useParser(options = {}) {
41194
- const exporter = useMemo42(() => new GLTFExporter3(), []);
41235
+ const exporter = useMemo41(() => new GLTFExporter3(), []);
41195
41236
  return (instance) => {
41196
41237
  const { promise, resolve, reject } = Promise.withResolvers();
41197
41238
  exporter.parse(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.641",
3
+ "version": "0.0.643",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/tscircuit/3d-viewer"