@viamrobotics/motion-tools 1.26.0 → 1.26.2
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.
- package/dist/FrameConfigUpdater.svelte.js +42 -29
- package/dist/buf/common/v1/common_pb.d.ts +19 -0
- package/dist/buf/common/v1/common_pb.js +32 -0
- package/dist/components/App.svelte +4 -1
- package/dist/components/BatchedArrows.svelte +31 -15
- package/dist/components/Entities/Entities.svelte +3 -8
- package/dist/components/Entities/Frame.svelte +25 -9
- package/dist/components/Entities/Frame.svelte.d.ts +0 -2
- package/dist/components/Entities/GLTF.svelte +5 -4
- package/dist/components/Entities/Line.svelte +5 -4
- package/dist/components/Entities/Mesh.svelte +12 -18
- package/dist/components/Entities/Points.svelte +5 -4
- package/dist/components/Entities/Pose.svelte +17 -24
- package/dist/components/Entities/Pose.svelte.d.ts +1 -4
- package/dist/components/Entities/hooks/useEntityEvents.svelte.js +40 -41
- package/dist/components/SceneProviders.svelte +2 -1
- package/dist/components/SelectedTransformControls.svelte +57 -34
- package/dist/components/StaticGeometries.svelte +1 -1
- package/dist/components/hover/HoveredEntity.svelte +33 -3
- package/dist/components/hover/LinkedHoveredEntity.svelte +2 -3
- package/dist/components/overlay/Details.svelte +72 -94
- package/dist/components/overlay/__tests__/__fixtures__/entity.js +14 -17
- package/dist/components/overlay/left-pane/Tree.svelte +9 -9
- package/dist/components/overlay/left-pane/Tree.svelte.d.ts +1 -2
- package/dist/components/overlay/left-pane/TreeContainer.svelte +4 -15
- package/dist/components/overlay/left-pane/TreeNode.svelte +1 -1
- package/dist/components/overlay/left-pane/TreeNode.svelte.d.ts +1 -1
- package/dist/components/overlay/left-pane/useTree.svelte.d.ts +14 -0
- package/dist/components/overlay/left-pane/useTree.svelte.js +63 -0
- package/dist/draw.js +21 -7
- package/dist/ecs/index.d.ts +1 -0
- package/dist/ecs/index.js +1 -0
- package/dist/ecs/provideWorldMatrix.svelte.d.ts +8 -0
- package/dist/ecs/provideWorldMatrix.svelte.js +13 -0
- package/dist/ecs/traits.d.ts +41 -45
- package/dist/ecs/traits.js +57 -28
- package/dist/ecs/useTrait.svelte.d.ts +1 -6
- package/dist/ecs/useTrait.svelte.js +21 -13
- package/dist/ecs/worldMatrix.d.ts +10 -0
- package/dist/ecs/worldMatrix.js +148 -0
- package/dist/editing/FrameEditSession.js +31 -18
- package/dist/hooks/use3DModels.svelte.js +1 -1
- package/dist/hooks/useConfigFrames.svelte.js +12 -0
- package/dist/hooks/useDrawAPI.svelte.js +14 -6
- package/dist/hooks/useFrames.svelte.js +23 -11
- package/dist/hooks/useGeometries.svelte.js +4 -2
- package/dist/hooks/usePartConfig.svelte.js +38 -3
- package/dist/hooks/useWorldState.svelte.js +10 -2
- package/dist/transform.js +55 -21
- package/package.json +4 -4
- package/dist/components/overlay/left-pane/buildTree.d.ts +0 -13
- package/dist/components/overlay/left-pane/buildTree.js +0 -48
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import { useCursor } from '@threlte/extras';
|
|
2
|
-
import { Vector2 } from 'three';
|
|
2
|
+
import { MathUtils, Matrix4, Quaternion, Vector2 } from 'three';
|
|
3
3
|
import { traits, useTrait } from '../../../ecs';
|
|
4
4
|
import { useFocusedEntity, useSelectedEntity } from '../../../hooks/useSelection.svelte';
|
|
5
5
|
import { updateHoverInfo } from '../../../HoverUpdater.svelte';
|
|
6
|
-
import {
|
|
6
|
+
import { OrientationVector } from '../../../three/OrientationVector';
|
|
7
|
+
const tempHoverMatrix = new Matrix4();
|
|
8
|
+
const hoverQuat = new Quaternion();
|
|
9
|
+
const hoverOv = new OrientationVector();
|
|
10
|
+
const infoToLocalMatrix = (info, out) => {
|
|
11
|
+
hoverOv.set(info.oX, info.oY, info.oZ, MathUtils.degToRad(info.theta));
|
|
12
|
+
hoverOv.toQuaternion(hoverQuat);
|
|
13
|
+
out.makeRotationFromQuaternion(hoverQuat);
|
|
14
|
+
out.setPosition(info.x, info.y, info.z);
|
|
15
|
+
};
|
|
7
16
|
export const useEntityEvents = (entity) => {
|
|
8
17
|
const down = new Vector2();
|
|
9
18
|
const selectedEntity = useSelectedEntity();
|
|
@@ -19,15 +28,18 @@ export const useEntityEvents = (entity) => {
|
|
|
19
28
|
if (currentEntity && !currentEntity.has(traits.Hovered)) {
|
|
20
29
|
const hoverInfo = updateHoverInfo(currentEntity, event);
|
|
21
30
|
if (hoverInfo) {
|
|
22
|
-
|
|
31
|
+
infoToLocalMatrix(hoverInfo, tempHoverMatrix);
|
|
32
|
+
const worldMatrix = currentEntity.get(traits.WorldMatrix);
|
|
33
|
+
const composed = new Matrix4();
|
|
34
|
+
if (worldMatrix) {
|
|
35
|
+
composed.copy(worldMatrix).multiply(tempHoverMatrix);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
composed.copy(tempHoverMatrix);
|
|
39
|
+
}
|
|
40
|
+
currentEntity.add(traits.InstancedMatrix({
|
|
41
|
+
matrix: composed,
|
|
23
42
|
index: hoverInfo.index,
|
|
24
|
-
x: hoverInfo.x,
|
|
25
|
-
y: hoverInfo.y,
|
|
26
|
-
z: hoverInfo.z,
|
|
27
|
-
oX: hoverInfo.oX,
|
|
28
|
-
oY: hoverInfo.oY,
|
|
29
|
-
oZ: hoverInfo.oZ,
|
|
30
|
-
theta: hoverInfo.theta,
|
|
31
43
|
}));
|
|
32
44
|
}
|
|
33
45
|
currentEntity.add(traits.Hovered);
|
|
@@ -40,34 +52,21 @@ export const useEntityEvents = (entity) => {
|
|
|
40
52
|
const currentEntity = entity();
|
|
41
53
|
if (currentEntity?.has(traits.Hovered)) {
|
|
42
54
|
const hoverInfo = updateHoverInfo(currentEntity, event);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const hoverPoseMatrix = poseToMatrix(hoverPose);
|
|
56
|
-
const worldPoseMatrix = poseToMatrix(worldPose);
|
|
57
|
-
const resultMatrix = worldPoseMatrix.multiply(hoverPoseMatrix);
|
|
58
|
-
const resultPose = matrixToPose(resultMatrix);
|
|
59
|
-
if (hoverInfo) {
|
|
60
|
-
currentEntity.set(traits.InstancedPose, {
|
|
61
|
-
index: hoverInfo.index,
|
|
62
|
-
x: resultPose.x,
|
|
63
|
-
y: resultPose.y,
|
|
64
|
-
z: resultPose.z,
|
|
65
|
-
oX: resultPose.oX,
|
|
66
|
-
oY: resultPose.oY,
|
|
67
|
-
oZ: resultPose.oZ,
|
|
68
|
-
theta: resultPose.theta,
|
|
69
|
-
});
|
|
55
|
+
if (!hoverInfo)
|
|
56
|
+
return;
|
|
57
|
+
infoToLocalMatrix(hoverInfo, tempHoverMatrix);
|
|
58
|
+
const instanced = currentEntity.get(traits.InstancedMatrix);
|
|
59
|
+
if (!instanced)
|
|
60
|
+
return;
|
|
61
|
+
const worldMatrix = currentEntity.get(traits.WorldMatrix);
|
|
62
|
+
if (worldMatrix) {
|
|
63
|
+
instanced.matrix.copy(worldMatrix).multiply(tempHoverMatrix);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
instanced.matrix.copy(tempHoverMatrix);
|
|
70
67
|
}
|
|
68
|
+
instanced.index = hoverInfo.index;
|
|
69
|
+
currentEntity.changed(traits.InstancedMatrix);
|
|
71
70
|
}
|
|
72
71
|
};
|
|
73
72
|
const onpointerleave = (event) => {
|
|
@@ -77,8 +76,8 @@ export const useEntityEvents = (entity) => {
|
|
|
77
76
|
if (currentEntity?.has(traits.Hovered)) {
|
|
78
77
|
currentEntity.remove(traits.Hovered);
|
|
79
78
|
}
|
|
80
|
-
if (currentEntity?.has(traits.
|
|
81
|
-
currentEntity.remove(traits.
|
|
79
|
+
if (currentEntity?.has(traits.InstancedMatrix)) {
|
|
80
|
+
currentEntity.remove(traits.InstancedMatrix);
|
|
82
81
|
}
|
|
83
82
|
};
|
|
84
83
|
const ondblclick = (event) => {
|
|
@@ -109,8 +108,8 @@ export const useEntityEvents = (entity) => {
|
|
|
109
108
|
if (currentEntity?.has(traits.Hovered)) {
|
|
110
109
|
currentEntity.remove(traits.Hovered);
|
|
111
110
|
}
|
|
112
|
-
if (currentEntity?.has(traits.
|
|
113
|
-
currentEntity.remove(traits.
|
|
111
|
+
if (currentEntity?.has(traits.InstancedMatrix)) {
|
|
112
|
+
currentEntity.remove(traits.InstancedMatrix);
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte'
|
|
3
3
|
|
|
4
|
-
import { provideHierarchy } from '../ecs'
|
|
4
|
+
import { provideHierarchy, provideWorldMatrix } from '../ecs'
|
|
5
5
|
import { provide3DModels } from '../hooks/use3DModels.svelte'
|
|
6
6
|
import { provideArmClient } from '../hooks/useArmClient.svelte'
|
|
7
7
|
import { provideArmKinematics } from '../hooks/useArmKinematics.svelte'
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
provideLogs()
|
|
44
44
|
|
|
45
45
|
provideHierarchy()
|
|
46
|
+
provideWorldMatrix()
|
|
46
47
|
provideOrigin()
|
|
47
48
|
provideDrawAPI()
|
|
48
49
|
provideRelationships()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { TransformControls } from '@threlte/extras'
|
|
3
|
-
import { Quaternion, Vector3 } from 'three'
|
|
3
|
+
import { Matrix4, Quaternion, Vector3 } from 'three'
|
|
4
4
|
|
|
5
5
|
import type { FrameEditSession } from '../editing/FrameEditSession'
|
|
6
6
|
|
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
import { useSelectedEntity, useSelectedObject3d } from '../hooks/useSelection.svelte'
|
|
12
12
|
import { useSettings } from '../hooks/useSettings.svelte'
|
|
13
13
|
import {
|
|
14
|
-
composeEditedPoseForRenderedPose,
|
|
15
14
|
createPose,
|
|
15
|
+
matrixToPose,
|
|
16
|
+
poseToMatrix,
|
|
16
17
|
quaternionToPose,
|
|
18
|
+
solveEditedMatrix,
|
|
17
19
|
vector3ToPose,
|
|
18
20
|
} from '../transform'
|
|
19
21
|
|
|
@@ -27,8 +29,8 @@
|
|
|
27
29
|
const mode = $derived(settings.current.transformMode)
|
|
28
30
|
const entity = $derived(selectedEntity.current)
|
|
29
31
|
const transformable = useTrait(() => entity, traits.Transformable)
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
+
const configMatrix = useTrait(() => entity, traits.Matrix)
|
|
33
|
+
const liveMatrix = useTrait(() => entity, traits.LiveMatrix)
|
|
32
34
|
const box = useTrait(() => entity, traits.Box)
|
|
33
35
|
const sphere = useTrait(() => entity, traits.Sphere)
|
|
34
36
|
const capsule = useTrait(() => entity, traits.Capsule)
|
|
@@ -42,10 +44,12 @@
|
|
|
42
44
|
// the geometry inside it.
|
|
43
45
|
const ref = $derived(selectedObject3d.current?.parent ?? selectedObject3d.current)
|
|
44
46
|
|
|
45
|
-
const activeMode = $derived.by(() => {
|
|
46
|
-
if (mode === 'none' || !transformable.current) return
|
|
47
|
+
const activeMode = $derived.by<'translate' | 'rotate' | 'scale' | undefined>(() => {
|
|
48
|
+
if (mode === 'none' || !transformable.current) return
|
|
49
|
+
|
|
47
50
|
// Scale only does anything for primitive geometries the gizmo can size.
|
|
48
|
-
if (mode === 'scale' && !hasScalableGeometry) return
|
|
51
|
+
if (mode === 'scale' && !hasScalableGeometry) return
|
|
52
|
+
|
|
49
53
|
return mode
|
|
50
54
|
})
|
|
51
55
|
const isSphereScale = $derived(activeMode === 'scale' && sphere.current !== undefined)
|
|
@@ -54,6 +58,9 @@
|
|
|
54
58
|
const quaternion = new Quaternion()
|
|
55
59
|
const vector3 = new Vector3()
|
|
56
60
|
const refPose = createPose()
|
|
61
|
+
const tempRefMatrix = new Matrix4()
|
|
62
|
+
const tempEditedMatrix = new Matrix4()
|
|
63
|
+
const tempPose = createPose()
|
|
57
64
|
|
|
58
65
|
let session: FrameEditSession | undefined
|
|
59
66
|
let scaleStart:
|
|
@@ -93,7 +100,9 @@
|
|
|
93
100
|
if (entity?.has(traits.FramesAPI)) {
|
|
94
101
|
session = sessions.begin([entity])
|
|
95
102
|
}
|
|
103
|
+
|
|
96
104
|
captureScaleStart()
|
|
105
|
+
|
|
97
106
|
environment.current.viewerMode = 'edit'
|
|
98
107
|
transformControls.setActive(true)
|
|
99
108
|
}
|
|
@@ -109,15 +118,17 @@
|
|
|
109
118
|
if (isFrameEntity) {
|
|
110
119
|
stageFrameTransform()
|
|
111
120
|
} else {
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
121
|
+
const matrix = entity.get(traits.Matrix)
|
|
122
|
+
if (matrix) {
|
|
123
|
+
matrixToPose(matrix, tempPose)
|
|
114
124
|
if (activeMode === 'translate') {
|
|
115
|
-
vector3ToPose(ref.getWorldPosition(vector3),
|
|
125
|
+
vector3ToPose(ref.getWorldPosition(vector3), tempPose)
|
|
116
126
|
} else {
|
|
117
|
-
quaternionToPose(ref.getWorldQuaternion(quaternion),
|
|
127
|
+
quaternionToPose(ref.getWorldQuaternion(quaternion), tempPose)
|
|
118
128
|
ref.quaternion.copy(quaternion)
|
|
119
129
|
}
|
|
120
|
-
|
|
130
|
+
poseToMatrix(tempPose, matrix)
|
|
131
|
+
entity.changed(traits.Matrix)
|
|
121
132
|
}
|
|
122
133
|
}
|
|
123
134
|
} else {
|
|
@@ -127,11 +138,14 @@
|
|
|
127
138
|
captureScaleStart()
|
|
128
139
|
}
|
|
129
140
|
|
|
141
|
+
// Clamp at 0 — the gizmo can produce negative scale factors when
|
|
142
|
+
// dragged past the origin, which would yield negative dimensions
|
|
143
|
+
// and a degenerate OBB.
|
|
130
144
|
if (scaleStart?.type === 'box') {
|
|
131
145
|
const next = {
|
|
132
|
-
x: scaleStart.x * ref.scale.x,
|
|
133
|
-
y: scaleStart.y * ref.scale.y,
|
|
134
|
-
z: scaleStart.z * ref.scale.z,
|
|
146
|
+
x: Math.max(0, scaleStart.x * ref.scale.x),
|
|
147
|
+
y: Math.max(0, scaleStart.y * ref.scale.y),
|
|
148
|
+
z: Math.max(0, scaleStart.z * ref.scale.z),
|
|
135
149
|
}
|
|
136
150
|
if (isFrameEntity) {
|
|
137
151
|
session?.stageGeometry(entity, { type: 'box', ...next })
|
|
@@ -139,14 +153,17 @@
|
|
|
139
153
|
entity.set(traits.Box, next)
|
|
140
154
|
}
|
|
141
155
|
} else if (scaleStart?.type === 'sphere') {
|
|
142
|
-
const next = { r: scaleStart.r * ref.scale.x }
|
|
156
|
+
const next = { r: Math.max(0, scaleStart.r * ref.scale.x) }
|
|
143
157
|
if (isFrameEntity) {
|
|
144
158
|
session?.stageGeometry(entity, { type: 'sphere', ...next })
|
|
145
159
|
} else {
|
|
146
160
|
entity.set(traits.Sphere, next)
|
|
147
161
|
}
|
|
148
162
|
} else if (scaleStart?.type === 'capsule') {
|
|
149
|
-
const next = {
|
|
163
|
+
const next = {
|
|
164
|
+
r: Math.max(0, scaleStart.r * ref.scale.x),
|
|
165
|
+
l: Math.max(0, scaleStart.l * ref.scale.y),
|
|
166
|
+
}
|
|
150
167
|
if (isFrameEntity) {
|
|
151
168
|
session?.stageGeometry(entity, { type: 'capsule', ...next })
|
|
152
169
|
} else {
|
|
@@ -165,29 +182,31 @@
|
|
|
165
182
|
transformControls.setActive(false)
|
|
166
183
|
}
|
|
167
184
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Frame.svelte renders frame entities by blending M(live) × M(config)⁻¹ × M(edited)
|
|
187
|
+
* so for the user's drag to render where they pulled the gizmo to,
|
|
188
|
+
* EditedMatrix must satisfy M(edited) = M(config) × M(live)⁻¹ × M(ref)
|
|
189
|
+
* where M(ref) is the gizmo-driven group's parent-relative matrix in mm.
|
|
190
|
+
*
|
|
191
|
+
* When live ≈ config (no kinematic offset), this collapses to
|
|
192
|
+
* M(edited) = M(ref) — the same as the naive writeback. When they diverge
|
|
193
|
+
* (e.g. an arm whose joints have moved away from its config pose), this
|
|
194
|
+
* composition is what keeps the rendering anchored to the user's pointer
|
|
195
|
+
* instead of shearing through the live × baseline⁻¹ offset.
|
|
196
|
+
*/
|
|
197
|
+
|
|
179
198
|
const stageFrameTransform = () => {
|
|
180
199
|
if (!ref || !entity) return
|
|
181
200
|
|
|
182
201
|
vector3ToPose(ref.position, refPose)
|
|
183
202
|
quaternionToPose(ref.quaternion, refPose)
|
|
184
203
|
|
|
185
|
-
const live =
|
|
186
|
-
const
|
|
204
|
+
const live = liveMatrix.current
|
|
205
|
+
const config = configMatrix.current
|
|
187
206
|
|
|
188
|
-
if (!live || !
|
|
189
|
-
// No live
|
|
190
|
-
//
|
|
207
|
+
if (!live || !config) {
|
|
208
|
+
// No live matrix available — Frame.svelte's blend short-circuits to
|
|
209
|
+
// editedMatrix, so naive writeback is correct.
|
|
191
210
|
if (activeMode === 'translate') {
|
|
192
211
|
session?.stagePose(entity, {
|
|
193
212
|
x: refPose.x,
|
|
@@ -205,7 +224,11 @@
|
|
|
205
224
|
return
|
|
206
225
|
}
|
|
207
226
|
|
|
208
|
-
|
|
227
|
+
poseToMatrix(refPose, tempRefMatrix)
|
|
228
|
+
|
|
229
|
+
solveEditedMatrix(config, live, tempRefMatrix, tempEditedMatrix)
|
|
230
|
+
matrixToPose(tempEditedMatrix, tempPose)
|
|
231
|
+
session?.stagePose(entity, { ...tempPose })
|
|
209
232
|
}
|
|
210
233
|
</script>
|
|
211
234
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { MathUtils, Quaternion, Vector3 } from 'three'
|
|
3
|
+
|
|
4
|
+
import type { HoverInfo } from '../../HoverUpdater.svelte'
|
|
5
|
+
|
|
2
6
|
import { traits, useTrait } from '../../ecs'
|
|
3
7
|
import { useFocusedEntity, useSelectedEntity } from '../../hooks/useSelection.svelte'
|
|
8
|
+
import { OrientationVector } from '../../three/OrientationVector'
|
|
4
9
|
|
|
5
10
|
import HoveredEntityTooltip from './HoveredEntityTooltip.svelte'
|
|
6
11
|
|
|
@@ -8,9 +13,34 @@
|
|
|
8
13
|
const focusedEntity = useFocusedEntity()
|
|
9
14
|
|
|
10
15
|
const displayEntity = $derived(selectedEntity.current ?? focusedEntity.current)
|
|
11
|
-
const
|
|
16
|
+
const instancedMatrix = useTrait(() => displayEntity, traits.InstancedMatrix)
|
|
17
|
+
|
|
18
|
+
// Pool: InstancedMatrix's `Matrix4` is in metres (matches Three.js).
|
|
19
|
+
// Decompose for the tooltip's display, which expects metres for position
|
|
20
|
+
// and OV+theta for orientation.
|
|
21
|
+
const translation = new Vector3()
|
|
22
|
+
const quaternion = new Quaternion()
|
|
23
|
+
const scaleVec = new Vector3()
|
|
24
|
+
const ov = new OrientationVector()
|
|
25
|
+
|
|
26
|
+
const hoverInfo = $derived.by((): HoverInfo | undefined => {
|
|
27
|
+
const data = instancedMatrix.current
|
|
28
|
+
if (!data) return undefined
|
|
29
|
+
data.matrix.decompose(translation, quaternion, scaleVec)
|
|
30
|
+
ov.setFromQuaternion(quaternion)
|
|
31
|
+
return {
|
|
32
|
+
index: data.index,
|
|
33
|
+
x: translation.x,
|
|
34
|
+
y: translation.y,
|
|
35
|
+
z: translation.z,
|
|
36
|
+
oX: ov.x,
|
|
37
|
+
oY: ov.y,
|
|
38
|
+
oZ: ov.z,
|
|
39
|
+
theta: MathUtils.radToDeg(ov.th),
|
|
40
|
+
}
|
|
41
|
+
})
|
|
12
42
|
</script>
|
|
13
43
|
|
|
14
|
-
{#if hoverInfo
|
|
15
|
-
<HoveredEntityTooltip
|
|
44
|
+
{#if hoverInfo}
|
|
45
|
+
<HoveredEntityTooltip {hoverInfo} />
|
|
16
46
|
{/if}
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { compileExpression } from 'filtrex'
|
|
5
5
|
|
|
6
|
-
import { relations, traits } from '../../ecs'
|
|
7
|
-
import { useTrait } from '../../ecs'
|
|
6
|
+
import { relations, traits, useTrait } from '../../ecs'
|
|
8
7
|
import { SubEntityLinkType } from '../../ecs/relations'
|
|
9
8
|
import { useSelectedEntity } from '../../hooks/useSelection.svelte'
|
|
10
9
|
import { useFocusedEntity } from '../../hooks/useSelection.svelte'
|
|
@@ -22,7 +21,7 @@
|
|
|
22
21
|
const focusedEntity = useFocusedEntity()
|
|
23
22
|
const displayEntity = $derived(selectedEntity.current ?? focusedEntity.current)
|
|
24
23
|
|
|
25
|
-
const displayedHoverInfo = useTrait(() => displayEntity, traits.
|
|
24
|
+
const displayedHoverInfo = useTrait(() => displayEntity, traits.InstancedMatrix)
|
|
26
25
|
|
|
27
26
|
let hoverInfo = $state.raw<HoverInfo | null>(null)
|
|
28
27
|
|