@babylonjs/inspector 8.31.1-preview → 8.31.2-preview

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/lib/index.js CHANGED
@@ -81,7 +81,7 @@ import { InstancedMesh } from '@babylonjs/core/Meshes/instancedMesh.js';
81
81
  import { RenderingManager } from '@babylonjs/core/Rendering/renderingManager.js';
82
82
  import '@babylonjs/core/Rendering/edgesRenderer.js';
83
83
  import '@babylonjs/core/Rendering/outlineRenderer.js';
84
- import { GaussianSplattingMesh } from '@babylonjs/core/Meshes.js';
84
+ import { GaussianSplattingMesh } from '@babylonjs/core/Meshes/GaussianSplatting/gaussianSplattingMesh.js';
85
85
  import { FactorGradient, Color3Gradient, ColorGradient } from '@babylonjs/core/Misc/gradients.js';
86
86
  import { GradientBlockColorStep } from '@babylonjs/core/Materials/Node/Blocks/gradientBlock.js';
87
87
  import { Attractor } from '@babylonjs/core/Particles/attractor.js';
@@ -1355,40 +1355,7 @@ const PropertiesPane = (props) => {
1355
1355
  return entity != null ? (jsx(ExtensibleAccordion, { ...props })) : (jsx("div", { className: classes.placeholderDiv, children: jsx(Body1Strong, { italic: true, children: "No entity selected." }) }));
1356
1356
  };
1357
1357
 
1358
- const SelectionServiceIdentity = Symbol("PropertiesService");
1359
- const SelectionServiceDefinition = {
1360
- friendlyName: "Selection Service",
1361
- produces: [SelectionServiceIdentity],
1362
- factory: () => {
1363
- let selectedEntityState = null;
1364
- const selectedEntityObservable = new Observable();
1365
- let disposedHook = null;
1366
- const setSelectedItem = (item) => {
1367
- if (item !== selectedEntityState) {
1368
- disposedHook?.dispose();
1369
- disposedHook = null;
1370
- selectedEntityState = item;
1371
- selectedEntityObservable.notifyObservers();
1372
- if (item) {
1373
- const disposable = item;
1374
- if (disposable.dispose) {
1375
- disposedHook = InterceptFunction(disposable, "dispose", { afterCall: () => setSelectedItem(null) });
1376
- }
1377
- }
1378
- }
1379
- };
1380
- return {
1381
- get selectedEntity() {
1382
- return selectedEntityState;
1383
- },
1384
- set selectedEntity(item) {
1385
- setSelectedItem(item);
1386
- },
1387
- onSelectedEntityChanged: selectedEntityObservable,
1388
- dispose: () => selectedEntityObservable.clear(),
1389
- };
1390
- },
1391
- };
1358
+ const SettingsContextIdentity = Symbol("SettingsContext");
1392
1359
 
1393
1360
  const ThemeModeStorageKey = `Babylon/Settings/ThemeMode`;
1394
1361
  /**
@@ -1636,7 +1603,7 @@ const SidePaneTab = (props) => {
1636
1603
  // This hook provides a side pane container and the tab list.
1637
1604
  // In "compact" mode, the tab list is integrated into the pane itself.
1638
1605
  // In "full" mode, the returned tab list is later injected into the toolbar.
1639
- function usePane(alignment, defaultWidth, minWidth, topPanes, bottomPanes, toolbarMode, topBarItems, bottomBarItems) {
1606
+ function usePane(alignment, defaultWidth, minWidth, topPanes, bottomPanes, onSelectSidePane, toolbarMode, topBarItems, bottomBarItems) {
1640
1607
  const classes = useStyles$d();
1641
1608
  const [topSelectedTab, setTopSelectedTab] = useState();
1642
1609
  const [bottomSelectedTab, setBottomSelectedTab] = useState();
@@ -1648,6 +1615,7 @@ function usePane(alignment, defaultWidth, minWidth, topPanes, bottomPanes, toolb
1648
1615
  const heightStorageKey = `Babylon/Settings/${alignment}Pane/HeightAdjust`;
1649
1616
  const [width, setWidth] = useState(Number.parseInt(localStorage.getItem(widthStorageKey) ?? "") || Math.max(defaultWidth, minWidth));
1650
1617
  const [resizing, setResizing] = useState(false);
1618
+ // Selects a default top tab (during initialization or if the selected tab is removed).
1651
1619
  useEffect(() => {
1652
1620
  if ((topSelectedTab && !topPanes.includes(topSelectedTab)) || (!topSelectedTab && topPanes.length > 0)) {
1653
1621
  setTopSelectedTab(topPanes[0]);
@@ -1656,6 +1624,7 @@ function usePane(alignment, defaultWidth, minWidth, topPanes, bottomPanes, toolb
1656
1624
  setTopSelectedTab(undefined);
1657
1625
  }
1658
1626
  }, [topSelectedTab, topPanes]);
1627
+ // Selects a default bottom tab (during initialization or if the selected tab is removed).
1659
1628
  useEffect(() => {
1660
1629
  if ((bottomSelectedTab && !bottomPanes.includes(bottomSelectedTab)) || (!bottomSelectedTab && bottomPanes.length > 0)) {
1661
1630
  setBottomSelectedTab(bottomPanes[0]);
@@ -1664,6 +1633,22 @@ function usePane(alignment, defaultWidth, minWidth, topPanes, bottomPanes, toolb
1664
1633
  setBottomSelectedTab(undefined);
1665
1634
  }
1666
1635
  }, [bottomSelectedTab, bottomPanes]);
1636
+ // Selects a tab when explicitly requested.
1637
+ useEffect(() => {
1638
+ const observer = onSelectSidePane.add((key) => {
1639
+ const topPane = topPanes.find((entry) => entry.key === key);
1640
+ if (topPane) {
1641
+ setTopSelectedTab(topPane);
1642
+ setCollapsed(false);
1643
+ }
1644
+ const bottomPane = bottomPanes.find((entry) => entry.key === key);
1645
+ if (bottomPane) {
1646
+ setBottomSelectedTab(bottomPane);
1647
+ setCollapsed(false);
1648
+ }
1649
+ });
1650
+ return () => observer.remove();
1651
+ }, [topPanes, bottomPanes, onSelectSidePane]);
1667
1652
  const expandCollapseIcon = useMemo(() => {
1668
1653
  if (alignment === "left") {
1669
1654
  return collapsed ? jsx(PanelLeftExpandRegular, {}) : jsx(PanelLeftContractRegular, {});
@@ -1751,6 +1736,7 @@ function MakeShellServiceDefinition({ leftPaneDefaultWidth = 350, leftPaneMinWid
1751
1736
  const bottomLeftPaneCollection = new ObservableCollection();
1752
1737
  const bottomRightPaneCollection = new ObservableCollection();
1753
1738
  const centralContentCollection = new ObservableCollection();
1739
+ const onSelectSidePane = new Observable();
1754
1740
  const rootComponent = () => {
1755
1741
  const classes = useStyles$d();
1756
1742
  const topBarItems = useOrderedObservableCollection(topBarItemCollection);
@@ -1781,8 +1767,8 @@ function MakeShellServiceDefinition({ leftPaneDefaultWidth = 350, leftPaneMinWid
1781
1767
  const bottomBarLeftItems = useMemo(() => bottomBarItems.filter((entry) => coerceToolBarItemHorizontalLocation(entry) === "left"), [bottomBarItems]);
1782
1768
  const bottomBarRightItems = useMemo(() => bottomBarItems.filter((entry) => coerceToolBarItemHorizontalLocation(entry) === "right"), [bottomBarItems]);
1783
1769
  const centralContents = useOrderedObservableCollection(centralContentCollection);
1784
- const [leftPaneTabList, leftPane] = usePane("left", leftPaneDefaultWidth, leftPaneMinWidth, topLeftPanes, bottomLeftPanes, toolbarMode, topBarLeftItems, bottomBarLeftItems);
1785
- const [rightPaneTabList, rightPane] = usePane("right", rightPaneDefaultWidth, rightPaneMinWidth, topRightPanes, bottomRightPanes, toolbarMode, topBarRightItems, bottomBarRightItems);
1770
+ const [leftPaneTabList, leftPane] = usePane("left", leftPaneDefaultWidth, leftPaneMinWidth, topLeftPanes, bottomLeftPanes, onSelectSidePane, toolbarMode, topBarLeftItems, bottomBarLeftItems);
1771
+ const [rightPaneTabList, rightPane] = usePane("right", rightPaneDefaultWidth, rightPaneMinWidth, topRightPanes, bottomRightPanes, onSelectSidePane, toolbarMode, topBarRightItems, bottomBarRightItems);
1786
1772
  return (jsxs("div", { className: classes.mainView, children: [toolbarMode === "full" && (jsx(Fragment, { children: jsxs("div", { className: classes.barDiv, children: [leftPaneTabList, jsx(Toolbar, { location: "top", components: topBarItems }), rightPaneTabList] }) })), jsxs("div", { className: classes.verticallyCentralContent, children: [leftPane, jsx("div", { className: classes.centralContent, children: centralContents.map((entry) => (jsx(entry.component, {}, entry.key))) }), rightPane] }), toolbarMode === "full" && (jsx(Fragment, { children: jsx("div", { className: classes.barDiv, children: jsx(Toolbar, { location: "bottom", components: bottomBarItems }) }) }))] }));
1787
1773
  };
1788
1774
  rootComponent.displayName = "Shell Service Root";
@@ -1837,12 +1823,60 @@ function MakeShellServiceDefinition({ leftPaneDefaultWidth = 350, leftPaneMinWid
1837
1823
  }
1838
1824
  },
1839
1825
  addCentralContent: (entry) => centralContentCollection.add(entry),
1826
+ get sidePanes() {
1827
+ return [...topLeftPaneCollection.items, ...bottomLeftPaneCollection.items, ...topRightPaneCollection.items, ...bottomRightPaneCollection.items].map((sidePaneDefinition) => {
1828
+ return {
1829
+ key: sidePaneDefinition.key,
1830
+ select: () => onSelectSidePane.notifyObservers(sidePaneDefinition.key),
1831
+ };
1832
+ });
1833
+ },
1840
1834
  rootComponent,
1841
1835
  };
1842
1836
  },
1843
1837
  };
1844
1838
  }
1845
1839
 
1840
+ const SelectionServiceIdentity = Symbol("PropertiesService");
1841
+ const SelectionServiceDefinition = {
1842
+ friendlyName: "Selection Service",
1843
+ produces: [SelectionServiceIdentity],
1844
+ consumes: [ShellServiceIdentity, SettingsContextIdentity],
1845
+ factory: (shellService, settingsContext) => {
1846
+ let selectedEntityState = null;
1847
+ const selectedEntityObservable = new Observable();
1848
+ let disposedHook = null;
1849
+ const setSelectedItem = (item) => {
1850
+ if (item !== selectedEntityState) {
1851
+ disposedHook?.dispose();
1852
+ disposedHook = null;
1853
+ selectedEntityState = item;
1854
+ selectedEntityObservable.notifyObservers();
1855
+ if (item) {
1856
+ const disposable = item;
1857
+ if (disposable.dispose) {
1858
+ disposedHook = InterceptFunction(disposable, "dispose", { afterCall: () => setSelectedItem(null) });
1859
+ }
1860
+ }
1861
+ // Automatically open the properties pane when an entity is selected.
1862
+ if (item && settingsContext.showPropertiesOnEntitySelection) {
1863
+ shellService.sidePanes.find((pane) => pane.key === "Properties")?.select();
1864
+ }
1865
+ }
1866
+ };
1867
+ return {
1868
+ get selectedEntity() {
1869
+ return selectedEntityState;
1870
+ },
1871
+ set selectedEntity(item) {
1872
+ setSelectedItem(item);
1873
+ },
1874
+ onSelectedEntityChanged: selectedEntityObservable,
1875
+ dispose: () => selectedEntityObservable.clear(),
1876
+ };
1877
+ },
1878
+ };
1879
+
1846
1880
  const PropertiesServiceIdentity = Symbol("PropertiesService");
1847
1881
  /**
1848
1882
  * Provides a properties pane that enables displaying and editing properties of an entity such as a mesh or a texture.
@@ -2625,8 +2659,6 @@ const DebugServiceDefinition = {
2625
2659
  },
2626
2660
  };
2627
2661
 
2628
- const SettingsContextIdentity = Symbol("SettingsContext");
2629
-
2630
2662
  const SettingsServiceIdentity = Symbol("SettingsService");
2631
2663
  const SettingsServiceDefinition = {
2632
2664
  friendlyName: "Settings",
@@ -2635,8 +2667,9 @@ const SettingsServiceDefinition = {
2635
2667
  factory: (shellService, sceneContext) => {
2636
2668
  const sectionsCollection = new ObservableCollection();
2637
2669
  const sectionContentCollection = new ObservableCollection();
2638
- let useDegrees = DataStorage.ReadBoolean("settings_useDegrees", false);
2639
- let ignoreBackfacesForPicking = DataStorage.ReadBoolean("settings_ignoreBackfacesForPicking", false);
2670
+ let useDegrees = DataStorage.ReadBoolean("Babylon/Settings/UseDegrees", false);
2671
+ let ignoreBackfacesForPicking = DataStorage.ReadBoolean("Babylon/Settings/IgnoreBackfacesForPicking", false);
2672
+ let showPropertiesOnEntitySelection = DataStorage.ReadBoolean("Babylon/Settings/ShowPropertiesOnEntitySelection", true);
2640
2673
  const settings = {
2641
2674
  get useDegrees() {
2642
2675
  return useDegrees;
@@ -2646,7 +2679,7 @@ const SettingsServiceDefinition = {
2646
2679
  return; // No change, no need to notify
2647
2680
  }
2648
2681
  useDegrees = value;
2649
- DataStorage.WriteBoolean("settings_useDegrees", useDegrees);
2682
+ DataStorage.WriteBoolean("Babylon/Settings/UseDegrees", useDegrees);
2650
2683
  this.settingsChangedObservable.notifyObservers(this);
2651
2684
  },
2652
2685
  get ignoreBackfacesForPicking() {
@@ -2657,7 +2690,18 @@ const SettingsServiceDefinition = {
2657
2690
  return; // No change, no need to notify
2658
2691
  }
2659
2692
  ignoreBackfacesForPicking = value;
2660
- DataStorage.WriteBoolean("settings_ignoreBackfacesForPicking", ignoreBackfacesForPicking);
2693
+ DataStorage.WriteBoolean("Babylon/Settings/IgnoreBackfacesForPicking", ignoreBackfacesForPicking);
2694
+ this.settingsChangedObservable.notifyObservers(this);
2695
+ },
2696
+ get showPropertiesOnEntitySelection() {
2697
+ return showPropertiesOnEntitySelection;
2698
+ },
2699
+ set showPropertiesOnEntitySelection(value) {
2700
+ if (showPropertiesOnEntitySelection === value) {
2701
+ return; // No change, no need to notify
2702
+ }
2703
+ showPropertiesOnEntitySelection = value;
2704
+ DataStorage.WriteBoolean("Babylon/Settings/ShowPropertiesOnEntitySelection", showPropertiesOnEntitySelection);
2661
2705
  this.settingsChangedObservable.notifyObservers(this);
2662
2706
  },
2663
2707
  settingsChangedObservable: new Observable(),
@@ -2681,6 +2725,8 @@ const SettingsServiceDefinition = {
2681
2725
  settings.useDegrees = checked;
2682
2726
  } }), jsx(SwitchPropertyLine, { label: "Ignore Backfaces for Picking", description: "Ignore backfaces when picking.", value: settings.ignoreBackfacesForPicking, onChange: (checked) => {
2683
2727
  settings.ignoreBackfacesForPicking = checked;
2728
+ } }), jsx(SwitchPropertyLine, { label: "Show Properties on Selection", description: "Shows the Properties pane when an entity is selected.", value: settings.showPropertiesOnEntitySelection, onChange: (checked) => {
2729
+ settings.showPropertiesOnEntitySelection = checked;
2684
2730
  } })] }) })) }));
2685
2731
  },
2686
2732
  });
@@ -2720,7 +2766,7 @@ const CountStats = ({ context: scene }) => {
2720
2766
  const totalVertices = useObservableState(() => scene.getTotalVertices(), pollingObservable);
2721
2767
  const totalMaterials = useObservableState(() => scene.materials.length, pollingObservable);
2722
2768
  const totalTextures = useObservableState(() => scene.textures.length, pollingObservable);
2723
- return (jsxs(Fragment, { children: [jsx(StringifiedPropertyLine, { label: "Total Meshes", value: totalMeshes }, "TotalMeshes"), jsx(StringifiedPropertyLine, { label: "Active Meshes", value: activeMeshes }, "ActiveMeshes"), jsx(StringifiedPropertyLine, { label: "Active Indeces", value: activeIndices }, "ActiveIndices"), jsx(StringifiedPropertyLine, { label: "Active Faces", value: activeIndices / 3 }, "ActiveFaces"), jsx(StringifiedPropertyLine, { label: "Active Bones", value: activeBones }, "ActiveBones"), jsx(StringifiedPropertyLine, { label: "Active Particles", value: activeParticles }, "ActiveParticles"), jsx(StringifiedPropertyLine, { label: "Draw Calls", value: drawCalls }, "DrawCalls"), jsx(StringifiedPropertyLine, { label: "Total Lights", value: totalLights }, "TotalLights"), jsx(StringifiedPropertyLine, { label: "Total Vertices", value: totalVertices }, "TotalVertices"), jsx(StringifiedPropertyLine, { label: "Total Materials", value: totalMaterials }, "TotalMaterials"), jsx(StringifiedPropertyLine, { label: "Total Textures", value: totalTextures }, "TotalTextures")] }));
2769
+ return (jsxs(Fragment, { children: [jsx(StringifiedPropertyLine, { label: "Total Meshes", value: totalMeshes }, "TotalMeshes"), jsx(StringifiedPropertyLine, { label: "Active Meshes", value: activeMeshes }, "ActiveMeshes"), jsx(StringifiedPropertyLine, { label: "Active Indices", value: activeIndices }, "ActiveIndices"), jsx(StringifiedPropertyLine, { label: "Active Faces", value: activeIndices / 3 }, "ActiveFaces"), jsx(StringifiedPropertyLine, { label: "Active Bones", value: activeBones }, "ActiveBones"), jsx(StringifiedPropertyLine, { label: "Active Particles", value: activeParticles }, "ActiveParticles"), jsx(StringifiedPropertyLine, { label: "Draw Calls", value: drawCalls }, "DrawCalls"), jsx(StringifiedPropertyLine, { label: "Total Lights", value: totalLights }, "TotalLights"), jsx(StringifiedPropertyLine, { label: "Total Vertices", value: totalVertices }, "TotalVertices"), jsx(StringifiedPropertyLine, { label: "Total Materials", value: totalMaterials }, "TotalMaterials"), jsx(StringifiedPropertyLine, { label: "Total Textures", value: totalTextures }, "TotalTextures")] }));
2724
2770
  };
2725
2771
 
2726
2772
  const FrameStepsStats = ({ context: scene }) => {
@@ -3073,19 +3119,19 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
3073
3119
  name: "Export Tools",
3074
3120
  description: "Adds new features to enable exporting Babylon assets such as .gltf, .glb, .babylon, and more.",
3075
3121
  keywords: ["export", "gltf", "glb", "babylon", "exporter", "tools"],
3076
- getExtensionModuleAsync: async () => await import('./exportService-CFGdt7eg.js'),
3122
+ getExtensionModuleAsync: async () => await import('./exportService-o9GjRLQl.js'),
3077
3123
  },
3078
3124
  {
3079
3125
  name: "Capture Tools",
3080
3126
  description: "Adds new features to enable capturing screenshots, GIFs, videos, and more.",
3081
3127
  keywords: ["capture", "screenshot", "gif", "video", "tools"],
3082
- getExtensionModuleAsync: async () => await import('./captureService-EFE-C_G5.js'),
3128
+ getExtensionModuleAsync: async () => await import('./captureService-BF3GdnfS.js'),
3083
3129
  },
3084
3130
  {
3085
3131
  name: "Import Tools",
3086
3132
  description: "Adds new features related to importing Babylon assets.",
3087
3133
  keywords: ["import", "tools"],
3088
- getExtensionModuleAsync: async () => await import('./importService-DEy_vKyx.js'),
3134
+ getExtensionModuleAsync: async () => await import('./importService-CLU6o05K.js'),
3089
3135
  },
3090
3136
  ]);
3091
3137
 
@@ -4111,7 +4157,7 @@ const SpinButton = (props) => {
4111
4157
  const lastCommittedValue = useRef(props.value);
4112
4158
  // step and forceInt are not mutually exclusive since there could be cases where you want to forceInt but have spinButton jump >1 int per spin
4113
4159
  const step = props.step != undefined ? props.step : props.forceInt ? 1 : undefined;
4114
- const precision = Math.min(4, step !== undefined ? CalculatePrecision(step) : 2); // If no step, set precision to 2. Regardless, cap precision at 4 to avoid wild numbers
4160
+ const precision = Math.min(4, step !== undefined ? Math.max(0, CalculatePrecision(step)) : 2); // If no step, set precision to 2. Regardless, cap precision at 4 to avoid wild numbers
4115
4161
  useEffect(() => {
4116
4162
  if (props.value !== lastCommittedValue.current) {
4117
4163
  lastCommittedValue.current = props.value;
@@ -4431,7 +4477,7 @@ const HasW = (vector) => vector instanceof Vector4 || vector instanceof Quaterni
4431
4477
  const TensorPropertyLine = (props) => {
4432
4478
  TensorPropertyLine.displayName = "TensorPropertyLine";
4433
4479
  const converted = (val) => (props.valueConverter ? props.valueConverter.from(val) : val);
4434
- const formatted = (val) => converted(val).toFixed(props.step !== undefined ? CalculatePrecision(props.step) : 2);
4480
+ const formatted = (val) => converted(val).toFixed(props.step !== undefined ? Math.max(0, CalculatePrecision(props.step)) : 2);
4435
4481
  const [vector, setVector] = useState(props.value);
4436
4482
  const { min, max } = props;
4437
4483
  const onChange = (val, key) => {
@@ -8644,7 +8690,7 @@ const UserFeedbackServiceDefinition = {
8644
8690
  horizontalLocation: "right",
8645
8691
  suppressTeachingMoment: true,
8646
8692
  component: () => {
8647
- return (jsx(Button, { appearance: "subtle", icon: PersonFeedbackRegular, title: "Give Feedback on Inspector v2", onClick: () => window.open("https://forum.babylonjs.com/", "_blank") }));
8693
+ return (jsx(Button, { appearance: "subtle", icon: PersonFeedbackRegular, title: "Give Feedback on Inspector v2", onClick: () => window.open("https://forum.babylonjs.com/t/introducing-inspector-v2/60937", "_blank") }));
8648
8694
  },
8649
8695
  });
8650
8696
  },