@tscircuit/3d-viewer 0.0.573 → 0.0.574

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 +90 -36
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -32429,7 +32429,7 @@ import * as THREE21 from "three";
32429
32429
  // package.json
32430
32430
  var package_default = {
32431
32431
  name: "@tscircuit/3d-viewer",
32432
- version: "0.0.572",
32432
+ version: "0.0.573",
32433
32433
  main: "./dist/index.js",
32434
32434
  module: "./dist/index.js",
32435
32435
  type: "module",
@@ -33076,6 +33076,7 @@ var Lights = ({
33076
33076
  );
33077
33077
  const shadowHalfSize = largestBoardDimension * 0.8;
33078
33078
  const lightDistance = largestBoardDimension;
33079
+ const keyLightDistance = largestBoardDimension * 8.3;
33079
33080
  const ambientLight = new THREE18.AmbientLight(16777215, 0.18);
33080
33081
  ambientLight.name = "cad-viewer-soft-ambient";
33081
33082
  rig.add(ambientLight);
@@ -33103,7 +33104,10 @@ var Lights = ({
33103
33104
  shadowCamera.top = shadowHalfSize;
33104
33105
  shadowCamera.bottom = -shadowHalfSize;
33105
33106
  shadowCamera.near = 0.5;
33106
- shadowCamera.far = largestBoardDimension * 4;
33107
+ shadowCamera.far = Math.max(
33108
+ largestBoardDimension * 4,
33109
+ Math.hypot(...position) + largestBoardDimension * 2
33110
+ );
33107
33111
  shadowCamera.updateProjectionMatrix();
33108
33112
  }
33109
33113
  rig.add(light);
@@ -33111,9 +33115,13 @@ var Lights = ({
33111
33115
  };
33112
33116
  addDirectionalLight(
33113
33117
  "cad-viewer-key-light",
33114
- 16773343,
33118
+ 16777215,
33115
33119
  2.4,
33116
- [lightDistance * 0.22, -lightDistance * 0.28, lightDistance * 1.15],
33120
+ [
33121
+ keyLightDistance * 0.22,
33122
+ -keyLightDistance * 0.28,
33123
+ keyLightDistance * 1.15
33124
+ ],
33117
33125
  shadowsEnabled
33118
33126
  );
33119
33127
  addDirectionalLight("cad-viewer-fill-light", 14543103, 0.7, [
@@ -33290,29 +33298,45 @@ import {
33290
33298
  } from "react";
33291
33299
  import { jsx as jsx13 } from "react/jsx-runtime";
33292
33300
  var STORAGE_KEY = "cadViewerRenderingMode";
33301
+ var LIGHTING_STORAGE_KEY = "cadViewerLightingEnabled";
33293
33302
  var readStoredRenderingMode = () => {
33294
33303
  if (typeof window === "undefined") return "engineering";
33295
33304
  const stored = window.localStorage.getItem(STORAGE_KEY);
33296
33305
  return stored === "realistic" || stored === "engineering" ? stored : "engineering";
33297
33306
  };
33307
+ var readStoredLightingEnabled = () => {
33308
+ if (typeof window === "undefined") return true;
33309
+ return window.localStorage.getItem(LIGHTING_STORAGE_KEY) !== "false";
33310
+ };
33298
33311
  var RenderingModeContext = createContext5(void 0);
33299
33312
  var RenderingModeProvider = ({ children }) => {
33300
33313
  const [renderingMode, setRenderingModeState] = useState10(
33301
33314
  readStoredRenderingMode
33302
33315
  );
33316
+ const [lightingEnabled, setLightingEnabled] = useState10(
33317
+ readStoredLightingEnabled
33318
+ );
33303
33319
  const setRenderingMode = useCallback7((mode) => {
33304
33320
  setRenderingModeState(mode);
33305
33321
  }, []);
33306
33322
  useEffect17(() => {
33307
33323
  window.localStorage.setItem(STORAGE_KEY, renderingMode);
33308
33324
  }, [renderingMode]);
33325
+ useEffect17(() => {
33326
+ window.localStorage.setItem(
33327
+ LIGHTING_STORAGE_KEY,
33328
+ lightingEnabled ? "true" : "false"
33329
+ );
33330
+ }, [lightingEnabled]);
33309
33331
  const value = useMemo14(
33310
33332
  () => ({
33311
33333
  renderingMode,
33312
33334
  setRenderingMode,
33313
- shadowsEnabled: renderingMode === "realistic"
33335
+ lightingEnabled,
33336
+ setLightingEnabled,
33337
+ shadowsEnabled: lightingEnabled && renderingMode === "realistic"
33314
33338
  }),
33315
- [renderingMode, setRenderingMode]
33339
+ [lightingEnabled, renderingMode, setRenderingMode]
33316
33340
  );
33317
33341
  return /* @__PURE__ */ jsx13(RenderingModeContext.Provider, { value, children });
33318
33342
  };
@@ -36829,10 +36853,57 @@ var toRgb3 = (colorArr) => {
36829
36853
  b * 255
36830
36854
  )})`;
36831
36855
  };
36856
+ var clampChannel = (value) => Math.max(0, Math.min(255, value));
36857
+ var applySoldermaskSurfaceFilter = (ctx, width10, height10, options = {}) => {
36858
+ const imageData = ctx.getImageData(0, 0, width10, height10);
36859
+ const data = imageData.data;
36860
+ const maxX = Math.max(width10 - 1, 1);
36861
+ const maxY = Math.max(height10 - 1, 1);
36862
+ for (let i = 0; i < data.length; i += 4) {
36863
+ const alpha = data[i + 3] ?? 0;
36864
+ if (alpha < 16) continue;
36865
+ const r = data[i] ?? 0;
36866
+ const g = data[i + 1] ?? 0;
36867
+ const b = data[i + 2] ?? 0;
36868
+ const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
36869
+ const isDarkGreen = g > r * 1.35 && g > b * 1.15 && luminance < 90 && r < 80 && b < 80;
36870
+ if (!isDarkGreen) continue;
36871
+ const pixelIndex = i / 4;
36872
+ const x = pixelIndex % width10;
36873
+ const y = Math.floor(pixelIndex / width10);
36874
+ const u = x / maxX;
36875
+ const v = y / maxY;
36876
+ const diagonalLight = u * 0.62 + (1 - v) * 0.38;
36877
+ const broadVariation = Math.sin((u * 1.15 + v * 0.35) * Math.PI) * 0.04;
36878
+ const lightFactor = 0.74 + diagonalLight * 0.18 + broadVariation;
36879
+ const whiteReflection = options.includeReflection ? (() => {
36880
+ const reflectionX = 0.36;
36881
+ const reflectionY = 0.22;
36882
+ const dx = u - reflectionX;
36883
+ const dy = v - reflectionY;
36884
+ const radialFalloff = Math.max(0, 1 - Math.hypot(dx, dy) / 0.38);
36885
+ return radialFalloff * radialFalloff * 0.07;
36886
+ })() : 0;
36887
+ const filteredR = (r * 0.9 + 3) * lightFactor;
36888
+ const filteredG = (g * 1.08 + 15) * lightFactor;
36889
+ const filteredB = (b * 1.28 + 13) * lightFactor;
36890
+ data[i] = clampChannel(
36891
+ filteredR * (1 - whiteReflection) + 255 * whiteReflection
36892
+ );
36893
+ data[i + 1] = clampChannel(
36894
+ filteredG * (1 - whiteReflection) + 255 * whiteReflection
36895
+ );
36896
+ data[i + 2] = clampChannel(
36897
+ filteredB * (1 - whiteReflection) + 255 * whiteReflection
36898
+ );
36899
+ }
36900
+ ctx.putImageData(imageData, 0, 0);
36901
+ };
36832
36902
  var createCombinedTexture = ({
36833
36903
  textures,
36834
36904
  boardData,
36835
- traceTextureResolution
36905
+ traceTextureResolution,
36906
+ layer
36836
36907
  }) => {
36837
36908
  const hasImage = textures.some((texture) => texture?.image);
36838
36909
  if (!hasImage) return null;
@@ -36854,6 +36925,9 @@ var createCombinedTexture = ({
36854
36925
  const image = texture.image;
36855
36926
  ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight);
36856
36927
  });
36928
+ applySoldermaskSurfaceFilter(ctx, canvasWidth, canvasHeight, {
36929
+ includeReflection: layer === "top"
36930
+ });
36857
36931
  const combinedTexture = new THREE35.CanvasTexture(canvas);
36858
36932
  combinedTexture.generateMipmaps = false;
36859
36933
  combinedTexture.minFilter = THREE35.LinearFilter;
@@ -36966,7 +37040,8 @@ function createCombinedBoardTextures({
36966
37040
  keepoutTexture
36967
37041
  ],
36968
37042
  boardData,
36969
- traceTextureResolution
37043
+ traceTextureResolution,
37044
+ layer
36970
37045
  });
36971
37046
  };
36972
37047
  const numLayers = boardData.num_layers ?? 2;
@@ -45421,7 +45496,7 @@ var iconContainerStyles = {
45421
45496
  };
45422
45497
  var AppearanceMenu = () => {
45423
45498
  const { visibility, setLayerVisibility } = useLayerVisibility();
45424
- const { renderingMode, setRenderingMode } = useRenderingMode();
45499
+ const { lightingEnabled, setLightingEnabled } = useRenderingMode();
45425
45500
  const [appearanceSubOpen, setAppearanceSubOpen] = useState35(false);
45426
45501
  const [hoveredItem, setHoveredItem] = useState35(null);
45427
45502
  return /* @__PURE__ */ jsxs8(Fragment11, { children: [
@@ -45467,40 +45542,19 @@ var AppearanceMenu = () => {
45467
45542
  {
45468
45543
  style: {
45469
45544
  ...itemStyles,
45470
- backgroundColor: hoveredItem === "engineeringMode" ? "#404040" : "transparent"
45471
- },
45472
- onSelect: (e) => e.preventDefault(),
45473
- onPointerDown: (e) => {
45474
- e.preventDefault();
45475
- setRenderingMode("engineering");
45476
- },
45477
- onMouseEnter: () => setHoveredItem("engineeringMode"),
45478
- onMouseLeave: () => setHoveredItem(null),
45479
- onTouchStart: () => setHoveredItem("engineeringMode"),
45480
- children: [
45481
- /* @__PURE__ */ jsx35("span", { style: iconContainerStyles, children: renderingMode === "engineering" && /* @__PURE__ */ jsx35(CheckIcon, {}) }),
45482
- /* @__PURE__ */ jsx35("span", { style: { display: "flex", alignItems: "center" }, children: "Engineering Mode" })
45483
- ]
45484
- }
45485
- ),
45486
- /* @__PURE__ */ jsxs8(
45487
- Item22,
45488
- {
45489
- style: {
45490
- ...itemStyles,
45491
- backgroundColor: hoveredItem === "realisticMode" ? "#404040" : "transparent"
45545
+ backgroundColor: hoveredItem === "lighting" ? "#404040" : "transparent"
45492
45546
  },
45493
45547
  onSelect: (e) => e.preventDefault(),
45494
45548
  onPointerDown: (e) => {
45495
45549
  e.preventDefault();
45496
- setRenderingMode("realistic");
45550
+ setLightingEnabled(!lightingEnabled);
45497
45551
  },
45498
- onMouseEnter: () => setHoveredItem("realisticMode"),
45552
+ onMouseEnter: () => setHoveredItem("lighting"),
45499
45553
  onMouseLeave: () => setHoveredItem(null),
45500
- onTouchStart: () => setHoveredItem("realisticMode"),
45554
+ onTouchStart: () => setHoveredItem("lighting"),
45501
45555
  children: [
45502
- /* @__PURE__ */ jsx35("span", { style: iconContainerStyles, children: renderingMode === "realistic" && /* @__PURE__ */ jsx35(CheckIcon, {}) }),
45503
- /* @__PURE__ */ jsx35("span", { style: { display: "flex", alignItems: "center" }, children: "Lighting Mode" })
45556
+ /* @__PURE__ */ jsx35("span", { style: iconContainerStyles, children: lightingEnabled && /* @__PURE__ */ jsx35(CheckIcon, {}) }),
45557
+ /* @__PURE__ */ jsx35("span", { style: { display: "flex", alignItems: "center" }, children: "Lighting" })
45504
45558
  ]
45505
45559
  }
45506
45560
  ),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/3d-viewer",
3
- "version": "0.0.573",
3
+ "version": "0.0.574",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.js",
6
6
  "type": "module",