babylon.quarks-editor 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +38 -5
  3. package/dist/core/assetDragSession.d.ts +1 -1
  4. package/dist/core/assetTree.d.ts +1 -1
  5. package/dist/core/binding.d.ts +2 -2
  6. package/dist/core/binding.js +1 -1
  7. package/dist/core/defaultEffect.d.ts +2 -2
  8. package/dist/core/defaultEffect.js +3 -3
  9. package/dist/core/editorScene.d.ts +1 -1
  10. package/dist/core/effectTree.d.ts +1 -1
  11. package/dist/core/effectTree.js +13 -88
  12. package/dist/core/emitterShapeWireframe.d.ts +2 -2
  13. package/dist/core/emitterShapeWireframe.js +45 -13
  14. package/dist/core/galleryDropMarker.d.ts +2 -2
  15. package/dist/core/galleryDropMarker.js +6 -6
  16. package/dist/core/galleryLayout.d.ts +3 -3
  17. package/dist/core/galleryLayout.js +1 -1
  18. package/dist/core/galleryPlayback.d.ts +1 -1
  19. package/dist/core/galleryScene.d.ts +4 -4
  20. package/dist/core/galleryScene.js +3 -3
  21. package/dist/core/gallerySelectionMarker.d.ts +4 -4
  22. package/dist/core/gallerySelectionMarker.js +5 -5
  23. package/dist/core/groups.d.ts +1 -1
  24. package/dist/core/groups.js +1 -1
  25. package/dist/core/history.d.ts +1 -1
  26. package/dist/core/indexedDbProjectStore.d.ts +1 -1
  27. package/dist/core/lineShaders.d.ts +2 -2
  28. package/dist/core/lineShaders.js +2 -2
  29. package/dist/core/loadEffect.d.ts +2 -2
  30. package/dist/core/loadEffect.js +1 -1
  31. package/dist/core/pickAssetFiles.js +1 -1
  32. package/dist/core/sceneEntries.d.ts +4 -4
  33. package/dist/core/sceneEntries.js +2 -2
  34. package/dist/core/scrub.d.ts +1 -1
  35. package/dist/core/shapes.d.ts +1 -1
  36. package/dist/core/systems.d.ts +2 -2
  37. package/dist/core/textureExport.d.ts +1 -1
  38. package/dist/core/timeline.d.ts +2 -2
  39. package/dist/core/transport.d.ts +3 -3
  40. package/dist/core/transport.js +2 -2
  41. package/dist/core/viewportPicker.d.ts +4 -4
  42. package/dist/core/viewportPicker.js +8 -7
  43. package/dist/index.d.ts +21 -21
  44. package/dist/index.js +12 -12
  45. package/dist/react/AssetsPanel.d.ts +2 -2
  46. package/dist/react/AssetsPanel.js +6 -6
  47. package/dist/react/ChoiceDialog.js +1 -1
  48. package/dist/react/ContextMenu.js +1 -1
  49. package/dist/react/CurveEditor.d.ts +1 -1
  50. package/dist/react/CurveEditor.js +2 -2
  51. package/dist/react/EditorWorkspace.d.ts +2 -2
  52. package/dist/react/EditorWorkspace.js +4 -4
  53. package/dist/react/EffectEditor.d.ts +3 -3
  54. package/dist/react/EffectEditor.js +7 -7
  55. package/dist/react/EffectEditorHost.d.ts +6 -6
  56. package/dist/react/EffectEditorHost.js +59 -62
  57. package/dist/react/EffectTreeView.d.ts +1 -1
  58. package/dist/react/EffectTreeView.js +3 -3
  59. package/dist/react/GradientEditor.d.ts +1 -1
  60. package/dist/react/GradientEditor.js +3 -3
  61. package/dist/react/InspectorInfoIcon.js +3 -3
  62. package/dist/react/InspectorLabel.js +3 -3
  63. package/dist/react/MessageDialog.js +1 -1
  64. package/dist/react/ModuleSection.js +4 -4
  65. package/dist/react/ObjectModule.d.ts +1 -1
  66. package/dist/react/ObjectModule.js +4 -4
  67. package/dist/react/ProjectsPage.d.ts +1 -1
  68. package/dist/react/ProjectsPage.js +6 -6
  69. package/dist/react/PromptDialog.js +1 -1
  70. package/dist/react/ScenePanel.d.ts +2 -2
  71. package/dist/react/ScenePanel.js +5 -5
  72. package/dist/react/SubEmittersModule.d.ts +1 -1
  73. package/dist/react/SubEmittersModule.js +5 -5
  74. package/dist/react/TextureSelect.d.ts +24 -0
  75. package/dist/react/TextureSelect.js +74 -0
  76. package/dist/react/TextureUVField.d.ts +14 -0
  77. package/dist/react/TextureUVField.js +23 -0
  78. package/dist/react/TimelinePanel.d.ts +7 -7
  79. package/dist/react/TimelinePanel.js +11 -9
  80. package/dist/react/TimelineTrackRow.d.ts +3 -3
  81. package/dist/react/TimelineTrackRow.js +6 -6
  82. package/dist/react/TransportBar.d.ts +4 -4
  83. package/dist/react/TransportBar.js +3 -3
  84. package/dist/react/ValueField.d.ts +1 -1
  85. package/dist/react/ValueField.js +3 -3
  86. package/dist/react/behaviorModules.d.ts +4 -2
  87. package/dist/react/behaviorModules.js +52 -16
  88. package/dist/react/fields.d.ts +1 -0
  89. package/dist/react/fields.js +3 -3
  90. package/dist/react/index.d.ts +40 -38
  91. package/dist/react/index.js +25 -23
  92. package/dist/react/inspectorHints.js +31 -0
  93. package/dist/react/modules.d.ts +3 -1
  94. package/dist/react/modules.js +99 -100
  95. package/package.json +3 -2
  96. package/src/core/assetDragSession.ts +1 -1
  97. package/src/core/assetTree.ts +1 -1
  98. package/src/core/binding.ts +3 -3
  99. package/src/core/defaultEffect.ts +4 -4
  100. package/src/core/editorScene.ts +1 -1
  101. package/src/core/effectTree.ts +13 -101
  102. package/src/core/emitterShapeWireframe.ts +48 -16
  103. package/src/core/galleryDropMarker.ts +8 -8
  104. package/src/core/galleryLayout.ts +4 -4
  105. package/src/core/galleryPlayback.ts +1 -1
  106. package/src/core/galleryScene.ts +5 -5
  107. package/src/core/gallerySelectionMarker.ts +7 -7
  108. package/src/core/groups.ts +1 -1
  109. package/src/core/history.ts +1 -1
  110. package/src/core/indexedDbProjectStore.ts +1 -1
  111. package/src/core/lineShaders.ts +2 -2
  112. package/src/core/loadEffect.ts +3 -3
  113. package/src/core/pickAssetFiles.ts +2 -2
  114. package/src/core/sceneEntries.ts +5 -5
  115. package/src/core/scrub.ts +1 -1
  116. package/src/core/shapes.ts +1 -1
  117. package/src/core/systems.ts +2 -2
  118. package/src/core/textureExport.ts +1 -1
  119. package/src/core/timeline.ts +3 -3
  120. package/src/core/transport.ts +4 -4
  121. package/src/core/viewportPicker.ts +12 -11
  122. package/src/index.ts +21 -21
  123. package/src/react/AssetsPanel.tsx +6 -6
  124. package/src/react/ChoiceDialog.tsx +1 -1
  125. package/src/react/ContextMenu.tsx +1 -1
  126. package/src/react/CurveEditor.tsx +2 -2
  127. package/src/react/EditorWorkspace.tsx +5 -5
  128. package/src/react/EffectEditor.tsx +10 -8
  129. package/src/react/EffectEditorHost.tsx +64 -69
  130. package/src/react/EffectTreeView.tsx +4 -4
  131. package/src/react/GradientEditor.tsx +3 -3
  132. package/src/react/InspectorInfoIcon.tsx +3 -3
  133. package/src/react/InspectorLabel.tsx +3 -3
  134. package/src/react/MessageDialog.tsx +1 -1
  135. package/src/react/ModuleSection.tsx +4 -4
  136. package/src/react/ObjectModule.tsx +5 -5
  137. package/src/react/ProjectsPage.tsx +6 -6
  138. package/src/react/PromptDialog.tsx +1 -1
  139. package/src/react/ScenePanel.tsx +7 -7
  140. package/src/react/SubEmittersModule.tsx +6 -6
  141. package/src/react/TextureSelect.tsx +118 -0
  142. package/src/react/TextureUVField.tsx +62 -0
  143. package/src/react/TimelinePanel.tsx +17 -15
  144. package/src/react/TimelineTrackRow.tsx +9 -9
  145. package/src/react/TransportBar.tsx +7 -7
  146. package/src/react/ValueField.tsx +3 -3
  147. package/src/react/behaviorModules.tsx +211 -28
  148. package/src/react/fields.tsx +10 -3
  149. package/src/react/index.ts +41 -38
  150. package/src/react/inspectorHints.ts +40 -0
  151. package/src/react/modules.tsx +375 -131
@@ -1,5 +1,5 @@
1
1
  import type { BatchedRenderer } from 'babylon.quarks';
2
- import type { EffectBinding } from './binding';
2
+ import type { EffectBinding } from './binding.js';
3
3
  /** Unpauses every system in the focused effect. */
4
4
  export declare function playFocus(binding: EffectBinding): void;
5
5
  /** Freezes the focused effect at its current simulation state. */
@@ -1,4 +1,4 @@
1
- import type { Mesh } from '@babylonjs/core/Meshes/mesh';
1
+ import type { Mesh } from '@babylonjs/core/Meshes/mesh.js';
2
2
  import type { EmitterShape } from 'babylon.quarks';
3
3
  import { BoxEmitFrom, EmitterMode } from 'babylon.quarks';
4
4
  export type ShapeType = 'point' | 'sphere' | 'hemisphere' | 'cone' | 'circle' | 'donut' | 'rectangle' | 'grid' | 'box' | 'edge' | 'mesh_surface';
@@ -1,6 +1,6 @@
1
- import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
1
+ import type { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
2
2
  import { ParticleSystem } from 'babylon.quarks';
3
- import type { EffectBinding } from './binding';
3
+ import type { EffectBinding } from './binding.js';
4
4
  export interface ChildSystemOptions {
5
5
  name?: string;
6
6
  /** One-shot burst (sub-emitter target) instead of a looping stream. */
@@ -1,4 +1,4 @@
1
- import type { Texture } from '@babylonjs/core/Materials/Textures/texture';
1
+ import type { Texture } from '@babylonjs/core/Materials/Textures/texture.js';
2
2
  /**
3
3
  * Ensures a texture's `.url` can be reloaded in a different Scene/Engine, baking its live
4
4
  * GPU pixels into a real base64 PNG data URI when it currently only carries Babylon's
@@ -1,6 +1,6 @@
1
- import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
1
+ import type { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
2
2
  import type { FunctionValueGenerator, ParticleSystem, ValueGenerator } from 'babylon.quarks';
3
- import type { EffectBinding } from './binding';
3
+ import type { EffectBinding } from './binding.js';
4
4
  export type TimelineRow = {
5
5
  kind: 'group';
6
6
  node: TransformNode;
@@ -1,7 +1,7 @@
1
- import type { Scene } from '@babylonjs/core/scene';
1
+ import type { Scene } from '@babylonjs/core/scene.js';
2
2
  import type { BatchedRenderer } from 'babylon.quarks';
3
- import type { EffectBinding } from './binding';
4
- import { type PlaybackState } from './playback';
3
+ import type { EffectBinding } from './binding.js';
4
+ import { type PlaybackState } from './playback.js';
5
5
  /**
6
6
  * Stage Play/Pause shared by the viewport transport bar and the timeline. Pressing Play on a
7
7
  * one-shot focus that already parked at its end replays it from the start.
@@ -1,5 +1,5 @@
1
- import { clearFocusFinished, isFocusFinished, setFocusElapsed } from './playback';
2
- import { playFocus, scrubFocusTo } from './scrub';
1
+ import { clearFocusFinished, isFocusFinished, setFocusElapsed } from './playback.js';
2
+ import { playFocus, scrubFocusTo } from './scrub.js';
3
3
  /**
4
4
  * Stage Play/Pause shared by the viewport transport bar and the timeline. Pressing Play on a
5
5
  * one-shot focus that already parked at its end replays it from the start.
@@ -1,7 +1,7 @@
1
- import '@babylonjs/core/Culling/ray';
2
- import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
3
- import type { Scene } from '@babylonjs/core/scene';
4
- import type { SceneEntry } from './sceneEntries';
1
+ import '@babylonjs/core/Culling/ray.js';
2
+ import { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
3
+ import type { Scene } from '@babylonjs/core/scene.js';
4
+ import type { SceneEntry } from './sceneEntries.js';
5
5
  /**
6
6
  * Viewport pick/hover for visible scene effect roots only (not child emitters).
7
7
  * Hover uses the same ground ring as focus selection, in yellow.
@@ -1,7 +1,7 @@
1
- import '@babylonjs/core/Culling/ray';
2
- import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder';
3
- import { EDITOR_SCENE_NODE_METADATA } from './editorScene';
4
- import { GROUND_RING_RADIUS, GalleryHoverMarker } from './gallerySelectionMarker';
1
+ import '@babylonjs/core/Culling/ray.js';
2
+ import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder.js';
3
+ import { EDITOR_SCENE_NODE_METADATA } from './editorScene.js';
4
+ import { GROUND_RING_RADIUS, GalleryHoverMarker } from './gallerySelectionMarker.js';
5
5
  /** Invisible pick proxy size — matches the ground ring footprint. */
6
6
  const PICK_DIAMETER = GROUND_RING_RADIUS * 2;
7
7
  /**
@@ -34,9 +34,10 @@ export class GalleryViewportPicker {
34
34
  else if (soloRoot && !soloRoot.isDisposed()) {
35
35
  this.createHandle(soloRoot);
36
36
  }
37
- const hovered = this.hoveredRoot;
38
- this.hoveredRoot = null;
39
- this.setHover(hovered && !hovered.isDisposed() ? hovered : null);
37
+ if (this.hoveredRoot?.isDisposed()) {
38
+ this.hoveredRoot = null;
39
+ this.hoverMarker.hide();
40
+ }
40
41
  }
41
42
  /** Yellow focus-style ring under the hovered effect root. */
42
43
  setHover(effectRoot) {
package/dist/index.d.ts CHANGED
@@ -1,21 +1,21 @@
1
- export { EffectBinding } from './core/binding';
2
- export type { EditorListener } from './core/binding';
3
- export { GroundPlaneResolver, ensureGroundResolver } from './core/collision';
4
- export { DEFAULT_GRADIENT_STOPS, buildColorOverLife, buildGradient, findBehavior, hexToRgb, rgbToHex, rgbaToVector4, stopToCss, stopsToCssGradient, } from './core/colors';
5
- export type { GradientStop } from './core/colors';
6
- export { buildEffectTree, collectSystems, serializeEffectForest, serializeEffectTree } from './core/effectTree';
7
- export type { EffectTreeNode } from './core/effectTree';
8
- export { EffectHistory } from './core/history';
9
- export type { HistoryStacks } from './core/history';
10
- export { IndexedDbProjectStore } from './core/indexedDbProjectStore';
11
- export { applyRendererMaterial, getMaterialLabel } from './core/material';
12
- export type { RendererMaterialPatch } from './core/material';
13
- export { formatBytes } from './core/projectStore';
14
- export type { ProjectMeta, ProjectStore, StorageEstimate, StoredAsset, StoredScene, StoredSceneEntry, } from './core/projectStore';
15
- export { DEFAULT_SHAPE_PARAMS, SHAPE_PARAM_KEYS, SHAPE_TYPES, createShape, getShapeType, readShapeParams, } from './core/shapes';
16
- export type { ShapeParams, ShapeType } from './core/shapes';
17
- export { createChildSystem } from './core/systems';
18
- export type { ChildSystemOptions } from './core/systems';
19
- export { ensurePortableTextureUrl } from './core/textureExport';
20
- export { buildCurve, buildScalar, mergePieces, readPieces, readScalar, sampleCurve, splitPieces } from './core/values';
21
- export type { CurvePiece, ScalarGenerator, ScalarMode, ScalarValueState } from './core/values';
1
+ export { EffectBinding } from './core/binding.js';
2
+ export type { EditorListener } from './core/binding.js';
3
+ export { GroundPlaneResolver, ensureGroundResolver } from './core/collision.js';
4
+ export { DEFAULT_GRADIENT_STOPS, buildColorOverLife, buildGradient, findBehavior, hexToRgb, rgbToHex, rgbaToVector4, stopToCss, stopsToCssGradient, } from './core/colors.js';
5
+ export type { GradientStop } from './core/colors.js';
6
+ export { buildEffectTree, collectSystems, serializeEffectForest, serializeEffectTree } from './core/effectTree.js';
7
+ export type { EffectTreeNode } from './core/effectTree.js';
8
+ export { EffectHistory } from './core/history.js';
9
+ export type { HistoryStacks } from './core/history.js';
10
+ export { IndexedDbProjectStore } from './core/indexedDbProjectStore.js';
11
+ export { applyRendererMaterial, getMaterialLabel } from './core/material.js';
12
+ export type { RendererMaterialPatch } from './core/material.js';
13
+ export { formatBytes } from './core/projectStore.js';
14
+ export type { ProjectMeta, ProjectStore, StorageEstimate, StoredAsset, StoredScene, StoredSceneEntry, } from './core/projectStore.js';
15
+ export { DEFAULT_SHAPE_PARAMS, SHAPE_PARAM_KEYS, SHAPE_TYPES, createShape, getShapeType, readShapeParams, } from './core/shapes.js';
16
+ export type { ShapeParams, ShapeType } from './core/shapes.js';
17
+ export { createChildSystem } from './core/systems.js';
18
+ export type { ChildSystemOptions } from './core/systems.js';
19
+ export { ensurePortableTextureUrl } from './core/textureExport.js';
20
+ export { buildCurve, buildScalar, mergePieces, readPieces, readScalar, sampleCurve, splitPieces } from './core/values.js';
21
+ export type { CurvePiece, ScalarGenerator, ScalarMode, ScalarValueState } from './core/values.js';
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
- export { EffectBinding } from './core/binding';
2
- export { GroundPlaneResolver, ensureGroundResolver } from './core/collision';
3
- export { DEFAULT_GRADIENT_STOPS, buildColorOverLife, buildGradient, findBehavior, hexToRgb, rgbToHex, rgbaToVector4, stopToCss, stopsToCssGradient, } from './core/colors';
4
- export { buildEffectTree, collectSystems, serializeEffectForest, serializeEffectTree } from './core/effectTree';
5
- export { EffectHistory } from './core/history';
6
- export { IndexedDbProjectStore } from './core/indexedDbProjectStore';
7
- export { applyRendererMaterial, getMaterialLabel } from './core/material';
8
- export { formatBytes } from './core/projectStore';
9
- export { DEFAULT_SHAPE_PARAMS, SHAPE_PARAM_KEYS, SHAPE_TYPES, createShape, getShapeType, readShapeParams, } from './core/shapes';
10
- export { createChildSystem } from './core/systems';
11
- export { ensurePortableTextureUrl } from './core/textureExport';
12
- export { buildCurve, buildScalar, mergePieces, readPieces, readScalar, sampleCurve, splitPieces } from './core/values';
1
+ export { EffectBinding } from './core/binding.js';
2
+ export { GroundPlaneResolver, ensureGroundResolver } from './core/collision.js';
3
+ export { DEFAULT_GRADIENT_STOPS, buildColorOverLife, buildGradient, findBehavior, hexToRgb, rgbToHex, rgbaToVector4, stopToCss, stopsToCssGradient, } from './core/colors.js';
4
+ export { buildEffectTree, collectSystems, serializeEffectForest, serializeEffectTree } from './core/effectTree.js';
5
+ export { EffectHistory } from './core/history.js';
6
+ export { IndexedDbProjectStore } from './core/indexedDbProjectStore.js';
7
+ export { applyRendererMaterial, getMaterialLabel } from './core/material.js';
8
+ export { formatBytes } from './core/projectStore.js';
9
+ export { DEFAULT_SHAPE_PARAMS, SHAPE_PARAM_KEYS, SHAPE_TYPES, createShape, getShapeType, readShapeParams, } from './core/shapes.js';
10
+ export { createChildSystem } from './core/systems.js';
11
+ export { ensurePortableTextureUrl } from './core/textureExport.js';
12
+ export { buildCurve, buildScalar, mergePieces, readPieces, readScalar, sampleCurve, splitPieces } from './core/values.js';
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { type AssetDragPayload } from '../core/assetTree';
3
- import { type AssetLoadProgress, type EffectAsset } from '../core/assets';
2
+ import { type AssetDragPayload } from '../core/assetTree.js';
3
+ import { type AssetLoadProgress, type EffectAsset } from '../core/assets.js';
4
4
  export interface AssetsPanelProps {
5
5
  assets: EffectAsset[];
6
6
  /** Scene instance count per asset id. */
@@ -1,12 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { ChevronDownIcon, ChevronRightIcon, ExclamationTriangleIcon, FolderIcon, FolderOpenIcon, SparklesIcon, } from '@heroicons/react/24/solid';
3
3
  import React, { useCallback, useMemo, useRef, useState } from 'react';
4
- import { setAssetDragSession } from '../core/assetDragSession';
5
- import { buildAssetTree, collectFolderAssets, folderChildren, searchAssets, writeAssetDrag, } from '../core/assetTree';
6
- import { assetIconUrl } from '../core/assets';
7
- import { ContextMenu } from './ContextMenu';
8
- import { iconStyle } from './icons';
9
- import { buttonStyle, hiddenFileInputStyle, inputStyle, theme } from './theme';
4
+ import { setAssetDragSession } from '../core/assetDragSession.js';
5
+ import { buildAssetTree, collectFolderAssets, folderChildren, searchAssets, writeAssetDrag, } from '../core/assetTree.js';
6
+ import { assetIconUrl } from '../core/assets.js';
7
+ import { ContextMenu } from './ContextMenu.js';
8
+ import { iconStyle } from './icons.js';
9
+ import { buttonStyle, hiddenFileInputStyle, inputStyle, theme } from './theme.js';
10
10
  const TREE_WIDTH = 200;
11
11
  const TILE_WIDTH = 92;
12
12
  function beginAssetDrag(e, payload) {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect } from 'react';
3
- import { buttonStyle, theme } from './theme';
3
+ import { buttonStyle, theme } from './theme.js';
4
4
  /** Confirmation modal with several outcomes (e.g. Save / Don't save / Cancel). */
5
5
  export function ChoiceDialog(props) {
6
6
  const { title, message, actions, onCancel } = props;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useLayoutEffect, useRef, useState } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
- import { theme } from './theme';
4
+ import { theme } from './theme.js';
5
5
  /** Right-click menu at the pointer; closes on outside click, Escape, scroll or window blur. */
6
6
  export function ContextMenu(props) {
7
7
  const { x, y, items, onClose } = props;
@@ -1,4 +1,4 @@
1
- import { CurvePiece } from '../core/values';
1
+ import { CurvePiece } from '../core/values.js';
2
2
  /**
3
3
  * Multi-segment piecewise-bezier curve editor. Drag keys/handles vertically,
4
4
  * drag inner keys horizontally, double-click the curve to add a key, double-click
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useRef, useState } from 'react';
3
- import { mergePieces, sampleCurve, splitPieces } from '../core/values';
4
- import { inputStyle, theme } from './theme';
3
+ import { mergePieces, sampleCurve, splitPieces } from '../core/values.js';
4
+ import { inputStyle, theme } from './theme.js';
5
5
  const WIDTH = 218;
6
6
  const HEIGHT = 84;
7
7
  const PAD = 8;
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import type { ProjectStore } from '../core/projectStore';
3
- import { type EffectEditorHostProps } from './EffectEditorHost';
2
+ import type { ProjectStore } from '../core/projectStore.js';
3
+ import { type EffectEditorHostProps } from './EffectEditorHost.js';
4
4
  export interface EditorWorkspaceProps extends Omit<EffectEditorHostProps, 'project' | 'onExitProject' | 'effectJson'> {
5
5
  /** Where projects are kept; defaults to the browser's IndexedDB. */
6
6
  store?: ProjectStore;
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from 'react';
3
3
  import { createRoot } from 'react-dom/client';
4
- import { IndexedDbProjectStore } from '../core/indexedDbProjectStore';
5
- import { EffectEditorHost } from './EffectEditorHost';
6
- import { ProjectsPage } from './ProjectsPage';
7
- import { theme } from './theme';
4
+ import { IndexedDbProjectStore } from '../core/indexedDbProjectStore.js';
5
+ import { EffectEditorHost } from './EffectEditorHost.js';
6
+ import { ProjectsPage } from './ProjectsPage.js';
7
+ import { theme } from './theme.js';
8
8
  /** Projects page → editor for the chosen project, with assets and scene saved in `store`. */
9
9
  export function EditorWorkspace(props) {
10
10
  const { store: storeProp, projectId, onProjectChange, ...hostProps } = props;
@@ -1,8 +1,8 @@
1
- import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
1
+ import type { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
2
2
  import type { ParticleSystem } from 'babylon.quarks';
3
3
  import React from 'react';
4
- import { EffectBinding } from '../core/binding';
5
- import type { GeometryData, GeometryOption, TextureOption } from './modules';
4
+ import { EffectBinding } from '../core/binding.js';
5
+ import type { GeometryData, GeometryOption, TextureOption } from './modules.js';
6
6
  export interface EffectEditorProps {
7
7
  binding: EffectBinding;
8
8
  /** Currently selected system, lifted up so the timeline panel and this module stack agree. */
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useEffect, useSyncExternalStore } from 'react';
3
- import { EffectBinding } from '../core/binding';
4
- import { CollisionModule, ColorBySpeedModule, EmitDirectionModule, ForceOverLifeModule, GravityModule, InheritVelocityModule, LimitSpeedOverLifeModule, NoiseModule, OrbitOverLifeModule, Rotation3DOverLifeModule, RotationBySpeedModule, RotationOverLifeModule, SequencesModule, SizeBySpeedModule, SpeedOverLifeModule, TextureSheetModule, TurbulenceModule, VelocityOverLifeModule, WidthOverTrailModule, } from './behaviorModules';
5
- import { ColorOverLifeModule, EmissionModule, MainModule, RendererModule, ShapeModule, SizeOverLifeModule, } from './modules';
6
- import { ObjectModule } from './ObjectModule';
7
- import { SubEmittersModule } from './SubEmittersModule';
8
- import { theme } from './theme';
3
+ import { EffectBinding } from '../core/binding.js';
4
+ import { AttractorModule, CollisionModule, ColorBySpeedModule, EmitDirectionModule, ForceOverLifeModule, GravityModule, InheritVelocityModule, LimitSpeedOverLifeModule, NoiseModule, OrbitOverLifeModule, Rotation3DOverLifeModule, RotationBySpeedModule, RotationOverLifeModule, SequencesModule, SizeBySpeedModule, SpeedOverLifeModule, TextureSheetModule, TurbulenceModule, VelocityOverLifeModule, WidthOverTrailModule, } from './behaviorModules.js';
5
+ import { ColorOverLifeModule, EmissionModule, MainModule, RendererModule, ShapeModule, SizeOverLifeModule, } from './modules.js';
6
+ import { ObjectModule } from './ObjectModule.js';
7
+ import { SubEmittersModule } from './SubEmittersModule.js';
8
+ import { theme } from './theme.js';
9
9
  /**
10
10
  * Shuriken-style effect editor: a stacked module inspector for the selected system.
11
11
  * Embed it anywhere React runs — the standalone examples page or a BabylonJS Editor plugin.
@@ -31,5 +31,5 @@ export const EffectEditor = React.memo(function EffectEditor(props) {
31
31
  useEffect(() => (binding === props.binding ? undefined : binding.subscribe(() => props.binding.markChanged())), [binding, props.binding]);
32
32
  useSyncExternalStore((onStoreChange) => binding.subscribe(onStoreChange), () => binding.getRevision());
33
33
  const gizmoTargetIsEmitter = allSystems.some((s) => s.emitter === props.gizmoTargetNode);
34
- return (_jsxs("div", { style: { fontFamily: theme.font, color: theme.text }, children: [_jsx(ObjectModule, { node: props.gizmoTargetNode, label: props.gizmoTargetLabel, onBeforeChange: () => props.binding.onBeforeChange?.(), onChanged: () => props.binding.markChanged() }), !gizmoTargetIsEmitter && (_jsxs("div", { style: { fontSize: 11, color: theme.textDim, margin: '0 0 10px', lineHeight: 1.45 }, children: ["Modules below edit ", _jsx("strong", { children: activeSystem.emitter.name || 'particle system' }), ". Select its emitter in the timeline to move it with the gizmo."] })), _jsx(MainModule, { binding: binding }), _jsx(EmissionModule, { binding: binding }), _jsx(ShapeModule, { binding: binding }), _jsx(EmitDirectionModule, { binding: binding }), _jsx(VelocityOverLifeModule, { binding: binding }), _jsx(SpeedOverLifeModule, { binding: binding }), _jsx(LimitSpeedOverLifeModule, { binding: binding }), _jsx(InheritVelocityModule, { binding: binding }), _jsx(ForceOverLifeModule, { binding: binding }), _jsx(GravityModule, { binding: binding }), _jsx(OrbitOverLifeModule, { binding: binding }), _jsx(ColorOverLifeModule, { binding: binding }), _jsx(ColorBySpeedModule, { binding: binding }), _jsx(SizeOverLifeModule, { binding: binding }), _jsx(SizeBySpeedModule, { binding: binding }), _jsx(RotationOverLifeModule, { binding: binding }), _jsx(Rotation3DOverLifeModule, { binding: binding }), _jsx(RotationBySpeedModule, { binding: binding }), _jsx(NoiseModule, { binding: binding }), _jsx(TurbulenceModule, { binding: binding }), _jsx(CollisionModule, { binding: binding }), _jsx(WidthOverTrailModule, { binding: binding }), _jsx(SubEmittersModule, { binding: binding, rootBinding: props.binding }), _jsx(TextureSheetModule, { binding: binding }), _jsx(SequencesModule, { binding: binding, textureOptions: props.textureOptions }), _jsx(RendererModule, { binding: binding, textureOptions: props.textureOptions, geometryOptions: props.geometryOptions, resolveTexture: props.resolveTexture, resolveGeometry: props.resolveGeometry })] }));
34
+ return (_jsxs("div", { style: { fontFamily: theme.font, color: theme.text }, children: [_jsx(ObjectModule, { node: props.gizmoTargetNode, label: props.gizmoTargetLabel, onBeforeChange: () => props.binding.onBeforeChange?.(), onChanged: () => props.binding.markChanged() }), !gizmoTargetIsEmitter && (_jsxs("div", { style: { fontSize: 11, color: theme.textDim, margin: '0 0 10px', lineHeight: 1.45 }, children: ["Modules below edit ", _jsx("strong", { children: activeSystem.emitter.name || 'particle system' }), ". Select its emitter in the timeline to move it with the gizmo."] })), _jsx(MainModule, { binding: binding }), _jsx(EmissionModule, { binding: binding }), _jsx(ShapeModule, { binding: binding }), _jsx(EmitDirectionModule, { binding: binding }), _jsx(VelocityOverLifeModule, { binding: binding }), _jsx(SpeedOverLifeModule, { binding: binding }), _jsx(LimitSpeedOverLifeModule, { binding: binding }), _jsx(InheritVelocityModule, { binding: binding }), _jsx(ForceOverLifeModule, { binding: binding }), _jsx(GravityModule, { binding: binding }), _jsx(AttractorModule, { binding: binding }), _jsx(OrbitOverLifeModule, { binding: binding }), _jsx(ColorOverLifeModule, { binding: binding }), _jsx(ColorBySpeedModule, { binding: binding }), _jsx(SizeOverLifeModule, { binding: binding }), _jsx(SizeBySpeedModule, { binding: binding }), _jsx(RotationOverLifeModule, { binding: binding }), _jsx(Rotation3DOverLifeModule, { binding: binding }), _jsx(RotationBySpeedModule, { binding: binding }), _jsx(NoiseModule, { binding: binding }), _jsx(TurbulenceModule, { binding: binding }), _jsx(CollisionModule, { binding: binding }), _jsx(WidthOverTrailModule, { binding: binding }), _jsx(SubEmittersModule, { binding: binding, rootBinding: props.binding }), _jsx(TextureSheetModule, { binding: binding }), _jsx(SequencesModule, { binding: binding, textureOptions: props.textureOptions }), _jsx(RendererModule, { binding: binding, textureOptions: props.textureOptions, geometryOptions: props.geometryOptions, resolveTexture: props.resolveTexture, resolveGeometry: props.resolveGeometry })] }));
35
35
  });
@@ -1,11 +1,11 @@
1
- import '@babylonjs/core/Culling/ray';
2
- import { Scene } from '@babylonjs/core/scene';
1
+ import '@babylonjs/core/Culling/ray.js';
2
+ import { Scene } from '@babylonjs/core/scene.js';
3
3
  import { BatchedRenderer } from 'babylon.quarks';
4
4
  import React from 'react';
5
- import { EffectBinding } from '../core/binding';
6
- import { EffectHistory } from '../core/history';
7
- import type { ProjectStore } from '../core/projectStore';
8
- import type { GeometryData, GeometryOption, TextureOption } from './modules';
5
+ import { EffectBinding } from '../core/binding.js';
6
+ import { EffectHistory } from '../core/history.js';
7
+ import type { ProjectStore } from '../core/projectStore.js';
8
+ import type { GeometryData, GeometryOption, TextureOption } from './modules.js';
9
9
  export interface EffectEditorHostHandle {
10
10
  binding: EffectBinding;
11
11
  history: EffectHistory;
@@ -1,55 +1,55 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera';
2
+ import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera.js';
3
3
  // scene.pick lives in Ray's side effect (Babylon 9.31 no longer pulls it in); gizmos pick through it.
4
- import '@babylonjs/core/Culling/ray';
5
- import { Engine } from '@babylonjs/core/Engines/engine';
6
- import { PointerEventTypes } from '@babylonjs/core/Events/pointerEvents';
7
- import { GizmoManager } from '@babylonjs/core/Gizmos/gizmoManager';
8
- import { DirectionalLight } from '@babylonjs/core/Lights/directionalLight';
9
- import { Color3, Color4 } from '@babylonjs/core/Maths/math.color';
10
- import { Vector3 as BVector3 } from '@babylonjs/core/Maths/math.vector';
11
- import { Viewport } from '@babylonjs/core/Maths/math.viewport';
12
- import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder';
13
- import { UtilityLayerRenderer } from '@babylonjs/core/Rendering/utilityLayerRenderer';
14
- import { Scene } from '@babylonjs/core/scene';
15
- import { GridMaterial } from '@babylonjs/materials/grid/gridMaterial';
4
+ import '@babylonjs/core/Culling/ray.js';
5
+ import { Engine } from '@babylonjs/core/Engines/engine.js';
6
+ import { PointerEventTypes } from '@babylonjs/core/Events/pointerEvents.js';
7
+ import { GizmoManager } from '@babylonjs/core/Gizmos/gizmoManager.js';
8
+ import { DirectionalLight } from '@babylonjs/core/Lights/directionalLight.js';
9
+ import { Color3, Color4 } from '@babylonjs/core/Maths/math.color.js';
10
+ import { Vector3 as BVector3 } from '@babylonjs/core/Maths/math.vector.js';
11
+ import { Viewport } from '@babylonjs/core/Maths/math.viewport.js';
12
+ import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder.js';
13
+ import { UtilityLayerRenderer } from '@babylonjs/core/Rendering/utilityLayerRenderer.js';
14
+ import { Scene } from '@babylonjs/core/scene.js';
15
+ import { GridMaterial } from '@babylonjs/materials/grid/gridMaterial.js';
16
16
  import { ArrowLeftIcon, ArrowPathIcon, ArrowsPointingOutIcon, ArrowUturnLeftIcon, ArrowUturnRightIcon, ChevronDownIcon, ChevronUpIcon, CubeTransparentIcon, CursorArrowRaysIcon, MapPinIcon, Square2StackIcon, XMarkIcon, } from '@heroicons/react/24/solid';
17
17
  import { BatchedRenderer, QuarksUtil } from 'babylon.quarks';
18
18
  import { useCallback, useDeferredValue, useEffect, useMemo, useReducer, useRef, useState } from 'react';
19
19
  import { createRoot } from 'react-dom/client';
20
- import { getAssetDragSession, setAssetDragSession } from '../core/assetDragSession';
21
- import { ASSET_DRAG_MIME, describeAssetDrag, readAssetDrag } from '../core/assetTree';
22
- import { collectJsonFiles, createEffectAsset, loadEffectAssets, mergeAssets, removeAssets, } from '../core/assets';
23
- import { createSceneDefaultEntry } from '../core/defaultEffect';
24
- import { serializeEffectTree } from '../core/effectTree';
25
- import { EmitterShapeWireframes } from '../core/emitterShapeWireframe';
26
- import { GalleryDropMarker } from '../core/galleryDropMarker';
27
- import { cancelGalleryCameraFocus, focusGalleryEntry } from '../core/galleryLayout';
28
- import { applyGalleryPlayback, countGalleryParticles, hasActivePreview, pauseFinishedPreviews, } from '../core/galleryPlayback';
29
- import { pickGroundPosition, placeSceneEntriesAt, setSceneEntryVisible } from '../core/galleryScene';
30
- import { GallerySelectionMarker } from '../core/gallerySelectionMarker';
31
- import { EffectHistory } from '../core/history';
32
- import { parseEffectFromJson } from '../core/loadEffect';
33
- import { pickAssetFolderFiles } from '../core/pickAssetFiles';
34
- import { clearFocusFinished, createPlaybackState, getFocusElapsed, isFocusFinished, markFocusFinished, setFocusElapsed, } from '../core/playback';
35
- import { logRenderMismatch } from '../core/renderDebug';
36
- import { bindingFromSceneEntry, countInstancesByAsset, disposeSceneEntry, instantiateSceneEntry, } from '../core/sceneEntries';
37
- import { pauseFocus, scrubFocusToSettled } from '../core/scrub';
38
- import { computeTimelineRows, computeTimelineSpan } from '../core/timeline';
39
- import { notifyTransformChanged, subscribeTransform } from '../core/transformStore';
40
- import { toggleStagePlayback } from '../core/transport';
41
- import { GalleryViewportPicker } from '../core/viewportPicker';
42
- import { AssetsPanel } from './AssetsPanel';
43
- import { ChoiceDialog } from './ChoiceDialog';
44
- import { EffectEditor } from './EffectEditor';
45
- import { EffectTreeView } from './EffectTreeView';
46
- import { MessageDialog } from './MessageDialog';
47
- import { PromptDialog } from './PromptDialog';
48
- import { ScenePanel } from './ScenePanel';
49
- import { TimelinePanel } from './TimelinePanel';
50
- import { TransportBar } from './TransportBar';
51
- import { iconStyle } from './icons';
52
- import { buttonStyle, globalEditorStyles, theme } from './theme';
20
+ import { getAssetDragSession, setAssetDragSession } from '../core/assetDragSession.js';
21
+ import { ASSET_DRAG_MIME, describeAssetDrag, readAssetDrag } from '../core/assetTree.js';
22
+ import { collectJsonFiles, createEffectAsset, loadEffectAssets, mergeAssets, removeAssets, } from '../core/assets.js';
23
+ import { createSceneDefaultEntry } from '../core/defaultEffect.js';
24
+ import { serializeEffectTree } from '../core/effectTree.js';
25
+ import { EmitterShapeWireframes } from '../core/emitterShapeWireframe.js';
26
+ import { GalleryDropMarker } from '../core/galleryDropMarker.js';
27
+ import { cancelGalleryCameraFocus, focusGalleryEntry } from '../core/galleryLayout.js';
28
+ import { applyGalleryPlayback, countGalleryParticles, hasActivePreview, pauseFinishedPreviews, } from '../core/galleryPlayback.js';
29
+ import { pickGroundPosition, placeSceneEntriesAt, setSceneEntryVisible } from '../core/galleryScene.js';
30
+ import { GallerySelectionMarker } from '../core/gallerySelectionMarker.js';
31
+ import { EffectHistory } from '../core/history.js';
32
+ import { parseEffectFromJson } from '../core/loadEffect.js';
33
+ import { pickAssetFolderFiles } from '../core/pickAssetFiles.js';
34
+ import { clearFocusFinished, createPlaybackState, getFocusElapsed, isFocusFinished, markFocusFinished, setFocusElapsed, } from '../core/playback.js';
35
+ import { logRenderMismatch } from '../core/renderDebug.js';
36
+ import { bindingFromSceneEntry, countInstancesByAsset, disposeSceneEntry, instantiateSceneEntry, } from '../core/sceneEntries.js';
37
+ import { pauseFocus, scrubFocusToSettled } from '../core/scrub.js';
38
+ import { computeTimelineRows, computeTimelineSpan } from '../core/timeline.js';
39
+ import { notifyTransformChanged, subscribeTransform } from '../core/transformStore.js';
40
+ import { toggleStagePlayback } from '../core/transport.js';
41
+ import { GalleryViewportPicker } from '../core/viewportPicker.js';
42
+ import { AssetsPanel } from './AssetsPanel.js';
43
+ import { ChoiceDialog } from './ChoiceDialog.js';
44
+ import { EffectEditor } from './EffectEditor.js';
45
+ import { EffectTreeView } from './EffectTreeView.js';
46
+ import { MessageDialog } from './MessageDialog.js';
47
+ import { PromptDialog } from './PromptDialog.js';
48
+ import { ScenePanel } from './ScenePanel.js';
49
+ import { TimelinePanel } from './TimelinePanel.js';
50
+ import { TransportBar } from './TransportBar.js';
51
+ import { iconStyle } from './icons.js';
52
+ import { buttonStyle, globalEditorStyles, theme } from './theme.js';
53
53
  /**
54
54
  * The effect's JSON, with a warning when it points at object URLs: a texture
55
55
  * dropped in from disk lives at a `blob:` URL that dies with the page, so the
@@ -274,11 +274,12 @@ export function EffectEditorHost(props) {
274
274
  })();
275
275
  };
276
276
  useEffect(() => {
277
- const engine = new Engine(canvasRef.current, true);
277
+ const canvas = canvasRef.current;
278
+ const engine = new Engine(canvas, true);
278
279
  const scene = new Scene(engine);
279
280
  scene.clearColor = new Color4(0.03, 0.04, 0.09, 1);
280
281
  const camera = new ArcRotateCamera('cam', -Math.PI / 2, 1.15, 9, new BVector3(0, 1.4, 0), scene);
281
- camera.attachControl(canvasRef.current, true);
282
+ camera.attachControl(canvas, true);
282
283
  camera.wheelDeltaPercentage = 0.01;
283
284
  // Mesh render mode particles are lit (billboard modes ignore these); the grid is visual
284
285
  // reference only and is not a physics collider.
@@ -330,7 +331,7 @@ export function EffectEditorHost(props) {
330
331
  };
331
332
  const state = stateRef.current;
332
333
  const handleViewportPointerLeave = () => viewportPicker.setHover(null);
333
- canvasRef.current?.addEventListener('pointerleave', handleViewportPointerLeave);
334
+ canvas.addEventListener('pointerleave', handleViewportPointerLeave);
334
335
  const pointerObserver = scene.onPointerObservable.add((pointerInfo) => {
335
336
  if (assetDragDepthRef.current > 0) {
336
337
  return;
@@ -1118,7 +1119,7 @@ export function EffectEditorHost(props) {
1118
1119
  }
1119
1120
  });
1120
1121
  const resizeObserver = new ResizeObserver(() => engine.resize());
1121
- resizeObserver.observe(canvasRef.current);
1122
+ resizeObserver.observe(canvas);
1122
1123
  const onKey = (e) => {
1123
1124
  const key = e.key.toLowerCase();
1124
1125
  if ((e.ctrlKey || e.metaKey) && key === 's') {
@@ -1181,13 +1182,13 @@ export function EffectEditorHost(props) {
1181
1182
  emitterWireframesRef.current = null;
1182
1183
  viewportPicker.dispose();
1183
1184
  viewportPickerRef.current = null;
1184
- canvasRef.current?.removeEventListener('pointerleave', handleViewportPointerLeave);
1185
+ canvas.removeEventListener('pointerleave', handleViewportPointerLeave);
1185
1186
  scene.onPointerObservable.remove(pointerObserver);
1186
1187
  gizmoManager.dispose();
1187
1188
  gizmoUtilityLayer.dispose();
1188
1189
  engine.dispose();
1189
1190
  };
1190
- // eslint-disable-next-line react-hooks/exhaustive-deps
1191
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- mount only: builds the engine and scene once
1191
1192
  }, []);
1192
1193
  useEffect(() => {
1193
1194
  playbackRef.current.stagePlaying = stagePlaying;
@@ -1320,11 +1321,6 @@ export function EffectEditorHost(props) {
1320
1321
  gm.attachToNode(target);
1321
1322
  }, [selectedNode, binding, isAssetsLoading]);
1322
1323
  const state = stateRef.current;
1323
- const gizmoNode = selectedNode && !selectedNode.isDisposed()
1324
- ? selectedNode
1325
- : binding?.root && !binding.root.isDisposed()
1326
- ? binding.root
1327
- : null;
1328
1324
  const allSystems = binding ? [binding.system, ...binding.subSystems] : [];
1329
1325
  const activeSystem = binding ? (allSystems.find((s) => s.emitter === selectedNode) ?? binding.system) : null;
1330
1326
  // The inspector is the expensive part of a selection change (every module re-renders for the
@@ -1344,17 +1340,18 @@ export function EffectEditorHost(props) {
1344
1340
  const instanceCounts = useMemo(() => countInstancesByAsset(sceneEntries), [sceneEntries]);
1345
1341
  const showTimeline = Boolean(binding && activeSystem && state);
1346
1342
  const timelinePlaybackEnabled = !focusedRoot || visibleRootIdSet.has(focusedRoot.uniqueId);
1343
+ const { resolveTexture, resolveGeometry } = props;
1347
1344
  const resolveTextureForEditor = useCallback((url) => {
1348
1345
  const scene = stateRef.current?.scene;
1349
- return scene && props.resolveTexture ? props.resolveTexture(url, scene) : undefined;
1350
- }, [props.resolveTexture]);
1346
+ return scene && resolveTexture ? resolveTexture(url, scene) : undefined;
1347
+ }, [resolveTexture]);
1351
1348
  const resolveGeometryForEditor = useCallback((file) => {
1352
1349
  const scene = stateRef.current?.scene;
1353
- if (!scene || !props.resolveGeometry) {
1350
+ if (!scene || !resolveGeometry) {
1354
1351
  return Promise.reject(new Error('Geometry loader is not available.'));
1355
1352
  }
1356
- return props.resolveGeometry(file, scene);
1357
- }, [props.resolveGeometry]);
1353
+ return resolveGeometry(file, scene);
1354
+ }, [resolveGeometry]);
1358
1355
  return (_jsxs("div", { className: "qe-root", style: {
1359
1356
  display: 'flex',
1360
1357
  flexDirection: 'column',
@@ -1,4 +1,4 @@
1
- import type { TransformNode } from '@babylonjs/core/Meshes/transformNode';
1
+ import type { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
2
2
  import React from 'react';
3
3
  export interface EffectTreeViewProps {
4
4
  root: TransformNode;
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { ChevronDownIcon, ChevronRightIcon, FolderIcon, SparklesIcon } from '@heroicons/react/24/solid';
3
3
  import { useState } from 'react';
4
- import { buildEffectTree } from '../core/effectTree';
5
- import { iconStyle } from './icons';
6
- import { theme } from './theme';
4
+ import { buildEffectTree } from '../core/effectTree.js';
5
+ import { iconStyle } from './icons.js';
6
+ import { theme } from './theme.js';
7
7
  const ROW_HEIGHT = 26;
8
8
  function TreeRow(props) {
9
9
  const { item, level, indent, selectedNode, collapsed, onToggle, onSelect } = props;
@@ -1,4 +1,4 @@
1
- import { GradientStop } from '../core/colors';
1
+ import { GradientStop } from '../core/colors.js';
2
2
  /** Gradient editor: RGBA stops on a bar — click to add, drag to move, edit the selected stop. */
3
3
  export declare function GradientEditor(props: {
4
4
  stops: GradientStop[];
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useRef, useState } from 'react';
3
- import { hexToRgb, rgbToHex, stopsToCssGradient } from '../core/colors';
4
- import { NumberField, Row } from './fields';
5
- import { buttonStyle, theme } from './theme';
3
+ import { hexToRgb, rgbToHex, stopsToCssGradient } from '../core/colors.js';
4
+ import { NumberField, Row } from './fields.js';
5
+ import { buttonStyle, theme } from './theme.js';
6
6
  const BAR_WIDTH = 218;
7
7
  /** Gradient editor: RGBA stops on a bar — click to add, drag to move, edit the selected stop. */
8
8
  export function GradientEditor(props) {
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { InformationCircleIcon } from '@heroicons/react/24/solid';
3
- import { iconStyle } from './icons';
4
- import { theme } from './theme';
5
- import { Tooltip } from './Tooltip';
3
+ import { iconStyle } from './icons.js';
4
+ import { theme } from './theme.js';
5
+ import { Tooltip } from './Tooltip.js';
6
6
  /** Small info icon with a themed inspector tooltip. */
7
7
  export function InspectorInfoIcon(props) {
8
8
  const size = props.size ?? 13;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { getInspectorHint } from './inspectorHints';
3
- import { InspectorInfoIcon } from './InspectorInfoIcon';
4
- import { labelStyle } from './theme';
2
+ import { getInspectorHint } from './inspectorHints.js';
3
+ import { InspectorInfoIcon } from './InspectorInfoIcon.js';
4
+ import { labelStyle } from './theme.js';
5
5
  /** Inspector row label with an optional info icon tooltip. */
6
6
  export function InspectorLabel(props) {
7
7
  if (!props.label) {
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { buttonStyle, theme } from './theme';
2
+ import { buttonStyle, theme } from './theme.js';
3
3
  /** Modal for info and error messages — same chrome as PromptDialog, no text input. */
4
4
  export function MessageDialog(props) {
5
5
  const { title, message, confirmLabel = 'OK', onClose } = props;