@fps-games/editor 0.1.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 (186) hide show
  1. package/dist/authoring-apply.d.ts +21 -0
  2. package/dist/authoring-apply.d.ts.map +1 -0
  3. package/dist/authoring-apply.js +45 -0
  4. package/dist/authoring-apply.js.map +1 -0
  5. package/dist/index.d.ts +85 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +539 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/local-editor-harness.d.ts +173 -0
  10. package/dist/local-editor-harness.d.ts.map +1 -0
  11. package/dist/local-editor-harness.js +969 -0
  12. package/dist/local-editor-harness.js.map +1 -0
  13. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.d.ts +20 -0
  14. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.d.ts.map +1 -0
  15. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.js +239 -0
  16. package/node_modules/@fps-games/editor-babylon/dist/camera-controller.js.map +1 -0
  17. package/node_modules/@fps-games/editor-babylon/dist/edit-session.d.ts +30 -0
  18. package/node_modules/@fps-games/editor-babylon/dist/edit-session.d.ts.map +1 -0
  19. package/node_modules/@fps-games/editor-babylon/dist/edit-session.js +297 -0
  20. package/node_modules/@fps-games/editor-babylon/dist/edit-session.js.map +1 -0
  21. package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts +30 -0
  22. package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts.map +1 -0
  23. package/node_modules/@fps-games/editor-babylon/dist/editor-world.js +67 -0
  24. package/node_modules/@fps-games/editor-babylon/dist/editor-world.js.map +1 -0
  25. package/node_modules/@fps-games/editor-babylon/dist/event-guard.d.ts +13 -0
  26. package/node_modules/@fps-games/editor-babylon/dist/event-guard.d.ts.map +1 -0
  27. package/node_modules/@fps-games/editor-babylon/dist/event-guard.js +101 -0
  28. package/node_modules/@fps-games/editor-babylon/dist/event-guard.js.map +1 -0
  29. package/node_modules/@fps-games/editor-babylon/dist/index.d.ts +19 -0
  30. package/node_modules/@fps-games/editor-babylon/dist/index.d.ts.map +1 -0
  31. package/node_modules/@fps-games/editor-babylon/dist/index.js +18 -0
  32. package/node_modules/@fps-games/editor-babylon/dist/index.js.map +1 -0
  33. package/node_modules/@fps-games/editor-babylon/dist/input-controller.d.ts +3 -0
  34. package/node_modules/@fps-games/editor-babylon/dist/input-controller.d.ts.map +1 -0
  35. package/node_modules/@fps-games/editor-babylon/dist/input-controller.js +182 -0
  36. package/node_modules/@fps-games/editor-babylon/dist/input-controller.js.map +1 -0
  37. package/node_modules/@fps-games/editor-babylon/dist/inspector-adapter.d.ts +13 -0
  38. package/node_modules/@fps-games/editor-babylon/dist/inspector-adapter.d.ts.map +1 -0
  39. package/node_modules/@fps-games/editor-babylon/dist/inspector-adapter.js +94 -0
  40. package/node_modules/@fps-games/editor-babylon/dist/inspector-adapter.js.map +1 -0
  41. package/node_modules/@fps-games/editor-babylon/dist/inspector-host.d.ts +43 -0
  42. package/node_modules/@fps-games/editor-babylon/dist/inspector-host.d.ts.map +1 -0
  43. package/node_modules/@fps-games/editor-babylon/dist/inspector-host.js +510 -0
  44. package/node_modules/@fps-games/editor-babylon/dist/inspector-host.js.map +1 -0
  45. package/node_modules/@fps-games/editor-babylon/dist/legacy-runtime.d.ts +5 -0
  46. package/node_modules/@fps-games/editor-babylon/dist/legacy-runtime.d.ts.map +1 -0
  47. package/node_modules/@fps-games/editor-babylon/dist/legacy-runtime.js +5 -0
  48. package/node_modules/@fps-games/editor-babylon/dist/legacy-runtime.js.map +1 -0
  49. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.d.ts +22 -0
  50. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.d.ts.map +1 -0
  51. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.js +408 -0
  52. package/node_modules/@fps-games/editor-babylon/dist/material-property-adapter.js.map +1 -0
  53. package/node_modules/@fps-games/editor-babylon/dist/monitor.d.ts +39 -0
  54. package/node_modules/@fps-games/editor-babylon/dist/monitor.d.ts.map +1 -0
  55. package/node_modules/@fps-games/editor-babylon/dist/monitor.js +780 -0
  56. package/node_modules/@fps-games/editor-babylon/dist/monitor.js.map +1 -0
  57. package/node_modules/@fps-games/editor-babylon/dist/outline-adapter.d.ts +37 -0
  58. package/node_modules/@fps-games/editor-babylon/dist/outline-adapter.d.ts.map +1 -0
  59. package/node_modules/@fps-games/editor-babylon/dist/outline-adapter.js +268 -0
  60. package/node_modules/@fps-games/editor-babylon/dist/outline-adapter.js.map +1 -0
  61. package/node_modules/@fps-games/editor-babylon/dist/projection-selection-controller.d.ts +34 -0
  62. package/node_modules/@fps-games/editor-babylon/dist/projection-selection-controller.d.ts.map +1 -0
  63. package/node_modules/@fps-games/editor-babylon/dist/projection-selection-controller.js +221 -0
  64. package/node_modules/@fps-games/editor-babylon/dist/projection-selection-controller.js.map +1 -0
  65. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts +90 -0
  66. package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts.map +1 -0
  67. package/node_modules/@fps-games/editor-babylon/dist/projection.js +479 -0
  68. package/node_modules/@fps-games/editor-babylon/dist/projection.js.map +1 -0
  69. package/node_modules/@fps-games/editor-babylon/dist/runtime-globals.d.ts +3 -0
  70. package/node_modules/@fps-games/editor-babylon/dist/runtime-globals.d.ts.map +1 -0
  71. package/node_modules/@fps-games/editor-babylon/dist/runtime-globals.js +7 -0
  72. package/node_modules/@fps-games/editor-babylon/dist/runtime-globals.js.map +1 -0
  73. package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts +18 -0
  74. package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts.map +1 -0
  75. package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js +213 -0
  76. package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js.map +1 -0
  77. package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.d.ts +36 -0
  78. package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.d.ts.map +1 -0
  79. package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.js +272 -0
  80. package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.js.map +1 -0
  81. package/node_modules/@fps-games/editor-babylon/dist/selection-controller.d.ts +27 -0
  82. package/node_modules/@fps-games/editor-babylon/dist/selection-controller.d.ts.map +1 -0
  83. package/node_modules/@fps-games/editor-babylon/dist/selection-controller.js +308 -0
  84. package/node_modules/@fps-games/editor-babylon/dist/selection-controller.js.map +1 -0
  85. package/node_modules/@fps-games/editor-babylon/dist/tool-controller.d.ts +17 -0
  86. package/node_modules/@fps-games/editor-babylon/dist/tool-controller.d.ts.map +1 -0
  87. package/node_modules/@fps-games/editor-babylon/dist/tool-controller.js +83 -0
  88. package/node_modules/@fps-games/editor-babylon/dist/tool-controller.js.map +1 -0
  89. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.d.ts +47 -0
  90. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.d.ts.map +1 -0
  91. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js +689 -0
  92. package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js.map +1 -0
  93. package/node_modules/@fps-games/editor-babylon/dist/types.d.ts +111 -0
  94. package/node_modules/@fps-games/editor-babylon/dist/types.d.ts.map +1 -0
  95. package/node_modules/@fps-games/editor-babylon/dist/types.js +2 -0
  96. package/node_modules/@fps-games/editor-babylon/dist/types.js.map +1 -0
  97. package/node_modules/@fps-games/editor-babylon/package.json +25 -0
  98. package/node_modules/@fps-games/editor-browser/dist/index.d.ts +28 -0
  99. package/node_modules/@fps-games/editor-browser/dist/index.d.ts.map +1 -0
  100. package/node_modules/@fps-games/editor-browser/dist/index.js +54 -0
  101. package/node_modules/@fps-games/editor-browser/dist/index.js.map +1 -0
  102. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-input-router.d.ts +12 -0
  103. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-input-router.d.ts.map +1 -0
  104. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-input-router.js +80 -0
  105. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-input-router.js.map +1 -0
  106. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.d.ts +11 -0
  107. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.d.ts.map +1 -0
  108. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.js +33 -0
  109. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panel-registry.js.map +1 -0
  110. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts +9 -0
  111. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts.map +1 -0
  112. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js +444 -0
  113. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js.map +1 -0
  114. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts +21 -0
  115. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.d.ts.map +1 -0
  116. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.js +103 -0
  117. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-primitives.js.map +1 -0
  118. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.d.ts +12 -0
  119. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.d.ts.map +1 -0
  120. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js +123 -0
  121. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js.map +1 -0
  122. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.d.ts +2 -0
  123. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.d.ts.map +1 -0
  124. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.js +115 -0
  125. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.js.map +1 -0
  126. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-theme.d.ts +3 -0
  127. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-theme.d.ts.map +1 -0
  128. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-theme.js +68 -0
  129. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-theme.js.map +1 -0
  130. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts +183 -0
  131. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts.map +1 -0
  132. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.js +2 -0
  133. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.js.map +1 -0
  134. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts +58 -0
  135. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts.map +1 -0
  136. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js +136 -0
  137. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js.map +1 -0
  138. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts +4 -0
  139. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts.map +1 -0
  140. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js +589 -0
  141. package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js.map +1 -0
  142. package/node_modules/@fps-games/editor-browser/package.json +16 -0
  143. package/node_modules/@fps-games/editor-core/dist/authoring-source.d.ts +211 -0
  144. package/node_modules/@fps-games/editor-core/dist/authoring-source.d.ts.map +1 -0
  145. package/node_modules/@fps-games/editor-core/dist/authoring-source.js +511 -0
  146. package/node_modules/@fps-games/editor-core/dist/authoring-source.js.map +1 -0
  147. package/node_modules/@fps-games/editor-core/dist/editor-session.d.ts +132 -0
  148. package/node_modules/@fps-games/editor-core/dist/editor-session.d.ts.map +1 -0
  149. package/node_modules/@fps-games/editor-core/dist/editor-session.js +265 -0
  150. package/node_modules/@fps-games/editor-core/dist/editor-session.js.map +1 -0
  151. package/node_modules/@fps-games/editor-core/dist/host-services.d.ts +24 -0
  152. package/node_modules/@fps-games/editor-core/dist/host-services.d.ts.map +1 -0
  153. package/node_modules/@fps-games/editor-core/dist/host-services.js +2 -0
  154. package/node_modules/@fps-games/editor-core/dist/host-services.js.map +1 -0
  155. package/node_modules/@fps-games/editor-core/dist/index.d.ts +106 -0
  156. package/node_modules/@fps-games/editor-core/dist/index.d.ts.map +1 -0
  157. package/node_modules/@fps-games/editor-core/dist/index.js +217 -0
  158. package/node_modules/@fps-games/editor-core/dist/index.js.map +1 -0
  159. package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts +44 -0
  160. package/node_modules/@fps-games/editor-core/dist/scene-graph.d.ts.map +1 -0
  161. package/node_modules/@fps-games/editor-core/dist/scene-graph.js +86 -0
  162. package/node_modules/@fps-games/editor-core/dist/scene-graph.js.map +1 -0
  163. package/node_modules/@fps-games/editor-core/dist/scene-view-input.d.ts +41 -0
  164. package/node_modules/@fps-games/editor-core/dist/scene-view-input.d.ts.map +1 -0
  165. package/node_modules/@fps-games/editor-core/dist/scene-view-input.js +2 -0
  166. package/node_modules/@fps-games/editor-core/dist/scene-view-input.js.map +1 -0
  167. package/node_modules/@fps-games/editor-core/dist/serialized-object.d.ts +53 -0
  168. package/node_modules/@fps-games/editor-core/dist/serialized-object.d.ts.map +1 -0
  169. package/node_modules/@fps-games/editor-core/dist/serialized-object.js +32 -0
  170. package/node_modules/@fps-games/editor-core/dist/serialized-object.js.map +1 -0
  171. package/node_modules/@fps-games/editor-core/dist/transform-gizmo.d.ts +48 -0
  172. package/node_modules/@fps-games/editor-core/dist/transform-gizmo.d.ts.map +1 -0
  173. package/node_modules/@fps-games/editor-core/dist/transform-gizmo.js +2 -0
  174. package/node_modules/@fps-games/editor-core/dist/transform-gizmo.js.map +1 -0
  175. package/node_modules/@fps-games/editor-core/package.json +19 -0
  176. package/node_modules/@fps-games/editor-forge-play/dist/index.d.ts +46 -0
  177. package/node_modules/@fps-games/editor-forge-play/dist/index.d.ts.map +1 -0
  178. package/node_modules/@fps-games/editor-forge-play/dist/index.js +156 -0
  179. package/node_modules/@fps-games/editor-forge-play/dist/index.js.map +1 -0
  180. package/node_modules/@fps-games/editor-forge-play/package.json +19 -0
  181. package/node_modules/@fps-games/editor-protocol/dist/index.d.ts +239 -0
  182. package/node_modules/@fps-games/editor-protocol/dist/index.d.ts.map +1 -0
  183. package/node_modules/@fps-games/editor-protocol/dist/index.js +54 -0
  184. package/node_modules/@fps-games/editor-protocol/dist/index.js.map +1 -0
  185. package/node_modules/@fps-games/editor-protocol/package.json +16 -0
  186. package/package.json +40 -0
@@ -0,0 +1,780 @@
1
+ import { createBrowserHost } from '@fps-games/editor-browser';
2
+ import { adaptMaterialPropertyChange, MATERIAL_CANONICAL_PATHS, resolveMaterialRuntimeKind } from './material-property-adapter';
3
+ import { adaptOutlinePropertyChange, OUTLINE_CANONICAL_PATHS, resolveOutlineTarget } from './outline-adapter';
4
+ const EPS = 1e-6;
5
+ function vecEq(a, b) {
6
+ return Math.abs(a.x - b.x) < EPS
7
+ && Math.abs(a.y - b.y) < EPS
8
+ && Math.abs(a.z - b.z) < EPS;
9
+ }
10
+ function cloneVec3Like(source) {
11
+ if (!source || typeof source !== 'object')
12
+ return null;
13
+ const x = typeof source.x === 'number' ? source.x : null;
14
+ const y = typeof source.y === 'number' ? source.y : null;
15
+ const z = typeof source.z === 'number' ? source.z : null;
16
+ if (x == null || y == null || z == null)
17
+ return null;
18
+ return { x, y, z };
19
+ }
20
+ function cloneColor3(value) {
21
+ if (!value || typeof value !== 'object')
22
+ return null;
23
+ const r = typeof value.r === 'number' ? value.r : typeof value._r === 'number' ? value._r : null;
24
+ const g = typeof value.g === 'number' ? value.g : typeof value._g === 'number' ? value._g : null;
25
+ const b = typeof value.b === 'number' ? value.b : typeof value._b === 'number' ? value._b : null;
26
+ if (r == null || g == null || b == null)
27
+ return null;
28
+ return { r, g, b };
29
+ }
30
+ function readTextureUrl(value) {
31
+ if (typeof value === 'string')
32
+ return value.trim() || null;
33
+ if (!value || typeof value !== 'object')
34
+ return null;
35
+ if (typeof value.url === 'string' && value.url.trim())
36
+ return value.url.trim();
37
+ if (typeof value.name === 'string' && value.name.trim())
38
+ return value.name.trim();
39
+ return null;
40
+ }
41
+ function cloneValue(value) {
42
+ if (value == null || typeof value !== 'object')
43
+ return value;
44
+ return JSON.parse(JSON.stringify(value));
45
+ }
46
+ function valueEq(a, b) {
47
+ if (Object.is(a, b))
48
+ return true;
49
+ if (typeof a === 'number' && typeof b === 'number')
50
+ return Math.abs(a - b) < EPS;
51
+ if (a && b && typeof a === 'object' && typeof b === 'object')
52
+ return JSON.stringify(a) === JSON.stringify(b);
53
+ return false;
54
+ }
55
+ function readRotation(node) {
56
+ const quat = node?.rotationQuaternion;
57
+ if (quat && typeof quat.toEulerAngles === 'function')
58
+ return cloneVec3Like(quat.toEulerAngles());
59
+ return cloneVec3Like(node?.rotation);
60
+ }
61
+ function snapshotTransform(node) {
62
+ if (!node)
63
+ return null;
64
+ const position = cloneVec3Like(node.position);
65
+ const rotation = readRotation(node);
66
+ const scaling = cloneVec3Like(node.scaling);
67
+ if (!position || !rotation || !scaling)
68
+ return null;
69
+ return { position, rotation, scaling };
70
+ }
71
+ function hasChanged(a, b) {
72
+ return !vecEq(a.position, b.position) || !vecEq(a.rotation, b.rotation) || !vecEq(a.scaling, b.scaling);
73
+ }
74
+ function cloneTransformSnapshot(value) {
75
+ return {
76
+ position: { ...value.position },
77
+ rotation: { ...value.rotation },
78
+ scaling: { ...value.scaling },
79
+ };
80
+ }
81
+ function hasTransform(node) {
82
+ return !!node?.position && (!!node?.rotation || !!node?.rotationQuaternion) && !!node?.scaling;
83
+ }
84
+ function resolveTrackedNode(scene, entity, previous) {
85
+ if (!entity)
86
+ return null;
87
+ if (hasTransform(entity))
88
+ return entity;
89
+ if (previous && previous.material === entity)
90
+ return previous;
91
+ const owner = (scene?.meshes || []).find((mesh) => mesh?.material === entity);
92
+ if (owner && hasTransform(owner))
93
+ return owner;
94
+ return previous ?? null;
95
+ }
96
+ function snapshotMaterial(node) {
97
+ const material = node?.material;
98
+ if (!material || typeof material !== 'object')
99
+ return {};
100
+ const materialRuntimeKind = resolveMaterialRuntimeKind(material);
101
+ const out = {};
102
+ for (const fieldPath of MATERIAL_CANONICAL_PATHS) {
103
+ switch (fieldPath) {
104
+ case 'material.albedoColor':
105
+ case 'material.emissiveColor': {
106
+ if (materialRuntimeKind !== 'unknown')
107
+ break;
108
+ const key = fieldPath === 'material.albedoColor'
109
+ ? ('albedoColor' in material ? 'albedoColor' : 'diffuseColor')
110
+ : 'emissiveColor';
111
+ const color = cloneColor3(material[key]);
112
+ if (color)
113
+ out[fieldPath] = color;
114
+ break;
115
+ }
116
+ case 'material.metallic':
117
+ case 'material.roughness':
118
+ case 'material.alpha': {
119
+ const key = fieldPath.split('.')[1];
120
+ const n = material[key];
121
+ if (typeof n === 'number' && Number.isFinite(n))
122
+ out[fieldPath] = n;
123
+ break;
124
+ }
125
+ case 'material.backFaceCulling': {
126
+ const v = material.backFaceCulling;
127
+ if (typeof v === 'boolean')
128
+ out[fieldPath] = v;
129
+ break;
130
+ }
131
+ case 'material.albedoTexture.url':
132
+ case 'material.normalTexture.url':
133
+ case 'material.metallicTexture.url': {
134
+ const key = fieldPath.split('.')[1];
135
+ out[fieldPath] = readTextureUrl(material[key]);
136
+ break;
137
+ }
138
+ case 'material.pbr.albedoColor':
139
+ case 'material.pbr.reflectivityColor':
140
+ case 'material.pbr.emissiveColor':
141
+ case 'material.pbr.ambientColor': {
142
+ if (materialRuntimeKind !== 'pbr')
143
+ break;
144
+ const key = fieldPath.split('.')[2];
145
+ const hidden = `_${key}`;
146
+ const color = cloneColor3(material[hidden] ?? material[key]);
147
+ if (color)
148
+ out[fieldPath] = color;
149
+ break;
150
+ }
151
+ case 'material.pbr.baseWeight':
152
+ case 'material.pbr.microSurface':
153
+ case 'material.pbr.lightFalloff': {
154
+ if (materialRuntimeKind !== 'pbr')
155
+ break;
156
+ const key = fieldPath.split('.')[2];
157
+ const hidden = `_${key}`;
158
+ const n = material[hidden] ?? material[key];
159
+ if (typeof n === 'number' && Number.isFinite(n))
160
+ out[fieldPath] = n;
161
+ break;
162
+ }
163
+ case 'material.standard.diffuseColor':
164
+ case 'material.standard.specularColor':
165
+ case 'material.standard.emissiveColor':
166
+ case 'material.standard.ambientColor': {
167
+ if (materialRuntimeKind !== 'standard')
168
+ break;
169
+ const key = fieldPath.split('.')[2];
170
+ const hidden = `_${key}`;
171
+ const color = cloneColor3(material[key] ?? material[hidden]);
172
+ if (color)
173
+ out[fieldPath] = color;
174
+ break;
175
+ }
176
+ case 'material.standard.specularPower': {
177
+ if (materialRuntimeKind !== 'standard')
178
+ break;
179
+ const n = material.specularPower ?? material._specularPower;
180
+ if (typeof n === 'number' && Number.isFinite(n))
181
+ out[fieldPath] = n;
182
+ break;
183
+ }
184
+ case 'material.standard.useSpecularOverAlpha': {
185
+ if (materialRuntimeKind !== 'standard')
186
+ break;
187
+ const v = material.useSpecularOverAlpha ?? material._useSpecularOverAlpha;
188
+ if (typeof v === 'boolean')
189
+ out[fieldPath] = v;
190
+ break;
191
+ }
192
+ default:
193
+ break;
194
+ }
195
+ }
196
+ return out;
197
+ }
198
+ function snapshotOutline(node) {
199
+ const { target } = resolveOutlineTarget(node);
200
+ const outlineTarget = target;
201
+ if (!outlineTarget || typeof outlineTarget !== 'object')
202
+ return {};
203
+ const out = {};
204
+ for (const fieldPath of OUTLINE_CANONICAL_PATHS) {
205
+ switch (fieldPath) {
206
+ case 'outline.renderOutline':
207
+ out[fieldPath] = !!outlineTarget.renderOutline;
208
+ break;
209
+ case 'outline.outlineWidth':
210
+ if (typeof outlineTarget.outlineWidth === 'number' && Number.isFinite(outlineTarget.outlineWidth)) {
211
+ out[fieldPath] = outlineTarget.outlineWidth;
212
+ }
213
+ break;
214
+ case 'outline.outlineColor': {
215
+ const color = cloneColor3(outlineTarget.outlineColor);
216
+ if (color)
217
+ out[fieldPath] = color;
218
+ break;
219
+ }
220
+ default:
221
+ break;
222
+ }
223
+ }
224
+ return out;
225
+ }
226
+ export function createEditorRuntimeMonitor(options) {
227
+ const host = options.host ?? createBrowserHost();
228
+ const debounceMs = options.debounceMs ?? 250;
229
+ let enabled = false;
230
+ let sceneObs = null;
231
+ let selectedNode = null;
232
+ let selectedNodes = [];
233
+ let baseline = null;
234
+ let materialBaseline = {};
235
+ let outlineBaseline = {};
236
+ let pendingByNode = new Map();
237
+ let pendingMaterialByKey = new Map();
238
+ let pendingOutlineByKey = new Map();
239
+ let transformTimer = null;
240
+ let materialTimer = null;
241
+ let outlineTimer = null;
242
+ let contextTimer = null;
243
+ let contextBuffer = [];
244
+ let pointerActive = false;
245
+ let hadDragDuringPointer = false;
246
+ let hadMaterialChangeDuringPointer = false;
247
+ let hadOutlineChangeDuringPointer = false;
248
+ function log(message, data) {
249
+ options.log?.(message, data);
250
+ }
251
+ function isSameNode(a, b) {
252
+ if (!a || !b)
253
+ return false;
254
+ if (a === b)
255
+ return true;
256
+ const aId = a.uniqueId;
257
+ const bId = b.uniqueId;
258
+ return typeof aId === 'number' && typeof bId === 'number' && aId === bId;
259
+ }
260
+ function collectSelectedNodes(primary) {
261
+ const out = [];
262
+ if (primary)
263
+ out.push(primary);
264
+ const fromOptions = options.getSelectedEntities?.() ?? [];
265
+ for (const node of fromOptions) {
266
+ if (!node || !hasTransform(node))
267
+ continue;
268
+ if (out.some(item => isSameNode(item, node)))
269
+ continue;
270
+ out.push(node);
271
+ }
272
+ return out;
273
+ }
274
+ function upsertPendingNode(node, start, latest) {
275
+ const existing = pendingByNode.get(node);
276
+ if (!existing) {
277
+ pendingByNode.set(node, { start: cloneTransformSnapshot(start), latest: cloneTransformSnapshot(latest) });
278
+ return;
279
+ }
280
+ existing.latest = cloneTransformSnapshot(latest);
281
+ }
282
+ function materialChangeKey(change) {
283
+ return [change.binding.kind, change.binding.nodeId, change.target, change.ownerNodePath, change.path].join('::');
284
+ }
285
+ function outlineChangeKey(change) {
286
+ return [change.binding.kind, change.binding.nodeId, change.target, change.ownerNodePath, change.path].join('::');
287
+ }
288
+ function upsertPendingMaterial(change) {
289
+ const key = materialChangeKey(change);
290
+ const existing = pendingMaterialByKey.get(key);
291
+ if (!existing) {
292
+ pendingMaterialByKey.set(key, { ...change, before: cloneValue(change.before), after: cloneValue(change.after) });
293
+ return;
294
+ }
295
+ existing.runtimeNode = change.runtimeNode;
296
+ existing.binding = change.binding;
297
+ existing.after = cloneValue(change.after);
298
+ }
299
+ function upsertPendingOutline(change) {
300
+ const key = outlineChangeKey(change);
301
+ const existing = pendingOutlineByKey.get(key);
302
+ if (!existing) {
303
+ pendingOutlineByKey.set(key, { ...change, before: cloneValue(change.before), after: cloneValue(change.after) });
304
+ return;
305
+ }
306
+ existing.runtimeNode = change.runtimeNode;
307
+ existing.binding = change.binding;
308
+ existing.after = cloneValue(change.after);
309
+ }
310
+ function pushContextChange(change) {
311
+ if (valueEq(change.old, change.new))
312
+ return;
313
+ contextBuffer.push({ ...change, old: cloneValue(change.old), new: cloneValue(change.new) });
314
+ scheduleContextFlush();
315
+ }
316
+ function flushContextChanges() {
317
+ if (!contextBuffer.length) {
318
+ if (contextTimer) {
319
+ host.clearTimeout(contextTimer);
320
+ contextTimer = null;
321
+ }
322
+ return;
323
+ }
324
+ if (pendingMaterialByKey.size > 0 && !pointerActive)
325
+ flushPendingMaterial();
326
+ if (pendingOutlineByKey.size > 0 && !pointerActive)
327
+ flushPendingOutline();
328
+ const payload = contextBuffer;
329
+ contextBuffer = [];
330
+ if (contextTimer) {
331
+ host.clearTimeout(contextTimer);
332
+ contextTimer = null;
333
+ }
334
+ options.onChangesFlushed?.(payload);
335
+ }
336
+ function scheduleContextFlush() {
337
+ if (contextTimer)
338
+ host.clearTimeout(contextTimer);
339
+ contextTimer = host.setTimeout(flushContextChanges, debounceMs);
340
+ }
341
+ function scheduleTransformFlush() {
342
+ if (transformTimer)
343
+ host.clearTimeout(transformTimer);
344
+ transformTimer = host.setTimeout(flushPending, debounceMs);
345
+ }
346
+ function scheduleMaterialFlush() {
347
+ if (materialTimer)
348
+ host.clearTimeout(materialTimer);
349
+ materialTimer = host.setTimeout(flushPendingMaterial, debounceMs);
350
+ }
351
+ function scheduleOutlineFlush() {
352
+ if (outlineTimer)
353
+ host.clearTimeout(outlineTimer);
354
+ outlineTimer = host.setTimeout(flushPendingOutline, debounceMs);
355
+ }
356
+ function clearPending() {
357
+ if (transformTimer) {
358
+ host.clearTimeout(transformTimer);
359
+ transformTimer = null;
360
+ }
361
+ pendingByNode.clear();
362
+ }
363
+ function clearPendingMaterial() {
364
+ if (materialTimer) {
365
+ host.clearTimeout(materialTimer);
366
+ materialTimer = null;
367
+ }
368
+ pendingMaterialByKey.clear();
369
+ }
370
+ function clearPendingOutline() {
371
+ if (outlineTimer) {
372
+ host.clearTimeout(outlineTimer);
373
+ outlineTimer = null;
374
+ }
375
+ pendingOutlineByKey.clear();
376
+ }
377
+ function applyDeltaToFollowers(previous, next) {
378
+ if (!selectedNode)
379
+ return;
380
+ const deltaPosition = {
381
+ x: next.position.x - previous.position.x,
382
+ y: next.position.y - previous.position.y,
383
+ z: next.position.z - previous.position.z,
384
+ };
385
+ const deltaRotation = {
386
+ x: next.rotation.x - previous.rotation.x,
387
+ y: next.rotation.y - previous.rotation.y,
388
+ z: next.rotation.z - previous.rotation.z,
389
+ };
390
+ const deltaScaling = {
391
+ x: next.scaling.x - previous.scaling.x,
392
+ y: next.scaling.y - previous.scaling.y,
393
+ z: next.scaling.z - previous.scaling.z,
394
+ };
395
+ for (const node of selectedNodes) {
396
+ if (isSameNode(node, selectedNode))
397
+ continue;
398
+ const before = snapshotTransform(node);
399
+ if (!before)
400
+ continue;
401
+ const position = node.position;
402
+ if (position?.addInPlaceFromFloats)
403
+ position.addInPlaceFromFloats(deltaPosition.x, deltaPosition.y, deltaPosition.z);
404
+ else if (position) {
405
+ position.x += deltaPosition.x;
406
+ position.y += deltaPosition.y;
407
+ position.z += deltaPosition.z;
408
+ }
409
+ if (node.rotationQuaternion)
410
+ node.rotationQuaternion = null;
411
+ const rotation = node.rotation;
412
+ if (rotation?.addInPlaceFromFloats)
413
+ rotation.addInPlaceFromFloats(deltaRotation.x, deltaRotation.y, deltaRotation.z);
414
+ else if (rotation) {
415
+ rotation.x += deltaRotation.x;
416
+ rotation.y += deltaRotation.y;
417
+ rotation.z += deltaRotation.z;
418
+ }
419
+ const scaling = node.scaling;
420
+ if (scaling?.addInPlaceFromFloats)
421
+ scaling.addInPlaceFromFloats(deltaScaling.x, deltaScaling.y, deltaScaling.z);
422
+ else if (scaling) {
423
+ scaling.x += deltaScaling.x;
424
+ scaling.y += deltaScaling.y;
425
+ scaling.z += deltaScaling.z;
426
+ }
427
+ const after = snapshotTransform(node);
428
+ if (!after)
429
+ continue;
430
+ upsertPendingNode(node, before, after);
431
+ }
432
+ }
433
+ function flushPending() {
434
+ if (!pendingByNode.size) {
435
+ clearPending();
436
+ return;
437
+ }
438
+ const pendingCount = pendingByNode.size;
439
+ log('flush transform pending', { pendingCount });
440
+ const timestamp = Date.now();
441
+ let changed = false;
442
+ options.onTransformBatchBegin?.();
443
+ try {
444
+ for (const [node, value] of pendingByNode.entries()) {
445
+ const binding = options.resolveBinding(node);
446
+ const { start, latest } = value;
447
+ for (const prop of ['position', 'rotation', 'scaling']) {
448
+ if (vecEq(start[prop], latest[prop]))
449
+ continue;
450
+ const change = {
451
+ runtimeNode: node,
452
+ binding,
453
+ prop,
454
+ before: start[prop],
455
+ after: latest[prop],
456
+ };
457
+ pushContextChange({ time: timestamp, obj: node, binding, prop, old: start[prop], new: latest[prop] });
458
+ changed = options.onTransformChange?.(change) === true || changed;
459
+ }
460
+ }
461
+ }
462
+ finally {
463
+ options.onTransformBatchEnd?.();
464
+ }
465
+ clearPending();
466
+ log('flush transform completed', { pendingCount, changed });
467
+ if (changed)
468
+ options.onDocumentChanged?.();
469
+ }
470
+ function flushPendingMaterial() {
471
+ if (!pendingMaterialByKey.size) {
472
+ clearPendingMaterial();
473
+ return;
474
+ }
475
+ const pendingCount = pendingMaterialByKey.size;
476
+ log('flush material pending', { pendingCount });
477
+ let changed = false;
478
+ for (const change of pendingMaterialByKey.values()) {
479
+ changed = options.onMaterialChange?.(change) === true || changed;
480
+ }
481
+ clearPendingMaterial();
482
+ log('flush material completed', { pendingCount, changed });
483
+ if (changed)
484
+ options.onDocumentChanged?.();
485
+ }
486
+ function flushPendingOutline() {
487
+ if (!pendingOutlineByKey.size) {
488
+ clearPendingOutline();
489
+ return;
490
+ }
491
+ const pendingCount = pendingOutlineByKey.size;
492
+ log('flush outline pending', { pendingCount });
493
+ let changed = false;
494
+ for (const change of pendingOutlineByKey.values()) {
495
+ changed = options.onOutlineChange?.(change) === true || changed;
496
+ }
497
+ clearPendingOutline();
498
+ log('flush outline completed', { pendingCount, changed });
499
+ if (changed)
500
+ options.onDocumentChanged?.();
501
+ }
502
+ function queuePending(next) {
503
+ if (!selectedNode)
504
+ return;
505
+ const existing = pendingByNode.get(selectedNode);
506
+ const start = existing?.start ?? baseline ?? next;
507
+ upsertPendingNode(selectedNode, start, next);
508
+ if (pointerActive) {
509
+ hadDragDuringPointer = true;
510
+ if (transformTimer) {
511
+ host.clearTimeout(transformTimer);
512
+ transformTimer = null;
513
+ }
514
+ return;
515
+ }
516
+ scheduleTransformFlush();
517
+ }
518
+ function syncSelection(nextNode) {
519
+ const scene = options.getScene();
520
+ const resolvedNode = resolveTrackedNode(scene, nextNode, selectedNode);
521
+ if (resolvedNode === selectedNode)
522
+ return;
523
+ flushPending();
524
+ flushPendingMaterial();
525
+ flushPendingOutline();
526
+ flushContextChanges();
527
+ selectedNode = resolvedNode;
528
+ selectedNodes = collectSelectedNodes(selectedNode);
529
+ baseline = snapshotTransform(selectedNode);
530
+ materialBaseline = snapshotMaterial(selectedNode);
531
+ outlineBaseline = snapshotOutline(selectedNode);
532
+ options.onSelectionChanged?.(selectedNode);
533
+ }
534
+ function rebaseSelection(nextNode) {
535
+ if (nextNode !== undefined)
536
+ selectedNode = nextNode;
537
+ selectedNodes = collectSelectedNodes(selectedNode);
538
+ clearPending();
539
+ clearPendingMaterial();
540
+ clearPendingOutline();
541
+ baseline = snapshotTransform(selectedNode);
542
+ materialBaseline = snapshotMaterial(selectedNode);
543
+ outlineBaseline = snapshotOutline(selectedNode);
544
+ }
545
+ function checkMaterial() {
546
+ if (!selectedNode)
547
+ return;
548
+ const next = snapshotMaterial(selectedNode);
549
+ const allPaths = new Set([...Object.keys(materialBaseline), ...Object.keys(next)]);
550
+ const binding = options.resolveBinding(selectedNode);
551
+ let recorded = false;
552
+ for (const path of allPaths) {
553
+ const oldValue = materialBaseline[path];
554
+ const newValue = next[path];
555
+ if (valueEq(oldValue, newValue))
556
+ continue;
557
+ pushContextChange({ time: Date.now(), obj: selectedNode, binding, prop: path, old: oldValue, new: newValue });
558
+ if (binding) {
559
+ const materialChange = adaptMaterialPropertyChange({
560
+ scene: options.getScene(),
561
+ selectedEntity: selectedNode,
562
+ entity: selectedNode,
563
+ propertyKey: path,
564
+ oldValue,
565
+ newValue,
566
+ resolveBinding: node => options.resolveBinding(node),
567
+ });
568
+ if (materialChange) {
569
+ upsertPendingMaterial(materialChange);
570
+ recorded = true;
571
+ }
572
+ }
573
+ }
574
+ materialBaseline = next;
575
+ if (!recorded)
576
+ return;
577
+ if (pointerActive) {
578
+ hadMaterialChangeDuringPointer = true;
579
+ if (materialTimer) {
580
+ host.clearTimeout(materialTimer);
581
+ materialTimer = null;
582
+ }
583
+ return;
584
+ }
585
+ scheduleMaterialFlush();
586
+ }
587
+ function recordCanonicalMaterialChange(change) {
588
+ upsertPendingMaterial(change);
589
+ if (selectedNode && isSameNode(selectedNode, change.runtimeNode))
590
+ materialBaseline[change.path] = cloneValue(change.after);
591
+ pushContextChange({
592
+ time: Date.now(),
593
+ obj: change.runtimeNode,
594
+ binding: change.binding,
595
+ prop: change.path,
596
+ old: change.before,
597
+ new: change.after,
598
+ });
599
+ if (pointerActive) {
600
+ hadMaterialChangeDuringPointer = true;
601
+ if (materialTimer) {
602
+ host.clearTimeout(materialTimer);
603
+ materialTimer = null;
604
+ }
605
+ if (contextTimer) {
606
+ host.clearTimeout(contextTimer);
607
+ contextTimer = null;
608
+ }
609
+ return;
610
+ }
611
+ scheduleMaterialFlush();
612
+ }
613
+ function checkOutline() {
614
+ if (!selectedNode)
615
+ return;
616
+ const next = snapshotOutline(selectedNode);
617
+ const allPaths = new Set([...Object.keys(outlineBaseline), ...Object.keys(next)]);
618
+ const binding = options.resolveBinding(selectedNode);
619
+ let recorded = false;
620
+ for (const path of allPaths) {
621
+ const oldValue = outlineBaseline[path];
622
+ const newValue = next[path];
623
+ if (valueEq(oldValue, newValue))
624
+ continue;
625
+ pushContextChange({ time: Date.now(), obj: selectedNode, binding, prop: path, old: oldValue, new: newValue });
626
+ if (binding) {
627
+ const outlineChange = adaptOutlinePropertyChange({
628
+ selectedEntity: selectedNode,
629
+ propertyKey: path,
630
+ oldValue,
631
+ newValue,
632
+ resolveBinding: node => options.resolveBinding(node),
633
+ });
634
+ if (outlineChange) {
635
+ upsertPendingOutline(outlineChange);
636
+ recorded = true;
637
+ }
638
+ }
639
+ }
640
+ outlineBaseline = next;
641
+ if (!recorded)
642
+ return;
643
+ if (pointerActive) {
644
+ hadOutlineChangeDuringPointer = true;
645
+ if (outlineTimer) {
646
+ host.clearTimeout(outlineTimer);
647
+ outlineTimer = null;
648
+ }
649
+ return;
650
+ }
651
+ scheduleOutlineFlush();
652
+ }
653
+ function tick() {
654
+ const rawEntity = options.getSelectedEntity();
655
+ const resolvedNode = resolveTrackedNode(options.getScene(), rawEntity, selectedNode);
656
+ if (resolvedNode !== selectedNode)
657
+ syncSelection(rawEntity);
658
+ if (!selectedNode)
659
+ return;
660
+ selectedNodes = collectSelectedNodes(selectedNode);
661
+ const next = snapshotTransform(selectedNode);
662
+ if (next && baseline) {
663
+ if (!hasChanged(baseline, next)) {
664
+ if (pendingByNode.size > 0 && !pointerActive && !transformTimer)
665
+ scheduleTransformFlush();
666
+ }
667
+ else {
668
+ const previous = baseline;
669
+ queuePending(next);
670
+ applyDeltaToFollowers(previous, next);
671
+ baseline = next;
672
+ }
673
+ }
674
+ else if (next && !baseline) {
675
+ baseline = next;
676
+ }
677
+ checkMaterial();
678
+ checkOutline();
679
+ }
680
+ function onPointerDown() {
681
+ if (!enabled)
682
+ return;
683
+ pointerActive = true;
684
+ hadDragDuringPointer = false;
685
+ hadMaterialChangeDuringPointer = false;
686
+ hadOutlineChangeDuringPointer = false;
687
+ }
688
+ function onPointerUp() {
689
+ if (!enabled)
690
+ return;
691
+ pointerActive = false;
692
+ if (hadDragDuringPointer)
693
+ flushPending();
694
+ if (hadMaterialChangeDuringPointer)
695
+ flushPendingMaterial();
696
+ if (hadOutlineChangeDuringPointer)
697
+ flushPendingOutline();
698
+ flushContextChanges();
699
+ hadDragDuringPointer = false;
700
+ hadMaterialChangeDuringPointer = false;
701
+ hadOutlineChangeDuringPointer = false;
702
+ }
703
+ return {
704
+ get isDragging() {
705
+ return pointerActive || pendingByNode.size > 0;
706
+ },
707
+ start() {
708
+ if (enabled)
709
+ return;
710
+ const scene = options.getScene();
711
+ if (!scene)
712
+ return;
713
+ syncSelection(options.getSelectedEntity());
714
+ sceneObs = scene.onAfterRenderObservable?.add?.(() => tick()) ?? null;
715
+ host.window.addEventListener('pointerdown', onPointerDown, true);
716
+ host.window.addEventListener('pointerup', onPointerUp, true);
717
+ enabled = true;
718
+ },
719
+ stop() {
720
+ if (!enabled)
721
+ return;
722
+ flushPending();
723
+ flushPendingMaterial();
724
+ flushPendingOutline();
725
+ flushContextChanges();
726
+ const scene = options.getScene();
727
+ if (sceneObs) {
728
+ scene?.onAfterRenderObservable?.remove?.(sceneObs);
729
+ sceneObs = null;
730
+ }
731
+ host.window.removeEventListener('pointerdown', onPointerDown, true);
732
+ host.window.removeEventListener('pointerup', onPointerUp, true);
733
+ pointerActive = false;
734
+ hadDragDuringPointer = false;
735
+ hadMaterialChangeDuringPointer = false;
736
+ hadOutlineChangeDuringPointer = false;
737
+ enabled = false;
738
+ },
739
+ reset() {
740
+ this.stop();
741
+ selectedNode = null;
742
+ baseline = null;
743
+ materialBaseline = {};
744
+ outlineBaseline = {};
745
+ contextBuffer = [];
746
+ if (contextTimer) {
747
+ host.clearTimeout(contextTimer);
748
+ contextTimer = null;
749
+ }
750
+ clearPending();
751
+ clearPendingMaterial();
752
+ clearPendingOutline();
753
+ },
754
+ flush() {
755
+ log('flush requested', {
756
+ transformPending: pendingByNode.size,
757
+ materialPending: pendingMaterialByKey.size,
758
+ outlinePending: pendingOutlineByKey.size,
759
+ contextPending: contextBuffer.length,
760
+ });
761
+ flushPending();
762
+ flushPendingMaterial();
763
+ flushPendingOutline();
764
+ flushContextChanges();
765
+ log('flush completed', {
766
+ transformPending: pendingByNode.size,
767
+ materialPending: pendingMaterialByKey.size,
768
+ outlinePending: pendingOutlineByKey.size,
769
+ contextPending: contextBuffer.length,
770
+ });
771
+ },
772
+ rebase(nextNode) {
773
+ rebaseSelection(nextNode);
774
+ },
775
+ recordCanonicalMaterialChange(change) {
776
+ recordCanonicalMaterialChange(change);
777
+ },
778
+ };
779
+ }
780
+ //# sourceMappingURL=monitor.js.map