@babylonjs/inspector 8.50.5 → 8.51.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.
@@ -0,0 +1,749 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { P as Popover, u as useToast, B as Button, L as LinkToEntity, T as TextInputPropertyLine, S as SpinButtonPropertyLine, C as CheckboxPropertyLine, V as Vector3PropertyLine, a as useProperty, M as MessageBar, b as ShellServiceIdentity, c as SceneContextIdentity, d as SelectionServiceIdentity, e as useObservableState, A as Accordion, f as AccordionSection } from './index-BYCyHkKl.js';
3
+ import { SettingsRegular, CollectionsAdd20Regular } from '@fluentui/react-icons';
4
+ import '@babylonjs/core/Particles/webgl2ParticleSystem.js';
5
+ import '@babylonjs/core/Rendering/prePassRendererSceneComponent.js';
6
+ import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder.js';
7
+ import { useState, useCallback, useRef } from 'react';
8
+ import { FilesInput } from '@babylonjs/core/Misc/filesInput.js';
9
+ import { makeStyles, tokens } from '@fluentui/react-components';
10
+ import { NodeMaterial } from '@babylonjs/core/Materials/Node/nodeMaterial.js';
11
+ import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial.js';
12
+ import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial.js';
13
+ import { PointLight } from '@babylonjs/core/Lights/pointLight.js';
14
+ import { DirectionalLight } from '@babylonjs/core/Lights/directionalLight.js';
15
+ import { SpotLight } from '@babylonjs/core/Lights/spotLight.js';
16
+ import { Vector3 } from '@babylonjs/core/Maths/math.vector.js';
17
+ import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera.js';
18
+ import { UniversalCamera } from '@babylonjs/core/Cameras/universalCamera.js';
19
+ import { FreeCamera } from '@babylonjs/core/Cameras/freeCamera.js';
20
+ import { FollowCamera } from '@babylonjs/core/Cameras/followCamera.js';
21
+ import { FlyCamera } from '@babylonjs/core/Cameras/flyCamera.js';
22
+ import { GeospatialCamera } from '@babylonjs/core/Cameras/geospatialCamera.js';
23
+ import { ParticleSystem } from '@babylonjs/core/Particles/particleSystem.js';
24
+ import { GPUParticleSystem } from '@babylonjs/core/Particles/gpuParticleSystem.js';
25
+ import { NodeParticleSystemSet } from '@babylonjs/core/Particles/Node/nodeParticleSystemSet.js';
26
+ import { Texture } from '@babylonjs/core/Materials/Textures/texture.js';
27
+ import { DefaultRenderingPipeline } from '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.js';
28
+ import { SSAORenderingPipeline } from '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/ssaoRenderingPipeline.js';
29
+ import { SSAO2RenderingPipeline } from '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.js';
30
+ import { SSRRenderingPipeline } from '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/ssrRenderingPipeline.js';
31
+ import { IblShadowsRenderPipeline } from '@babylonjs/core/Rendering/IBLShadows/iblShadowsRenderPipeline.js';
32
+ import { NodeRenderGraph } from '@babylonjs/core/FrameGraph/Node/nodeRenderGraph.js';
33
+ import { SpriteManager } from '@babylonjs/core/Sprites/spriteManager.js';
34
+ import '@babylonjs/core/Maths/math.color.js';
35
+ import '@babylonjs/core/Misc/observable.js';
36
+ import '@babylonjs/core/Misc/typeStore.js';
37
+ import '@babylonjs/core/Misc/dataStorage.js';
38
+ import '@babylonjs/core/Misc/logger.js';
39
+ import '@fluentui/react-motion-components-preview';
40
+ import '@babylonjs/core/Misc/asyncLock.js';
41
+ import '@babylonjs/core/Misc/deferred.js';
42
+ import '@babylonjs/core/Maths/math.scalar.functions.js';
43
+ import '@fluentui-contrib/react-virtualizer';
44
+ import '@babylonjs/core/Misc/uniqueIdGenerator.js';
45
+ import '@babylonjs/addons/msdfText/fontAsset.js';
46
+ import '@babylonjs/addons/msdfText/textRenderer.js';
47
+ import '@babylonjs/core/Debug/physicsViewer.js';
48
+ import '@babylonjs/core/Materials/materialFlags.js';
49
+ import '@babylonjs/core/Meshes/Builders/groundBuilder.js';
50
+ import '@babylonjs/core/Misc/tools.js';
51
+ import '@babylonjs/core/Rendering/utilityLayerRenderer.js';
52
+ import '@babylonjs/materials/grid/gridMaterial.js';
53
+ import '@babylonjs/core/Instrumentation/engineInstrumentation.js';
54
+ import '@babylonjs/core/Instrumentation/sceneInstrumentation.js';
55
+ import '@babylonjs/core/Engines/AbstractEngine/abstractEngine.timeQuery.js';
56
+ import '@babylonjs/core/Engines/Extensions/engine.query.js';
57
+ import '@babylonjs/core/Engines/WebGPU/Extensions/engine.query.js';
58
+ import '@babylonjs/core/Misc/PerformanceViewer/performanceViewerCollectionStrategies.js';
59
+ import '@babylonjs/core/Misc/PerformanceViewer/performanceViewerSceneExtension.js';
60
+ import '@babylonjs/core/Misc/pressureObserverWrapper.js';
61
+ import '@babylonjs/core/Maths/math.scalar.js';
62
+ import '@babylonjs/core/Misc/PerformanceViewer/performanceViewerCollector.js';
63
+ import '@babylonjs/core/Engines/abstractEngine.js';
64
+ import '@babylonjs/core/Bones/bone.js';
65
+ import '@babylonjs/core/Cameras/camera.js';
66
+ import '@babylonjs/core/FrameGraph/frameGraphUtils.js';
67
+ import '@babylonjs/core/Gizmos/cameraGizmo.js';
68
+ import '@babylonjs/core/Gizmos/gizmoManager.js';
69
+ import '@babylonjs/core/Gizmos/lightGizmo.js';
70
+ import '@babylonjs/core/Lights/light.js';
71
+ import '@babylonjs/core/Meshes/abstractMesh.js';
72
+ import '@babylonjs/core/node.js';
73
+ import 'react-dom/client';
74
+ import '@babylonjs/core/Animations/animationGroup.js';
75
+ import '@babylonjs/core/Animations/animation.js';
76
+ import '@babylonjs/core/Animations/animationPropertiesOverride.js';
77
+ import '@babylonjs/core/Audio/sound.js';
78
+ import '@babylonjs/core/Cameras/targetCamera.js';
79
+ import '@babylonjs/core/scene.js';
80
+ import '@babylonjs/core/FrameGraph/frameGraph.js';
81
+ import '@babylonjs/core/Lights/hemisphericLight.js';
82
+ import '@babylonjs/core/Lights/rectAreaLight.js';
83
+ import '@babylonjs/core/Lights/shadowLight.js';
84
+ import '@babylonjs/core/Lights/Shadows/cascadedShadowGenerator.js';
85
+ import '@babylonjs/core/Debug/directionalLightFrustumViewer.js';
86
+ import '@babylonjs/core/Lights/Shadows/shadowGenerator.js';
87
+ import '@babylonjs/core/Lights/Shadows/shadowGeneratorSceneComponent.js';
88
+ import '@babylonjs/core/Materials/material.js';
89
+ import '@babylonjs/core/Materials/multiMaterial.js';
90
+ import '@babylonjs/core/Materials/PBR/openpbrMaterial.js';
91
+ import '@babylonjs/core/Materials/PBR/pbrBaseMaterial.js';
92
+ import '@babylonjs/materials/sky/skyMaterial.js';
93
+ import '@babylonjs/core/Engines/constants.js';
94
+ import '@babylonjs/core/Engines/engine.js';
95
+ import '@babylonjs/core/Materials/Node/Blocks/gradientBlock.js';
96
+ import '@babylonjs/core/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes.js';
97
+ import '@babylonjs/core/Misc/gradients.js';
98
+ import '@babylonjs/core/Misc/fileTools.js';
99
+ import '@babylonjs/core/Materials/Textures/cubeTexture.js';
100
+ import '@babylonjs/core/Meshes/GaussianSplatting/gaussianSplattingMesh.js';
101
+ import '@babylonjs/core/Meshes/mesh.js';
102
+ import '@babylonjs/core/Debug/skeletonViewer.js';
103
+ import '@babylonjs/core/Meshes/buffer.js';
104
+ import '@babylonjs/core/Meshes/Builders/linesBuilder.js';
105
+ import '@babylonjs/core/Meshes/instancedMesh.js';
106
+ import '@babylonjs/core/Rendering/renderingManager.js';
107
+ import '@babylonjs/core/Rendering/edgesRenderer.js';
108
+ import '@babylonjs/core/Rendering/outlineRenderer.js';
109
+ import '@babylonjs/core/Particles/Node/nodeParticleSystemSet.helper.js';
110
+ import '@babylonjs/core/Particles/particleHelper.js';
111
+ import '@babylonjs/core/Particles/EmitterTypes/boxParticleEmitter.js';
112
+ import '@babylonjs/core/Particles/EmitterTypes/coneParticleEmitter.js';
113
+ import '@babylonjs/core/Particles/EmitterTypes/cylinderParticleEmitter.js';
114
+ import '@babylonjs/core/Particles/EmitterTypes/hemisphericParticleEmitter.js';
115
+ import '@babylonjs/core/Particles/EmitterTypes/meshParticleEmitter.js';
116
+ import '@babylonjs/core/Particles/EmitterTypes/pointParticleEmitter.js';
117
+ import '@babylonjs/core/Particles/EmitterTypes/sphereParticleEmitter.js';
118
+ import '@babylonjs/core/Particles/attractor.js';
119
+ import '@babylonjs/core/Meshes/Builders/sphereBuilder.js';
120
+ import '@babylonjs/core/Particles/Node/Blocks/particleInputBlock.js';
121
+ import '@babylonjs/core/Particles/Node/Blocks/Update/updateAttractorBlock.js';
122
+ import '@babylonjs/core/Particles/Node/Enums/nodeParticleBlockConnectionPointTypes.js';
123
+ import '@babylonjs/core/Meshes/transformNode.js';
124
+ import '@babylonjs/core/Physics/v2/IPhysicsEnginePlugin.js';
125
+ import '@babylonjs/core/Physics/v2/physicsEngineComponent.js';
126
+ import '@babylonjs/core/PostProcesses/postProcess.js';
127
+ import '@babylonjs/core/PostProcesses/RenderPipeline/postProcessRenderPipeline.js';
128
+ import '@babylonjs/core/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline.js';
129
+ import '@babylonjs/core/Materials/imageProcessingConfiguration.js';
130
+ import '@babylonjs/core/Bones/skeleton.js';
131
+ import '@babylonjs/core/Sprites/sprite.js';
132
+ import '@babylonjs/core/Misc/textureTools.js';
133
+ import '@babylonjs/core/Materials/Textures/baseTexture.js';
134
+ import '@babylonjs/core/Materials/Textures/multiRenderTarget.js';
135
+ import '@babylonjs/core/Materials/Textures/renderTargetTexture.js';
136
+ import '@babylonjs/core/Materials/Textures/thinTexture.js';
137
+ import '@babylonjs/core/Events/keyboardEvents.js';
138
+ import '@babylonjs/core/Events/pointerEvents.js';
139
+ import '@babylonjs/core/Materials/Textures/htmlElementTexture.js';
140
+ import '@babylonjs/core/Materials/shaderMaterial.js';
141
+ import '@babylonjs/core/Meshes/Builders/planeBuilder.js';
142
+ import '@babylonjs/core/Lights/Clustered/clusteredLightContainer.js';
143
+ import '@babylonjs/core/Rendering/boundingBoxRenderer.js';
144
+ import '@babylonjs/core/PostProcesses/RenderPipeline/postProcessRenderPipelineManagerSceneComponent.js';
145
+ import '@babylonjs/core/Sprites/spriteSceneComponent.js';
146
+ import '@babylonjs/core/Materials/Textures/dynamicTexture.js';
147
+ import '@babylonjs/core/Misc/equirectangularCapture.js';
148
+ import '@babylonjs/core/Misc/sceneRecorder.js';
149
+ import '@babylonjs/core/Misc/screenshotTools.js';
150
+ import '@babylonjs/core/Misc/videoRecorder.js';
151
+ import '@babylonjs/core/Misc/sceneSerializer.js';
152
+ import '@babylonjs/core/Misc/environmentTextureTools.js';
153
+ import '@babylonjs/core/Loading/sceneLoader.js';
154
+ import '@babylonjs/loaders/glTF/glTFFileLoader.js';
155
+ import '@babylonjs/loaders/glTF/glTFValidation.js';
156
+ import '@babylonjs/core/Layers/selectionOutlineLayer.js';
157
+ import '@babylonjs/core/Engines/engineStore.js';
158
+ import '@babylonjs/core/Debug/debugLayer.js';
159
+ import '@babylonjs/core/Misc/lazy.js';
160
+
161
+ /**
162
+ * Settings popover component
163
+ * @param props
164
+ * @returns
165
+ */
166
+ const SettingsPopover = (props) => {
167
+ return (jsx(Popover, { icon: SettingsRegular, open: props.open, onOpenChange: props.onOpenChange, children: props.children }));
168
+ };
169
+
170
+ const useStyles = makeStyles({
171
+ section: {
172
+ display: "flex",
173
+ flexDirection: "column",
174
+ rowGap: tokens.spacingVerticalM,
175
+ },
176
+ row: { display: "flex", alignItems: "center", gap: "4px" },
177
+ rightAligned: { marginLeft: "auto" },
178
+ });
179
+ /**
180
+ * Container component for quick create sections that provides consistent column layout with spacing
181
+ * @param props - Component props
182
+ * @returns React component
183
+ */
184
+ const QuickCreateSection = ({ children }) => {
185
+ const classes = useStyles();
186
+ return jsx("div", { className: classes.section, children: children });
187
+ };
188
+ /**
189
+ * Container component for quick create rows that provides consistent row layout for button + settings popover
190
+ * @param props - Component props
191
+ * @returns React component
192
+ */
193
+ const QuickCreateRow = ({ children }) => {
194
+ const classes = useStyles();
195
+ return jsx("div", { className: classes.row, children: children });
196
+ };
197
+ /**
198
+ * Reusable row component for entity creation. Renders a quick-create button, an optional settings popover
199
+ * (with a baked-in Create button), and a "go to entity" button. Manages its own state for the last created entity
200
+ * and shows a toast on creation.
201
+ * @param props - The label, creation handler, selection service, and optional settings content
202
+ * @returns A row with a button, optional settings popover, and go-to-entity button
203
+ */
204
+ const QuickCreateItem = ({ selectionService, label, onCreate, onSettingsCreate, children }) => {
205
+ const [lastCreatedEntity, setLastCreatedEntity] = useState(null);
206
+ const [popoverOpen, setPopoverOpen] = useState(false);
207
+ const { showToast } = useToast();
208
+ const classes = useStyles();
209
+ const handleCreate = useCallback(async (factory) => {
210
+ try {
211
+ const entity = await factory();
212
+ setLastCreatedEntity(entity);
213
+ showToast(`Created ${entity.name}`);
214
+ }
215
+ catch (e) {
216
+ showToast(`Creation failed: ${e instanceof Error ? e.message : String(e)}`);
217
+ }
218
+ }, [showToast]);
219
+ return (jsxs("div", { className: classes.row, children: [jsx(Button, { onClick: () => void handleCreate(onCreate), label: label }), children && (jsxs(SettingsPopover, { open: popoverOpen, onOpenChange: setPopoverOpen, children: [children, jsx(Button, { appearance: "primary", onClick: () => {
220
+ setPopoverOpen(false);
221
+ void handleCreate(onSettingsCreate ?? onCreate);
222
+ }, label: "Create" })] })), jsx("div", { className: classes.rightAligned, children: jsx(LinkToEntity, { entity: lastCreatedEntity, selectionService: selectionService }) })] }));
223
+ };
224
+
225
+ const SetCamera = function (scene) {
226
+ const camera = scene.activeCamera;
227
+ if (camera && camera.radius !== undefined) {
228
+ camera.radius = 5;
229
+ }
230
+ };
231
+ /**
232
+ * @internal
233
+ */
234
+ const MeshesContent = ({ scene, selectionService }) => {
235
+ const [sphereParams, setSphereParams] = useState({
236
+ name: "Sphere",
237
+ segments: 32,
238
+ diameter: 1,
239
+ diameterX: 1,
240
+ diameterY: 1,
241
+ diameterZ: 1,
242
+ arc: 1,
243
+ slice: 1,
244
+ uniform: true,
245
+ });
246
+ const handleSphereParamChange = (key, value) => {
247
+ setSphereParams((prev) => ({
248
+ ...prev,
249
+ [key]: value,
250
+ }));
251
+ };
252
+ const [boxParams, setBoxParams] = useState({
253
+ name: "Box",
254
+ size: 1,
255
+ width: 1,
256
+ height: 1,
257
+ depth: 1,
258
+ });
259
+ const handleBoxParamChange = (key, value) => {
260
+ setBoxParams((prev) => ({
261
+ ...prev,
262
+ [key]: value,
263
+ }));
264
+ };
265
+ const [cylinderParams, setCylinderParams] = useState({
266
+ name: "Cylinder",
267
+ height: 2,
268
+ diameterTop: 1,
269
+ diameterBottom: 1,
270
+ diameter: 1,
271
+ tessellation: 32,
272
+ subdivisions: 1,
273
+ arc: 1,
274
+ });
275
+ const handleCylinderParamChange = (key, value) => {
276
+ setCylinderParams((prev) => ({
277
+ ...prev,
278
+ [key]: value,
279
+ }));
280
+ };
281
+ const [coneParams, setConeParams] = useState({
282
+ name: "Cone",
283
+ height: 2,
284
+ diameter: 1,
285
+ diameterTop: 0,
286
+ diameterBottom: 1,
287
+ tessellation: 32,
288
+ subdivisions: 1,
289
+ arc: 1,
290
+ });
291
+ const [coneUp, setConeUp] = useState(true);
292
+ const handleConeParamChange = (key, value) => {
293
+ setConeParams((prev) => ({
294
+ ...prev,
295
+ [key]: value,
296
+ }));
297
+ };
298
+ const [groundParams, setGroundParams] = useState({
299
+ name: "Ground",
300
+ width: 10,
301
+ height: 10,
302
+ subdivisions: 1,
303
+ subdivisionsX: 1,
304
+ subdivisionsY: 1,
305
+ });
306
+ const handleGroundParamChange = (key, value) => {
307
+ setGroundParams((prev) => ({
308
+ ...prev,
309
+ [key]: value,
310
+ }));
311
+ };
312
+ const fileInputRef = useRef(null);
313
+ const [importMeshName, setImportMeshName] = useState("ImportedMesh");
314
+ const handleLocalMeshImport = (event) => {
315
+ const files = event.target.files;
316
+ if (!files || files.length === 0) {
317
+ return;
318
+ }
319
+ const filesArray = Array.from(files);
320
+ if (importMeshName.trim().length > 0 && filesArray.length > 0) {
321
+ const originalFile = filesArray[0];
322
+ const extensionIndex = originalFile.name.lastIndexOf(".");
323
+ const extension = extensionIndex >= 0 ? originalFile.name.substring(extensionIndex) : "";
324
+ const sanitizedName = importMeshName.trim();
325
+ const desiredFileName = sanitizedName.toLowerCase().endsWith(extension.toLowerCase()) ? sanitizedName : `${sanitizedName}${extension}`;
326
+ filesArray[0] = new File([originalFile], desiredFileName, { type: originalFile.type, lastModified: originalFile.lastModified });
327
+ }
328
+ const filesInput = new FilesInput(scene.getEngine(), scene, null, null, null, null, null, null, (_sceneFile, _scene, message) => {
329
+ alert(message ? `Failed to import mesh: ${message}` : "Failed to import mesh.");
330
+ }, true);
331
+ filesInput.displayLoadingUI = false;
332
+ filesInput.loadFiles({ target: { files: filesArray } });
333
+ filesInput.dispose();
334
+ event.target.value = "";
335
+ };
336
+ return (jsxs(QuickCreateSection, { children: [jsxs(QuickCreateItem, { selectionService: selectionService, label: "Sphere", onCreate: () => {
337
+ const mesh = MeshBuilder.CreateSphere("Sphere", {}, scene);
338
+ SetCamera(scene);
339
+ return mesh;
340
+ }, onSettingsCreate: () => {
341
+ const createParams = {
342
+ segments: sphereParams.segments,
343
+ arc: sphereParams.arc,
344
+ slice: sphereParams.slice,
345
+ };
346
+ if (sphereParams.uniform) {
347
+ createParams.diameter = sphereParams.diameter;
348
+ }
349
+ else {
350
+ createParams.diameterX = sphereParams.diameterX;
351
+ createParams.diameterY = sphereParams.diameterY;
352
+ createParams.diameterZ = sphereParams.diameterZ;
353
+ }
354
+ const mesh = MeshBuilder.CreateSphere(sphereParams.name, createParams, scene);
355
+ SetCamera(scene);
356
+ return mesh;
357
+ }, children: [jsx(TextInputPropertyLine, { label: "Name", value: sphereParams.name, onChange: (val) => handleSphereParamChange("name", val) }), jsx(SpinButtonPropertyLine, { label: "Segments", value: sphereParams.segments, min: 0, onChange: (val) => handleSphereParamChange("segments", val) }), jsx(SpinButtonPropertyLine, { label: "Diameter", value: sphereParams.diameter, min: 0, step: 0.1, onChange: (val) => handleSphereParamChange("diameter", val), disabled: !sphereParams.uniform }), jsx(CheckboxPropertyLine, { label: "Uniform", value: sphereParams.uniform, onChange: (checked) => handleSphereParamChange("uniform", checked) }), jsx(SpinButtonPropertyLine, { label: "Diameter X", value: sphereParams.diameterX, min: 0, step: 0.1, onChange: (val) => handleSphereParamChange("diameterX", val), disabled: sphereParams.uniform }), jsx(SpinButtonPropertyLine, { label: "Diameter Y", value: sphereParams.diameterY, min: 0, step: 0.1, onChange: (val) => handleSphereParamChange("diameterY", val), disabled: sphereParams.uniform }), jsx(SpinButtonPropertyLine, { label: "Diameter Z", value: sphereParams.diameterZ, min: 0, step: 0.1, onChange: (val) => handleSphereParamChange("diameterZ", val), disabled: sphereParams.uniform }), jsx(SpinButtonPropertyLine, { label: "Arc", value: sphereParams.arc, min: 0, max: 1, step: 0.1, onChange: (val) => handleSphereParamChange("arc", val) }), jsx(SpinButtonPropertyLine, { label: "Slice", value: sphereParams.slice, min: 0, max: 1, step: 0.1, onChange: (val) => handleSphereParamChange("slice", val) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Box", onCreate: () => {
358
+ const mesh = MeshBuilder.CreateBox("Box", {}, scene);
359
+ SetCamera(scene);
360
+ return mesh;
361
+ }, onSettingsCreate: () => {
362
+ const mesh = MeshBuilder.CreateBox(boxParams.name, boxParams, scene);
363
+ SetCamera(scene);
364
+ return mesh;
365
+ }, children: [jsx(TextInputPropertyLine, { label: "Name", value: boxParams.name, onChange: (val) => handleBoxParamChange("name", val) }), jsx(SpinButtonPropertyLine, { label: "Size", value: boxParams.size, min: 0, step: 0.1, onChange: (val) => handleBoxParamChange("size", val) }), jsx(SpinButtonPropertyLine, { label: "Width", value: boxParams.width, min: 0, step: 0.1, onChange: (val) => handleBoxParamChange("width", val) }), jsx(SpinButtonPropertyLine, { label: "Height", value: boxParams.height, min: 0, step: 0.1, onChange: (val) => handleBoxParamChange("height", val) }), jsx(SpinButtonPropertyLine, { label: "Depth", value: boxParams.depth, min: 0, step: 0.1, onChange: (val) => handleBoxParamChange("depth", val) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Cylinder", onCreate: () => {
366
+ const mesh = MeshBuilder.CreateCylinder("Cylinder", {}, scene);
367
+ SetCamera(scene);
368
+ return mesh;
369
+ }, onSettingsCreate: () => {
370
+ const mesh = MeshBuilder.CreateCylinder(cylinderParams.name, cylinderParams, scene);
371
+ SetCamera(scene);
372
+ return mesh;
373
+ }, children: [jsx(TextInputPropertyLine, { label: "Name", value: cylinderParams.name, onChange: (val) => handleCylinderParamChange("name", val) }), jsx(SpinButtonPropertyLine, { label: "Height", value: cylinderParams.height, min: 0, step: 0.1, onChange: (val) => handleCylinderParamChange("height", val) }), jsx(SpinButtonPropertyLine, { label: "Diameter Top", value: cylinderParams.diameterTop, min: 0, step: 0.1, onChange: (val) => handleCylinderParamChange("diameterTop", val) }), jsx(SpinButtonPropertyLine, { label: "Diameter Bottom", value: cylinderParams.diameterBottom, min: 0, step: 0.1, onChange: (val) => handleCylinderParamChange("diameterBottom", val) }), jsx(SpinButtonPropertyLine, { label: "Diameter", value: cylinderParams.diameter, min: 0, step: 0.1, onChange: (val) => handleCylinderParamChange("diameter", val) }), jsx(SpinButtonPropertyLine, { label: "Tessellation", value: cylinderParams.tessellation, min: 3, onChange: (val) => handleCylinderParamChange("tessellation", val) }), jsx(SpinButtonPropertyLine, { label: "Subdivisions", value: cylinderParams.subdivisions, min: 1, onChange: (val) => handleCylinderParamChange("subdivisions", val) }), jsx(SpinButtonPropertyLine, { label: "Arc", value: cylinderParams.arc, min: 0, max: 1, step: 0.1, onChange: (val) => handleCylinderParamChange("arc", val) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Cone", onCreate: () => {
374
+ const mesh = MeshBuilder.CreateCylinder("Cone", { diameterTop: 0 }, scene);
375
+ SetCamera(scene);
376
+ return mesh;
377
+ }, onSettingsCreate: () => {
378
+ const coneParamsToUse = {
379
+ ...coneParams,
380
+ diameterTop: coneUp ? 0 : coneParams.diameterTop,
381
+ diameterBottom: coneUp ? coneParams.diameterBottom : 0,
382
+ };
383
+ const mesh = MeshBuilder.CreateCylinder(coneParams.name, coneParamsToUse, scene);
384
+ SetCamera(scene);
385
+ return mesh;
386
+ }, children: [jsx(TextInputPropertyLine, { label: "Name", value: coneParams.name, onChange: (val) => handleConeParamChange("name", val) }), jsx(SpinButtonPropertyLine, { label: "Height", value: coneParams.height, min: 0, step: 0.1, onChange: (val) => handleConeParamChange("height", val) }), jsx(SpinButtonPropertyLine, { label: "Diameter", value: coneParams.diameter, min: 0, step: 0.1, onChange: (val) => handleConeParamChange("diameter", val) }), jsx(SpinButtonPropertyLine, { label: "Tessellation", value: coneParams.tessellation, min: 3, onChange: (val) => handleConeParamChange("tessellation", val) }), jsx(SpinButtonPropertyLine, { label: "Subdivisions", value: coneParams.subdivisions, min: 1, onChange: (val) => handleConeParamChange("subdivisions", val) }), jsx(SpinButtonPropertyLine, { label: "Arc", value: coneParams.arc, min: 0, max: 1, step: 0.1, onChange: (val) => handleConeParamChange("arc", val) }), jsx(CheckboxPropertyLine, { label: "Up", value: coneUp, onChange: (val) => setConeUp(val) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Ground", onCreate: () => {
387
+ const mesh = MeshBuilder.CreateGround("Ground", {}, scene);
388
+ SetCamera(scene);
389
+ return mesh;
390
+ }, onSettingsCreate: () => {
391
+ const mesh = MeshBuilder.CreateGround(groundParams.name, groundParams, scene);
392
+ SetCamera(scene);
393
+ return mesh;
394
+ }, children: [jsx(TextInputPropertyLine, { label: "Name", value: groundParams.name, onChange: (val) => handleGroundParamChange("name", val) }), jsx(SpinButtonPropertyLine, { label: "Width", value: groundParams.width, min: 0, step: 0.1, onChange: (val) => handleGroundParamChange("width", val) }), jsx(SpinButtonPropertyLine, { label: "Height", value: groundParams.height, min: 0, step: 0.1, onChange: (val) => handleGroundParamChange("height", val) }), jsx(SpinButtonPropertyLine, { label: "Subdivisions", value: groundParams.subdivisions, min: 1, onChange: (val) => handleGroundParamChange("subdivisions", val) }), jsx(SpinButtonPropertyLine, { label: "Subdivisions X", value: groundParams.subdivisionsX, min: 1, onChange: (val) => handleGroundParamChange("subdivisionsX", val) }), jsx(SpinButtonPropertyLine, { label: "Subdivisions Y", value: groundParams.subdivisionsY, min: 1, onChange: (val) => handleGroundParamChange("subdivisionsY", val) })] }), jsxs(QuickCreateRow, { children: [jsx(Button, { onClick: () => {
395
+ fileInputRef.current?.click();
396
+ }, label: "Import Mesh" }), jsxs(SettingsPopover, { children: [jsx(TextInputPropertyLine, { label: "Name", value: importMeshName, onChange: (val) => setImportMeshName(val) }), jsx("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 }, children: jsx(Button, { appearance: "primary", onClick: () => {
397
+ fileInputRef.current?.click();
398
+ }, label: "Import" }) })] }), jsx("input", { ref: fileInputRef, type: "file", accept: ".babylon,.glb,.gltf,.obj,.stl,.ply,.mesh,.babylonmeshdata", multiple: true, style: { display: "none" }, onChange: handleLocalMeshImport })] })] }));
399
+ };
400
+
401
+ /**
402
+ * Materials content component
403
+ * @param props - Component props
404
+ * @returns React component
405
+ */
406
+ const MaterialsContent = ({ scene, selectionService }) => {
407
+ // Node Material state
408
+ const [nodeMaterialName, setNodeMaterialName] = useState("Node Material");
409
+ const [nodeMaterialSnippetId, setNodeMaterialSnippetId] = useState("");
410
+ // PBR Material state
411
+ const [pbrMaterialName, setPbrMaterialName] = useState("PBR Material");
412
+ // Standard Material state
413
+ const [standardMaterialName, setStandardMaterialName] = useState("Standard Material");
414
+ const createPBRMaterial = () => {
415
+ return new PBRMaterial(pbrMaterialName, scene);
416
+ };
417
+ const createStandardMaterial = () => {
418
+ return new StandardMaterial(standardMaterialName, scene);
419
+ };
420
+ const handleCreateNodeMaterialAsync = async () => {
421
+ if (nodeMaterialSnippetId) {
422
+ const nodeMaterial = await NodeMaterial.ParseFromSnippetAsync(nodeMaterialSnippetId, scene);
423
+ nodeMaterial.name = nodeMaterialName;
424
+ return nodeMaterial;
425
+ }
426
+ else {
427
+ const nodeMaterial = new NodeMaterial(nodeMaterialName, scene);
428
+ nodeMaterial.setToDefault();
429
+ nodeMaterial.build();
430
+ return nodeMaterial;
431
+ }
432
+ };
433
+ return (jsxs(QuickCreateSection, { children: [jsxs(QuickCreateItem, { selectionService: selectionService, label: "Node Material", onCreate: handleCreateNodeMaterialAsync, children: [jsx(TextInputPropertyLine, { label: "Name", value: nodeMaterialName, onChange: (value) => setNodeMaterialName(value) }), jsx(TextInputPropertyLine, { label: "Snippet ID", value: nodeMaterialSnippetId, onChange: (value) => setNodeMaterialSnippetId(value) })] }), jsx(QuickCreateItem, { selectionService: selectionService, label: "PBR Material", onCreate: () => createPBRMaterial(), children: jsx(TextInputPropertyLine, { label: "Name", value: pbrMaterialName, onChange: (value) => setPbrMaterialName(value) }) }), jsx(QuickCreateItem, { selectionService: selectionService, label: "Standard Material", onCreate: () => createStandardMaterial(), children: jsx(TextInputPropertyLine, { label: "Name", value: standardMaterialName, onChange: (value) => setStandardMaterialName(value) }) })] }));
434
+ };
435
+
436
+ /**
437
+ * Lights content component
438
+ * @param props - Component props
439
+ * @returns React component
440
+ */
441
+ const LightsContent = ({ scene, selectionService }) => {
442
+ // Point Light state
443
+ const [pointLightName, setPointLightName] = useState("Point Light");
444
+ const [pointLightPosition, setPointLightPosition] = useState(new Vector3(0, 5, 0));
445
+ // Directional Light state
446
+ const [directionalLightName, setDirectionalLightName] = useState("Directional Light");
447
+ const [directionalLightDirection, setDirectionalLightDirection] = useState(new Vector3(1, -1, 0));
448
+ // Spotlight state
449
+ const [spotlightName, setSpotlightName] = useState("Spotlight");
450
+ const [spotlightPosition, setSpotlightPosition] = useState(new Vector3(0, 5, 0));
451
+ const [spotlightDirection, setSpotlightDirection] = useState(new Vector3(0, -1, 0));
452
+ const [spotlightAngle, setSpotlightAngle] = useState(1);
453
+ const [spotlightExponent, setSpotlightExponent] = useState(1);
454
+ const createPointLight = () => {
455
+ const light = new PointLight(pointLightName, pointLightPosition, scene);
456
+ light.intensity = 1.0;
457
+ return light;
458
+ };
459
+ const createDirectionalLight = () => {
460
+ const dirLight = new DirectionalLight(directionalLightName, directionalLightDirection, scene);
461
+ dirLight.intensity = 1.0;
462
+ return dirLight;
463
+ };
464
+ const createSpotlight = () => {
465
+ const spotlight = new SpotLight(spotlightName, spotlightPosition, spotlightDirection, spotlightAngle, spotlightExponent, scene);
466
+ spotlight.intensity = 1.0;
467
+ return spotlight;
468
+ };
469
+ return (jsxs(QuickCreateSection, { children: [jsxs(QuickCreateItem, { selectionService: selectionService, label: "Point Light", onCreate: () => createPointLight(), children: [jsx(TextInputPropertyLine, { label: "Name", value: pointLightName, onChange: (value) => setPointLightName(value) }), jsx(Vector3PropertyLine, { label: "Position", value: pointLightPosition, onChange: (value) => setPointLightPosition(value) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Directional Light", onCreate: () => createDirectionalLight(), children: [jsx(TextInputPropertyLine, { label: "Name", value: directionalLightName, onChange: (value) => setDirectionalLightName(value) }), jsx(Vector3PropertyLine, { label: "Direction", value: directionalLightDirection, onChange: (value) => setDirectionalLightDirection(value) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Spotlight", onCreate: () => createSpotlight(), children: [jsx(TextInputPropertyLine, { label: "Name", value: spotlightName, onChange: (value) => setSpotlightName(value) }), jsx(Vector3PropertyLine, { label: "Position", value: spotlightPosition, onChange: (value) => setSpotlightPosition(value) }), jsx(Vector3PropertyLine, { label: "Direction", value: spotlightDirection, onChange: (value) => setSpotlightDirection(value) }), jsx(SpinButtonPropertyLine, { label: "Angle", value: spotlightAngle, onChange: (value) => setSpotlightAngle(value), min: 0, max: Math.PI, step: 0.1 }), jsx(SpinButtonPropertyLine, { label: "Exponent", value: spotlightExponent, onChange: (value) => setSpotlightExponent(value), min: 0, max: 10, step: 0.1 })] })] }));
470
+ };
471
+
472
+ /**
473
+ * Cameras content component
474
+ * @param props - Component props
475
+ * @returns React component
476
+ */
477
+ const CamerasContent = ({ scene, selectionService }) => {
478
+ // ArcRotate Camera state
479
+ const [arcRotateCameraName, setArcRotateCameraName] = useState("ArcRotate Camera");
480
+ const [arcRotateCameraTarget, setArcRotateCameraTarget] = useState(new Vector3(0, 0, 0));
481
+ const [arcRotateCameraRadius, setArcRotateCameraRadius] = useState(10);
482
+ const [arcRotateCameraAlpha, setArcRotateCameraAlpha] = useState(0);
483
+ const [arcRotateCameraBeta, setArcRotateCameraBeta] = useState(45);
484
+ const [arcRotateCameraUseRadians, setArcRotateCameraUseRadians] = useState(false);
485
+ // Universal Camera state
486
+ const [universalCameraName, setUniversalCameraName] = useState("Universal Camera");
487
+ const [universalCameraPosition, setUniversalCameraPosition] = useState(new Vector3(0, 1, -10));
488
+ // Free Camera state
489
+ const [freeCameraName, setFreeCameraName] = useState("Free Camera");
490
+ const [freeCameraPosition, setFreeCameraPosition] = useState(new Vector3(0, 1, -10));
491
+ // Follow Camera state
492
+ const [followCameraName, setFollowCameraName] = useState("Follow Camera");
493
+ const [followCameraPosition, setFollowCameraPosition] = useState(new Vector3(0, 5, -10));
494
+ const [followCameraRadius, setFollowCameraRadius] = useState(10);
495
+ const [followCameraHeightOffset, setFollowCameraHeightOffset] = useState(4);
496
+ const [followCameraRotationOffset, setFollowCameraRotationOffset] = useState(0);
497
+ // Fly Camera state
498
+ const [flyCameraName, setFlyCameraName] = useState("Fly Camera");
499
+ const [flyCameraPosition, setFlyCameraPosition] = useState(new Vector3(0, 1, -10));
500
+ // Geospatial Camera state
501
+ const [geospatialCameraName, setGeospatialCameraName] = useState("Geospatial Camera");
502
+ const [geospatialCameraPlanetRadius, setGeospatialCameraPlanetRadius] = useState(6371000);
503
+ const setAsActiveIfNeeded = (camera) => {
504
+ if (!scene.activeCamera) {
505
+ scene.activeCamera = camera;
506
+ }
507
+ };
508
+ const createArcRotateCamera = () => {
509
+ const alpha = arcRotateCameraUseRadians ? arcRotateCameraAlpha : (arcRotateCameraAlpha * Math.PI) / 180;
510
+ const beta = arcRotateCameraUseRadians ? arcRotateCameraBeta : (arcRotateCameraBeta * Math.PI) / 180;
511
+ const camera = new ArcRotateCamera(arcRotateCameraName, alpha, beta, arcRotateCameraRadius, arcRotateCameraTarget, scene);
512
+ camera.attachControl(scene.getEngine().getRenderingCanvas(), true);
513
+ setAsActiveIfNeeded(camera);
514
+ return camera;
515
+ };
516
+ const createUniversalCamera = () => {
517
+ const camera = new UniversalCamera(universalCameraName, universalCameraPosition, scene);
518
+ camera.attachControl(scene.getEngine().getRenderingCanvas(), true);
519
+ setAsActiveIfNeeded(camera);
520
+ return camera;
521
+ };
522
+ const createFreeCamera = () => {
523
+ const camera = new FreeCamera(freeCameraName, freeCameraPosition, scene);
524
+ camera.attachControl(scene.getEngine().getRenderingCanvas(), true);
525
+ setAsActiveIfNeeded(camera);
526
+ return camera;
527
+ };
528
+ const createFollowCamera = () => {
529
+ const camera = new FollowCamera(followCameraName, followCameraPosition, scene);
530
+ camera.radius = followCameraRadius;
531
+ camera.heightOffset = followCameraHeightOffset;
532
+ camera.rotationOffset = followCameraRotationOffset;
533
+ camera.attachControl(true);
534
+ setAsActiveIfNeeded(camera);
535
+ return camera;
536
+ };
537
+ const createFlyCamera = () => {
538
+ const camera = new FlyCamera(flyCameraName, flyCameraPosition, scene);
539
+ camera.attachControl(true);
540
+ setAsActiveIfNeeded(camera);
541
+ return camera;
542
+ };
543
+ const createGeospatialCamera = () => {
544
+ const camera = new GeospatialCamera(geospatialCameraName, scene, { planetRadius: geospatialCameraPlanetRadius });
545
+ camera.attachControl(true);
546
+ setAsActiveIfNeeded(camera);
547
+ return camera;
548
+ };
549
+ return (jsxs(QuickCreateSection, { children: [jsxs(QuickCreateItem, { selectionService: selectionService, label: "ArcRotate Camera", onCreate: () => createArcRotateCamera(), children: [jsx(TextInputPropertyLine, { label: "Name", value: arcRotateCameraName, onChange: (value) => setArcRotateCameraName(value) }), jsx(Vector3PropertyLine, { label: "Target", value: arcRotateCameraTarget, onChange: (value) => setArcRotateCameraTarget(value) }), jsx(SpinButtonPropertyLine, { label: "Radius", value: arcRotateCameraRadius, onChange: (value) => setArcRotateCameraRadius(value), min: 0.1, max: 1000, step: 0.5 }), jsx(SpinButtonPropertyLine, { label: `Alpha ${arcRotateCameraUseRadians ? "(rad)" : "(deg)"}`, value: arcRotateCameraAlpha, onChange: (value) => setArcRotateCameraAlpha(value), min: arcRotateCameraUseRadians ? -Math.PI * 2 : -360, max: arcRotateCameraUseRadians ? Math.PI * 2 : 360, step: arcRotateCameraUseRadians ? 0.1 : 5 }), jsx(SpinButtonPropertyLine, { label: `Beta ${arcRotateCameraUseRadians ? "(rad)" : "(deg)"}`, value: arcRotateCameraBeta, onChange: (value) => setArcRotateCameraBeta(value), min: arcRotateCameraUseRadians ? 0 : 0, max: arcRotateCameraUseRadians ? Math.PI : 180, step: arcRotateCameraUseRadians ? 0.1 : 5 }), jsx(CheckboxPropertyLine, { label: "Use Radians", value: arcRotateCameraUseRadians, onChange: (value) => setArcRotateCameraUseRadians(value) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Universal Camera", onCreate: () => createUniversalCamera(), children: [jsx(TextInputPropertyLine, { label: "Name", value: universalCameraName, onChange: (value) => setUniversalCameraName(value) }), jsx(Vector3PropertyLine, { label: "Position", value: universalCameraPosition, onChange: (value) => setUniversalCameraPosition(value) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Free Camera", onCreate: () => createFreeCamera(), children: [jsx(TextInputPropertyLine, { label: "Name", value: freeCameraName, onChange: (value) => setFreeCameraName(value) }), jsx(Vector3PropertyLine, { label: "Position", value: freeCameraPosition, onChange: (value) => setFreeCameraPosition(value) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Follow Camera", onCreate: () => createFollowCamera(), children: [jsx(TextInputPropertyLine, { label: "Name", value: followCameraName, onChange: (value) => setFollowCameraName(value) }), jsx(Vector3PropertyLine, { label: "Position", value: followCameraPosition, onChange: (value) => setFollowCameraPosition(value) }), jsx(SpinButtonPropertyLine, { label: "Radius", value: followCameraRadius, onChange: (value) => setFollowCameraRadius(value), min: 0.1, max: 1000, step: 0.5 }), jsx(SpinButtonPropertyLine, { label: "Height Offset", value: followCameraHeightOffset, onChange: (value) => setFollowCameraHeightOffset(value), min: -100, max: 100, step: 0.5 }), jsx(SpinButtonPropertyLine, { label: "Rotation Offset (deg)", value: followCameraRotationOffset, onChange: (value) => setFollowCameraRotationOffset(value), min: -180, max: 180, step: 5 })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Fly Camera", onCreate: () => createFlyCamera(), children: [jsx(TextInputPropertyLine, { label: "Name", value: flyCameraName, onChange: (value) => setFlyCameraName(value) }), jsx(Vector3PropertyLine, { label: "Position", value: flyCameraPosition, onChange: (value) => setFlyCameraPosition(value) })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Geospatial Camera", onCreate: () => createGeospatialCamera(), children: [jsx(TextInputPropertyLine, { label: "Name", value: geospatialCameraName, onChange: (value) => setGeospatialCameraName(value) }), jsx(SpinButtonPropertyLine, { label: "Planet Radius (m)", value: geospatialCameraPlanetRadius, onChange: (value) => setGeospatialCameraPlanetRadius(value), min: 1000, max: 100000000, step: 1000 })] })] }));
550
+ };
551
+
552
+ /**
553
+ * Particles content component
554
+ * @param props - Component props
555
+ * @returns React component
556
+ */
557
+ const ParticlesContent = ({ scene, selectionService }) => {
558
+ // CPU Particle System state
559
+ const [cpuParticleSystemName, setCpuParticleSystemName] = useState("Particle System");
560
+ const [cpuParticleSystemCapacity, setCpuParticleSystemCapacity] = useState(2000);
561
+ // GPU Particle System state
562
+ const [gpuParticleSystemName, setGpuParticleSystemName] = useState("GPU Particle System");
563
+ const [gpuParticleSystemCapacity, setGpuParticleSystemCapacity] = useState(2000);
564
+ // Node Particle System state
565
+ const [nodeParticleSystemName, setNodeParticleSystemName] = useState("Node Particle System");
566
+ const [nodeParticleSystemSnippetId, setNodeParticleSystemSnippetId] = useState("");
567
+ const handleCreateCPUAsync = async () => {
568
+ return await new Promise((resolve) => {
569
+ setTimeout(() => {
570
+ const system = new ParticleSystem(cpuParticleSystemName, cpuParticleSystemCapacity, scene);
571
+ system.particleTexture = new Texture("https://assets.babylonjs.com/textures/flare.png", scene);
572
+ system.start();
573
+ resolve(system);
574
+ }, 0);
575
+ });
576
+ };
577
+ const handleCreateGPUAsync = async () => {
578
+ if (!GPUParticleSystem.IsSupported) {
579
+ alert("GPU Particle System is not supported.");
580
+ throw new Error("GPU Particle System is not supported.");
581
+ }
582
+ return await new Promise((resolve) => {
583
+ setTimeout(() => {
584
+ const system = new GPUParticleSystem(gpuParticleSystemName, { capacity: gpuParticleSystemCapacity }, scene);
585
+ system.particleTexture = new Texture("https://assets.babylonjs.com/textures/flare.png", scene);
586
+ system.start();
587
+ resolve(system);
588
+ }, 0);
589
+ });
590
+ };
591
+ const handleCreateNodeAsync = async () => {
592
+ let nodeParticleSet;
593
+ const snippetId = nodeParticleSystemSnippetId.trim();
594
+ if (snippetId) {
595
+ nodeParticleSet = await NodeParticleSystemSet.ParseFromSnippetAsync(snippetId);
596
+ nodeParticleSet.name = nodeParticleSystemName;
597
+ }
598
+ else {
599
+ nodeParticleSet = NodeParticleSystemSet.CreateDefault(nodeParticleSystemName);
600
+ }
601
+ const particleSystemSet = await nodeParticleSet.buildAsync(scene);
602
+ const systems = particleSystemSet.systems;
603
+ if (systems.length === 0) {
604
+ throw new Error("No particle systems were produced by the node particle system.");
605
+ }
606
+ for (const system of systems) {
607
+ system.name = nodeParticleSystemName;
608
+ }
609
+ particleSystemSet.start();
610
+ return systems[0];
611
+ };
612
+ return (jsxs(QuickCreateSection, { children: [jsxs(QuickCreateItem, { selectionService: selectionService, label: "CPU Particle System", onCreate: handleCreateCPUAsync, children: [jsx(TextInputPropertyLine, { label: "Name", value: cpuParticleSystemName, onChange: (value) => setCpuParticleSystemName(value) }), jsx(SpinButtonPropertyLine, { label: "Capacity", value: cpuParticleSystemCapacity, onChange: (value) => setCpuParticleSystemCapacity(value), min: 1, max: 100000, step: 100 })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "GPU Particle System", onCreate: handleCreateGPUAsync, children: [jsx(TextInputPropertyLine, { label: "Name", value: gpuParticleSystemName, onChange: (value) => setGpuParticleSystemName(value) }), jsx(SpinButtonPropertyLine, { label: "Capacity", value: gpuParticleSystemCapacity, onChange: (value) => setGpuParticleSystemCapacity(value), min: 1, max: 1000000, step: 1000 })] }), jsxs(QuickCreateItem, { selectionService: selectionService, label: "Node Particle System", onCreate: handleCreateNodeAsync, children: [jsx(TextInputPropertyLine, { label: "Name", value: nodeParticleSystemName, onChange: (value) => setNodeParticleSystemName(value) }), jsx(TextInputPropertyLine, { label: "Snippet ID", value: nodeParticleSystemSnippetId, onChange: (value) => setNodeParticleSystemSnippetId(value) })] })] }));
613
+ };
614
+
615
+ const GetUniquePipelineName = (baseName, scene) => {
616
+ const pipelines = scene.postProcessRenderPipelineManager.supportedPipelines;
617
+ const existingNames = new Set(pipelines.map((p) => p._name));
618
+ if (!existingNames.has(baseName)) {
619
+ return baseName;
620
+ }
621
+ let counter = 1;
622
+ let uniqueName = `${baseName} ${counter}`;
623
+ while (existingNames.has(uniqueName)) {
624
+ counter++;
625
+ uniqueName = `${baseName} ${counter}`;
626
+ }
627
+ return uniqueName;
628
+ };
629
+ /**
630
+ * Rendering Pipelines content component
631
+ * @param props - Component props
632
+ * @returns React component
633
+ */
634
+ const RenderingPipelinesContent = ({ scene, selectionService }) => {
635
+ // Default Rendering Pipeline state
636
+ const [defaultPipelineName, setDefaultPipelineName] = useState("Default rendering pipeline");
637
+ // SSAO Pipeline state
638
+ const [ssaoPipelineName, setSsaoPipelineName] = useState("SSAO rendering pipeline");
639
+ // SSAO2 Pipeline state
640
+ const [ssao2PipelineName, setSsao2PipelineName] = useState("SSAO2 rendering pipeline");
641
+ // SSR Pipeline state
642
+ const [ssrPipelineName, setSsrPipelineName] = useState("SSR rendering pipeline");
643
+ // IBL Shadows Pipeline state
644
+ const [iblShadowsPipelineName, setIblShadowsPipelineName] = useState("IBL Shadows rendering pipeline");
645
+ const createDefaultPipeline = () => {
646
+ const name = GetUniquePipelineName(defaultPipelineName, scene);
647
+ return new DefaultRenderingPipeline(name, true, scene, scene.cameras);
648
+ };
649
+ const createSSAOPipeline = () => {
650
+ const name = GetUniquePipelineName(ssaoPipelineName, scene);
651
+ return new SSAORenderingPipeline(name, scene, 1, scene.cameras);
652
+ };
653
+ const createSSAO2Pipeline = () => {
654
+ const name = GetUniquePipelineName(ssao2PipelineName, scene);
655
+ return new SSAO2RenderingPipeline(name, scene, 1, scene.cameras);
656
+ };
657
+ const createSSRPipeline = () => {
658
+ const name = GetUniquePipelineName(ssrPipelineName, scene);
659
+ return new SSRRenderingPipeline(name, scene, scene.cameras);
660
+ };
661
+ const createIBLShadowsPipeline = () => {
662
+ const name = GetUniquePipelineName(iblShadowsPipelineName, scene);
663
+ return new IblShadowsRenderPipeline(name, scene, {}, scene.cameras);
664
+ };
665
+ const caps = scene.getEngine().getCaps();
666
+ const hasDrawBuffers = caps.drawBuffersExtension;
667
+ const hasTexelFetch = caps.texelFetch;
668
+ const camera = useProperty(scene, "activeCamera");
669
+ return (jsx(QuickCreateSection, { children: !camera ? (jsx(MessageBar, { message: "Cannot create rendering pipeline without an active camera.", title: "No active camera", intent: "info" })) : (jsxs(Fragment, { children: [jsx(QuickCreateItem, { selectionService: selectionService, label: "Default Pipeline", onCreate: () => createDefaultPipeline(), children: jsx(TextInputPropertyLine, { label: "Name", value: defaultPipelineName, onChange: (value) => setDefaultPipelineName(value) }) }), jsx(QuickCreateItem, { selectionService: selectionService, label: "SSAO Pipeline", onCreate: () => createSSAOPipeline(), children: jsx(TextInputPropertyLine, { label: "Name", value: ssaoPipelineName, onChange: (value) => setSsaoPipelineName(value) }) }), hasDrawBuffers && (jsx(QuickCreateItem, { selectionService: selectionService, label: "SSAO2 Pipeline", onCreate: () => createSSAO2Pipeline(), children: jsx(TextInputPropertyLine, { label: "Name", value: ssao2PipelineName, onChange: (value) => setSsao2PipelineName(value) }) })), hasDrawBuffers && hasTexelFetch && (jsx(QuickCreateItem, { selectionService: selectionService, label: "SSR Pipeline", onCreate: () => createSSRPipeline(), children: jsx(TextInputPropertyLine, { label: "Name", value: ssrPipelineName, onChange: (value) => setSsrPipelineName(value) }) })), hasDrawBuffers && hasTexelFetch && (jsx(QuickCreateItem, { selectionService: selectionService, label: "IBL Shadows Pipeline", onCreate: () => createIBLShadowsPipeline(), children: jsx(TextInputPropertyLine, { label: "Name", value: iblShadowsPipelineName, onChange: (value) => setIblShadowsPipelineName(value) }) }))] })) }));
670
+ };
671
+
672
+ /**
673
+ * Helper to generate a unique frame graph name
674
+ * @param baseName - The base name to use
675
+ * @param scene - The scene to check for existing frame graphs
676
+ * @returns A unique name
677
+ */
678
+ function GetUniqueName(baseName, scene) {
679
+ let name = baseName;
680
+ let idSubscript = 1;
681
+ while (scene.getFrameGraphByName(name)) {
682
+ name = baseName + " " + idSubscript++;
683
+ }
684
+ return name;
685
+ }
686
+ /**
687
+ * Frame Graphs content component
688
+ * @param props - Component props
689
+ * @returns React component
690
+ */
691
+ const FrameGraphsContent = ({ scene, selectionService }) => {
692
+ // Node Render Graph state
693
+ const [frameGraphName, setFrameGraphName] = useState("Frame Graph");
694
+ const createFrameGraph = () => {
695
+ const uniqueName = GetUniqueName(frameGraphName, scene);
696
+ const newNodeRenderGraph = new NodeRenderGraph(uniqueName, scene);
697
+ newNodeRenderGraph.setToDefault();
698
+ void newNodeRenderGraph.buildAsync();
699
+ // Return the underlying FrameGraph, which is what gets registered with the scene
700
+ // and matched by the properties/explorer services via `instanceof FrameGraph`.
701
+ return newNodeRenderGraph.frameGraph;
702
+ };
703
+ return (jsx(QuickCreateSection, { children: jsx(QuickCreateItem, { selectionService: selectionService, label: "Frame Graph", onCreate: () => createFrameGraph(), children: jsx(TextInputPropertyLine, { label: "Name", value: frameGraphName, onChange: (value) => setFrameGraphName(value) }) }) }));
704
+ };
705
+
706
+ /**
707
+ * Sprite Managers content component
708
+ * @param props - Component props
709
+ * @returns React component
710
+ */
711
+ const SpriteManagersContent = ({ scene, selectionService }) => {
712
+ // Sprite Manager state
713
+ const [spriteManagerName, setSpriteManagerName] = useState("Sprite Manager");
714
+ const [spriteManagerCapacity, setSpriteManagerCapacity] = useState(500);
715
+ const [spriteManagerCellSize, setSpriteManagerCellSize] = useState(64);
716
+ const [spriteManagerTextureUrl, setSpriteManagerTextureUrl] = useState("https://assets.babylonjs.com/textures/player.png");
717
+ const createSpriteManager = () => {
718
+ return new SpriteManager(spriteManagerName, spriteManagerTextureUrl, spriteManagerCapacity, spriteManagerCellSize, scene);
719
+ };
720
+ return (jsx(QuickCreateSection, { children: jsxs(QuickCreateItem, { selectionService: selectionService, label: "Sprite Manager", onCreate: () => createSpriteManager(), children: [jsx(TextInputPropertyLine, { label: "Name", value: spriteManagerName, onChange: (value) => setSpriteManagerName(value) }), jsx(TextInputPropertyLine, { label: "Texture URL", value: spriteManagerTextureUrl, onChange: (value) => setSpriteManagerTextureUrl(value) }), jsx(SpinButtonPropertyLine, { label: "Capacity", value: spriteManagerCapacity, onChange: (value) => setSpriteManagerCapacity(value), min: 1, max: 10000, step: 100 }), jsx(SpinButtonPropertyLine, { label: "Cell Size", value: spriteManagerCellSize, onChange: (value) => setSpriteManagerCellSize(value), min: 1, max: 1024, step: 1 })] }) }));
721
+ };
722
+
723
+ // TODO: This is just a placeholder for a dynamically installed extension that brings in asset creation tools (node materials, etc.).
724
+ const CreateToolsServiceDefinition = {
725
+ friendlyName: "Creation Tools",
726
+ consumes: [ShellServiceIdentity, SceneContextIdentity, SelectionServiceIdentity],
727
+ factory: (shellService, sceneContext, selectionService) => {
728
+ const registration = shellService.addSidePane({
729
+ key: "Create",
730
+ title: "Creation Tools",
731
+ icon: CollectionsAdd20Regular,
732
+ horizontalLocation: "left",
733
+ verticalLocation: "top",
734
+ content: () => {
735
+ const scene = useObservableState(() => sceneContext.currentScene, sceneContext.currentSceneObservable);
736
+ return (scene && (jsx(Fragment, { children: jsxs(Accordion, { children: [jsx(AccordionSection, { title: "Meshes", children: jsx(MeshesContent, { scene: scene, selectionService: selectionService }) }), jsx(AccordionSection, { title: "Materials", children: jsx(MaterialsContent, { scene: scene, selectionService: selectionService }) }), jsx(AccordionSection, { title: "Lights", children: jsx(LightsContent, { scene: scene, selectionService: selectionService }) }), jsx(AccordionSection, { title: "Particles", children: jsx(ParticlesContent, { scene: scene, selectionService: selectionService }) }), jsx(AccordionSection, { title: "Cameras", children: jsx(CamerasContent, { scene: scene, selectionService: selectionService }) }), jsx(AccordionSection, { title: "Rendering Pipelines", children: jsx(RenderingPipelinesContent, { scene: scene, selectionService: selectionService }) }), jsx(AccordionSection, { title: "Frame Graphs", children: jsx(FrameGraphsContent, { scene: scene, selectionService: selectionService }) }), jsx(AccordionSection, { title: "Sprite Managers", children: jsx(SpriteManagersContent, { scene: scene, selectionService: selectionService }) })] }) })));
737
+ },
738
+ });
739
+ return {
740
+ dispose: () => registration.dispose(),
741
+ };
742
+ },
743
+ };
744
+ var quickCreateToolsService = {
745
+ serviceDefinitions: [CreateToolsServiceDefinition],
746
+ };
747
+
748
+ export { CreateToolsServiceDefinition, quickCreateToolsService as default };
749
+ //# sourceMappingURL=quickCreateToolsService-DrHWIQRV.js.map