@babylonjs/inspector 8.52.1 → 8.53.1

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.
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { createContext, forwardRef, useContext, useState, useCallback, Component, useMemo, useEffect, useRef, useReducer, Children, isValidElement, useLayoutEffect, cloneElement, useImperativeHandle, createElement, Suspense, memo, Fragment as Fragment$1, lazy } from 'react';
3
- import { tokens, makeStyles, Tooltip as Tooltip$1, Button as Button$1, Spinner, Link as Link$1, Caption1, Body1, useFluent, Accordion as Accordion$1, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, MessageBar as MessageBar$1, MessageBarBody, AccordionItem, SearchBox as SearchBox$1, Portal, ToggleButton as ToggleButton$1, InfoLabel as InfoLabel$1, mergeClasses, Body1Strong, useId, useToastController, Toast, ToastTitle, FluentProvider, Toaster, Checkbox as Checkbox$1, createLightTheme, createDarkTheme, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Switch as Switch$1, createDOMRenderer, RendererProvider, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, treeItemLevelToken, FlatTree, FlatTreeItem, TreeItemLayout, MenuDivider, MenuItemCheckbox, useMergedRefs, Input, Dropdown as Dropdown$1, Option, Popover as Popover$1, PopoverTrigger, PopoverSurface, ColorPicker, ColorArea, ColorSlider, AlphaSlider, ColorSwatch, PresenceBadge, Slider as Slider$1, MenuItemRadio, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, List as List$1, ListItem, Badge, Label, MessageBarTitle, Subtitle2, useComboboxFilter, Combobox, Textarea as Textarea$1, ToolbarButton, ToolbarDivider, Field } from '@fluentui/react-components';
3
+ import { tokens, makeStyles, Tooltip as Tooltip$1, Button as Button$1, Spinner, Link as Link$1, Caption1, Body1, useFluent, Accordion as Accordion$1, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, MessageBar as MessageBar$1, MessageBarBody, AccordionItem, SearchBox as SearchBox$1, Portal, ToggleButton as ToggleButton$1, InfoLabel as InfoLabel$1, Body1Strong, mergeClasses, useId, useToastController, Toast, ToastTitle, FluentProvider, Toaster, Checkbox as Checkbox$1, createLightTheme, createDarkTheme, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Switch as Switch$1, createDOMRenderer, RendererProvider, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, treeItemLevelToken, FlatTree, FlatTreeItem, TreeItemLayout, MenuDivider, MenuItemCheckbox, useMergedRefs, Input, Dropdown as Dropdown$1, Option, Popover as Popover$1, PopoverTrigger, PopoverSurface, ColorPicker, ColorArea, ColorSlider, AlphaSlider, ColorSwatch, PresenceBadge, Slider as Slider$1, MenuItemRadio, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, List as List$1, ListItem, Badge, Label, MessageBarTitle, Subtitle2, useComboboxFilter, Combobox, Textarea as Textarea$1, ToolbarButton, ToolbarDivider, Field } from '@fluentui/react-components';
4
4
  import { ErrorCircleRegular, EyeFilled, EyeOffRegular, CheckmarkFilled, EditRegular, FilterRegular, PinFilled, PinRegular, ArrowCircleUpRegular, ChevronCircleRight16Regular, ChevronCircleRight20Regular, ChevronCircleDown16Regular, ChevronCircleDown20Regular, Copy16Regular, CopyRegular, PanelLeftExpandRegular, PanelRightExpandRegular, PanelLeftContractRegular, PanelRightContractRegular, PictureInPictureEnterRegular, MoreHorizontalRegular, LayoutColumnTwoFocusLeftFilled, LayoutColumnTwoSplitLeftFocusTopLeftFilled, LayoutColumnTwoSplitLeftFocusBottomLeftFilled, LayoutColumnTwoFocusRightFilled, LayoutColumnTwoSplitRightFocusTopRightFilled, LayoutColumnTwoSplitRightFocusBottomRightFilled, SettingsRegular, DocumentTextRegular, createFluentIcon, TextSortAscendingRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, ArrowUploadRegular, ArrowBidirectionalUpDownFilled, ArrowDownloadRegular, StopRegular, RecordRegular, DataBarHorizontalRegular, WrenchRegular, ArrowClockwiseRegular, WeatherSunnyRegular, WeatherMoonRegular, ArrowRotateClockwiseRegular, ArrowExpandRegular, SelectObjectRegular, CubeRegular, CameraRegular, AddRegular, DeleteRegular, FullScreenMaximizeRegular, ChevronDownRegular, ChevronRightRegular, CircleSmallFilled, SaveRegular, PreviousRegular, ArrowPreviousRegular, TriangleLeftRegular, RecordStopRegular, PlayRegular, ArrowNextRegular, NextRegular, PauseRegular, LinkDismissRegular, LinkEditRegular, ArrowUndoRegular, BracesRegular, BracesDismiss16Regular, EyeRegular, CloudArrowUpRegular, CloudArrowDownRegular, EyeOffFilled, ArrowMoveFilled, StopFilled, PlayFilled, LockOpenRegular, LockClosedRegular, ResizeRegular, ChevronUpRegular, ArrowResetRegular, CircleHalfFillRegular, EyedropperRegular, PaintBucketRegular, InkStrokeRegular, StackRegular, FilmstripRegular, PauseFilled, WeatherSunnyLowFilled, LayerRegular, FrameRegular, AppGenericRegular, RectangleLandscapeRegular, BorderOutsideRegular, BorderNoneRegular, MyLocationRegular, LightbulbRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular, SoundWaveCircleRegular, PersonSquareRegular, LayerDiagonalPersonRegular, ImageEditRegular, ImageRegular, TargetRegular, PersonFeedbackRegular, BranchRegular, DeleteFilled } from '@fluentui/react-icons';
5
5
  import { Color3, Color4 } from '@babylonjs/core/Maths/math.color.js';
6
6
  import { Vector3, Quaternion, Matrix, Vector2, Vector4, TmpVectors } from '@babylonjs/core/Maths/math.vector.js';
@@ -37,7 +37,7 @@ import { PerformanceViewerCollector } from '@babylonjs/core/Misc/PerformanceView
37
37
  import { AbstractEngine } from '@babylonjs/core/Engines/abstractEngine.js';
38
38
  import { Bone } from '@babylonjs/core/Bones/bone.js';
39
39
  import { Camera } from '@babylonjs/core/Cameras/camera.js';
40
- import { FrameGraphUtils } from '@babylonjs/core/FrameGraph/frameGraphUtils.js';
40
+ import { FrameGraphUtils, FindMainObjectRenderer, FindMainCamera } from '@babylonjs/core/FrameGraph/frameGraphUtils.js';
41
41
  import { CameraGizmo } from '@babylonjs/core/Gizmos/cameraGizmo.js';
42
42
  import { GizmoManager } from '@babylonjs/core/Gizmos/gizmoManager.js';
43
43
  import { LightGizmo } from '@babylonjs/core/Gizmos/lightGizmo.js';
@@ -79,7 +79,7 @@ import { Engine } from '@babylonjs/core/Engines/engine.js';
79
79
  import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem.js';
80
80
  import { GradientBlockColorStep } from '@babylonjs/core/Materials/Node/Blocks/gradientBlock.js';
81
81
  import { NodeMaterialBlockConnectionPointTypes } from '@babylonjs/core/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes.js';
82
- import { FactorGradient, Color3Gradient, ColorGradient } from '@babylonjs/core/Misc/gradients.js';
82
+ import { Color3Gradient, ColorGradient, FactorGradient } from '@babylonjs/core/Misc/gradients.js';
83
83
  import { ReadFile } from '@babylonjs/core/Misc/fileTools.js';
84
84
  import { CubeTexture } from '@babylonjs/core/Materials/Textures/cubeTexture.js';
85
85
  import { Mesh } from '@babylonjs/core/Meshes/mesh.js';
@@ -276,7 +276,7 @@ const Button = forwardRef((props, ref) => {
276
276
  });
277
277
  Button.displayName = "Button";
278
278
 
279
- const useStyles$U = makeStyles({
279
+ const useStyles$V = makeStyles({
280
280
  root: {
281
281
  display: "flex",
282
282
  flexDirection: "column",
@@ -357,11 +357,18 @@ class ErrorBoundary extends Component {
357
357
  }
358
358
  }
359
359
  function ErrorFallback({ error, onRetry }) {
360
- const styles = useStyles$U();
360
+ const styles = useStyles$V();
361
361
  return (jsxs("div", { className: styles.root, children: [jsx(ErrorCircleRegular, { className: styles.icon }), jsx("div", { className: styles.title, children: "Something went wrong" }), jsx("div", { className: styles.message, children: "An error occurred in this component. You can try again or continue using other parts of the tool." }), jsx(Button, { label: "Try Again", appearance: "primary", onClick: onRetry }), error && jsx("div", { className: styles.details, children: error.message })] }));
362
362
  }
363
363
 
364
+ /**
365
+ * React context for accessing the property change observable.
366
+ */
364
367
  const PropertyContext = createContext(undefined);
368
+ /**
369
+ * Hook that returns a callback to notify the property context when a property has been changed.
370
+ * @returns A function that accepts (entity, propertyKey, oldValue, newValue) and notifies observers.
371
+ */
365
372
  function usePropertyChangedNotifier() {
366
373
  const propertyContext = useContext(PropertyContext);
367
374
  return useCallback((entity, propertyKey, oldValue, newValue) => {
@@ -1354,7 +1361,7 @@ function useIsSectionEmpty(sectionId) {
1354
1361
  return hasItems;
1355
1362
  }
1356
1363
 
1357
- const useStyles$T = makeStyles({
1364
+ const useStyles$U = makeStyles({
1358
1365
  accordion: {
1359
1366
  display: "flex",
1360
1367
  flexDirection: "column",
@@ -1399,6 +1406,7 @@ const useStyles$T = makeStyles({
1399
1406
  },
1400
1407
  menuBar: {
1401
1408
  display: "flex",
1409
+ padding: `0 ${tokens.spacingHorizontalM}`,
1402
1410
  },
1403
1411
  menuBarControls: {
1404
1412
  display: "flex",
@@ -1432,6 +1440,7 @@ const useStyles$T = makeStyles({
1432
1440
  },
1433
1441
  searchBox: {
1434
1442
  width: "100%",
1443
+ maxWidth: "none",
1435
1444
  },
1436
1445
  });
1437
1446
  /**
@@ -1441,19 +1450,19 @@ const useStyles$T = makeStyles({
1441
1450
  */
1442
1451
  const AccordionMenuBar = () => {
1443
1452
  AccordionMenuBar.displayName = "AccordionMenuBar";
1444
- const classes = useStyles$T();
1453
+ const classes = useStyles$U();
1445
1454
  const accordionCtx = useContext(AccordionContext);
1446
1455
  if (!accordionCtx) {
1447
1456
  return null;
1448
1457
  }
1449
1458
  const { state, dispatch, features } = accordionCtx;
1450
1459
  const { editMode } = state;
1451
- return (jsxs("div", { className: classes.menuBar, children: [jsx(AccordionSearchBox, {}), jsxs("div", { className: classes.menuBarControls, children: [features.hiding && editMode && (jsxs(Fragment, { children: [jsx(Button, { title: "Show all", icon: EyeFilled, appearance: "subtle", onClick: () => dispatch({ type: "SHOW_ALL" }) }), jsx(Button, { title: "Hide all", icon: EyeOffRegular, appearance: "subtle", onClick: () => {
1460
+ return (jsxs("div", { className: classes.menuBar, children: [jsx(AccordionSearchBox, {}), jsxs("div", { className: classes.menuBarControls, children: [features.hiding && editMode && (jsxs(Fragment, { children: [jsx(Button, { title: "Show all", icon: EyeFilled, appearance: "transparent", onClick: () => dispatch({ type: "SHOW_ALL" }) }), jsx(Button, { title: "Hide all", icon: EyeOffRegular, appearance: "transparent", onClick: () => {
1452
1461
  // Hide all visible (non-hidden) items using the registered item IDs
1453
1462
  const { registeredItemIds, state: currentState } = accordionCtx;
1454
1463
  const visibleItemIds = Array.from(registeredItemIds.keys()).filter((id) => !currentState.hiddenIds.includes(id));
1455
1464
  dispatch({ type: "HIDE_ALL_VISIBLE", visibleItemIds });
1456
- } })] })), (features.pinning || features.hiding) && (jsx(Button, { title: "Edit mode", icon: editMode ? CheckmarkFilled : EditRegular, appearance: editMode ? "primary" : "subtle", onClick: () => dispatch({ type: "SET_EDIT_MODE", enabled: !editMode }) }))] })] }));
1465
+ } })] })), (features.pinning || features.hiding) && (jsx(Button, { title: "Edit mode", icon: editMode ? CheckmarkFilled : EditRegular, appearance: editMode ? "primary" : "transparent", onClick: () => dispatch({ type: "SET_EDIT_MODE", enabled: !editMode }) }))] })] }));
1457
1466
  };
1458
1467
  /**
1459
1468
  * Wrapper component that must encapsulate the section headers and panels.
@@ -1484,7 +1493,7 @@ const AccordionSectionBlock = (props) => {
1484
1493
  const AccordionSectionItem = (props) => {
1485
1494
  AccordionSectionItem.displayName = "AccordionSectionItem";
1486
1495
  const { children, staticItem } = props;
1487
- const classes = useStyles$T();
1496
+ const classes = useStyles$U();
1488
1497
  const accordionCtx = useContext(AccordionContext);
1489
1498
  const itemState = useAccordionSectionItemState(props);
1490
1499
  const [ctrlMode, setCtrlMode] = useState(false);
@@ -1524,7 +1533,7 @@ const AccordionSectionItem = (props) => {
1524
1533
  */
1525
1534
  const AccordionPinnedContainer = () => {
1526
1535
  AccordionPinnedContainer.displayName = "AccordionPinnedContainer";
1527
- const classes = useStyles$T();
1536
+ const classes = useStyles$U();
1528
1537
  const accordionCtx = useContext(AccordionContext);
1529
1538
  return (jsx("div", { ref: accordionCtx?.pinnedContainerRef, className: classes.pinnedContainer, children: jsx(MessageBar$1, { className: classes.pinnedContainerEmpty, children: jsx(MessageBarBody, { children: "No pinned items" }) }) }));
1530
1539
  };
@@ -1535,7 +1544,7 @@ const AccordionPinnedContainer = () => {
1535
1544
  */
1536
1545
  const AccordionSearchBox = () => {
1537
1546
  AccordionSearchBox.displayName = "AccordionSearchBox";
1538
- const classes = useStyles$T();
1547
+ const classes = useStyles$U();
1539
1548
  const accordionCtx = useContext(AccordionContext);
1540
1549
  if (!accordionCtx?.features.search) {
1541
1550
  return null;
@@ -1551,14 +1560,15 @@ const AccordionSearchBox = () => {
1551
1560
  */
1552
1561
  const AccordionSection = (props) => {
1553
1562
  AccordionSection.displayName = "AccordionSection";
1554
- const classes = useStyles$T();
1563
+ const classes = useStyles$U();
1555
1564
  return jsx("div", { className: classes.panelDiv, children: props.children });
1556
1565
  };
1557
1566
  const StringAccordion = Accordion$1;
1558
1567
  const Accordion = forwardRef((props, ref) => {
1559
1568
  Accordion.displayName = "Accordion";
1560
- const { children, highlightSections, ...rest } = props;
1561
- const classes = useStyles$T();
1569
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1570
+ const { children, highlightSections, uniqueId, enablePinnedItems, enableHiddenItems, enableSearchItems, ...rest } = props;
1571
+ const classes = useStyles$U();
1562
1572
  const { size } = useContext(ToolContext);
1563
1573
  const accordionCtx = useAccordionContext(props);
1564
1574
  const hasPinning = accordionCtx?.features.pinning ?? false;
@@ -1655,7 +1665,7 @@ const Collapse = (props) => {
1655
1665
  return (jsx(Collapse$1, { visible: props.visible, orientation: props.orientation, unmountOnExit: true, children: jsx("div", { className: `${classes.collapseContent} ${props.orientation === "horizontal" ? classes.horizontal : classes.vertical}`, children: props.children }) }));
1656
1666
  };
1657
1667
 
1658
- const useStyles$S = makeStyles({
1668
+ const useStyles$T = makeStyles({
1659
1669
  button: {
1660
1670
  display: "flex",
1661
1671
  alignItems: "center",
@@ -1673,7 +1683,7 @@ const ToggleButton = (props) => {
1673
1683
  ToggleButton.displayName = "ToggleButton";
1674
1684
  const { value, onChange, title, appearance = "subtle" } = props;
1675
1685
  const { size } = useContext(ToolContext);
1676
- const classes = useStyles$S();
1686
+ const classes = useStyles$T();
1677
1687
  const [checked, setChecked] = useState(value);
1678
1688
  const toggle = useCallback(() => {
1679
1689
  setChecked((prevChecked) => {
@@ -1935,6 +1945,11 @@ const DisableCopySettingDescriptor = {
1935
1945
  defaultValue: false,
1936
1946
  };
1937
1947
 
1948
+ /**
1949
+ * Hook that reads and writes a setting from the settings store.
1950
+ * @param descriptor The setting descriptor that identifies the setting and its default value.
1951
+ * @returns A tuple of [currentValue, setValue, resetValue] similar to React's useState.
1952
+ */
1938
1953
  function useSetting(descriptor) {
1939
1954
  const settingsStore = useSettingsStore();
1940
1955
  // Only watch for this specific setting to change. Otherwise, any time any setting changes we would
@@ -2012,7 +2027,7 @@ const UXContextProvider = (props) => {
2012
2027
  function AsReadonlyArray(array) {
2013
2028
  return array;
2014
2029
  }
2015
- const useStyles$R = makeStyles({
2030
+ const useStyles$S = makeStyles({
2016
2031
  rootDiv: {
2017
2032
  flex: 1,
2018
2033
  overflow: "hidden",
@@ -2020,8 +2035,14 @@ const useStyles$R = makeStyles({
2020
2035
  flexDirection: "column",
2021
2036
  },
2022
2037
  });
2038
+ /**
2039
+ * An accordion component that supports dynamically adding sections and section content at runtime.
2040
+ * Combines statically defined children sections with dynamically registered sections and content.
2041
+ * @param props The accordion props including sections, section content, context, and an optional imperative ref.
2042
+ * @returns The extensible accordion component.
2043
+ */
2023
2044
  function ExtensibleAccordion(props) {
2024
- const classes = useStyles$R();
2045
+ const classes = useStyles$S();
2025
2046
  const { children, sections, sectionContent, context, sectionsRef, ...rest } = props;
2026
2047
  const defaultSections = useMemo(() => {
2027
2048
  const defaultSections = [];
@@ -2146,7 +2167,7 @@ function ExtensibleAccordion(props) {
2146
2167
  })] }) })) }));
2147
2168
  }
2148
2169
 
2149
- const useStyles$Q = makeStyles({
2170
+ const useStyles$R = makeStyles({
2150
2171
  paneRootDiv: {
2151
2172
  display: "flex",
2152
2173
  flex: 1,
@@ -2159,7 +2180,7 @@ const useStyles$Q = makeStyles({
2159
2180
  */
2160
2181
  const SidePaneContainer = forwardRef((props, ref) => {
2161
2182
  const { className, ...rest } = props;
2162
- const classes = useStyles$Q();
2183
+ const classes = useStyles$R();
2163
2184
  return (jsx("div", { className: mergeClasses(classes.paneRootDiv, className), ref: ref, ...rest, children: props.children }));
2164
2185
  });
2165
2186
 
@@ -2198,11 +2219,21 @@ const DarkTheme = {
2198
2219
  colorNeutralForeground1: BaseDarkTheme.colorNeutralForeground2,
2199
2220
  };
2200
2221
 
2222
+ /**
2223
+ * The unique identity symbol for the settings store service.
2224
+ */
2201
2225
  const SettingsStoreIdentity = Symbol("SettingsStore");
2202
2226
  function GetKey(namespace, settingKey) {
2203
2227
  return `Babylon/${namespace}/${settingKey}`;
2204
2228
  }
2229
+ /**
2230
+ * Default implementation of {@link ISettingsStore} that persists settings using browser local storage.
2231
+ */
2205
2232
  class SettingsStore {
2233
+ /**
2234
+ * Creates a new settings store.
2235
+ * @param _namespace A namespace used to scope the settings keys to avoid collisions with other stores.
2236
+ */
2206
2237
  constructor(_namespace) {
2207
2238
  this._namespace = _namespace;
2208
2239
  this._onChanged = new Observable();
@@ -2221,10 +2252,17 @@ class SettingsStore {
2221
2252
  }
2222
2253
  }
2223
2254
 
2255
+ /**
2256
+ * The setting descriptor for persisting the theme mode preference.
2257
+ */
2224
2258
  const ThemeModeSettingDescriptor = {
2225
2259
  key: "ThemeMode",
2226
2260
  defaultValue: "system",
2227
2261
  };
2262
+ /**
2263
+ * Resolves the current theme based on user preference and system settings.
2264
+ * Listens for changes to both the persisted theme mode and the OS-level dark mode preference.
2265
+ */
2228
2266
  class ThemeResolver {
2229
2267
  constructor(_settingsStore) {
2230
2268
  this._settingsStore = _settingsStore;
@@ -2262,6 +2300,9 @@ class ThemeResolver {
2262
2300
  this._settingsStoreObserver.remove();
2263
2301
  }
2264
2302
  }
2303
+ /**
2304
+ * The unique identity symbol for the theme service.
2305
+ */
2265
2306
  const ThemeServiceIdentity = Symbol("ThemeService");
2266
2307
  const ThemeServiceDefinition = {
2267
2308
  friendlyName: "Theme Service",
@@ -2377,6 +2418,10 @@ function DepsEqual(a, b) {
2377
2418
  return true;
2378
2419
  }
2379
2420
 
2421
+ /**
2422
+ * Hook that provides the current theme mode state and controls for changing it.
2423
+ * @returns An object with the current dark mode state, theme mode, and functions to set or toggle the theme.
2424
+ */
2380
2425
  function useThemeMode() {
2381
2426
  const settingsStore = useSettingsStore();
2382
2427
  const themeResolver = useResource(useCallback(() => (settingsStore ? new ThemeResolver(settingsStore) : undefined), [settingsStore]));
@@ -2395,18 +2440,35 @@ function useThemeMode() {
2395
2440
  }
2396
2441
  return state;
2397
2442
  }
2443
+ /**
2444
+ * Hook that returns the current Fluent UI theme based on the active theme mode.
2445
+ * @param invert If true, inverts the theme (returns light theme in dark mode and vice versa). Defaults to false.
2446
+ * @returns The current Fluent UI theme object.
2447
+ */
2398
2448
  function useTheme(invert = false) {
2399
2449
  const { isDarkMode } = useThemeMode();
2400
2450
  return isDarkMode !== invert ? DarkTheme : LightTheme;
2401
2451
  }
2402
2452
 
2453
+ // Fluent doesn't apply styling to scrollbars by default, so provide our own reasonable default.
2454
+ const useStyles$Q = makeStyles({
2455
+ root: {
2456
+ scrollbarColor: `${tokens.colorNeutralForeground3} ${tokens.colorTransparentBackground}`,
2457
+ },
2458
+ });
2459
+ /**
2460
+ * A themed Fluent UI provider that applies the current theme mode (light or dark).
2461
+ * @param props Fluent provider props, plus an optional `invert` flag to swap the theme.
2462
+ * @returns The themed Fluent UI provider component.
2463
+ */
2403
2464
  const Theme = (props) => {
2404
- // NOTE: We do not want to applyStylesToPortals by default. If makes classes flow into portals
2465
+ // NOTE: We do not want to applyStylesToPortals by default. It makes classes flow into portals
2405
2466
  // (like popovers), and if those styles do things like disable overflow, they can completely
2406
2467
  // break any UI within the portal. Therefore, default to false.
2407
- const { invert = false, applyStylesToPortals = false, ...rest } = props;
2468
+ const { invert = false, applyStylesToPortals = false, className, ...rest } = props;
2408
2469
  const theme = useTheme(invert);
2409
- return (jsx(FluentProvider, { theme: theme, applyStylesToPortals: applyStylesToPortals, ...rest, children: props.children }));
2470
+ const classes = useStyles$Q();
2471
+ return (jsx(FluentProvider, { theme: theme, className: mergeClasses(classes.root, className), applyStylesToPortals: applyStylesToPortals, ...rest, children: props.children }));
2410
2472
  };
2411
2473
 
2412
2474
  const useStyles$P = makeStyles({
@@ -2604,6 +2666,25 @@ function ConstructorFactory(constructor) {
2604
2666
  return (...args) => new constructor(...args);
2605
2667
  }
2606
2668
 
2669
+ /**
2670
+ * A hook that provides a transient state value and a "pulse" function to set it.
2671
+ * The transient value is meant to be consumed immediately after being set, and will be cleared on the next render.
2672
+ * @typeParam T The type of the transient value.
2673
+ * @returns A tuple containing the transient value and a function to "pulse" the state.
2674
+ */
2675
+ function useImpulse() {
2676
+ const impulseRef = useRef(undefined);
2677
+ const [, setVersion] = useState(0);
2678
+ const pulse = useCallback((value) => {
2679
+ impulseRef.current = value;
2680
+ setVersion((v) => v + 1);
2681
+ }, []);
2682
+ // Consume the impulse value and clear it
2683
+ const value = impulseRef.current;
2684
+ impulseRef.current = undefined;
2685
+ return [value, pulse];
2686
+ }
2687
+
2607
2688
  const useStyles$O = makeStyles({
2608
2689
  placeholderDiv: {
2609
2690
  padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalM}`,
@@ -2662,7 +2743,10 @@ const SwitchPropertyLine = (props) => {
2662
2743
  return (jsx(PropertyLine, { ...props, children: jsx(Switch, { ...switchProps }) }));
2663
2744
  };
2664
2745
 
2665
- const SceneContextIdentity = Symbol("SceneScontext");
2746
+ /**
2747
+ * The unique identity symbol for the scene context service.
2748
+ */
2749
+ const SceneContextIdentity = Symbol("SceneContext");
2666
2750
 
2667
2751
  function ToFeaturesString(options) {
2668
2752
  const { defaultWidth, defaultHeight, defaultLeft, defaultTop } = options;
@@ -2890,27 +2974,48 @@ function useResizeHandle(params) {
2890
2974
  };
2891
2975
  }
2892
2976
 
2977
+ /**
2978
+ * Setting descriptor for persisting side pane dock location overrides.
2979
+ */
2893
2980
  const SidePaneDockOverridesSettingDescriptor = {
2894
2981
  key: "SidePaneDockOverrides",
2895
2982
  defaultValue: {},
2896
2983
  };
2984
+ /**
2985
+ * Setting descriptor for persisting the left side pane width adjustment.
2986
+ */
2897
2987
  const LeftSidePaneWidthAdjustSettingDescriptor = {
2898
2988
  key: "Shell/LeftPane/WidthAdjust",
2899
2989
  defaultValue: 0,
2900
2990
  };
2991
+ /**
2992
+ * Setting descriptor for persisting the left side pane height adjustment.
2993
+ */
2901
2994
  const LeftSidePaneHeightAdjustSettingDescriptor = {
2902
2995
  key: "Shell/LeftPane/HeightAdjust",
2903
2996
  defaultValue: 0,
2904
2997
  };
2998
+ /**
2999
+ * Setting descriptor for persisting the right side pane width adjustment.
3000
+ */
2905
3001
  const RightSidePaneWidthAdjustSettingDescriptor = {
2906
3002
  key: "Shell/RightPane/WidthAdjust",
2907
3003
  defaultValue: 0,
2908
3004
  };
3005
+ /**
3006
+ * Setting descriptor for persisting the right side pane height adjustment.
3007
+ */
2909
3008
  const RightSidePaneHeightAdjustSettingDescriptor = {
2910
3009
  key: "Shell/RightPane/HeightAdjust",
2911
3010
  defaultValue: 0,
2912
3011
  };
3012
+ /**
3013
+ * The unique identity symbol for the root component service.
3014
+ */
2913
3015
  const RootComponentServiceIdentity = Symbol("RootComponent");
3016
+ /**
3017
+ * The unique identity symbol for the shell service.
3018
+ */
2914
3019
  const ShellServiceIdentity = Symbol("ShellService");
2915
3020
  const useStyles$N = makeStyles({
2916
3021
  mainView: {
@@ -3026,8 +3131,18 @@ const useStyles$N = makeStyles({
3026
3131
  },
3027
3132
  paneHeaderText: {
3028
3133
  flex: 1,
3134
+ },
3135
+ paneHeaderTextNoIcon: {
3029
3136
  marginLeft: tokens.spacingHorizontalM,
3030
3137
  },
3138
+ paneHeaderIcon: {
3139
+ display: "flex",
3140
+ alignItems: "center",
3141
+ justifyContent: "center",
3142
+ height: "100%",
3143
+ aspectRatio: "1",
3144
+ fontSize: "20px",
3145
+ },
3031
3146
  paneHeaderButton: {
3032
3147
  color: "inherit",
3033
3148
  },
@@ -3116,7 +3231,7 @@ const DockMenu = (props) => {
3116
3231
  const PaneHeader = (props) => {
3117
3232
  const { id, title, dockOptions } = props;
3118
3233
  const classes = useStyles$N();
3119
- return (jsxs("div", { className: classes.paneHeaderDiv, children: [jsx(Subtitle2Stronger, { className: classes.paneHeaderText, children: title }), jsx(DockMenu, { sidePaneId: id, dockOptions: dockOptions, children: jsx(Button$1, { className: classes.paneHeaderButton, appearance: "transparent", icon: jsx(MoreHorizontalRegular, {}) }) })] }));
3234
+ return (jsxs("div", { className: classes.paneHeaderDiv, children: [props.icon && (jsx("div", { className: classes.paneHeaderIcon, children: jsx(props.icon, {}) })), jsx(Subtitle2Stronger, { className: mergeClasses(classes.paneHeaderText, !props.icon && classes.paneHeaderTextNoIcon), children: title }), jsx(DockMenu, { sidePaneId: id, dockOptions: dockOptions, children: jsx(Button$1, { className: classes.paneHeaderButton, appearance: "transparent", icon: jsx(MoreHorizontalRegular, {}) }) })] }));
3120
3235
  };
3121
3236
  // This is a wrapper for an item in a toolbar that simply adds a teaching moment, which is useful for dynamically added items, possibly from extensions.
3122
3237
  const ToolbarItem = (props) => {
@@ -3296,9 +3411,9 @@ function usePane(location, defaultWidth, minWidth, sidePanes, onSelectSidePane,
3296
3411
  }, [childWindow, isChildWindowOpen, topPanes, bottomPanes]);
3297
3412
  // This memoizes the pane itself, which may or may not include the tab list, depending on the toolbar mode.
3298
3413
  const corePane = useMemo(() => {
3299
- return (jsxs(Fragment, { children: [toolbarMode === "compact" && (topPanes.length > 1 || topBarItems.length > 0) && (jsx(Fragment, { children: jsxs("div", { className: classes.barDiv, children: [!isChildWindowOpen && location === "left" && expandCollapseButton, topPaneTabList, jsx(Toolbar, { location: "top", components: topBarItems }), !isChildWindowOpen && location === "right" && expandCollapseButton] }) })), topPanes.length > 0 && (jsx("div", { className: classes.paneContent, children: topSelectedTab && (jsxs(Fragment, { children: [jsx(PaneHeader, { id: topSelectedTab.key, title: topSelectedTab.title, dockOptions: validTopDockOptions }), topPanes
3414
+ return (jsxs(Fragment, { children: [toolbarMode === "compact" && (topPanes.length > 1 || topBarItems.length > 0) && (jsx(Fragment, { children: jsxs("div", { className: classes.barDiv, children: [!isChildWindowOpen && location === "left" && expandCollapseButton, topPaneTabList, jsx(Toolbar, { location: "top", components: topBarItems }), !isChildWindowOpen && location === "right" && expandCollapseButton] }) })), topPanes.length > 0 && (jsx("div", { className: classes.paneContent, children: topSelectedTab && (jsxs(Fragment, { children: [jsx(PaneHeader, { id: topSelectedTab.key, title: topSelectedTab.title, icon: topPanes.length > 1 ? undefined : topSelectedTab.icon, dockOptions: validTopDockOptions }), topPanes
3300
3415
  .filter((pane) => pane.key === topSelectedTab.key || pane.keepMounted)
3301
- .map((pane) => (jsx("div", { className: mergeClasses(classes.paneContent, pane.key !== topSelectedTab.key ? classes.unselectedPane : undefined), children: jsx(ErrorBoundary, { name: pane.title, children: jsx(pane.content, {}) }) }, pane.key)))] })) })), topPanes.length > 0 && bottomPanes.length > 0 && jsx(Divider, { ref: paneVerticalResizeHandleRef, className: classes.paneDivider }), bottomPanes.length > 1 && (jsx(Fragment, { children: jsx("div", { className: classes.barDiv, children: bottomPaneTabList }) })), bottomPanes.length > 0 && (jsx("div", { ref: paneVerticalResizeElementRef, className: classes.paneContent, style: { height: `clamp(200px, calc(45% + var(${paneHeightAdjustCSSVar}, 0px)), 100% - 300px)`, flex: "0 0 auto" }, children: bottomSelectedTab && (jsxs(Fragment, { children: [jsx(PaneHeader, { id: bottomSelectedTab.key, title: bottomSelectedTab.title, dockOptions: validBottomDockOptions }), bottomPanes
3416
+ .map((pane) => (jsx("div", { className: mergeClasses(classes.paneContent, pane.key !== topSelectedTab.key ? classes.unselectedPane : undefined), children: jsx(ErrorBoundary, { name: pane.title, children: jsx(pane.content, {}) }) }, pane.key)))] })) })), topPanes.length > 0 && bottomPanes.length > 0 && jsx(Divider, { ref: paneVerticalResizeHandleRef, className: classes.paneDivider }), bottomPanes.length > 1 && (jsx(Fragment, { children: jsx("div", { className: classes.barDiv, children: bottomPaneTabList }) })), bottomPanes.length > 0 && (jsx("div", { ref: paneVerticalResizeElementRef, className: classes.paneContent, style: { height: `clamp(200px, calc(45% + var(${paneHeightAdjustCSSVar}, 0px)), 100% - 300px)`, flex: "0 0 auto" }, children: bottomSelectedTab && (jsxs(Fragment, { children: [jsx(PaneHeader, { id: bottomSelectedTab.key, title: bottomSelectedTab.title, icon: bottomPanes.length > 1 ? undefined : bottomSelectedTab.icon, dockOptions: validBottomDockOptions }), bottomPanes
3302
3417
  .filter((pane) => pane.key === bottomSelectedTab.key || pane.keepMounted)
3303
3418
  .map((pane) => (jsx("div", { className: mergeClasses(classes.paneContent, pane.key !== bottomSelectedTab.key ? classes.unselectedPane : undefined), children: jsx(ErrorBoundary, { name: pane.title, children: jsx(pane.content, {}) }) }, pane.key)))] })) })), toolbarMode === "compact" && bottomBarItems.length > 0 && (jsx(Fragment, { children: jsx("div", { className: classes.barDiv, children: jsx(Toolbar, { location: "bottom", components: bottomBarItems }) }) }))] }));
3304
3419
  }, [
@@ -3571,6 +3686,9 @@ function MakeShellServiceDefinition({ leftPaneDefaultWidth = 350, leftPaneMinWid
3571
3686
  };
3572
3687
  }
3573
3688
 
3689
+ /**
3690
+ * The unique identity symbol for the settings service.
3691
+ */
3574
3692
  const SettingsServiceIdentity = Symbol("SettingsService");
3575
3693
  const SettingsServiceDefinition = {
3576
3694
  friendlyName: "Settings",
@@ -3616,7 +3734,10 @@ const SettingsServiceDefinition = {
3616
3734
  },
3617
3735
  };
3618
3736
 
3619
- const SelectionServiceIdentity = Symbol("PropertiesService");
3737
+ /**
3738
+ * The unique identity symbol for the selection service.
3739
+ */
3740
+ const SelectionServiceIdentity = Symbol("SelectionService");
3620
3741
  const ShowPropertiesOnSelectionSettingDescriptor = {
3621
3742
  key: "ShowPropertiesOnSelection",
3622
3743
  defaultValue: true,
@@ -3624,8 +3745,8 @@ const ShowPropertiesOnSelectionSettingDescriptor = {
3624
3745
  const SelectionServiceDefinition = {
3625
3746
  friendlyName: "Selection Service",
3626
3747
  produces: [SelectionServiceIdentity],
3627
- consumes: [ShellServiceIdentity, SettingsStoreIdentity, SettingsServiceIdentity],
3628
- factory: (shellService, settingsStore, settingsService) => {
3748
+ consumes: [ShellServiceIdentity, SettingsStoreIdentity, SettingsServiceIdentity, SceneContextIdentity],
3749
+ factory: (shellService, settingsStore, settingsService, sceneContext) => {
3629
3750
  settingsService.addSectionContent({
3630
3751
  key: "Selection Service Settings",
3631
3752
  section: "UI",
@@ -3659,6 +3780,8 @@ const SelectionServiceDefinition = {
3659
3780
  }
3660
3781
  }
3661
3782
  };
3783
+ // Set the scene as the default selected entity.
3784
+ setSelectedItem(sceneContext.currentScene);
3662
3785
  return {
3663
3786
  get selectedEntity() {
3664
3787
  return selectedEntityState;
@@ -3672,6 +3795,9 @@ const SelectionServiceDefinition = {
3672
3795
  },
3673
3796
  };
3674
3797
 
3798
+ /**
3799
+ * The unique identity symbol for the properties service.
3800
+ */
3675
3801
  const PropertiesServiceIdentity = Symbol("PropertiesService");
3676
3802
  /**
3677
3803
  * Provides a properties pane that enables displaying and editing properties of an entity such as a mesh or a texture.
@@ -3684,7 +3810,7 @@ const PropertiesServiceDefinition = {
3684
3810
  const sectionsCollection = new ObservableCollection();
3685
3811
  const sectionContentCollection = new ObservableCollection();
3686
3812
  const onPropertyChanged = new Observable();
3687
- const onHighlightSectionsRequested = new Observable();
3813
+ const onHighlightSectionsRequested = new Observable(undefined, true);
3688
3814
  const registration = shellService.addSidePane({
3689
3815
  key: "Properties",
3690
3816
  title: "Properties",
@@ -3716,15 +3842,23 @@ const PropertiesServiceDefinition = {
3716
3842
  // The selected entity may be set at the same time as a highlight is requested.
3717
3843
  // To account for this, we need to wait for one React render to complete before
3718
3844
  // requesting the section highlight.
3719
- const [pendingHighlight, setPendingHighlight] = useState();
3845
+ const [pendingHighlight, pulsePendingHighlightSections] = useImpulse();
3720
3846
  useEffect(() => {
3721
- const observer = onHighlightSectionsRequested.add(setPendingHighlight);
3722
- return () => observer.remove();
3847
+ const observer = onHighlightSectionsRequested.add((sectionIds) => {
3848
+ // Now this UI component is observing, so we don't need to cache pending requests anymore.
3849
+ onHighlightSectionsRequested.notifyIfTriggered = false;
3850
+ onHighlightSectionsRequested.cleanLastNotifiedState();
3851
+ pulsePendingHighlightSections(sectionIds);
3852
+ });
3853
+ return () => {
3854
+ observer.remove();
3855
+ // Now this UI component is no longer observing, so we need to cache pending requests again.
3856
+ onHighlightSectionsRequested.notifyIfTriggered = true;
3857
+ };
3723
3858
  }, []);
3724
3859
  useEffect(() => {
3725
3860
  if (pendingHighlight && sectionsRef.current) {
3726
3861
  sectionsRef.current.highlightSections(pendingHighlight);
3727
- setPendingHighlight(undefined);
3728
3862
  }
3729
3863
  }, [pendingHighlight]);
3730
3864
  return (jsx(PropertyContext.Provider, { value: { onPropertyChanged }, children: jsx(PropertiesPane, { uniqueId: "Properties", sections: sections, sectionContent: applicableContent, context: entity, sectionsRef: sectionsRef, enablePinnedItems: true, enableHiddenItems: true, enableSearchItems: true }) }));
@@ -4112,6 +4246,7 @@ const useStyles$M = makeStyles({
4112
4246
  searchBox: {
4113
4247
  flex: 1,
4114
4248
  padding: 0,
4249
+ maxWidth: "none",
4115
4250
  },
4116
4251
  tree: {
4117
4252
  rowGap: 0,
@@ -4619,6 +4754,9 @@ const SceneExplorer = (props) => {
4619
4754
  } }) })] }));
4620
4755
  };
4621
4756
 
4757
+ /**
4758
+ * The unique identity symbol for the scene explorer service.
4759
+ */
4622
4760
  const SceneExplorerServiceIdentity = Symbol("SceneExplorer");
4623
4761
  /**
4624
4762
  * Provides a scene explorer pane that enables browsing the scene graph and executing commands on entities.
@@ -4783,6 +4921,9 @@ const DebugPane = (props) => {
4783
4921
  return (jsxs(ExtensibleAccordion, { ...props, children: [jsxs(AccordionSection, { title: "Helpers", children: [jsx(SwitchPropertyLine, { label: "Grid", description: "Display a ground grid.", value: !!scene.reservedDataStore.gridMesh, onChange: () => SwitchGrid(scene) }), jsx(SwitchPropertyLine, { label: "Physics", description: "Display physic debug info.", value: !!scene.reservedDataStore.physicsViewer, onChange: () => SwitchPhysicsViewers(scene) }), jsx(SwitchPropertyLine, { label: "Names", description: "Display mesh names.", value: !!scene.reservedDataStore.textRenderersHook, onChange: () => void SwitchNameViewerAsync(scene) })] }), jsxs(AccordionSection, { title: "Texture Channels", children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Diffuse", target: StandardMaterial, propertyKey: "DiffuseTextureEnabled" }, "Diffuse"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Ambient", target: StandardMaterial, propertyKey: "AmbientTextureEnabled" }, "Ambient"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Specular", target: StandardMaterial, propertyKey: "SpecularTextureEnabled" }, "Specular"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Emissive", target: StandardMaterial, propertyKey: "EmissiveTextureEnabled" }, "Emissive"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Bump", target: StandardMaterial, propertyKey: "BumpTextureEnabled" }, "Bump"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Opacity", target: StandardMaterial, propertyKey: "OpacityTextureEnabled" }, "Opacity"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Reflection", target: StandardMaterial, propertyKey: "ReflectionTextureEnabled" }, "Reflection"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Refraction", target: StandardMaterial, propertyKey: "RefractionTextureEnabled" }, "Refraction"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Color Grading", target: StandardMaterial, propertyKey: "ColorGradingTextureEnabled" }, "ColorGrading"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Lightmap", target: StandardMaterial, propertyKey: "LightmapTextureEnabled" }, "Lightmap"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Fresnel", target: StandardMaterial, propertyKey: "FresnelEnabled" }, "Fresnel"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Detail", target: MaterialFlags, propertyKey: "DetailTextureEnabled" }, "Detail"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Decal", target: MaterialFlags, propertyKey: "DecalMapEnabled" }, "Decal")] }), jsxs(AccordionSection, { title: "Features", children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Animations", target: scene, propertyKey: "animationsEnabled" }, "Animations"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Physics", target: scene, propertyKey: "physicsEnabled" }, "Physics"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Collisions", target: scene, propertyKey: "collisionsEnabled" }, "Collisions"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Fog", target: scene, propertyKey: "fogEnabled" }, "Fog"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Lens Flares", target: scene, propertyKey: "lensFlaresEnabled" }, "Lens flares"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Lights", target: scene, propertyKey: "lightsEnabled" }, "Lights"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Particles", target: scene, propertyKey: "particlesEnabled" }, "Particles"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Post-processes", target: scene, propertyKey: "postProcessesEnabled" }, "Post-processes"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Probes", target: scene, propertyKey: "probesEnabled" }, "Probes"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Textures", target: scene, propertyKey: "texturesEnabled" }, "Textures"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Procedural Textures", target: scene, propertyKey: "proceduralTexturesEnabled" }, "Procedural textures"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Render Targets", target: scene, propertyKey: "renderTargetsEnabled" }, "Render targets"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Shadows", target: scene, propertyKey: "shadowsEnabled" }, "Shadows"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Skeletons", target: scene, propertyKey: "skeletonsEnabled" }, "Skeletons"), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Sprites", target: scene, propertyKey: "spritesEnabled" }, "Sprites")] })] }));
4784
4922
  };
4785
4923
 
4924
+ /**
4925
+ * The unique identity symbol for the debug service.
4926
+ */
4786
4927
  const DebugServiceIdentity = Symbol("DebugService");
4787
4928
  const DebugServiceDefinition = {
4788
4929
  friendlyName: "Debug",
@@ -4921,7 +5062,7 @@ const UploadButton = (props) => {
4921
5062
  */
4922
5063
  const FileUploadLine = ({ onClick, label, accept, ...buttonProps }) => {
4923
5064
  FileUploadLine.displayName = "FileUploadLine";
4924
- return (jsx(LineContainer, { uniqueId: label, children: jsx(UploadButton, { onUpload: onClick, accept: accept, label: label, ...buttonProps }) }));
5065
+ return (jsx(LineContainer, { uniqueId: `${label}_upload`, label: label, children: jsx(UploadButton, { onUpload: onClick, accept: accept, label: label, ...buttonProps }) }));
4925
5066
  };
4926
5067
 
4927
5068
  /**
@@ -6895,6 +7036,9 @@ const SystemStats = ({ context: scene }) => {
6895
7036
  return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Resolution", value: resolution }, "Resolution"), jsx(StringifiedPropertyLine, { label: "Hardware Scaling Level", value: hardwareScalingLevel }, "HardwareScalingLevel"), jsx(TextPropertyLine, { label: "Engine", value: engine.description }, "Engine"), jsx(BooleanBadgePropertyLine, { label: "StdDerivatives", value: caps.standardDerivatives }, "StdDerivatives"), jsx(BooleanBadgePropertyLine, { label: "Compressed Textures", value: caps.s3tc !== undefined }, "CompressedTextures"), jsx(BooleanBadgePropertyLine, { label: "Hardware Instances", value: caps.instancedArrays }, "HardwareInstances"), jsx(BooleanBadgePropertyLine, { label: "Texture Float", value: caps.textureFloat }, "TextureFloat"), jsx(BooleanBadgePropertyLine, { label: "Texture Half Float", value: caps.textureHalfFloat }, "TextureHalfFloat"), jsx(BooleanBadgePropertyLine, { label: "Render to Texture Float", value: caps.textureFloatRender }, "RenderToTextureFloat"), jsx(BooleanBadgePropertyLine, { label: "Render to Texture Half Float", value: caps.textureHalfFloatRender }, "RenderToTextureHalfFloat"), jsx(BooleanBadgePropertyLine, { label: "32bits Indices", value: caps.uintIndices }, "32bitsIndices"), jsx(BooleanBadgePropertyLine, { label: "Fragment Depth", value: caps.fragmentDepthSupported }, "FragmentDepth"), jsx(BooleanBadgePropertyLine, { label: "High Precision Shaders", value: caps.highPrecisionShaderSupported }, "HighPrecisionShaders"), jsx(BooleanBadgePropertyLine, { label: "Draw Buffers", value: caps.drawBuffersExtension }, "DrawBuffers"), jsx(BooleanBadgePropertyLine, { label: "Vertex Array Object", value: caps.vertexArrayObject }, "VertexArrayObject"), jsx(BooleanBadgePropertyLine, { label: "Timer Query", value: caps.timerQuery !== undefined }, "TimerQuery"), jsx(BooleanBadgePropertyLine, { label: "Stencil", value: engine.isStencilEnable }, "Stencil"), jsx(BooleanBadgePropertyLine, { label: "Parallel Shader Compilation", value: caps.parallelShaderCompile != null }, "ParallelShaderCompilation"), jsx(StringifiedPropertyLine, { label: "Max Textures Units", value: caps.maxTexturesImageUnits }, "MaxTexturesUnits"), jsx(StringifiedPropertyLine, { label: "Max Textures Size", value: caps.maxTextureSize }, "MaxTexturesSize"), jsx(StringifiedPropertyLine, { label: "Max Anisotropy", value: caps.maxAnisotropy }, "MaxAnisotropy"), jsx(TextPropertyLine, { label: "Driver", value: engine.extractDriverInfo() }, "Driver")] }));
6896
7037
  };
6897
7038
 
7039
+ /**
7040
+ * The unique identity symbol for the stats service.
7041
+ */
6898
7042
  const StatsServiceIdentity = Symbol("StatsService");
6899
7043
  /**
6900
7044
  * Provides a scene stats pane.
@@ -6975,6 +7119,9 @@ const ToolsPane = (props) => {
6975
7119
  return jsx(ExtensibleAccordion, { ...props });
6976
7120
  };
6977
7121
 
7122
+ /**
7123
+ * The unique identity symbol for the tools service.
7124
+ */
6978
7125
  const ToolsServiceIdentity = Symbol("ToolsService");
6979
7126
  /**
6980
7127
  * A collection of usually optional, dynamic extensions.
@@ -7200,6 +7347,9 @@ const WatcherSettingDescriptor = {
7200
7347
  mode: "intercept",
7201
7348
  },
7202
7349
  };
7350
+ /**
7351
+ * The unique identity symbol for the watcher service.
7352
+ */
7203
7353
  const WatcherServiceIdentity = Symbol("WatcherService");
7204
7354
  const WatcherServiceDefinition = {
7205
7355
  friendlyName: "Watcher Service",
@@ -7345,6 +7495,9 @@ const WatcherRefreshToolbarServiceDefinition = {
7345
7495
  },
7346
7496
  };
7347
7497
 
7498
+ /**
7499
+ * The unique identity symbol for the gizmo service.
7500
+ */
7348
7501
  const GizmoServiceIdentity = Symbol("GizmoService");
7349
7502
  const GizmoServiceDefinition = {
7350
7503
  friendlyName: "Gizmo Service",
@@ -7626,7 +7779,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
7626
7779
  keywords: ["creation", "tools"],
7627
7780
  ...BabylonWebResources,
7628
7781
  author: { name: "Babylon.js", forumUserName: "" },
7629
- getExtensionModuleAsync: async () => await import('./quickCreateToolsService-DHfs_EZ6.js'),
7782
+ getExtensionModuleAsync: async () => await import('./quickCreateToolsService-B8OEbZg5.js'),
7630
7783
  },
7631
7784
  {
7632
7785
  name: "Reflector",
@@ -7634,7 +7787,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
7634
7787
  keywords: ["reflector", "bridge", "sync", "sandbox", "tools"],
7635
7788
  ...BabylonWebResources,
7636
7789
  author: { name: "Babylon.js", forumUserName: "" },
7637
- getExtensionModuleAsync: async () => await import('./reflectorService-DEPuGTAZ.js'),
7790
+ getExtensionModuleAsync: async () => await import('./reflectorService-LPThzOok.js'),
7638
7791
  },
7639
7792
  ]);
7640
7793
 
@@ -8363,7 +8516,7 @@ function MakeModularTool(options) {
8363
8516
  }
8364
8517
  // Register the extension list service (for browsing/installing extensions) if extension feeds are provided.
8365
8518
  if (extensionFeeds.length > 0) {
8366
- const { ExtensionListServiceDefinition } = await import('./extensionsListService-Duej2zkq.js');
8519
+ const { ExtensionListServiceDefinition } = await import('./extensionsListService-J1zZuhYY.js');
8367
8520
  await serviceContainer.addServiceAsync(ExtensionListServiceDefinition);
8368
8521
  }
8369
8522
  // Register all external services (that make up a unique tool).
@@ -8504,11 +8657,10 @@ const GizmoToolbar = (props) => {
8504
8657
  const onCameraGizmoChange = useCallback((e, data) => {
8505
8658
  const value = data.checkedItems[0];
8506
8659
  gizmoService.gizmoCamera = value === "-1" ? null : (cameras.find((camera) => camera.uniqueId.toString() === value) ?? null);
8507
- }, [gizmoService]);
8660
+ }, [gizmoService, cameras]);
8508
8661
  return (jsxs(Fragment, { children: [jsx(ToggleButton, { title: "Translate", checkedIcon: TranslateIcon, value: gizmoMode === "translate", onChange: () => updateGizmoMode("translate") }), jsx(ToggleButton, { title: "Rotate", checkedIcon: ArrowRotateClockwiseRegular, value: gizmoMode === "rotate", onChange: () => updateGizmoMode("rotate") }), jsx(ToggleButton, { title: "Scale", checkedIcon: ArrowExpandRegular, value: gizmoMode === "scale", onChange: () => updateGizmoMode("scale") }), jsx(ToggleButton, { title: "Bounding Box", checkedIcon: SelectObjectRegular, value: gizmoMode === "boundingBox", onChange: () => updateGizmoMode("boundingBox") }), jsx(Collapse, { visible: !!gizmoMode, orientation: "horizontal", children: jsxs(Menu, { positioning: "below-end", checkedValues: { coordinatesMode: [coordinatesMode.toString()] }, onCheckedValueChange: onCoordinatesModeChange, children: [jsx(MenuTrigger, { disableButtonEnhancement: true, children: (triggerProps) => (jsx(Tooltip$1, { content: "Coordinates Mode", relationship: "label", children: jsx(SplitButton, { className: classes.coordinatesModeButton, menuButton: triggerProps, primaryActionButton: {
8509
8662
  onClick: toggleCoordinatesMode,
8510
- }, size: "small", appearance: "transparent", shape: "rounded", icon: coordinatesMode === 1 /* GizmoCoordinatesMode.Local */ ? jsx(CubeRegular, {}) : jsx(GlobeRegular, {}) }) })) }), jsx(MenuPopover, { className: classes.coordinatesModeMenu, children: jsxs(MenuList, { children: [jsx(MenuItemRadio, { name: "coordinatesMode", value: 1 /* GizmoCoordinatesMode.Local */.toString(), children: "Local" }), jsx(MenuItemRadio, { name: "coordinatesMode", value: 0 /* GizmoCoordinatesMode.World */.toString(), children: "World" })] }) })] }) }), jsx(Collapse, { visible: !!gizmoMode, orientation: "horizontal", children: jsxs(Menu, { positioning: "below-end", checkedValues: { cameraGizmo: [cameraGizmo?.uniqueId.toString() ?? "-1"] }, onCheckedValueChange: onCameraGizmoChange, children: [jsx(MenuTrigger, { disableButtonEnhancement: true, children: (triggerProps) => (jsx(Tooltip$1, { content: "Camera Gizmo", relationship: "label", children: jsx(SplitButton, { className: classes.cameraGizmoButton, menuButton: triggerProps, size: "small", appearance: "transparent", shape: "rounded", icon: jsx(CameraRegular, {}) }) })) }), jsx(MenuPopover, { className: classes.cameraGizmoMenu, children: jsxs(MenuList, { children: [jsx(MenuItemRadio, { name: "cameraGizmo", value: "-1", children: "Automatic" }), sceneContext.currentScene &&
8511
- sceneContext.currentScene.activeCameras?.map((camera, index) => (jsx(MenuItemRadio, { name: "cameraGizmo", value: camera.uniqueId.toString(), children: camera.name }, camera.uniqueId)))] }) })] }) })] }));
8663
+ }, size: "small", appearance: "transparent", shape: "rounded", icon: coordinatesMode === 1 /* GizmoCoordinatesMode.Local */ ? jsx(CubeRegular, {}) : jsx(GlobeRegular, {}) }) })) }), jsx(MenuPopover, { className: classes.coordinatesModeMenu, children: jsxs(MenuList, { children: [jsx(MenuItemRadio, { name: "coordinatesMode", value: 1 /* GizmoCoordinatesMode.Local */.toString(), children: "Local" }), jsx(MenuItemRadio, { name: "coordinatesMode", value: 0 /* GizmoCoordinatesMode.World */.toString(), children: "World" })] }) })] }) }), jsx(Collapse, { visible: !!gizmoMode && !!cameras && cameras.length > 1, orientation: "horizontal", children: jsxs(Menu, { positioning: "below-end", checkedValues: { cameraGizmo: [cameraGizmo?.uniqueId.toString() ?? "-1"] }, onCheckedValueChange: onCameraGizmoChange, children: [jsx(MenuTrigger, { disableButtonEnhancement: true, children: (triggerProps) => (jsx(Tooltip$1, { content: "Camera Gizmo", relationship: "label", children: jsx(SplitButton, { className: classes.cameraGizmoButton, menuButton: triggerProps, size: "small", appearance: "transparent", shape: "rounded", icon: jsx(CameraRegular, {}) }) })) }), jsx(MenuPopover, { className: classes.cameraGizmoMenu, children: jsxs(MenuList, { children: [jsx(MenuItemRadio, { name: "cameraGizmo", value: "-1", children: "Automatic" }), cameras?.map((camera) => (jsx(MenuItemRadio, { name: "cameraGizmo", value: camera.uniqueId.toString(), children: camera.name }, camera.uniqueId)))] }) })] }) })] }));
8512
8664
  };
8513
8665
 
8514
8666
  const GizmoToolbarServiceDefinition = {
@@ -11937,7 +12089,7 @@ const RangeFrameBar = ({ width }) => {
11937
12089
  const x = frameToX(displayFrame);
11938
12090
  return jsx("line", { className: styles.activeFrameLine, x1: x, y1: 0, x2: x, y2: 40 });
11939
12091
  }, [displayFrame, frameToX, styles.activeFrameLine]);
11940
- const viewBox = `${ -10} 0 ${viewWidth + OFFSET_X * 4} 40`;
12092
+ const viewBox = `${-OFFSET_X} 0 ${viewWidth + OFFSET_X * 4} 40`;
11941
12093
  return (jsx("div", { className: styles.root, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, onPointerCancel: handlePointerUp, children: jsxs("svg", { ref: svgRef, className: styles.svg, viewBox: viewBox, children: [frameTicks.map((frame, i) => {
11942
12094
  const x = frameToX(frame);
11943
12095
  return (jsxs("g", { children: [jsx("line", { className: styles.tickLine, x1: x, y1: 22, x2: x, y2: 40 }), jsx("text", { className: styles.tickLabel, x: x, y: 14, children: Math.round(frame) })] }, `tick-${frame}-${i}`));
@@ -13411,7 +13563,7 @@ const ShadowsSetupProperties = ({ context: shadowLight }) => {
13411
13563
  };
13412
13564
 
13413
13565
  const SpotLightSetupProperties = ({ context: spotLight }) => {
13414
- return (jsxs(Fragment, { children: [jsx(BoundProperty, { label: "Diffuse", component: Color3PropertyLine, target: spotLight, propertyKey: "diffuse" }), jsx(BoundProperty, { label: "Specular", component: Color3PropertyLine, target: spotLight, propertyKey: "specular" }), jsx(BoundProperty, { label: "Direction", component: Vector3PropertyLine, target: spotLight, propertyKey: "direction" }), jsx(BoundProperty, { label: "Position", component: Vector3PropertyLine, target: spotLight, propertyKey: "position" }), jsx(BoundProperty, { label: "Angle", component: SyncedSliderPropertyLine, target: spotLight, propertyKey: "angle", convertTo: Tools.ToDegrees, convertFrom: Tools.ToRadians, min: 0, max: 90, step: 0.1 }), jsx(BoundProperty, { label: "InnerAngle", component: SyncedSliderPropertyLine, target: spotLight, propertyKey: "innerAngle", convertTo: Tools.ToDegrees, convertFrom: Tools.ToRadians, min: 0, max: 90, step: 0.1 }), jsx(BoundProperty, { label: "Exponent", component: NumberInputPropertyLine, target: spotLight, propertyKey: "exponent" })] }));
13566
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { label: "Diffuse", component: Color3PropertyLine, target: spotLight, propertyKey: "diffuse" }), jsx(BoundProperty, { label: "Specular", component: Color3PropertyLine, target: spotLight, propertyKey: "specular" }), jsx(BoundProperty, { label: "Direction", component: Vector3PropertyLine, target: spotLight, propertyKey: "direction" }), jsx(BoundProperty, { label: "Position", component: Vector3PropertyLine, target: spotLight, propertyKey: "position" }), jsx(BoundProperty, { label: "Angle", component: SyncedSliderPropertyLine, target: spotLight, propertyKey: "angle", convertTo: Tools.ToDegrees, convertFrom: Tools.ToRadians, min: 0, max: 90, step: 0.1 }), jsx(BoundProperty, { label: "InnerAngle", component: SyncedSliderPropertyLine, target: spotLight, propertyKey: "innerAngle", convertTo: Tools.ToDegrees, convertFrom: Tools.ToRadians, min: 0, max: 90, step: 0.1 }), jsx(BoundProperty, { label: "Intensity", component: NumberInputPropertyLine, target: spotLight, propertyKey: "intensity" }), jsx(BoundProperty, { label: "Exponent", component: NumberInputPropertyLine, target: spotLight, propertyKey: "exponent" })] }));
13415
13567
  };
13416
13568
 
13417
13569
  const LightPropertiesServiceDefinition = {
@@ -14170,25 +14322,6 @@ const ComboBox = forwardRef((props, ref) => {
14170
14322
  return (jsxs("div", { className: styles.root, children: [jsx("label", { id: comboId, children: props.label }), jsx(Combobox, { ref: ref, defaultOpen: props.defaultOpen, size: size, root: { className: styles.comboBox }, input: { className: styles.input }, listbox: { className: styles.listbox }, onOptionSelect: onOptionSelect, "aria-labelledby": comboId, placeholder: "Search..", onChange: (ev) => setQuery(ev.target.value), value: query, children: children })] }));
14171
14323
  });
14172
14324
 
14173
- /**
14174
- * A hook that provides a transient state value and a "pulse" function to set it.
14175
- * The transient value is meant to be consumed immediately after being set, and will be cleared on the next render.
14176
- * @typeParam T The type of the transient value.
14177
- * @returns A tuple containing the transient value and a function to "pulse" the state.
14178
- */
14179
- function useImpulse() {
14180
- const impulseRef = useRef(undefined);
14181
- const [, setVersion] = useState(0);
14182
- const pulse = useCallback((value) => {
14183
- impulseRef.current = value;
14184
- setVersion((v) => v + 1);
14185
- }, []);
14186
- // Consume the impulse value and clear it
14187
- const value = impulseRef.current;
14188
- impulseRef.current = undefined;
14189
- return [value, pulse];
14190
- }
14191
-
14192
14325
  const useStyles$j = makeStyles({
14193
14326
  linkDiv: {
14194
14327
  display: "flex",
@@ -14735,35 +14868,35 @@ const MaterialPropertiesServiceDefinition = {
14735
14868
  predicate: (entity) => entity instanceof OpenPBRMaterial,
14736
14869
  content: [
14737
14870
  {
14738
- section: "Base",
14871
+ section: "OpenPBR",
14739
14872
  component: ({ context }) => jsx(OpenPBRMaterialBaseProperties, { material: context }),
14740
14873
  },
14741
14874
  {
14742
- section: "Specular",
14875
+ section: "OpenPBR",
14743
14876
  component: ({ context }) => jsx(OpenPBRMaterialSpecularProperties, { material: context }),
14744
14877
  },
14745
14878
  {
14746
- section: "Transmission",
14879
+ section: "OpenPBR",
14747
14880
  component: ({ context }) => jsx(OpenPBRMaterialTransmissionProperties, { material: context }),
14748
14881
  },
14749
14882
  {
14750
- section: "Coat",
14883
+ section: "OpenPBR",
14751
14884
  component: ({ context }) => jsx(OpenPBRMaterialCoatProperties, { material: context }),
14752
14885
  },
14753
14886
  {
14754
- section: "Fuzz",
14887
+ section: "OpenPBR",
14755
14888
  component: ({ context }) => jsx(OpenPBRMaterialFuzzProperties, { material: context }),
14756
14889
  },
14757
14890
  {
14758
- section: "Emission",
14891
+ section: "OpenPBR",
14759
14892
  component: ({ context }) => jsx(OpenPBRMaterialEmissionProperties, { material: context }),
14760
14893
  },
14761
14894
  {
14762
- section: "Thin Film",
14895
+ section: "OpenPBR",
14763
14896
  component: ({ context }) => jsx(OpenPBRMaterialThinFilmProperties, { material: context }),
14764
14897
  },
14765
14898
  {
14766
- section: "Geometry",
14899
+ section: "OpenPBR",
14767
14900
  component: ({ context }) => jsx(OpenPBRMaterialGeometryProperties, { material: context }),
14768
14901
  },
14769
14902
  ],
@@ -14906,10 +15039,13 @@ function StringifyMetadata(metadata, format) {
14906
15039
  return metadata;
14907
15040
  }
14908
15041
  if (metadata) {
14909
- if (ObjectCanSafelyStringify(metadata)) {
14910
- return JSON.stringify(metadata, undefined, undefined);
15042
+ // Try JSON.stringify even for objects with functions — it safely omits
15043
+ // function-valued and undefined properties. Only fall back to String()
15044
+ // for cases that actually throw (e.g. circular references).
15045
+ try {
15046
+ return JSON.stringify(metadata, undefined, format ? PrettyJSONIndent : undefined);
14911
15047
  }
14912
- else {
15048
+ catch {
14913
15049
  return String(metadata);
14914
15050
  }
14915
15051
  }
@@ -14974,7 +15110,7 @@ const MetadataProperties = (props) => {
14974
15110
  const classes = useStyles$h();
14975
15111
  const { size } = useContext(ToolContext);
14976
15112
  const metadata = useProperty(entity, "metadata");
14977
- const stringifiedMetadata = useMemo(() => StringifyMetadata(metadata) ?? "", [metadata]);
15113
+ const stringifiedMetadata = useMemo(() => StringifyMetadata(metadata, false) ?? "", [metadata]);
14978
15114
  const metadataType = useMemo(() => GetMetadataEntityType(metadata), [metadata]);
14979
15115
  const canPreventObjectCorruption = metadataType === "object";
14980
15116
  const [preventObjectCorruption, setPreventObjectCorruption] = useState(false);
@@ -15333,7 +15469,7 @@ const MeshMorphTargetsProperties = (props) => {
15333
15469
  if (morphTargets.length === 0) {
15334
15470
  return null;
15335
15471
  }
15336
- return (jsx(Fragment, { children: morphTargets.map((target, index) => (jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: target.name || `Target ${index}`, description: `Influence of morph target "${target.name || `Target ${index}`}"`, target: target, propertyKey: "influence", min: 0, max: 1, step: 0.01 }, index))) }));
15472
+ return (jsx(Fragment, { children: morphTargets.map((target, index) => (jsx(BoundProperty, { component: NumberInputPropertyLine, label: target.name || `Target ${index}`, description: `Influence of morph target "${target.name || `Target ${index}`}"`, target: target, propertyKey: "influence", step: 0.01 }, index))) }));
15337
15473
  };
15338
15474
 
15339
15475
  const NodeGeneralProperties = (props) => {
@@ -17216,7 +17352,8 @@ const SceneRenderingProperties = (props) => {
17216
17352
  const { scene, selectionService } = props;
17217
17353
  const envTexture = useProperty(scene, "environmentTexture");
17218
17354
  const fogMode = useProperty(scene, "fogMode");
17219
- return (jsxs(Fragment, { children: [jsx(NumberDropdownPropertyLine, { options: [
17355
+ const useOIT = useProperty(scene, "useOrderIndependentTransparency");
17356
+ return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "OIT", description: "Order Independent Transparency", target: scene, propertyKey: "useOrderIndependentTransparency" }), jsx(Collapse, { visible: useOIT, children: useOIT && scene.depthPeelingRenderer && (jsx(BoundProperty, { component: SyncedSliderPropertyLine, label: "passCount", description: "Render the number of transparent layers", target: scene.depthPeelingRenderer, propertyKey: "passCount", min: 2, max: 8, step: 1 })) }), jsx(NumberDropdownPropertyLine, { options: [
17220
17357
  { label: "Point", value: 0 },
17221
17358
  { label: "Wireframe", value: 1 },
17222
17359
  { label: "Solid", value: 2 },
@@ -19850,7 +19987,7 @@ const AnimationGroupExplorerServiceDefinition = {
19850
19987
  },
19851
19988
  };
19852
19989
  },
19853
- entityIcon: ({ entity }) => (entity instanceof AnimationGroup ? jsx(StackRegular, {}) : jsx(FilmstripRegular, {})),
19990
+ entityIcon: ({ entity }) => entity instanceof AnimationGroup ? jsx(StackRegular, { color: tokens.colorPaletteBlueForeground2 }) : jsx(FilmstripRegular, { color: tokens.colorPaletteBlueForeground2 }),
19854
19991
  getEntityAddedObservables: () => [scene.onNewAnimationGroupAddedObservable],
19855
19992
  getEntityRemovedObservables: () => [scene.onAnimationGroupRemovedObservable],
19856
19993
  });
@@ -19928,7 +20065,7 @@ const AtmosphereExplorerServiceDefinition = {
19928
20065
  },
19929
20066
  };
19930
20067
  },
19931
- entityIcon: () => jsx(WeatherSunnyLowFilled, {}),
20068
+ entityIcon: () => jsx(WeatherSunnyLowFilled, { color: tokens.colorPaletteYellowForeground2 }),
19932
20069
  // TODO in order for inspector UX to display atmosphere created after inspector is created
19933
20070
  getEntityAddedObservables: () => [],
19934
20071
  getEntityRemovedObservables: () => [],
@@ -19999,7 +20136,7 @@ const EffectLayerExplorerServiceDefinition = {
19999
20136
  },
20000
20137
  };
20001
20138
  },
20002
- entityIcon: () => jsx(LayerRegular, {}),
20139
+ entityIcon: () => jsx(LayerRegular, { color: tokens.colorPaletteRedForeground2 }),
20003
20140
  getEntityAddedObservables: () => [scene.onNewEffectLayerAddedObservable],
20004
20141
  getEntityRemovedObservables: () => [scene.onEffectLayerRemovedObservable],
20005
20142
  });
@@ -20037,7 +20174,7 @@ const FrameGraphExplorerServiceDefinition = {
20037
20174
  },
20038
20175
  };
20039
20176
  },
20040
- entityIcon: () => jsx(FrameRegular, {}),
20177
+ entityIcon: () => jsx(FrameRegular, { color: tokens.colorPaletteGreenForeground2 }),
20041
20178
  getEntityAddedObservables: () => [scene.onNewFrameGraphAddedObservable],
20042
20179
  getEntityRemovedObservables: () => [scene.onFrameGraphRemovedObservable],
20043
20180
  });
@@ -20169,7 +20306,7 @@ const GuiExplorerServiceDefinition = {
20169
20306
  },
20170
20307
  };
20171
20308
  },
20172
- entityIcon: ({ entity }) => (IsAdvancedDynamicTexture(entity) ? jsx(AppGenericRegular, {}) : jsx(RectangleLandscapeRegular, {})),
20309
+ entityIcon: ({ entity }) => IsAdvancedDynamicTexture(entity) ? (jsx(AppGenericRegular, { color: tokens.colorPaletteLilacForeground2 })) : (jsx(RectangleLandscapeRegular, { color: tokens.colorPaletteSeafoamForeground2 })),
20173
20310
  getEntityAddedObservables: () => [guiEntityAddedObservable],
20174
20311
  getEntityRemovedObservables: () => [guiEntityRemovedObservable],
20175
20312
  });
@@ -20274,7 +20411,7 @@ const MaterialExplorerServiceDefinition = {
20274
20411
  },
20275
20412
  };
20276
20413
  },
20277
- entityIcon: () => jsx(MaterialIcon, {}),
20414
+ entityIcon: () => jsx(MaterialIcon, { color: tokens.colorPaletteMarigoldForeground2 }),
20278
20415
  getEntityAddedObservables: () => [scene.onNewMaterialAddedObservable],
20279
20416
  getEntityRemovedObservables: () => [scene.onMaterialRemovedObservable],
20280
20417
  });
@@ -20356,7 +20493,7 @@ const NodeExplorerServiceDefinition = {
20356
20493
  },
20357
20494
  };
20358
20495
  },
20359
- entityIcon: ({ entity: node }) => node instanceof AbstractMesh ? (jsx(MeshIcon, {})) : node instanceof TransformNode ? (jsx(MyLocationRegular, {})) : node instanceof Camera ? (jsx(CameraRegular, {})) : node instanceof Light ? (jsx(LightbulbRegular, {})) : (jsx(Fragment, {})),
20496
+ entityIcon: ({ entity: node }) => node instanceof AbstractMesh ? (jsx(MeshIcon, { color: tokens.colorPaletteBlueForeground2 })) : node instanceof TransformNode ? (jsx(MyLocationRegular, { color: tokens.colorPaletteBlueForeground2 })) : node instanceof Camera ? (jsx(CameraRegular, { color: tokens.colorPaletteGreenForeground2 })) : node instanceof Light ? (jsx(LightbulbRegular, { color: tokens.colorPaletteYellowForeground2 })) : (jsx(Fragment, {})),
20360
20497
  getEntityAddedObservables: () => [
20361
20498
  scene.onNewMeshAddedObservable,
20362
20499
  scene.onNewTransformNodeAddedObservable,
@@ -20457,6 +20594,7 @@ const NodeExplorerServiceDefinition = {
20457
20594
  };
20458
20595
  },
20459
20596
  });
20597
+ const getActiveCamera = () => (scene.frameGraph ? FindMainCamera(scene.frameGraph) : scene.activeCamera);
20460
20598
  const activeCameraCommandRegistration = sceneExplorerService.addEntityCommand({
20461
20599
  predicate: (entity) => entity instanceof Camera,
20462
20600
  order: 700 /* DefaultCommandsOrder.CameraActive */,
@@ -20469,15 +20607,28 @@ const NodeExplorerServiceDefinition = {
20469
20607
  return {
20470
20608
  type: "toggle",
20471
20609
  displayName: "Activate and Attach Controls",
20472
- icon: () => (scene.activeCamera === camera ? jsx(VideoFilled, {}) : jsx(VideoRegular, {})),
20610
+ icon: () => {
20611
+ return getActiveCamera() === camera ? jsx(VideoFilled, {}) : jsx(VideoRegular, {});
20612
+ },
20473
20613
  get isEnabled() {
20474
- return scene.activeCamera === camera;
20614
+ return getActiveCamera() === camera;
20475
20615
  },
20476
20616
  set isEnabled(enabled) {
20477
- if (enabled && scene.activeCamera !== camera) {
20478
- scene.activeCamera?.detachControl();
20479
- scene.activeCamera = camera;
20480
- camera.attachControl(true);
20617
+ const activeCamera = getActiveCamera();
20618
+ if (enabled && activeCamera !== camera) {
20619
+ activeCamera?.detachControl();
20620
+ if (scene.frameGraph) {
20621
+ const objectRenderer = FindMainObjectRenderer(scene.frameGraph);
20622
+ if (objectRenderer) {
20623
+ objectRenderer.camera = camera;
20624
+ onChangeObservable.notifyObservers(); // manual trigger, because scene.onActiveCameraChanged won't be triggered by the line above
20625
+ camera.attachControl(true);
20626
+ }
20627
+ }
20628
+ else {
20629
+ scene.activeCamera = camera;
20630
+ camera.attachControl(true);
20631
+ }
20481
20632
  }
20482
20633
  },
20483
20634
  onChange: onChangeObservable,
@@ -20608,7 +20759,7 @@ const ParticleSystemExplorerServiceDefinition = {
20608
20759
  },
20609
20760
  };
20610
20761
  },
20611
- entityIcon: () => jsx(DropRegular, {}),
20762
+ entityIcon: () => jsx(DropRegular, { color: tokens.colorPaletteCranberryForeground2 }),
20612
20763
  getEntityAddedObservables: () => [scene.onNewParticleSystemAddedObservable],
20613
20764
  getEntityRemovedObservables: () => [scene.onParticleSystemRemovedObservable],
20614
20765
  });
@@ -20660,7 +20811,7 @@ const PostProcessExplorerServiceDefinition = {
20660
20811
  },
20661
20812
  };
20662
20813
  },
20663
- entityIcon: () => jsx(BlurRegular, {}),
20814
+ entityIcon: () => jsx(BlurRegular, { color: tokens.colorPaletteRedForeground2 }),
20664
20815
  getEntityAddedObservables: () => [scene.onNewPostProcessAddedObservable],
20665
20816
  getEntityRemovedObservables: () => [scene.onPostProcessRemovedObservable],
20666
20817
  });
@@ -20692,7 +20843,7 @@ const RenderingPipelineExplorerServiceDefinition = {
20692
20843
  },
20693
20844
  };
20694
20845
  },
20695
- entityIcon: () => jsx(PipelineRegular, {}),
20846
+ entityIcon: () => jsx(PipelineRegular, { color: tokens.colorPaletteRedForeground2 }),
20696
20847
  getEntityAddedObservables: () => [scene.postProcessRenderPipelineManager.onNewPipelineAddedObservable],
20697
20848
  getEntityRemovedObservables: () => [scene.postProcessRenderPipelineManager.onPipelineRemovedObservable],
20698
20849
  });
@@ -20734,7 +20885,7 @@ const SkeletonExplorerServiceDefinition = {
20734
20885
  },
20735
20886
  };
20736
20887
  },
20737
- entityIcon: ({ entity: skeletonOrBone }) => (skeletonOrBone instanceof Skeleton ? jsx(PersonWalkingRegular, {}) : jsx(DataLineRegular, {})),
20888
+ entityIcon: ({ entity: skeletonOrBone }) => skeletonOrBone instanceof Skeleton ? (jsx(PersonWalkingRegular, { color: tokens.colorPaletteAnchorForeground2 })) : (jsx(DataLineRegular, { color: tokens.colorPaletteBeigeForeground2 })),
20738
20889
  getEntityAddedObservables: () => [scene.onNewSkeletonAddedObservable],
20739
20890
  getEntityRemovedObservables: () => [scene.onSkeletonRemovedObservable],
20740
20891
  getEntityMovedObservables: () => [boneMovedObservable],
@@ -20795,7 +20946,7 @@ const SoundExplorerServiceDefinition = {
20795
20946
  },
20796
20947
  };
20797
20948
  },
20798
- entityIcon: () => jsx(SoundWaveCircleRegular, {}),
20949
+ entityIcon: () => jsx(SoundWaveCircleRegular, { color: tokens.colorPaletteForestForeground2 }),
20799
20950
  getEntityAddedObservables: () => [soundAddedObservable],
20800
20951
  getEntityRemovedObservables: () => [soundRemovedObservable],
20801
20952
  });
@@ -20839,7 +20990,7 @@ const SpriteManagerExplorerServiceDefinition = {
20839
20990
  },
20840
20991
  };
20841
20992
  },
20842
- entityIcon: ({ entity: spriteEntity }) => (spriteEntity instanceof Sprite ? jsx(PersonSquareRegular, {}) : jsx(LayerDiagonalPersonRegular, {})),
20993
+ entityIcon: ({ entity: spriteEntity }) => spriteEntity instanceof Sprite ? (jsx(PersonSquareRegular, { color: tokens.colorPalettePeachForeground2 })) : (jsx(LayerDiagonalPersonRegular, { color: tokens.colorPalettePeachForeground2 })),
20843
20994
  getEntityAddedObservables: () => [scene.onNewSpriteManagerAddedObservable],
20844
20995
  getEntityRemovedObservables: () => [scene.onSpriteManagerRemovedObservable],
20845
20996
  });
@@ -20911,7 +21062,7 @@ const TextureExplorerServiceDefinition = {
20911
21062
  },
20912
21063
  };
20913
21064
  },
20914
- entityIcon: ({ entity: texture }) => (texture instanceof DynamicTexture ? jsx(ImageEditRegular, {}) : jsx(ImageRegular, {})),
21065
+ entityIcon: ({ entity: texture }) => texture instanceof DynamicTexture ? jsx(ImageEditRegular, { color: tokens.colorPaletteGrapeForeground2 }) : jsx(ImageRegular, { color: tokens.colorPaletteGrapeForeground2 }),
20915
21066
  getEntityAddedObservables: () => [scene.onNewTextureAddedObservable],
20916
21067
  getEntityRemovedObservables: () => [scene.onTextureRemovedObservable],
20917
21068
  });
@@ -20939,7 +21090,7 @@ const EquirectangularCaptureTool = ({ scene }) => {
20939
21090
  };
20940
21091
 
20941
21092
  const GIFCaptureTool = MakeLazyComponent(async () => {
20942
- const gif = (await import('./gif-D_8cJm3S.js').then(function (n) { return n.g; })).default;
21093
+ const gif = (await import('./gif-CdXfT-By.js').then(function (n) { return n.g; })).default;
20943
21094
  // TODO: Figure out how to grab this from NPM package instead of CDN
20944
21095
  const workerContent = await Tools.LoadFileAsync("https://cdn.jsdelivr.net/gh//terikon/gif.js.optimized@0.1.6/dist/gif.worker.js");
20945
21096
  const workerBlob = new Blob([workerContent], { type: "application/javascript" });
@@ -21631,6 +21782,12 @@ const InspectorTokens = new WeakMap();
21631
21782
  // This async lock is used to sequentialize all calls to ShowInspector and dispose of existing inspectors.
21632
21783
  // This is needed because each time Inspector is shown or hidden, it is potentially mutating the same DOM element.
21633
21784
  const InspectorLock = new AsyncLock();
21785
+ /**
21786
+ * Shows the inspector for the specified scene.
21787
+ * @param scene The scene to inspect.
21788
+ * @param options Optional configuration for the inspector.
21789
+ * @returns An {@link InspectorToken} that can be disposed to hide the inspector.
21790
+ */
21634
21791
  function ShowInspector(scene, options = {}) {
21635
21792
  // Dispose of any existing inspector for this scene.
21636
21793
  InspectorTokens.get(scene)?.dispose();
@@ -22185,7 +22342,7 @@ class Inspector {
22185
22342
  this.MarkMultipleLineContainerTitlesForHighlighting([title]);
22186
22343
  }
22187
22344
  static MarkMultipleLineContainerTitlesForHighlighting(titles) {
22188
- this._SectionHighlighter?.(titles);
22345
+ this._OnMarkLineContainerObservable.notifyObservers(titles);
22189
22346
  }
22190
22347
  static PopupEmbed() {
22191
22348
  this._PopupToggler?.("right");
@@ -22209,6 +22366,13 @@ class Inspector {
22209
22366
  if (!scene || scene.isDisposed) {
22210
22367
  return;
22211
22368
  }
22369
+ // Inspector setup is async, so we need to cache pending selection requests.
22370
+ // Additionally, we manually track this (rather than relying on the observable's notifyIfTriggered property)
22371
+ // for behavior backward compatibility.
22372
+ let pendingSelection = null;
22373
+ const pendingSelectionObserver = this.OnSelectionChangeObservable.add((entity) => {
22374
+ pendingSelection = entity;
22375
+ });
22212
22376
  let options = ConvertOptions(userOptions);
22213
22377
  const serviceDefinitions = [];
22214
22378
  const popupServiceDefinition = {
@@ -22242,6 +22406,13 @@ class Inspector {
22242
22406
  const legacyObserver = this.OnSelectionChangeObservable.add((entity) => {
22243
22407
  selectionService.selectedEntity = entity;
22244
22408
  });
22409
+ // If a selection was requested before async setup completed, apply it now.
22410
+ if (pendingSelection) {
22411
+ selectionService.selectedEntity = pendingSelection;
22412
+ pendingSelection = null;
22413
+ }
22414
+ // Now the service is alive so we don't need to track pending selection requests.
22415
+ pendingSelectionObserver.remove();
22245
22416
  return {
22246
22417
  dispose: () => {
22247
22418
  selectionServiceObserver.remove();
@@ -22275,12 +22446,17 @@ class Inspector {
22275
22446
  friendlyName: "Section Highlighter Service (Backward Compatibility)",
22276
22447
  consumes: [PropertiesServiceIdentity],
22277
22448
  factory: (propertiesService) => {
22278
- this._SectionHighlighter = (sectionIds) => {
22279
- propertiesService.highlightSections(sectionIds.map((id) => LegacyPropertiesSectionMapping[id] ?? id));
22280
- };
22449
+ const markLineContainerObserver = this._OnMarkLineContainerObservable.add((sections) => {
22450
+ propertiesService.highlightSections(sections.map((id) => LegacyPropertiesSectionMapping[id] ?? id));
22451
+ });
22452
+ // Now the service is alive so we don't need to track pending highlight requests.
22453
+ this._OnMarkLineContainerObservable.notifyIfTriggered = false;
22454
+ this._OnMarkLineContainerObservable.cleanLastNotifiedState();
22281
22455
  return {
22282
22456
  dispose: () => {
22283
- this._SectionHighlighter = null;
22457
+ // Service is being torn down, so start caching pending highlight requests again.
22458
+ markLineContainerObserver.remove();
22459
+ this._OnMarkLineContainerObservable.notifyIfTriggered = true;
22284
22460
  },
22285
22461
  };
22286
22462
  },
@@ -22330,10 +22506,10 @@ class Inspector {
22330
22506
  }
22331
22507
  Inspector._CurrentInstance = null;
22332
22508
  Inspector._PopupToggler = null;
22333
- Inspector._SectionHighlighter = null;
22334
22509
  Inspector._SidePaneOpenCounter = null;
22335
22510
  Inspector.OnSelectionChangeObservable = new Observable();
22336
22511
  Inspector.OnPropertyChangedObservable = new Observable();
22512
+ Inspector._OnMarkLineContainerObservable = new Observable(undefined, true);
22337
22513
 
22338
22514
  var inspector = /*#__PURE__*/Object.freeze({
22339
22515
  __proto__: null,
@@ -22642,5 +22818,5 @@ const TextAreaPropertyLine = (props) => {
22642
22818
  // Attach Inspector v2 to Scene.debugLayer as a side effect for back compat.
22643
22819
  AttachDebugLayer();
22644
22820
 
22645
- export { useObservableCollection as $, Accordion as A, Button as B, CheckboxPropertyLine as C, DebugServiceIdentity as D, ErrorBoundary as E, ExtensibleAccordion as F, GizmoServiceIdentity as G, Theme as H, Inspector as I, TeachingMoment as J, PropertyContext as K, LinkToEntity as L, MessageBar as M, NumberInputPropertyLine as N, usePropertyChangedNotifier as O, Popover as P, BuiltInsExtensionFeed as Q, useVector3Property as R, SpinButtonPropertyLine as S, TextInputPropertyLine as T, useColor3Property as U, Vector3PropertyLine as V, useColor4Property as W, useQuaternionProperty as X, MakePropertyHook as Y, useInterceptObservable as Z, useEventfulState as _, useProperty as a, Pane as a$, useOrderedObservableCollection as a0, usePollingObservable as a1, useResource as a2, useAsyncResource as a3, useSetting as a4, useAngleConverters as a5, MakeTeachingMoment as a6, MakeDialogTeachingMoment as a7, MakePopoverTeachingMoment as a8, useThemeMode as a9, Color3GradientComponent as aA, Color4GradientComponent as aB, ColorStepGradientComponent as aC, InfoLabel as aD, MakeLazyComponent as aE, List as aF, MaterialSelector as aG, NodeSelector as aH, PositionedPopover as aI, SearchBar as aJ, SearchBox as aK, SkeletonSelector as aL, SpinButton as aM, Switch as aN, SyncedSliderInput as aO, Textarea as aP, TextInput as aQ, TextureSelector as aR, ToastProvider as aS, ToggleButton as aT, Tooltip as aU, UploadButton as aV, ChildWindow as aW, FileUploadLine as aX, FactorGradientList as aY, Color3GradientList as aZ, Color4GradientList as a_, useTheme as aa, InterceptFunction as ab, GetPropertyDescriptor as ac, IsPropertyReadonly as ad, InterceptProperty as ae, ObservableCollection as af, ConstructorFactory as ag, SelectionServiceDefinition as ah, SettingsStore as ai, ShowInspector as aj, useKeyListener as ak, useKeyState as al, useEventListener as am, AccordionSectionItem as an, Checkbox as ao, Collapse as ap, ColorPickerPopup as aq, InputHexField as ar, InputHsvField as as, ComboBox as at, DraggableLine as au, Dropdown as av, NumberDropdown as aw, StringDropdown as ax, EntitySelector as ay, FactorGradientComponent as az, ShellServiceIdentity as b, TextureUpload as b0, BooleanBadgePropertyLine as b1, Color3PropertyLine as b2, Color4PropertyLine as b3, ComboBoxPropertyLine as b4, HexPropertyLine as b5, LinkPropertyLine as b6, PropertyLine as b7, LineContainer as b8, PlaceholderPropertyLine as b9, StringifiedPropertyLine as ba, SwitchPropertyLine as bb, SyncedSliderPropertyLine as bc, TextAreaPropertyLine as bd, TextPropertyLine as be, RotationVectorPropertyLine as bf, QuaternionPropertyLine as bg, Vector2PropertyLine as bh, Vector4PropertyLine as bi, SceneContextIdentity as c, SelectionServiceIdentity as d, useObservableState as e, AccordionSection as f, ButtonLine as g, ToolsServiceIdentity as h, useExtensionManager as i, Link as j, SidePaneContainer as k, PropertiesServiceIdentity as l, SceneExplorerServiceIdentity as m, SettingsServiceIdentity as n, StatsServiceIdentity as o, ThemeServiceIdentity as p, SettingsStoreIdentity as q, ConvertOptions as r, AttachDebugLayer as s, DetachDebugLayer as t, useToast as u, NumberDropdownPropertyLine as v, StringDropdownPropertyLine as w, BoundProperty as x, Property as y, LinkToEntityPropertyLine as z };
22646
- //# sourceMappingURL=index-BvYg0Psk.js.map
22821
+ export { HexPropertyLine as $, Accordion as A, Button as B, CheckboxPropertyLine as C, ColorStepGradientComponent as D, ComboBox as E, ComboBoxPropertyLine as F, ConstructorFactory as G, ConvertOptions as H, DebugServiceIdentity as I, DetachDebugLayer as J, DraggableLine as K, LinkToEntity as L, MessageBar as M, NumberInputPropertyLine as N, Dropdown as O, Popover as P, EntitySelector as Q, ErrorBoundary as R, SpinButtonPropertyLine as S, TextInputPropertyLine as T, ExtensibleAccordion as U, Vector3PropertyLine as V, FactorGradientComponent as W, FactorGradientList as X, FileUploadLine as Y, GetPropertyDescriptor as Z, GizmoServiceIdentity as _, useProperty as a, Vector2PropertyLine as a$, InfoLabel as a0, InputHexField as a1, InputHsvField as a2, Inspector as a3, InterceptFunction as a4, InterceptProperty as a5, IsPropertyReadonly as a6, LineContainer as a7, LinkPropertyLine as a8, LinkToEntityPropertyLine as a9, SettingsStoreIdentity as aA, ShowInspector as aB, SidePaneContainer as aC, SkeletonSelector as aD, Slider as aE, SpinButton as aF, StatsServiceIdentity as aG, StringDropdown as aH, StringDropdownPropertyLine as aI, StringifiedPropertyLine as aJ, Switch as aK, SwitchPropertyLine as aL, SyncedSliderInput as aM, SyncedSliderPropertyLine as aN, TeachingMoment as aO, TextAreaPropertyLine as aP, TextInput as aQ, TextPropertyLine as aR, Textarea as aS, TextureSelector as aT, TextureUpload as aU, Theme as aV, ThemeServiceIdentity as aW, ToastProvider as aX, ToggleButton as aY, Tooltip as aZ, UploadButton as a_, List as aa, MakeDialogTeachingMoment as ab, MakeLazyComponent as ac, MakePopoverTeachingMoment as ad, MakePropertyHook as ae, MakeTeachingMoment as af, MaterialSelector as ag, NodeSelector as ah, NumberDropdown as ai, NumberDropdownPropertyLine as aj, ObservableCollection as ak, Pane as al, PlaceholderPropertyLine as am, PositionedPopover as an, PropertiesServiceIdentity as ao, Property as ap, PropertyContext as aq, PropertyLine as ar, QuaternionPropertyLine as as, RotationVectorPropertyLine as at, SceneExplorerServiceIdentity as au, SearchBar as av, SearchBox as aw, SelectionServiceDefinition as ax, SettingsServiceIdentity as ay, SettingsStore as az, ShellServiceIdentity as b, Vector4PropertyLine as b0, WatcherServiceIdentity as b1, useAngleConverters as b2, useAsyncResource as b3, useColor3Property as b4, useColor4Property as b5, useEventListener as b6, useEventfulState as b7, useInterceptObservable as b8, useKeyListener as b9, useKeyState as ba, useObservableCollection as bb, useOrderedObservableCollection as bc, usePollingObservable as bd, usePropertyChangedNotifier as be, useQuaternionProperty as bf, useResource as bg, useSetting as bh, useTheme as bi, useThemeMode as bj, useVector3Property as bk, SceneContextIdentity as c, SelectionServiceIdentity as d, useObservableState as e, AccordionSection as f, ButtonLine as g, ToolsServiceIdentity as h, useExtensionManager as i, Link as j, AccordionSectionItem as k, AttachDebugLayer as l, BooleanBadgePropertyLine as m, BoundProperty as n, BuiltInsExtensionFeed as o, Checkbox as p, ChildWindow as q, Collapse as r, Color3GradientComponent as s, Color3GradientList as t, useToast as u, Color3PropertyLine as v, Color4GradientComponent as w, Color4GradientList as x, Color4PropertyLine as y, ColorPickerPopup as z };
22822
+ //# sourceMappingURL=index-xzWdtYzo.js.map