@tscircuit/3d-viewer 0.0.605 → 0.0.607

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.
Files changed (2) hide show
  1. package/dist/index.js +54 -50
  2. package/package.json +6 -4
package/dist/index.js CHANGED
@@ -39224,7 +39224,7 @@ import * as THREE23 from "three";
39224
39224
  // package.json
39225
39225
  var package_default = {
39226
39226
  name: "@tscircuit/3d-viewer",
39227
- version: "0.0.604",
39227
+ version: "0.0.606",
39228
39228
  repository: {
39229
39229
  type: "git",
39230
39230
  url: "https://github.com/tscircuit/3d-viewer"
@@ -39270,7 +39270,7 @@ var package_default = {
39270
39270
  "troika-three-text": "^0.52.4"
39271
39271
  },
39272
39272
  peerDependencies: {
39273
- zod: "3",
39273
+ zod: "*",
39274
39274
  react: "19.1.0",
39275
39275
  "react-dom": "19.1.0",
39276
39276
  "@tscircuit/core": "*",
@@ -39289,7 +39289,7 @@ var package_default = {
39289
39289
  "@tscircuit/alphabet": "^0.0.25",
39290
39290
  "@tscircuit/circuit-json-util": "^0.0.116",
39291
39291
  "@tscircuit/copper-pour-solver": "^0.0.29",
39292
- "@tscircuit/core": "^0.0.1964",
39292
+ "@tscircuit/core": "^0.0.1972",
39293
39293
  "@tscircuit/props": "^0.0.666",
39294
39294
  "@tscircuit/solver-utils": "^0.0.4",
39295
39295
  "@types/jsdom": "^21.1.7",
@@ -39312,7 +39312,9 @@ var package_default = {
39312
39312
  typescript: "^5.7.3",
39313
39313
  vite: "^7.1.5",
39314
39314
  "vite-tsconfig-paths": "^4.3.2",
39315
- "circuit-json-to-gltf": "0.0.129"
39315
+ "circuit-json-to-gltf": "0.0.129",
39316
+ modelprinter: "https://jscdn.tscircuit.com/@tscircuit/modelprinter/0.0.4.tgz",
39317
+ zod: "^3.25.67"
39316
39318
  },
39317
39319
  patchedDependencies: {
39318
39320
  "@tscircuit/fanout-solver@0.0.78": "patches/@tscircuit%2Ffanout-solver@0.0.78.patch"
@@ -39872,16 +39874,23 @@ var Canvas = forwardRef(
39872
39874
  onCreatedRef.current?.({ camera, renderer });
39873
39875
  let animationFrameId;
39874
39876
  const clock = new THREE16.Clock();
39877
+ let isVisible = true;
39878
+ const visibilityObserver = new IntersectionObserver(([entry]) => {
39879
+ isVisible = entry?.isIntersecting ?? false;
39880
+ if (isVisible) handleResize();
39881
+ });
39882
+ visibilityObserver.observe(mountRef.current);
39875
39883
  const animate = () => {
39884
+ animationFrameId = requestAnimationFrame(animate);
39885
+ if (!isVisible) return;
39876
39886
  const time = clock.getElapsedTime();
39877
39887
  const delta = clock.getDelta();
39878
39888
  frameListeners.current.forEach((listener) => listener(time, delta));
39879
39889
  renderer.render(scene, camera);
39880
- animationFrameId = requestAnimationFrame(animate);
39881
39890
  };
39882
39891
  animate();
39883
39892
  const handleResize = () => {
39884
- if (mountRef.current) {
39893
+ if (mountRef.current?.clientWidth && mountRef.current.clientHeight) {
39885
39894
  const newAspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
39886
39895
  if (camera instanceof THREE16.PerspectiveCamera) {
39887
39896
  camera.aspect = newAspect;
@@ -39907,6 +39916,7 @@ var Canvas = forwardRef(
39907
39916
  };
39908
39917
  window.removeEventListener("resize", handleResize);
39909
39918
  cancelAnimationFrame(animationFrameId);
39919
+ visibilityObserver.disconnect();
39910
39920
  if (mountRef.current && renderer.domElement) {
39911
39921
  mountRef.current.removeChild(renderer.domElement);
39912
39922
  }
@@ -40404,7 +40414,14 @@ var OrientationCubeCanvas = () => {
40404
40414
  group.add(topText);
40405
40415
  group.add(bottomText);
40406
40416
  let animationFrameId = null;
40417
+ let isVisible = true;
40418
+ const visibilityObserver = new IntersectionObserver(([entry]) => {
40419
+ isVisible = entry?.isIntersecting ?? false;
40420
+ });
40421
+ visibilityObserver.observe(canvas);
40407
40422
  const animate = () => {
40423
+ animationFrameId = requestAnimationFrame(animate);
40424
+ if (!isVisible) return;
40408
40425
  if (mainCameraRef.current) {
40409
40426
  const cameraPosition = computePointInFront(
40410
40427
  mainCameraRef.current.rotation ?? new THREE20.Euler(0, 0, 0),
@@ -40416,10 +40433,10 @@ var OrientationCubeCanvas = () => {
40416
40433
  }
40417
40434
  }
40418
40435
  renderer.render(scene, camera);
40419
- animationFrameId = requestAnimationFrame(animate);
40420
40436
  };
40421
40437
  animate();
40422
40438
  return () => {
40439
+ visibilityObserver.disconnect();
40423
40440
  canvas.remove();
40424
40441
  if (animationFrameId !== null) {
40425
40442
  cancelAnimationFrame(animationFrameId);
@@ -44657,6 +44674,7 @@ var createDataTexture = (canvas) => {
44657
44674
  var createBoardReliefTextures = (texture, maskedCopperMask) => {
44658
44675
  const sourceCanvas = texture.image;
44659
44676
  if (!sourceCanvas?.width || !sourceCanvas.height) return null;
44677
+ const { width: canvasWidth, height: canvasHeight } = sourceCanvas;
44660
44678
  const sourceCtx = sourceCanvas.getContext("2d");
44661
44679
  if (!sourceCtx) return null;
44662
44680
  const maskCanvas = maskedCopperMask?.image;
@@ -44664,48 +44682,37 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
44664
44682
  const maskWidth = maskCanvas?.width ?? 0;
44665
44683
  const maskHeight = maskCanvas?.height ?? 0;
44666
44684
  const maskImageData = maskCtx && maskWidth && maskHeight ? maskCtx.getImageData(0, 0, maskWidth, maskHeight) : null;
44667
- const imageData = sourceCtx.getImageData(
44668
- 0,
44669
- 0,
44670
- sourceCanvas.width,
44671
- sourceCanvas.height
44672
- );
44685
+ const imageData = sourceCtx.getImageData(0, 0, canvasWidth, canvasHeight);
44673
44686
  const data = imageData.data;
44674
- const heights = new Float32Array(sourceCanvas.width * sourceCanvas.height);
44687
+ const heights = new Float32Array(canvasWidth * canvasHeight);
44675
44688
  const roughnessCanvas = document.createElement("canvas");
44676
44689
  const metalnessCanvas = document.createElement("canvas");
44677
- roughnessCanvas.width = metalnessCanvas.width = sourceCanvas.width;
44678
- roughnessCanvas.height = metalnessCanvas.height = sourceCanvas.height;
44690
+ roughnessCanvas.width = metalnessCanvas.width = canvasWidth;
44691
+ roughnessCanvas.height = metalnessCanvas.height = canvasHeight;
44679
44692
  const roughnessCtx = roughnessCanvas.getContext("2d");
44680
44693
  const metalnessCtx = metalnessCanvas.getContext("2d");
44681
44694
  if (!roughnessCtx || !metalnessCtx) return null;
44682
44695
  const roughnessImageData = roughnessCtx.createImageData(
44683
- sourceCanvas.width,
44684
- sourceCanvas.height
44696
+ canvasWidth,
44697
+ canvasHeight
44685
44698
  );
44686
44699
  const metalnessImageData = metalnessCtx.createImageData(
44687
- sourceCanvas.width,
44688
- sourceCanvas.height
44700
+ canvasWidth,
44701
+ canvasHeight
44689
44702
  );
44690
44703
  const roughnessData = roughnessImageData.data;
44691
44704
  const metalnessData = metalnessImageData.data;
44692
44705
  for (let i = 0; i < data.length; i += 4) {
44693
44706
  const pixelIndex = i / 4;
44694
- const x = pixelIndex % sourceCanvas.width;
44695
- const y = Math.floor(pixelIndex / sourceCanvas.width);
44707
+ const x = pixelIndex % canvasWidth;
44708
+ const y = Math.floor(pixelIndex / canvasWidth);
44696
44709
  const alpha = data[i + 3] ?? 0;
44697
44710
  if (alpha < 16) {
44698
44711
  heights[pixelIndex] = invertSurfaceHeight(PLAIN_SOLDERMASK_HEIGHT);
44699
44712
  continue;
44700
44713
  }
44701
- const maskX = maskImageData ? Math.min(
44702
- maskWidth - 1,
44703
- Math.floor(x / sourceCanvas.width * maskWidth)
44704
- ) : 0;
44705
- const maskY = maskImageData ? Math.min(
44706
- maskHeight - 1,
44707
- Math.floor(y / sourceCanvas.height * maskHeight)
44708
- ) : 0;
44714
+ const maskX = maskImageData ? Math.min(maskWidth - 1, Math.floor(x / canvasWidth * maskWidth)) : 0;
44715
+ const maskY = maskImageData ? Math.min(maskHeight - 1, Math.floor(y / canvasHeight * maskHeight)) : 0;
44709
44716
  const maskAlpha = maskImageData ? maskImageData.data[(maskY * maskWidth + maskX) * 4 + 3] ?? 0 : 0;
44710
44717
  const profile = getBoardSurfaceProfile(
44711
44718
  data[i] ?? 0,
@@ -44713,13 +44720,13 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
44713
44720
  data[i + 2] ?? 0,
44714
44721
  maskAlpha >= 16
44715
44722
  );
44716
- const salt = sourceCanvas.width + sourceCanvas.height;
44723
+ const salt = canvasWidth + canvasHeight;
44717
44724
  const fineGrain = profile.isExposedCopper ? createCopperDetail(x, y, salt) : profile.isMaskedCopper ? createMaskedTraceDetail(x, y, salt) : 0;
44718
- const height10 = clamp01(
44725
+ const surfaceHeight = clamp01(
44719
44726
  invertSurfaceHeight(profile.height) + fineGrain * profile.microSurfaceWeight
44720
44727
  );
44721
- heights[pixelIndex] = height10;
44722
- const heightChannel = height10 * 255;
44728
+ heights[pixelIndex] = surfaceHeight;
44729
+ const heightChannel = surfaceHeight * 255;
44723
44730
  data[i] = data[i + 1] = data[i + 2] = heightChannel;
44724
44731
  data[i + 3] = 255;
44725
44732
  const roughness = profile.isExposedCopper ? clamp01(
@@ -44737,31 +44744,28 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
44737
44744
  roughnessCtx.putImageData(roughnessImageData, 0, 0);
44738
44745
  metalnessCtx.putImageData(metalnessImageData, 0, 0);
44739
44746
  const bumpCanvas = document.createElement("canvas");
44740
- bumpCanvas.width = sourceCanvas.width;
44741
- bumpCanvas.height = sourceCanvas.height;
44747
+ bumpCanvas.width = canvasWidth;
44748
+ bumpCanvas.height = canvasHeight;
44742
44749
  const bumpCtx = bumpCanvas.getContext("2d");
44743
44750
  if (!bumpCtx) return null;
44744
44751
  bumpCtx.putImageData(imageData, 0, 0);
44745
44752
  const normalCanvas = document.createElement("canvas");
44746
- normalCanvas.width = sourceCanvas.width;
44747
- normalCanvas.height = sourceCanvas.height;
44753
+ normalCanvas.width = canvasWidth;
44754
+ normalCanvas.height = canvasHeight;
44748
44755
  const normalCtx = normalCanvas.getContext("2d");
44749
44756
  if (!normalCtx) return null;
44750
- const normalImageData = normalCtx.createImageData(
44751
- sourceCanvas.width,
44752
- sourceCanvas.height
44753
- );
44757
+ const normalImageData = normalCtx.createImageData(canvasWidth, canvasHeight);
44754
44758
  const normalData = normalImageData.data;
44755
- const getHeight4 = (x, y) => heights[Math.max(0, Math.min(sourceCanvas.height - 1, y)) * sourceCanvas.width + Math.max(0, Math.min(sourceCanvas.width - 1, x))] ?? 0;
44756
- for (let y = 0; y < sourceCanvas.height; y++) {
44757
- for (let x = 0; x < sourceCanvas.width; x++) {
44759
+ const getHeight4 = (x, y) => heights[Math.max(0, Math.min(canvasHeight - 1, y)) * canvasWidth + Math.max(0, Math.min(canvasWidth - 1, x))] ?? 0;
44760
+ for (let y = 0; y < canvasHeight; y++) {
44761
+ for (let x = 0; x < canvasWidth; x++) {
44758
44762
  const dx = (getHeight4(x + 1, y) - getHeight4(x - 1, y)) * 4;
44759
44763
  const dy = (getHeight4(x, y + 1) - getHeight4(x, y - 1)) * 4;
44760
- const normal = new THREE40.Vector3(-dx, -dy, 1).normalize();
44761
- const i = (y * sourceCanvas.width + x) * 4;
44762
- normalData[i] = (normal.x * 0.5 + 0.5) * 255;
44763
- normalData[i + 1] = (normal.y * 0.5 + 0.5) * 255;
44764
- normalData[i + 2] = (normal.z * 0.5 + 0.5) * 255;
44764
+ const inverseLength = 1 / Math.sqrt(dx * dx + dy * dy + 1);
44765
+ const i = (y * canvasWidth + x) * 4;
44766
+ normalData[i] = (-dx * inverseLength * 0.5 + 0.5) * 255;
44767
+ normalData[i + 1] = (-dy * inverseLength * 0.5 + 0.5) * 255;
44768
+ normalData[i + 2] = (inverseLength * 0.5 + 0.5) * 255;
44765
44769
  normalData[i + 3] = 255;
44766
44770
  }
44767
44771
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.605",
3
+ "version": "0.0.607",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/tscircuit/3d-viewer"
@@ -46,7 +46,7 @@
46
46
  "troika-three-text": "^0.52.4"
47
47
  },
48
48
  "peerDependencies": {
49
- "zod": "3",
49
+ "zod": "*",
50
50
  "react": "19.1.0",
51
51
  "react-dom": "19.1.0",
52
52
  "@tscircuit/core": "*",
@@ -65,7 +65,7 @@
65
65
  "@tscircuit/alphabet": "^0.0.25",
66
66
  "@tscircuit/circuit-json-util": "^0.0.116",
67
67
  "@tscircuit/copper-pour-solver": "^0.0.29",
68
- "@tscircuit/core": "^0.0.1964",
68
+ "@tscircuit/core": "^0.0.1972",
69
69
  "@tscircuit/props": "^0.0.666",
70
70
  "@tscircuit/solver-utils": "^0.0.4",
71
71
  "@types/jsdom": "^21.1.7",
@@ -88,7 +88,9 @@
88
88
  "typescript": "^5.7.3",
89
89
  "vite": "^7.1.5",
90
90
  "vite-tsconfig-paths": "^4.3.2",
91
- "circuit-json-to-gltf": "0.0.129"
91
+ "circuit-json-to-gltf": "0.0.129",
92
+ "modelprinter": "https://jscdn.tscircuit.com/@tscircuit/modelprinter/0.0.4.tgz",
93
+ "zod": "^3.25.67"
92
94
  },
93
95
  "patchedDependencies": {
94
96
  "@tscircuit/fanout-solver@0.0.78": "patches/@tscircuit%2Ffanout-solver@0.0.78.patch"