@fps-games/editor 0.1.5-beta.5 → 0.1.6-beta.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.
Files changed (218) hide show
  1. package/dist/build-info.json +16 -16
  2. package/dist/local-editor-agent-actions.d.ts +8 -1
  3. package/dist/local-editor-agent-actions.d.ts.map +1 -1
  4. package/dist/local-editor-agent-actions.js +171 -12
  5. package/dist/local-editor-agent-actions.js.map +1 -1
  6. package/dist/local-editor-agent-context.d.ts +29 -1
  7. package/dist/local-editor-agent-context.d.ts.map +1 -1
  8. package/dist/local-editor-agent-context.js +403 -0
  9. package/dist/local-editor-agent-context.js.map +1 -1
  10. package/dist/local-editor-harness.d.ts +103 -5
  11. package/dist/local-editor-harness.d.ts.map +1 -1
  12. package/dist/local-editor-harness.js +1982 -101
  13. package/dist/local-editor-harness.js.map +1 -1
  14. package/dist/local-editor-marker-graph.d.ts +92 -0
  15. package/dist/local-editor-marker-graph.d.ts.map +1 -0
  16. package/dist/local-editor-marker-graph.js +1432 -0
  17. package/dist/local-editor-marker-graph.js.map +1 -0
  18. package/dist/local-editor-performance-stats.js +1 -1
  19. package/dist/local-editor-performance-stats.js.map +1 -1
  20. package/dist/playable-babylon-facade.d.ts +2 -2
  21. package/dist/playable-babylon-facade.d.ts.map +1 -1
  22. package/dist/playable-babylon-facade.js +1 -1
  23. package/dist/playable-babylon-facade.js.map +1 -1
  24. package/dist/playable-local-editor-host.d.ts +52 -7
  25. package/dist/playable-local-editor-host.d.ts.map +1 -1
  26. package/dist/playable-local-editor-host.js +23 -1
  27. package/dist/playable-local-editor-host.js.map +1 -1
  28. package/dist/playable-sdk.d.ts +4 -2
  29. package/dist/playable-sdk.d.ts.map +1 -1
  30. package/dist/playable-sdk.js +2 -1
  31. package/dist/playable-sdk.js.map +1 -1
  32. package/node_modules/@fps-games/babylon-renderer/package.json +1 -1
  33. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.d.ts.map +1 -1
  34. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.js +11 -0
  35. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.js.map +1 -1
  36. package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts +3 -1
  37. package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts.map +1 -1
  38. package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js +114 -18
  39. package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js.map +1 -1
  40. package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts +1 -0
  41. package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts.map +1 -1
  42. package/node_modules/@fps-games/editor-babylon/dist/editor-world.js +3 -0
  43. package/node_modules/@fps-games/editor-babylon/dist/editor-world.js.map +1 -1
  44. package/node_modules/@fps-games/editor-babylon/dist/index.d.ts +3 -0
  45. package/node_modules/@fps-games/editor-babylon/dist/index.d.ts.map +1 -1
  46. package/node_modules/@fps-games/editor-babylon/dist/index.js +3 -0
  47. package/node_modules/@fps-games/editor-babylon/dist/index.js.map +1 -1
  48. package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.d.ts +52 -0
  49. package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.d.ts.map +1 -0
  50. package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.js +1395 -0
  51. package/node_modules/@fps-games/editor-babylon/dist/marker-overlay.js.map +1 -0
  52. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.d.ts.map +1 -1
  53. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.js +4 -65
  54. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.js.map +1 -1
  55. package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.d.ts +28 -0
  56. package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.d.ts.map +1 -0
  57. package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.js +235 -0
  58. package/node_modules/@fps-games/editor-babylon/dist/material-slot-source-resolver.js.map +1 -0
  59. package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.d.ts +37 -0
  60. package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.d.ts.map +1 -0
  61. package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.js +451 -0
  62. package/node_modules/@fps-games/editor-babylon/dist/prefab-comparison-preview-controller.js.map +1 -0
  63. package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.d.ts.map +1 -1
  64. package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.js +14 -3
  65. package/node_modules/@fps-games/editor-babylon/dist/projection-asset-container-importer.js.map +1 -1
  66. package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.d.ts +1 -0
  67. package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.d.ts.map +1 -1
  68. package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.js +20 -4
  69. package/node_modules/@fps-games/editor-babylon/dist/projection-pick-resolver.js.map +1 -1
  70. package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.d.ts +3 -6
  71. package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.d.ts.map +1 -1
  72. package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.js +4 -37
  73. package/node_modules/@fps-games/editor-babylon/dist/projection-source-owner-path.js.map +1 -1
  74. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts +44 -1
  75. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts.map +1 -1
  76. package/node_modules/@fps-games/editor-babylon/dist/projection.js +295 -41
  77. package/node_modules/@fps-games/editor-babylon/dist/projection.js.map +1 -1
  78. package/node_modules/@fps-games/editor-babylon/package.json +5 -5
  79. package/node_modules/@fps-games/editor-browser/dist/index.d.ts +5 -2
  80. package/node_modules/@fps-games/editor-browser/dist/index.d.ts.map +1 -1
  81. package/node_modules/@fps-games/editor-browser/dist/index.js +2 -0
  82. package/node_modules/@fps-games/editor-browser/dist/index.js.map +1 -1
  83. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.d.ts +5 -0
  84. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.d.ts.map +1 -0
  85. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.js +23 -0
  86. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-asset-kind.js.map +1 -0
  87. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.d.ts.map +1 -1
  88. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js +69 -0
  89. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js.map +1 -1
  90. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.d.ts.map +1 -1
  91. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.js +1 -0
  92. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-attach-dialog.js.map +1 -1
  93. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts +2 -0
  94. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts.map +1 -1
  95. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js +38 -1
  96. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js.map +1 -1
  97. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.d.ts +1 -1
  98. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-tree.d.ts.map +1 -1
  99. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts.map +1 -1
  100. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js +8 -2
  101. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js.map +1 -1
  102. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts +1 -1
  103. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.d.ts.map +1 -1
  104. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js +7 -0
  105. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-icons.js.map +1 -1
  106. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.js +1 -1
  107. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.js.map +1 -1
  108. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts +4 -0
  109. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts.map +1 -1
  110. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js +1471 -29
  111. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js.map +1 -1
  112. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.d.ts +52 -0
  113. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.d.ts.map +1 -0
  114. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.js +131 -0
  115. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-prefab-stage.js.map +1 -0
  116. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts +1 -1
  117. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts.map +1 -1
  118. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.d.ts.map +1 -1
  119. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js +9 -2
  120. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js.map +1 -1
  121. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts +234 -3
  122. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts.map +1 -1
  123. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts +10 -1
  124. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts.map +1 -1
  125. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js +3 -1
  126. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js.map +1 -1
  127. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts +4 -3
  128. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts.map +1 -1
  129. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js +1274 -55
  130. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js.map +1 -1
  131. package/node_modules/@fps-games/editor-browser/package.json +3 -3
  132. package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts +1 -1
  133. package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts.map +1 -1
  134. package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts +2 -0
  135. package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts.map +1 -1
  136. package/node_modules/@fps-games/editor-core/dist/viewport-tools.js +1 -0
  137. package/node_modules/@fps-games/editor-core/dist/viewport-tools.js.map +1 -1
  138. package/node_modules/@fps-games/editor-core/package.json +2 -2
  139. package/node_modules/@fps-games/editor-forge-play/package.json +2 -2
  140. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.d.ts.map +1 -1
  141. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.js +17 -3
  142. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/catalog.js.map +1 -1
  143. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.d.ts.map +1 -1
  144. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.js +2 -1
  145. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/document.js.map +1 -1
  146. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/types.d.ts +3 -2
  147. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-library/types.d.ts.map +1 -1
  148. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.d.ts +1 -0
  149. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.d.ts.map +1 -1
  150. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.js +68 -2
  151. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/document.js.map +1 -1
  152. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.d.ts +1 -1
  153. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.d.ts.map +1 -1
  154. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.js +1 -1
  155. package/node_modules/@fps-games/editor-playable-sdk/dist/asset-placement/index.js.map +1 -1
  156. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts +56 -1
  157. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.d.ts.map +1 -1
  158. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js +531 -0
  159. package/node_modules/@fps-games/editor-playable-sdk/dist/document/helpers.js.map +1 -1
  160. package/node_modules/@fps-games/editor-playable-sdk/dist/document/types.d.ts +103 -2
  161. package/node_modules/@fps-games/editor-playable-sdk/dist/document/types.d.ts.map +1 -1
  162. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.d.ts +1 -1
  163. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.d.ts.map +1 -1
  164. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.js +1 -1
  165. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/index.js.map +1 -1
  166. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.d.ts.map +1 -1
  167. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.js +9 -1
  168. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/schema.js.map +1 -1
  169. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.d.ts +1 -0
  170. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.d.ts.map +1 -1
  171. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.js +3 -0
  172. package/node_modules/@fps-games/editor-playable-sdk/dist/field-schema/validators.js.map +1 -1
  173. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.d.ts.map +1 -1
  174. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.js +3 -7
  175. package/node_modules/@fps-games/editor-playable-sdk/dist/local-harness/lifecycle.js.map +1 -1
  176. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.d.ts.map +1 -1
  177. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.js +6 -0
  178. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/binding.js.map +1 -1
  179. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/types.d.ts +2 -10
  180. package/node_modules/@fps-games/editor-playable-sdk/dist/material-binding/types.d.ts.map +1 -1
  181. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.d.ts.map +1 -1
  182. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.js +8 -0
  183. package/node_modules/@fps-games/editor-playable-sdk/dist/mutation/field-patch.js.map +1 -1
  184. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.d.ts.map +1 -1
  185. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.js +66 -31
  186. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/nodes.js.map +1 -1
  187. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/types.d.ts +2 -1
  188. package/node_modules/@fps-games/editor-playable-sdk/dist/runtime-preview/types.d.ts.map +1 -1
  189. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.d.ts.map +1 -1
  190. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.js +40 -2
  191. package/node_modules/@fps-games/editor-playable-sdk/dist/scene-source/protocol.js.map +1 -1
  192. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.d.ts +1 -0
  193. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.d.ts.map +1 -1
  194. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.js +20 -0
  195. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/descriptors.js.map +1 -1
  196. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.d.ts.map +1 -1
  197. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.js +68 -27
  198. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/inspector.js.map +1 -1
  199. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.d.ts.map +1 -1
  200. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.js +7 -4
  201. package/node_modules/@fps-games/editor-playable-sdk/dist/serialized-property/object.js.map +1 -1
  202. package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.d.ts.map +1 -1
  203. package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.js +2 -1
  204. package/node_modules/@fps-games/editor-playable-sdk/dist/session/hierarchy.js.map +1 -1
  205. package/node_modules/@fps-games/editor-playable-sdk/package.json +3 -3
  206. package/node_modules/@fps-games/editor-protocol/dist/agent.d.ts +57 -3
  207. package/node_modules/@fps-games/editor-protocol/dist/agent.d.ts.map +1 -1
  208. package/node_modules/@fps-games/editor-protocol/dist/agent.js.map +1 -1
  209. package/node_modules/@fps-games/editor-protocol/dist/index.d.ts +19 -0
  210. package/node_modules/@fps-games/editor-protocol/dist/index.d.ts.map +1 -1
  211. package/node_modules/@fps-games/editor-protocol/dist/index.js +1 -0
  212. package/node_modules/@fps-games/editor-protocol/dist/index.js.map +1 -1
  213. package/node_modules/@fps-games/editor-protocol/dist/marker-graph.d.ts +128 -0
  214. package/node_modules/@fps-games/editor-protocol/dist/marker-graph.d.ts.map +1 -0
  215. package/node_modules/@fps-games/editor-protocol/dist/marker-graph.js +2 -0
  216. package/node_modules/@fps-games/editor-protocol/dist/marker-graph.js.map +1 -0
  217. package/node_modules/@fps-games/editor-protocol/package.json +1 -1
  218. package/package.json +8 -8
@@ -3,6 +3,7 @@ import { applyBabylonDefaultOutline } from '@fps-games/babylon-renderer';
3
3
  import { applyArtistMaterialProfileToRuntimeMaterial } from './material-property-adapter.js';
4
4
  import { pickBabylonProjectionNodeIdAt, resolveBabylonPickSelectionNodeId, resolveBabylonProjectionNodeId, } from './projection-pick-resolver.js';
5
5
  import { normalizeProjectionOwnerNodePath, readProjectionSourceNodeSegment, } from './projection-source-owner-path.js';
6
+ import { createMaterialSlotOwnerPathMatchKey, isMaterialSlotOwnerPathMatch, } from './material-slot-source-resolver.js';
6
7
  const LARGE_SELECTION_EDGE_LIMIT = 200;
7
8
  const PROJECTION_LOCAL_MATRIX_METADATA_KEY = 'editorLocalTransformMatrix';
8
9
  const ASSET_MESH_SELECTION_SEPARATOR = '::assetMesh::';
@@ -124,6 +125,7 @@ export function createBabylonEditorProjection(options) {
124
125
  const disposeProjectedNode = (projection) => {
125
126
  projection.selectionEdgesPrewarmCancel?.();
126
127
  projection.selectionEdgesPrewarmCancel = null;
128
+ projection.importStructure = null;
127
129
  for (const animationGroup of projection.animationGroups) {
128
130
  animationGroup.dispose?.();
129
131
  }
@@ -262,6 +264,9 @@ export function createBabylonEditorProjection(options) {
262
264
  }
263
265
  return transforms;
264
266
  },
267
+ readNodeImportStructure(nodeId) {
268
+ return cloneProjectionImportStructureSnapshot(projections.get(nodeId)?.importStructure ?? null);
269
+ },
265
270
  setNodeTransformPreview(nodeId, transform) {
266
271
  const projection = projections.get(nodeId);
267
272
  if (!projection?.root)
@@ -581,12 +586,215 @@ function attachImportedProjectionResult(options, node, asset, projection, result
581
586
  }
582
587
  projection.animationGroups = result.animationGroups ?? [];
583
588
  projection.outlineMeshes = (result.meshes ?? []).filter((mesh) => mesh.getTotalVertices?.() > 0);
589
+ projection.importStructure = createProjectionImportStructureSnapshot(node, asset, modelRoot, result);
584
590
  }
585
591
  catch (error) {
586
592
  disposeImportedProjectionResult(result);
587
593
  throw error;
588
594
  }
589
595
  }
596
+ function createProjectionImportStructureSnapshot(node, asset, modelRoot, result) {
597
+ const runtimeNodes = collectProjectionImportRuntimeNodes(modelRoot, result);
598
+ const nodeIdByRuntimeNode = new Map();
599
+ const materialIdByRuntimeMaterial = new Map();
600
+ const textureIdByRuntimeTexture = new Map();
601
+ const materialNodeIds = new Map();
602
+ const materialTextureIds = new Map();
603
+ const rootSnapshotId = 'root';
604
+ const snapshots = [{
605
+ id: rootSnapshotId,
606
+ parentId: null,
607
+ name: readProjectionRuntimeName(modelRoot, node.name ?? node.id),
608
+ kind: 'root',
609
+ }];
610
+ for (const runtimeNode of runtimeNodes) {
611
+ const snapshotId = createProjectionImportRuntimeNodeId(runtimeNode, nodeIdByRuntimeNode.size);
612
+ nodeIdByRuntimeNode.set(runtimeNode, snapshotId);
613
+ }
614
+ for (const runtimeNode of runtimeNodes) {
615
+ const snapshotId = nodeIdByRuntimeNode.get(runtimeNode);
616
+ if (!snapshotId)
617
+ continue;
618
+ const materialIds = readProjectionRuntimeNodeMaterials(runtimeNode)
619
+ .map(runtimeMaterial => getProjectionImportMaterialSnapshotId(runtimeMaterial, materialIdByRuntimeMaterial))
620
+ .filter((materialId) => !!materialId);
621
+ for (const materialId of materialIds) {
622
+ const nodeIds = materialNodeIds.get(materialId) ?? new Set();
623
+ nodeIds.add(snapshotId);
624
+ materialNodeIds.set(materialId, nodeIds);
625
+ const textureIds = readProjectionRuntimeMaterialTextures(readProjectionRuntimeNodeMaterialById(runtimeNode, runtimeNode, materialId, materialIdByRuntimeMaterial))
626
+ .map(runtimeTexture => getProjectionImportTextureSnapshotId(runtimeTexture, textureIdByRuntimeTexture))
627
+ .filter((textureId) => !!textureId);
628
+ const materialTextures = materialTextureIds.get(materialId) ?? new Set();
629
+ for (const textureId of textureIds)
630
+ materialTextures.add(textureId);
631
+ materialTextureIds.set(materialId, materialTextures);
632
+ }
633
+ snapshots.push({
634
+ id: snapshotId,
635
+ parentId: resolveProjectionImportRuntimeParentId(runtimeNode, modelRoot, nodeIdByRuntimeNode, rootSnapshotId),
636
+ name: readProjectionRuntimeName(runtimeNode, snapshotId),
637
+ kind: isProjectionRuntimeMeshLike(runtimeNode) ? 'mesh' : 'transform',
638
+ ...readProjectionRuntimeSourceName(runtimeNode),
639
+ ...readProjectionRuntimeOwnerNodePath(runtimeNode),
640
+ ...(materialIds.length > 0 ? { materialIds } : {}),
641
+ });
642
+ }
643
+ const materials = [...materialIdByRuntimeMaterial.entries()].map(([runtimeMaterial, id]) => ({
644
+ id,
645
+ name: readProjectionRuntimeName(runtimeMaterial, id),
646
+ ...readProjectionRuntimeKind(runtimeMaterial),
647
+ nodeIds: [...(materialNodeIds.get(id) ?? [])],
648
+ textureIds: [...(materialTextureIds.get(id) ?? [])],
649
+ }));
650
+ const textures = [...textureIdByRuntimeTexture.entries()].map(([runtimeTexture, id]) => ({
651
+ id,
652
+ name: readProjectionRuntimeName(runtimeTexture, id),
653
+ ...readProjectionRuntimeKind(runtimeTexture),
654
+ ...readProjectionRuntimeTextureUrl(runtimeTexture),
655
+ }));
656
+ const animations = createProjectionImportAnimationSnapshots(result.animationGroups ?? []);
657
+ return {
658
+ projectionNodeId: node.id,
659
+ ...(asset.id ? { assetId: asset.id } : {}),
660
+ ...(asset.sourceId ? { sourceId: asset.sourceId } : {}),
661
+ nodes: snapshots,
662
+ materials,
663
+ textures,
664
+ animations,
665
+ };
666
+ }
667
+ function collectProjectionImportRuntimeNodes(modelRoot, result) {
668
+ const known = new Set([
669
+ ...(result.transformNodes ?? []),
670
+ ...(result.meshes ?? []),
671
+ ].filter(Boolean));
672
+ const ordered = [];
673
+ const visit = (runtimeNode) => {
674
+ for (const child of readProjectionRuntimeChildren(runtimeNode)) {
675
+ if (!known.has(child) || ordered.includes(child))
676
+ continue;
677
+ ordered.push(child);
678
+ visit(child);
679
+ }
680
+ };
681
+ visit(modelRoot);
682
+ for (const runtimeNode of known) {
683
+ if (!ordered.includes(runtimeNode))
684
+ ordered.push(runtimeNode);
685
+ }
686
+ return ordered;
687
+ }
688
+ function readProjectionRuntimeChildren(runtimeNode) {
689
+ const children = runtimeNode?.getChildren?.();
690
+ return Array.isArray(children) ? children : [];
691
+ }
692
+ function createProjectionImportRuntimeNodeId(runtimeNode, index) {
693
+ const sourceName = readProjectionSourceNodeSegment(runtimeNode);
694
+ const rawName = sourceName || runtimeNode?.name || runtimeNode?.id || `node-${index + 1}`;
695
+ return `${isProjectionRuntimeMeshLike(runtimeNode) ? 'mesh' : 'node'}:${sanitizeProjectionImportSnapshotId(rawName)}:${index + 1}`;
696
+ }
697
+ function resolveProjectionImportRuntimeParentId(runtimeNode, modelRoot, nodeIdByRuntimeNode, rootSnapshotId) {
698
+ const parent = runtimeNode?.parent ?? null;
699
+ if (!parent || parent === modelRoot)
700
+ return rootSnapshotId;
701
+ return nodeIdByRuntimeNode.get(parent) ?? rootSnapshotId;
702
+ }
703
+ function isProjectionRuntimeMeshLike(runtimeNode) {
704
+ return typeof runtimeNode?.getTotalVertices === 'function';
705
+ }
706
+ function readProjectionRuntimeNodeMaterials(runtimeNode) {
707
+ const material = runtimeNode?.material;
708
+ if (!material)
709
+ return [];
710
+ const subMaterials = material.subMaterials;
711
+ if (Array.isArray(subMaterials) && subMaterials.length > 0) {
712
+ return subMaterials.filter(Boolean);
713
+ }
714
+ return [material];
715
+ }
716
+ function readProjectionRuntimeNodeMaterialById(runtimeNode, _fallbackNode, materialId, materialIdByRuntimeMaterial) {
717
+ for (const material of readProjectionRuntimeNodeMaterials(runtimeNode)) {
718
+ if (materialIdByRuntimeMaterial.get(material) === materialId)
719
+ return material;
720
+ }
721
+ return null;
722
+ }
723
+ function getProjectionImportMaterialSnapshotId(runtimeMaterial, materialIdByRuntimeMaterial) {
724
+ if (!runtimeMaterial)
725
+ return null;
726
+ const existing = materialIdByRuntimeMaterial.get(runtimeMaterial);
727
+ if (existing)
728
+ return existing;
729
+ const id = `material:${sanitizeProjectionImportSnapshotId(readProjectionRuntimeName(runtimeMaterial, 'material'))}:${materialIdByRuntimeMaterial.size + 1}`;
730
+ materialIdByRuntimeMaterial.set(runtimeMaterial, id);
731
+ return id;
732
+ }
733
+ function readProjectionRuntimeMaterialTextures(runtimeMaterial) {
734
+ if (!runtimeMaterial)
735
+ return [];
736
+ const textures = runtimeMaterial.getActiveTextures?.();
737
+ return Array.isArray(textures) ? textures.filter(Boolean) : [];
738
+ }
739
+ function getProjectionImportTextureSnapshotId(runtimeTexture, textureIdByRuntimeTexture) {
740
+ if (!runtimeTexture)
741
+ return null;
742
+ const existing = textureIdByRuntimeTexture.get(runtimeTexture);
743
+ if (existing)
744
+ return existing;
745
+ const name = readProjectionRuntimeTextureUrl(runtimeTexture).url
746
+ ?? readProjectionRuntimeName(runtimeTexture, 'texture');
747
+ const id = `texture:${sanitizeProjectionImportSnapshotId(name)}:${textureIdByRuntimeTexture.size + 1}`;
748
+ textureIdByRuntimeTexture.set(runtimeTexture, id);
749
+ return id;
750
+ }
751
+ function createProjectionImportAnimationSnapshots(animationGroups) {
752
+ return animationGroups.filter(Boolean).map((animationGroup, index) => ({
753
+ id: `animation:${sanitizeProjectionImportSnapshotId(readProjectionRuntimeName(animationGroup, 'animation'))}:${index + 1}`,
754
+ name: readProjectionRuntimeName(animationGroup, `Animation ${index + 1}`),
755
+ }));
756
+ }
757
+ function readProjectionRuntimeName(runtimeObject, fallback) {
758
+ const name = runtimeObject?.name ?? runtimeObject?.id;
759
+ return typeof name === 'string' && name.trim() ? name.trim() : fallback;
760
+ }
761
+ function readProjectionRuntimeKind(runtimeObject) {
762
+ const kind = runtimeObject?.getClassName?.();
763
+ return typeof kind === 'string' && kind.trim() ? { kind: kind.trim() } : {};
764
+ }
765
+ function readProjectionRuntimeTextureUrl(runtimeTexture) {
766
+ const url = runtimeTexture?.url ?? runtimeTexture?.name;
767
+ return typeof url === 'string' && url.trim() ? { url: url.trim() } : {};
768
+ }
769
+ function readProjectionRuntimeSourceName(runtimeNode) {
770
+ const sourceName = readProjectionSourceNodeSegment(runtimeNode);
771
+ return sourceName ? { sourceName } : {};
772
+ }
773
+ function readProjectionRuntimeOwnerNodePath(runtimeNode) {
774
+ const ownerNodePath = runtimeNode?.metadata?.editorProjection?.ownerNodePath;
775
+ return typeof ownerNodePath === 'string' && ownerNodePath.trim() ? { ownerNodePath: ownerNodePath.trim() } : {};
776
+ }
777
+ function sanitizeProjectionImportSnapshotId(value) {
778
+ return value.trim().toLowerCase().replace(/[^a-z0-9_.:-]+/gi, '-').replace(/^-+|-+$/g, '') || 'item';
779
+ }
780
+ function cloneProjectionImportStructureSnapshot(snapshot) {
781
+ if (!snapshot)
782
+ return null;
783
+ return {
784
+ ...snapshot,
785
+ nodes: snapshot.nodes.map(item => ({
786
+ ...item,
787
+ ...(item.materialIds ? { materialIds: [...item.materialIds] } : {}),
788
+ })),
789
+ materials: snapshot.materials.map(item => ({
790
+ ...item,
791
+ nodeIds: [...item.nodeIds],
792
+ textureIds: [...item.textureIds],
793
+ })),
794
+ textures: snapshot.textures.map(item => ({ ...item })),
795
+ animations: snapshot.animations.map(item => ({ ...item })),
796
+ };
797
+ }
590
798
  function disposeImportedProjectionResult(result) {
591
799
  for (const animationGroup of result.animationGroups ?? []) {
592
800
  animationGroup.dispose?.();
@@ -655,6 +863,8 @@ function attachDirectionalLightProjection(babylon, scene, node, projection) {
655
863
  light.setEnabled?.(node.active !== false);
656
864
  projection.runtimeObjects.push(light);
657
865
  }
866
+ if (!settings.helperVisible)
867
+ return;
658
868
  const helper = MeshBuilder.CreateBox(`${node.id}.lightHelper`, {
659
869
  size: 0.28,
660
870
  }, scene);
@@ -760,9 +970,9 @@ function createPrimitiveProjectionMesh(babylon, scene, node, options) {
760
970
  return mesh;
761
971
  }
762
972
  function applyProjectionArtistMaterialProfilesToMeshes(options, node, modelRoot, meshes) {
763
- const slotProfiles = node.artistMaterialSlotProfiles ?? {};
973
+ const slotBindings = createProjectionMaterialSlotBindings(node);
764
974
  const hasRootProfile = !!node.artistMaterialProfile;
765
- const hasSlotProfiles = Object.keys(slotProfiles).length > 0;
975
+ const hasSlotProfiles = slotBindings.length > 0;
766
976
  if (!hasRootProfile && !hasSlotProfiles)
767
977
  return [];
768
978
  const clonedMaterials = [];
@@ -785,15 +995,15 @@ function applyProjectionArtistMaterialProfilesToMeshes(options, node, modelRoot,
785
995
  if (!material)
786
996
  continue;
787
997
  const ownerNodePath = buildProjectionOwnerNodePath(mesh, modelRoot, node.id);
788
- const slotProfile = resolveProjectionSlotProfile(slotProfiles, ownerNodePath, node.id);
789
- if (!slotProfile)
998
+ const slotBinding = resolveProjectionSlotBinding(slotBindings, ownerNodePath, node.id);
999
+ if (!slotBinding)
790
1000
  continue;
791
1001
  const slotMaterial = detachProjectionSlotMaterial(mesh, materialCounts, ownerNodePath);
792
1002
  if (!slotMaterial)
793
1003
  continue;
794
1004
  if (slotMaterial !== material)
795
1005
  clonedMaterials.push(slotMaterial);
796
- applyProjectionArtistMaterialProfile(options, slotMaterial, slotProfile);
1006
+ applyProjectionArtistMaterialProfile(options, slotMaterial, slotBinding.profile);
797
1007
  }
798
1008
  return clonedMaterials;
799
1009
  }
@@ -805,27 +1015,85 @@ function applyProjectionArtistMaterialProfile(options, material, profile) {
805
1015
  resolveTextureUrl: options.resolveTextureUrl,
806
1016
  });
807
1017
  }
808
- function resolveProjectionSlotProfile(slotProfiles, ownerNodePath, projectionNodeId) {
1018
+ function createProjectionMaterialSlotBindings(node) {
1019
+ const bindings = [];
1020
+ const occupiedOwnerPaths = new Set();
1021
+ for (const binding of node.artistMaterialSlotBindings ?? []) {
1022
+ const profile = binding?.profile;
1023
+ const slot = createProjectionMaterialSlotDescriptor(binding?.slot, node.id);
1024
+ if (!profile || !slot)
1025
+ continue;
1026
+ bindings.push({ slot, profile });
1027
+ occupiedOwnerPaths.add(slot.matchKey);
1028
+ }
1029
+ for (const [ownerNodePath, profile] of Object.entries(node.artistMaterialSlotProfiles ?? {})) {
1030
+ const slot = createProjectionMaterialSlotDescriptor({ ownerNodePath }, node.id);
1031
+ if (!profile || !slot || occupiedOwnerPaths.has(slot.matchKey))
1032
+ continue;
1033
+ bindings.push({ slot, profile });
1034
+ occupiedOwnerPaths.add(slot.matchKey);
1035
+ }
1036
+ return bindings;
1037
+ }
1038
+ function createProjectionMaterialSlotDescriptor(value, projectionNodeId) {
1039
+ if (!value || typeof value !== 'object')
1040
+ return null;
1041
+ const ownerNodePath = typeof value.ownerNodePath === 'string'
1042
+ ? normalizeProjectionOwnerNodePath(value.ownerNodePath, { projectionNodeId })
1043
+ : '';
1044
+ if (!ownerNodePath)
1045
+ return null;
1046
+ const slotId = typeof value.slotId === 'string' && value.slotId.trim() ? value.slotId.trim() : '';
1047
+ const label = typeof value.label === 'string' && value.label.trim() ? value.label.trim() : '';
1048
+ const nodeIndex = Number.isInteger(value.nodeIndex) ? value.nodeIndex : undefined;
1049
+ const nodeIndexPath = Array.isArray(value.nodeIndexPath)
1050
+ ? value.nodeIndexPath.filter((item) => Number.isInteger(item))
1051
+ : undefined;
1052
+ const meshIndex = Number.isInteger(value.meshIndex) ? value.meshIndex : undefined;
1053
+ const primitiveIndex = Number.isInteger(value.primitiveIndex) ? value.primitiveIndex : undefined;
1054
+ const sourceMaterialIndex = Number.isInteger(value.sourceMaterialIndex) ? value.sourceMaterialIndex : undefined;
1055
+ const sourceMaterialIndices = Array.isArray(value.sourceMaterialIndices)
1056
+ ? value.sourceMaterialIndices.filter((item) => Number.isInteger(item))
1057
+ : undefined;
1058
+ const materialName = typeof value.materialName === 'string' && value.materialName.trim() ? value.materialName.trim() : '';
1059
+ const materialNames = Array.isArray(value.materialNames)
1060
+ ? value.materialNames.filter((item) => typeof item === 'string' && !!item.trim()).map(item => item.trim())
1061
+ : undefined;
1062
+ return {
1063
+ ...(slotId ? { slotId } : {}),
1064
+ ownerNodePath,
1065
+ ...(label ? { label } : {}),
1066
+ ...(nodeIndex != null ? { nodeIndex } : {}),
1067
+ ...(nodeIndexPath && nodeIndexPath.length > 0 ? { nodeIndexPath } : {}),
1068
+ ...(meshIndex != null ? { meshIndex } : {}),
1069
+ ...(primitiveIndex != null ? { primitiveIndex } : {}),
1070
+ ...(sourceMaterialIndex != null ? { sourceMaterialIndex } : {}),
1071
+ ...(sourceMaterialIndices && sourceMaterialIndices.length > 0
1072
+ ? { sourceMaterialIndices }
1073
+ : {}),
1074
+ ...(materialName ? { materialName } : {}),
1075
+ ...(materialNames && materialNames.length > 0 ? { materialNames } : {}),
1076
+ key: slotId || ownerNodePath,
1077
+ normalizedOwnerNodePath: ownerNodePath,
1078
+ matchKey: createMaterialSlotOwnerPathMatchKey(ownerNodePath, { projectionNodeId }),
1079
+ };
1080
+ }
1081
+ function resolveProjectionSlotBinding(slotBindings, ownerNodePath, projectionNodeId) {
809
1082
  if (ownerNodePath == null)
810
1083
  return null;
811
- const direct = slotProfiles[ownerNodePath];
812
- if (direct)
813
- return direct;
814
1084
  const normalized = normalizeProjectionOwnerNodePath(ownerNodePath, { projectionNodeId });
815
- if (normalized !== ownerNodePath && slotProfiles[normalized])
816
- return slotProfiles[normalized];
1085
+ const normalizedMatchKey = createMaterialSlotOwnerPathMatchKey(normalized, { projectionNodeId });
817
1086
  let descendantMatch = null;
818
- for (const [candidatePath, profile] of Object.entries(slotProfiles)) {
819
- const normalizedCandidate = normalizeProjectionOwnerNodePath(candidatePath, { projectionNodeId });
820
- if (normalizedCandidate === normalized)
821
- return profile;
822
- if (isProjectionOwnerPathDescendant(normalized, normalizedCandidate)) {
823
- if (!descendantMatch || normalizedCandidate.length > descendantMatch.path.length) {
824
- descendantMatch = { path: normalizedCandidate, profile };
1087
+ for (const binding of slotBindings) {
1088
+ if (binding.slot.matchKey === normalizedMatchKey)
1089
+ return binding;
1090
+ if (isMaterialSlotOwnerPathMatch(normalized, binding.slot.normalizedOwnerNodePath, { projectionNodeId })) {
1091
+ if (!descendantMatch || binding.slot.matchKey.length > descendantMatch.slot.matchKey.length) {
1092
+ descendantMatch = binding;
825
1093
  }
826
1094
  }
827
1095
  }
828
- return descendantMatch?.profile ?? null;
1096
+ return descendantMatch;
829
1097
  }
830
1098
  function buildProjectionOwnerNodePath(node, rootNode, projectionNodeId) {
831
1099
  if (!node || !rootNode || node === rootNode)
@@ -857,11 +1125,6 @@ function stableProjectionNodeSegment(node) {
857
1125
  }
858
1126
  return null;
859
1127
  }
860
- function isProjectionOwnerPathDescendant(ownerNodePath, candidateAncestorPath) {
861
- if (!ownerNodePath || !candidateAncestorPath)
862
- return false;
863
- return ownerNodePath.startsWith(`${candidateAncestorPath}/`);
864
- }
865
1128
  function createAssetMeshProjectionNodeId(rootNodeId, ownerNodePath) {
866
1129
  return `${rootNodeId}${ASSET_MESH_SELECTION_SEPARATOR}${encodeURIComponent(ownerNodePath)}`;
867
1130
  }
@@ -869,9 +1132,9 @@ function resolveProjectionAssetMeshSelectionKey(asset, ownerNodePath, projection
869
1132
  const normalizedOwnerPath = normalizeProjectionOwnerNodePath(ownerNodePath, { projectionNodeId });
870
1133
  let bestSlot = null;
871
1134
  for (const slot of readProjectionAssetMaterialSlots(asset, projectionNodeId)) {
872
- if (!isProjectionOwnerPathSlotMatch(normalizedOwnerPath, slot.path))
1135
+ if (!isMaterialSlotOwnerPathMatch(normalizedOwnerPath, slot.normalizedOwnerNodePath, { projectionNodeId }))
873
1136
  continue;
874
- if (!bestSlot || slot.path.length > bestSlot.path.length) {
1137
+ if (!bestSlot || slot.matchKey.length > bestSlot.matchKey.length) {
875
1138
  bestSlot = slot;
876
1139
  }
877
1140
  }
@@ -891,8 +1154,7 @@ function readProjectionAssetMaterialSlots(asset, projectionNodeId) {
891
1154
  }
892
1155
  function readProjectionAssetMaterialSlot(value, projectionNodeId) {
893
1156
  if (typeof value === 'string') {
894
- const path = normalizeProjectionOwnerNodePath(value, { projectionNodeId });
895
- return path ? { key: path, path } : null;
1157
+ return createProjectionMaterialSlotDescriptor({ ownerNodePath: value }, projectionNodeId);
896
1158
  }
897
1159
  if (!value || typeof value !== 'object' || Array.isArray(value))
898
1160
  return null;
@@ -900,23 +1162,11 @@ function readProjectionAssetMaterialSlot(value, projectionNodeId) {
900
1162
  const rawOwnerPath = readProjectionAssetMaterialSlotString(record.ownerNodePath)
901
1163
  || readProjectionAssetMaterialSlotString(record.path)
902
1164
  || readProjectionAssetMaterialSlotString(record.name);
903
- const path = normalizeProjectionOwnerNodePath(rawOwnerPath, { projectionNodeId });
904
- if (!path)
905
- return null;
906
- const slotId = readProjectionAssetMaterialSlotString(record.slotId);
907
- return {
908
- key: slotId || path,
909
- path,
910
- };
1165
+ return createProjectionMaterialSlotDescriptor({ ...record, ownerNodePath: rawOwnerPath }, projectionNodeId);
911
1166
  }
912
1167
  function readProjectionAssetMaterialSlotString(value) {
913
1168
  return typeof value === 'string' ? value.trim() : '';
914
1169
  }
915
- function isProjectionOwnerPathSlotMatch(ownerNodePath, slotOwnerPath) {
916
- if (!ownerNodePath || !slotOwnerPath)
917
- return false;
918
- return ownerNodePath === slotOwnerPath || isProjectionOwnerPathDescendant(ownerNodePath, slotOwnerPath);
919
- }
920
1170
  function countProjectionMeshMaterials(meshes) {
921
1171
  const counts = new Map();
922
1172
  for (const mesh of meshes) {
@@ -1112,6 +1362,8 @@ function attachHemisphericLightProjection(babylon, scene, node, projection) {
1112
1362
  light.setEnabled?.(node.active !== false);
1113
1363
  projection.runtimeObjects.push(light);
1114
1364
  }
1365
+ if (!settings.helperVisible)
1366
+ return;
1115
1367
  const helper = MeshBuilder.CreateSphere?.(`${node.id}.hemisphericLightHelper`, {
1116
1368
  diameter: 0.32,
1117
1369
  segments: 18,
@@ -1258,6 +1510,7 @@ function readProjectionDirectionalLightSettings(settings) {
1258
1510
  intensity: Math.max(0, readFiniteNumber(settings?.intensity, 2)),
1259
1511
  direction: readVector3(settings?.direction, { x: -0.3, y: -1, z: -0.2 }),
1260
1512
  diffuseColor: readProjectionColor(settings?.diffuseColor, { r: 1, g: 1, b: 1 }),
1513
+ helperVisible: settings?.helperVisible !== false,
1261
1514
  };
1262
1515
  }
1263
1516
  function readProjectionHemisphericLightSettings(settings) {
@@ -1266,6 +1519,7 @@ function readProjectionHemisphericLightSettings(settings) {
1266
1519
  intensity: Math.max(0, readFiniteNumber(settings?.intensity, 0.8)),
1267
1520
  diffuseColor: readProjectionColor(settings?.diffuseColor, { r: 1, g: 1, b: 1 }),
1268
1521
  groundColor: readProjectionColor(settings?.groundColor, { r: 0.48, g: 0.52, b: 0.62 }),
1522
+ helperVisible: settings?.helperVisible !== false,
1269
1523
  };
1270
1524
  }
1271
1525
  function readProjectionColor(value, fallback) {