@viamrobotics/motion-tools 1.13.0 → 1.14.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 (102) hide show
  1. package/dist/FrameConfigUpdater.svelte.js +1 -1
  2. package/dist/attribute.js +10 -2
  3. package/dist/buf/draw/v1/service_connect.d.ts +14 -25
  4. package/dist/buf/draw/v1/service_connect.js +14 -25
  5. package/dist/buf/draw/v1/service_pb.d.ts +61 -76
  6. package/dist/buf/draw/v1/service_pb.js +58 -111
  7. package/dist/buffer.d.ts +56 -7
  8. package/dist/buffer.js +70 -12
  9. package/dist/color.js +3 -3
  10. package/dist/components/App.svelte +1 -5
  11. package/dist/components/Camera.svelte +1 -7
  12. package/dist/components/Camera.svelte.d.ts +0 -1
  13. package/dist/components/CameraControls.svelte +2 -2
  14. package/dist/components/{Arrows → Entities/Arrows}/ArrowGroups.svelte +3 -3
  15. package/dist/components/{Arrows → Entities/Arrows}/Arrows.svelte +6 -6
  16. package/dist/components/{Arrows → Entities/Arrows}/Arrows.svelte.d.ts +1 -1
  17. package/dist/components/{Entities.svelte → Entities/Entities.svelte} +7 -3
  18. package/dist/components/Entities/Frame.svelte +86 -0
  19. package/dist/components/{Frame.svelte.d.ts → Entities/Frame.svelte.d.ts} +1 -0
  20. package/dist/components/{GLTF.svelte → Entities/GLTF.svelte} +5 -5
  21. package/dist/components/Entities/Geometry.svelte +75 -0
  22. package/dist/components/Entities/Geometry.svelte.d.ts +10 -0
  23. package/dist/components/{Label.svelte → Entities/Label.svelte} +1 -1
  24. package/dist/components/Entities/Line.svelte +90 -0
  25. package/dist/components/Entities/Mesh.svelte +130 -0
  26. package/dist/components/Entities/Mesh.svelte.d.ts +4 -0
  27. package/dist/components/{Points.svelte → Entities/Points.svelte} +5 -5
  28. package/dist/components/{Pose.svelte → Entities/Pose.svelte} +3 -3
  29. package/dist/{hooks/useObjectEvents.svelte.d.ts → components/Entities/hooks/useEntityEvents.svelte.d.ts} +1 -1
  30. package/dist/{hooks/useObjectEvents.svelte.js → components/Entities/hooks/useEntityEvents.svelte.js} +6 -6
  31. package/dist/components/FileDrop/file-names.js +6 -3
  32. package/dist/components/FileDrop/snapshot-dropper.js +8 -4
  33. package/dist/components/FileDrop/useFileDrop.svelte.js +9 -6
  34. package/dist/components/Lasso/Lasso.svelte +4 -4
  35. package/dist/components/PCD.svelte +14 -6
  36. package/dist/components/PCD.svelte.d.ts +2 -0
  37. package/dist/components/Scene.svelte +1 -3
  38. package/dist/components/Selected.svelte +2 -0
  39. package/dist/components/StaticGeometries.svelte +1 -1
  40. package/dist/components/overlay/AddRelationship.svelte +1 -1
  41. package/dist/components/overlay/LiveUpdatesBanner.svelte +4 -6
  42. package/dist/components/overlay/left-pane/buildTree.js +15 -0
  43. package/dist/components/overlay/settings/Settings.svelte +11 -13
  44. package/dist/components/overlay/widgets/Camera.svelte +11 -9
  45. package/dist/components/xr/ArmTeleop.svelte +33 -33
  46. package/dist/components/xr/CameraFeed.svelte +21 -23
  47. package/dist/components/xr/JointLimitsWidget.svelte +19 -5
  48. package/dist/components/xr/XRConfigPanel.svelte +17 -16
  49. package/dist/components/xr/XRControllerSettings.svelte +5 -4
  50. package/dist/components/xr/XRToast.svelte +11 -6
  51. package/dist/ecs/relations.d.ts +1 -0
  52. package/dist/ecs/relations.js +1 -0
  53. package/dist/ecs/traits.d.ts +2 -19
  54. package/dist/ecs/traits.js +33 -6
  55. package/dist/ecs/useQuery.svelte.js +3 -3
  56. package/dist/format.js +1 -1
  57. package/dist/hooks/use3DModels.svelte.js +36 -38
  58. package/dist/hooks/useConfigFrames.svelte.js +2 -7
  59. package/dist/hooks/useDrawAPI.svelte.js +1 -1
  60. package/dist/hooks/useFramelessComponents.svelte.js +1 -1
  61. package/dist/hooks/useFrames.svelte.js +62 -56
  62. package/dist/hooks/useGeometries.svelte.js +59 -36
  63. package/dist/hooks/useLinked.svelte.js +5 -4
  64. package/dist/hooks/usePartConfig.svelte.js +16 -17
  65. package/dist/hooks/usePointcloudObjects.svelte.js +107 -62
  66. package/dist/hooks/usePointclouds.svelte.js +50 -32
  67. package/dist/hooks/usePose.svelte.js +3 -7
  68. package/dist/hooks/useResizable.svelte.js +4 -3
  69. package/dist/hooks/useSettings.svelte.js +2 -2
  70. package/dist/hooks/useWeblabs.svelte.js +3 -2
  71. package/dist/hooks/useWorldState.svelte.js +31 -28
  72. package/dist/loaders/pcd/index.js +2 -1
  73. package/dist/loaders/pcd/worker.inline.d.ts +1 -1
  74. package/dist/loaders/pcd/worker.inline.js +1 -1
  75. package/dist/loaders/pcd/worker.js +1 -1
  76. package/dist/metadata.d.ts +22 -0
  77. package/dist/metadata.js +66 -0
  78. package/dist/snapshot.d.ts +20 -0
  79. package/dist/snapshot.js +72 -28
  80. package/dist/three/InstancedArrows/InstancedArrows.js +1 -1
  81. package/dist/three/InstancedArrows/box.js +1 -1
  82. package/dist/three/InstancedArrows/raycast.js +12 -12
  83. package/dist/three/OBBHelper.d.ts +3 -2
  84. package/dist/three/OBBHelper.js +17 -5
  85. package/package.json +19 -11
  86. package/dist/WorldObject.svelte.d.ts +0 -27
  87. package/dist/WorldObject.svelte.js +0 -114
  88. package/dist/components/Frame.svelte +0 -89
  89. package/dist/components/Geometry.svelte +0 -211
  90. package/dist/components/Geometry.svelte.d.ts +0 -19
  91. package/dist/components/Line.svelte +0 -43
  92. /package/dist/components/{Arrows → Entities/Arrows}/ArrowGroups.svelte.d.ts +0 -0
  93. /package/dist/components/{Entities.svelte.d.ts → Entities/Entities.svelte.d.ts} +0 -0
  94. /package/dist/components/{GLTF.svelte.d.ts → Entities/GLTF.svelte.d.ts} +0 -0
  95. /package/dist/components/{Label.svelte.d.ts → Entities/Label.svelte.d.ts} +0 -0
  96. /package/dist/components/{Line.svelte.d.ts → Entities/Line.svelte.d.ts} +0 -0
  97. /package/dist/components/{LineDots.svelte → Entities/LineDots.svelte} +0 -0
  98. /package/dist/components/{LineDots.svelte.d.ts → Entities/LineDots.svelte.d.ts} +0 -0
  99. /package/dist/components/{LineGeometry.svelte → Entities/LineGeometry.svelte} +0 -0
  100. /package/dist/components/{LineGeometry.svelte.d.ts → Entities/LineGeometry.svelte.d.ts} +0 -0
  101. /package/dist/components/{Points.svelte.d.ts → Entities/Points.svelte.d.ts} +0 -0
  102. /package/dist/components/{Pose.svelte.d.ts → Entities/Pose.svelte.d.ts} +0 -0
package/dist/buffer.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * Proto messages pack float32 data as `Uint8Array` (bytes fields). These utilities
5
5
  * provide efficient conversion to `Float32Array` for Three.js BufferAttributes.
6
6
  */
7
+ import { Color } from 'three';
7
8
  /**
8
9
  * Stride constants for proto binary data formats.
9
10
  * Each value represents the number of float32 elements per item.
@@ -37,16 +38,64 @@ export declare const STRIDE: {
37
38
  */
38
39
  export declare const asFloat32Array: (bytes: Uint8Array<ArrayBuffer>) => Float32Array<ArrayBuffer>;
39
40
  /**
40
- * Converts uint8 RGBA colors to normalized float32 colors (0-1 range).
41
- * Three.js expects colors in 0-1 range for BufferAttributes.
41
+ * Sets a Three.js Color from 3 bytes of a uint8 color array starting at `offset`.
42
+ * Mutates and returns `target` — pass a pre-allocated Color to avoid allocations
43
+ * in hot paths.
42
44
  *
43
- * @param colors - Uint8Array of RGBA color data [r, g, b, a, ...]
44
- * @returns Float32Array with normalized color values
45
+ * @param bytes - Uint8Array with at least `offset + 3` elements [r, g, b, ...]
46
+ * @param target - Color instance to write into
47
+ * @param offset - Byte offset to start reading from (default 0)
48
+ * @returns The mutated `target`, or black if the array has fewer than `offset + 3` elements
45
49
  *
46
50
  * @example
47
51
  * ```ts
48
- * const colors = normalizeColorsRGBA(metadata.colors)
49
- * geometry.setAttribute('color', new BufferAttribute(colors, 4))
52
+ * asColor(colors.current, material.color)
53
+ * asColor(colors.current, pointColorUtil, stride) // read second color
50
54
  * ```
51
55
  */
52
- export declare const normalizeColorsRGBA: (colors: Float32Array) => Float32Array;
56
+ export declare const asColor: (bytes: Uint8Array<ArrayBuffer>, target: Color, offset?: number) => Color;
57
+ /**
58
+ * Creates a Uint8Array from a Three.js Color.
59
+ *
60
+ * @param color - The Three.js Color to convert
61
+ * @returns A Uint8Array with the RGBA values
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const color = fromColor(new Color(0, 1, 0))
66
+ * ```
67
+ */
68
+ export declare const fromColor: (color: Color) => Uint8Array<ArrayBuffer>;
69
+ /**
70
+ * Reads a byte from a uint8 color array at `offset` and normalizes it to 0-1.
71
+ * Returns `fallback` when the array has fewer than `offset + 1` elements.
72
+ *
73
+ * @param bytes - ArrayLike of uint8 color values
74
+ * @param fallback - Value to return when no alpha byte is present (default 1)
75
+ * @param offset - Byte index to read from (default 3, the alpha channel of the first color)
76
+ * @returns Normalized opacity in 0-1 range, or the fallback value
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * material.opacity = asOpacity(colors.current)
81
+ * material.opacity = asOpacity(colors.current, 1, stride + 3) // alpha of second color
82
+ * ```
83
+ */
84
+ export declare const asOpacity: (bytes: Uint8Array<ArrayBuffer>, fallback?: number, offset?: number) => number;
85
+ /**
86
+ * Returns true when `colors` contains exactly one color entry per point (RGB or RGBA).
87
+ * Use this to distinguish per-vertex color buffers from a single uniform color.
88
+ *
89
+ * @param colors - Uint8Array of packed color bytes
90
+ * @param numVertex - Number of points/vertices the color buffer should cover
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * if (isPerVertexColors(colors, positions.length / STRIDE.POSITIONS)) {
95
+ * // treat as per-vertex
96
+ * } else {
97
+ * addColorTraits(entityTraits, colors)
98
+ * }
99
+ * ```
100
+ */
101
+ export declare const isPerVertexColors: (colors: Uint8Array<ArrayBuffer>, numVertex: number) => boolean;
package/dist/buffer.js CHANGED
@@ -4,6 +4,7 @@
4
4
  * Proto messages pack float32 data as `Uint8Array` (bytes fields). These utilities
5
5
  * provide efficient conversion to `Float32Array` for Three.js BufferAttributes.
6
6
  */
7
+ import { Color } from 'three';
7
8
  /**
8
9
  * Stride constants for proto binary data formats.
9
10
  * Each value represents the number of float32 elements per item.
@@ -50,22 +51,79 @@ export const asFloat32Array = (bytes) => {
50
51
  return aligned;
51
52
  };
52
53
  /**
53
- * Converts uint8 RGBA colors to normalized float32 colors (0-1 range).
54
- * Three.js expects colors in 0-1 range for BufferAttributes.
54
+ * Sets a Three.js Color from 3 bytes of a uint8 color array starting at `offset`.
55
+ * Mutates and returns `target` — pass a pre-allocated Color to avoid allocations
56
+ * in hot paths.
55
57
  *
56
- * @param colors - Uint8Array of RGBA color data [r, g, b, a, ...]
57
- * @returns Float32Array with normalized color values
58
+ * @param bytes - Uint8Array with at least `offset + 3` elements [r, g, b, ...]
59
+ * @param target - Color instance to write into
60
+ * @param offset - Byte offset to start reading from (default 0)
61
+ * @returns The mutated `target`, or black if the array has fewer than `offset + 3` elements
58
62
  *
59
63
  * @example
60
64
  * ```ts
61
- * const colors = normalizeColorsRGBA(metadata.colors)
62
- * geometry.setAttribute('color', new BufferAttribute(colors, 4))
65
+ * asColor(colors.current, material.color)
66
+ * asColor(colors.current, pointColorUtil, stride) // read second color
63
67
  * ```
64
68
  */
65
- export const normalizeColorsRGBA = (colors) => {
66
- const normalized = new Float32Array(colors.length);
67
- for (let i = 0; i < colors.length; i++) {
68
- normalized[i] = colors[i] / 255;
69
- }
70
- return normalized;
69
+ export const asColor = (bytes, target, offset = 0) => {
70
+ if (bytes.length < offset + 3)
71
+ return target.setRGB(0, 0, 0);
72
+ return target.setRGB(bytes[offset] / 255, bytes[offset + 1] / 255, bytes[offset + 2] / 255);
73
+ };
74
+ /**
75
+ * Creates a Uint8Array from a Three.js Color.
76
+ *
77
+ * @param color - The Three.js Color to convert
78
+ * @returns A Uint8Array with the RGBA values
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * const color = fromColor(new Color(0, 1, 0))
83
+ * ```
84
+ */
85
+ export const fromColor = (color) => {
86
+ return new Uint8Array([
87
+ Math.round(color.r * 255),
88
+ Math.round(color.g * 255),
89
+ Math.round(color.b * 255),
90
+ ]);
91
+ };
92
+ /**
93
+ * Reads a byte from a uint8 color array at `offset` and normalizes it to 0-1.
94
+ * Returns `fallback` when the array has fewer than `offset + 1` elements.
95
+ *
96
+ * @param bytes - ArrayLike of uint8 color values
97
+ * @param fallback - Value to return when no alpha byte is present (default 1)
98
+ * @param offset - Byte index to read from (default 3, the alpha channel of the first color)
99
+ * @returns Normalized opacity in 0-1 range, or the fallback value
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * material.opacity = asOpacity(colors.current)
104
+ * material.opacity = asOpacity(colors.current, 1, stride + 3) // alpha of second color
105
+ * ```
106
+ */
107
+ export const asOpacity = (bytes, fallback = 1, offset = 3) => {
108
+ if (bytes.length < offset + 1)
109
+ return fallback;
110
+ return bytes[offset] / 255;
71
111
  };
112
+ /**
113
+ * Returns true when `colors` contains exactly one color entry per point (RGB or RGBA).
114
+ * Use this to distinguish per-vertex color buffers from a single uniform color.
115
+ *
116
+ * @param colors - Uint8Array of packed color bytes
117
+ * @param numVertex - Number of points/vertices the color buffer should cover
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * if (isPerVertexColors(colors, positions.length / STRIDE.POSITIONS)) {
122
+ * // treat as per-vertex
123
+ * } else {
124
+ * addColorTraits(entityTraits, colors)
125
+ * }
126
+ * ```
127
+ */
128
+ export const isPerVertexColors = (colors, numVertex) => colors.length === numVertex * STRIDE.COLORS_RGB ||
129
+ colors.length === numVertex * STRIDE.COLORS_RGBA;
package/dist/color.js CHANGED
@@ -17,9 +17,9 @@ const oklchToHex = (raw) => {
17
17
  if (!match) {
18
18
  return raw;
19
19
  }
20
- const l = parseFloat(match[1]) / 100;
21
- const c = parseFloat(match[2]);
22
- const h = parseFloat(match[3]);
20
+ const l = Number.parseFloat(match[1]) / 100;
21
+ const c = Number.parseFloat(match[2]);
22
+ const h = Number.parseFloat(match[3]);
23
23
  // Convert h from degrees to radians
24
24
  const hRad = (h * Math.PI) / 180;
25
25
  // Step 1: OKLCH → OKLab
@@ -87,11 +87,7 @@
87
87
  )
88
88
 
89
89
  $effect.pre(() => {
90
- if (localConfigProps) {
91
- environment.current.isStandalone = false
92
- } else {
93
- environment.current.isStandalone = true
94
- }
90
+ environment.current.isStandalone = !localConfigProps
95
91
  })
96
92
  </script>
97
93
 
@@ -1,17 +1,11 @@
1
1
  <script lang="ts">
2
- import { T, useThrelte } from '@threlte/core'
2
+ import { T } from '@threlte/core'
3
3
  import { useSettings } from '../hooks/useSettings.svelte'
4
- import type { Camera } from 'three'
5
4
 
6
5
  let { children, ...rest } = $props()
7
6
 
8
- const { camera } = useThrelte()
9
7
  const settings = useSettings()
10
8
  const mode = $derived(settings.current.cameraMode)
11
-
12
- $effect(() => {
13
- ;(window as unknown as { camera: Camera }).camera = $camera
14
- })
15
9
  </script>
16
10
 
17
11
  {#if mode === 'perspective'}
@@ -1,4 +1,3 @@
1
- import type { Camera } from 'three';
2
1
  declare const Camera: import("svelte").Component<{
3
2
  children: any;
4
3
  } & Record<string, any>, {}, "">;
@@ -30,8 +30,8 @@
30
30
  enabled={!transformControls.active}
31
31
  oncreate={(ref) => {
32
32
  cameraControls.set(ref)
33
- ;(window as unknown as { MathUtils: typeof MathUtils }).MathUtils = MathUtils
34
- ;(window as unknown as { cameraControls: CameraControlsRef }).cameraControls = ref
33
+ ;(globalThis as unknown as { MathUtils: typeof MathUtils }).MathUtils = MathUtils
34
+ ;(globalThis as unknown as { cameraControls: CameraControlsRef }).cameraControls = ref
35
35
  }}
36
36
  >
37
37
  {#snippet children({ ref }: { ref: CameraControlsRef })}
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
- import { InstancedArrows } from '../../three/InstancedArrows/InstancedArrows'
3
- import { traits, useWorld } from '../../ecs'
2
+ import { InstancedArrows } from '../../../three/InstancedArrows/InstancedArrows'
3
+ import { traits, useWorld } from '../../../ecs'
4
4
  import type { Entity } from 'koota'
5
- import { STRIDE } from '../../buffer'
5
+ import { STRIDE } from '../../../buffer'
6
6
  import { SvelteMap } from 'svelte/reactivity'
7
7
  import { Color } from 'three'
8
8
  import Arrows from './Arrows.svelte'
@@ -2,11 +2,11 @@
2
2
  import { T } from '@threlte/core'
3
3
  import { Portal } from '@threlte/extras'
4
4
  import type { Entity } from 'koota'
5
- import { traits } from '../../ecs'
6
- import { useObjectEvents } from '../../hooks/useObjectEvents.svelte'
7
- import type { InstancedArrows } from '../../three/InstancedArrows/InstancedArrows'
8
- import { useFocusedEntity, useSelectedEntity } from '../../hooks/useSelection.svelte'
9
- import { meshBoundsRaycast, raycast } from '../../three/InstancedArrows/raycast'
5
+ import { traits } from '../../../ecs'
6
+ import { useEntityEvents } from '../hooks/useEntityEvents.svelte'
7
+ import type { InstancedArrows } from '../../../three/InstancedArrows/InstancedArrows'
8
+ import { useFocusedEntity, useSelectedEntity } from '../../../hooks/useSelection.svelte'
9
+ import { meshBoundsRaycast, raycast } from '../../../three/InstancedArrows/raycast'
10
10
 
11
11
  interface Props {
12
12
  entity: Entity
@@ -15,7 +15,7 @@
15
15
 
16
16
  let { entity, arrows }: Props = $props()
17
17
 
18
- const events = useObjectEvents(() => entity)
18
+ const events = useEntityEvents(() => entity)
19
19
  const selectedEntity = useSelectedEntity()
20
20
  const focusedEntity = useFocusedEntity()
21
21
 
@@ -1,5 +1,5 @@
1
1
  import type { Entity } from 'koota';
2
- import type { InstancedArrows } from '../../three/InstancedArrows/InstancedArrows';
2
+ import type { InstancedArrows } from '../../../three/InstancedArrows/InstancedArrows';
3
3
  interface Props {
4
4
  entity: Entity;
5
5
  arrows: InstancedArrows;
@@ -5,8 +5,10 @@
5
5
  import Label from './Label.svelte'
6
6
  import Line from './Line.svelte'
7
7
  import Points from './Points.svelte'
8
- import { traits, useQuery } from '../ecs'
8
+ import Arrows from './Arrows/ArrowGroups.svelte'
9
+ import { traits, useQuery } from '../../ecs'
9
10
  import { Not, Or } from 'koota'
11
+ import Geometry from './Geometry.svelte'
10
12
 
11
13
  /**
12
14
  * Frames from a live machine are bucketed into their own query
@@ -60,9 +62,9 @@
60
62
  {/each}
61
63
 
62
64
  {#each resourceGeometriesEntities.current as entity (entity)}
63
- <Frame {entity}>
65
+ <Geometry {entity}>
64
66
  <Label text={entity.get(traits.Name)} />
65
- </Frame>
67
+ </Geometry>
66
68
  {/each}
67
69
 
68
70
  {#each worldStateEntities.current as entity (entity)}
@@ -94,3 +96,5 @@
94
96
  <Label text={entity.get(traits.Name)} />
95
97
  </GLTF>
96
98
  {/each}
99
+
100
+ <Arrows />
@@ -0,0 +1,86 @@
1
+ <!--
2
+ @component
3
+
4
+ Renders a Viam Frame object
5
+ -->
6
+ <script module>
7
+ import { Color } from 'three'
8
+
9
+ const colorUtil = new Color()
10
+ </script>
11
+
12
+ <script lang="ts">
13
+ import type { Snippet } from 'svelte'
14
+ import { Group, type Object3D } from 'three'
15
+ import { T, useThrelte } from '@threlte/core'
16
+ import { Portal, PortalTarget } from '@threlte/extras'
17
+ import { useEntityEvents } from './hooks/useEntityEvents.svelte'
18
+ import Mesh from './Mesh.svelte'
19
+ import { colors, resourceColors } from '../../color'
20
+ import type { Entity } from 'koota'
21
+ import { traits, useTrait } from '../../ecs'
22
+ import type { Pose } from '@viamrobotics/sdk'
23
+ import { useResourceByName } from '../../hooks/useResourceByName.svelte'
24
+ import { poseToObject3d } from '../../transform'
25
+
26
+ interface Props {
27
+ entity: Entity
28
+ pose?: Pose
29
+ children?: Snippet<[{ ref: Object3D }]>
30
+ }
31
+
32
+ let { entity, pose, children }: Props = $props()
33
+
34
+ const { invalidate } = useThrelte()
35
+ const resourceByName = useResourceByName()
36
+
37
+ const name = useTrait(() => entity, traits.Name)
38
+ const parent = useTrait(() => entity, traits.Parent)
39
+ const entityColor = useTrait(() => entity, traits.Color)
40
+ const entityPose = useTrait(() => entity, traits.Pose)
41
+ const center = useTrait(() => entity, traits.Center)
42
+
43
+ const events = useEntityEvents(() => entity)
44
+
45
+ const color = $derived.by(() => {
46
+ if (entityColor.current) {
47
+ return `#${colorUtil.set(entityColor.current.r, entityColor.current.g, entityColor.current.b).getHexString()}`
48
+ }
49
+
50
+ const subtype = resourceByName.current[name.current ?? '']?.subtype
51
+ const resourceColor = resourceColors[subtype as keyof typeof resourceColors]
52
+
53
+ if (resourceColor) {
54
+ return resourceColor
55
+ }
56
+
57
+ return colors.default
58
+ })
59
+
60
+ const group = new Group()
61
+
62
+ const resolvedPose = $derived(pose ?? entityPose.current)
63
+ $effect.pre(() => {
64
+ if (resolvedPose) {
65
+ poseToObject3d(resolvedPose, group)
66
+ invalidate()
67
+ }
68
+ })
69
+ </script>
70
+
71
+ <Portal id={parent.current}>
72
+ <T is={group}>
73
+ <Mesh
74
+ {entity}
75
+ {color}
76
+ {...events}
77
+ center={center.current}
78
+ />
79
+
80
+ {#if name.current}
81
+ <PortalTarget id={name.current} />
82
+ {/if}
83
+
84
+ {@render children?.({ ref: group })}
85
+ </T>
86
+ </Portal>
@@ -9,6 +9,7 @@ interface Props {
9
9
  ref: Object3D;
10
10
  }]>;
11
11
  }
12
+ /** Renders a Viam Frame object */
12
13
  declare const Frame: import("svelte").Component<Props, {}, "">;
13
14
  type Frame = ReturnType<typeof Frame>;
14
15
  export default Frame;
@@ -16,10 +16,10 @@
16
16
  import { Portal, PortalTarget, useGltfAnimations, type ThrelteGltf } from '@threlte/extras'
17
17
  import type { Snippet } from 'svelte'
18
18
  import { Group, type Object3D } from 'three'
19
- import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
19
+ import { useEntityEvents } from './hooks/useEntityEvents.svelte'
20
20
  import type { Entity } from 'koota'
21
- import { traits, useTrait } from '../ecs'
22
- import { poseToObject3d } from '../transform'
21
+ import { traits, useTrait } from '../../ecs'
22
+ import { poseToObject3d } from '../../transform'
23
23
 
24
24
  interface Props extends ThrelteProps<Object3D> {
25
25
  entity: Entity
@@ -35,7 +35,7 @@
35
35
  const pose = useTrait(() => entity, traits.Pose)
36
36
  const gltfTrait = useTrait(() => entity, traits.GLTF)
37
37
  const scale = useTrait(() => entity, traits.Scale)
38
- const objectProps = useObjectEvents(() => entity)
38
+ const events = useEntityEvents(() => entity)
39
39
 
40
40
  const animationName = $derived(gltfTrait.current?.animationName)
41
41
 
@@ -85,7 +85,7 @@
85
85
  is={$gltf.scene as Object3D}
86
86
  scale={[scale.current?.x ?? 1, scale.current?.y ?? 1, scale.current?.z ?? 1]}
87
87
  name={entity}
88
- {...objectProps}
88
+ {...events}
89
89
  {...rest}
90
90
  >
91
91
  {@render children?.()}
@@ -0,0 +1,75 @@
1
+ <!--
2
+ @component
3
+
4
+ Renders a Viam Geometry object
5
+ -->
6
+ <script lang="ts">
7
+ import { T, useThrelte } from '@threlte/core'
8
+ import { traits, useTrait } from '../../ecs'
9
+ import { use3DModels } from '../../hooks/use3DModels.svelte'
10
+ import { Portal } from '@threlte/extras'
11
+ import { poseToObject3d } from '../../transform'
12
+ import { useSettings } from '../../hooks/useSettings.svelte'
13
+ import Mesh from './Mesh.svelte'
14
+ import { useEntityEvents } from './hooks/useEntityEvents.svelte'
15
+ import type { Entity } from 'koota'
16
+ import type { Snippet } from 'svelte'
17
+
18
+ interface Props {
19
+ entity: Entity
20
+ children?: Snippet
21
+ }
22
+
23
+ const { entity, children }: Props = $props()
24
+
25
+ const settings = useSettings()
26
+
27
+ const { invalidate } = useThrelte()
28
+ const models = use3DModels()
29
+
30
+ const name = useTrait(() => entity, traits.Name)
31
+ const parent = useTrait(() => entity, traits.Parent)
32
+ const center = useTrait(() => entity, traits.Center)
33
+
34
+ const model = $derived.by(() => {
35
+ if (!settings.current.renderArmModels.includes('model')) {
36
+ return
37
+ }
38
+
39
+ if (!name.current) {
40
+ return
41
+ }
42
+
43
+ const [componentName, id] = name.current.split(':')
44
+ if (!componentName || !id) {
45
+ return
46
+ }
47
+
48
+ return models.current[componentName]?.[id].clone()
49
+ })
50
+
51
+ $effect.pre(() => {
52
+ if (model && center.current) {
53
+ poseToObject3d(center.current, model)
54
+ invalidate()
55
+ }
56
+ })
57
+
58
+ const events = useEntityEvents(() => entity)
59
+ </script>
60
+
61
+ <Portal id={parent.current}>
62
+ {#if model}
63
+ <T is={model} />
64
+ {/if}
65
+
66
+ {#if settings.current.renderArmModels.includes('colliders') || !model}
67
+ <Mesh
68
+ {entity}
69
+ center={center.current}
70
+ {...events}
71
+ >
72
+ {@render children?.()}
73
+ </Mesh>
74
+ {/if}
75
+ </Portal>
@@ -0,0 +1,10 @@
1
+ import type { Entity } from 'koota';
2
+ import type { Snippet } from 'svelte';
3
+ interface Props {
4
+ entity: Entity;
5
+ children?: Snippet;
6
+ }
7
+ /** Renders a Viam Geometry object */
8
+ declare const Geometry: import("svelte").Component<Props, {}, "">;
9
+ type Geometry = ReturnType<typeof Geometry>;
10
+ export default Geometry;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { HTML } from '@threlte/extras'
3
3
 
4
- import { useSettings } from '../hooks/useSettings.svelte'
4
+ import { useSettings } from '../../hooks/useSettings.svelte'
5
5
 
6
6
  interface Props {
7
7
  text?: string
@@ -0,0 +1,90 @@
1
+ <script module>
2
+ import { Color } from 'three'
3
+
4
+ const colorUtil = new Color()
5
+ </script>
6
+
7
+ <script lang="ts">
8
+ import type { Snippet } from 'svelte'
9
+ import { T, useThrelte } from '@threlte/core'
10
+ import { meshBounds, Portal, PortalTarget } from '@threlte/extras'
11
+ import type { Entity } from 'koota'
12
+ import { traits, useTrait } from '../../ecs'
13
+ import LineDots from './LineDots.svelte'
14
+ import { darkenColor } from '../../color'
15
+ import { useEntityEvents } from './hooks/useEntityEvents.svelte'
16
+ import { Line2, LineMaterial } from 'three/examples/jsm/Addons.js'
17
+ import LineGeometry from './LineGeometry.svelte'
18
+ import { poseToObject3d } from '../../transform'
19
+
20
+ interface Props {
21
+ entity: Entity
22
+ children?: Snippet
23
+ }
24
+
25
+ let { entity, children }: Props = $props()
26
+
27
+ const { invalidate } = useThrelte()
28
+ const name = useTrait(() => entity, traits.Name)
29
+ const parent = useTrait(() => entity, traits.Parent)
30
+ const pose = useTrait(() => entity, traits.Pose)
31
+ const color = useTrait(() => entity, traits.Color)
32
+ const pointSize = useTrait(() => entity, traits.PointSize)
33
+ const linePositions = useTrait(() => entity, traits.LinePositions)
34
+ const lineWidth = useTrait(() => entity, traits.LineWidth)
35
+ const opacity = useTrait(() => entity, traits.Opacity)
36
+ const materialProps = useTrait(() => entity, traits.Material)
37
+ const renderOrder = useTrait(() => entity, traits.RenderOrder)
38
+
39
+ const events = useEntityEvents(() => entity)
40
+
41
+ const currentOpacity = $derived(opacity.current ?? 0.7)
42
+
43
+ const mesh = new Line2()
44
+
45
+ $effect.pre(() => {
46
+ if (pose.current) {
47
+ poseToObject3d(pose.current, mesh)
48
+ invalidate()
49
+ }
50
+ })
51
+ </script>
52
+
53
+ <Portal id={parent.current}>
54
+ <T
55
+ is={mesh}
56
+ name={entity}
57
+ userData.name={name}
58
+ raycast={meshBounds}
59
+ renderOrder={renderOrder.current}
60
+ {...events}
61
+ >
62
+ <LineGeometry positions={linePositions.current} />
63
+ <T
64
+ is={LineMaterial}
65
+ color={[color.current?.r ?? 1, color.current?.g ?? 0, color.current?.b ?? 0]}
66
+ transparent={currentOpacity < 1}
67
+ depthWrite={currentOpacity === 1}
68
+ opacity={currentOpacity}
69
+ width={lineWidth.current ? lineWidth.current * 0.001 : 0.5}
70
+ depthTest={materialProps.current?.depthTest ?? true}
71
+ />
72
+ </T>
73
+
74
+ {#if linePositions.current && pointSize.current}
75
+ <LineDots
76
+ color={darkenColor(
77
+ colorUtil.setRGB(color.current?.r ?? 1, color.current?.g ?? 0, color.current?.b ?? 0),
78
+ 10
79
+ )}
80
+ positions={linePositions.current}
81
+ scale={pointSize.current * 0.001}
82
+ />
83
+ {/if}
84
+
85
+ {#if name.current}
86
+ <PortalTarget id={name.current} />
87
+ {/if}
88
+
89
+ {@render children?.()}
90
+ </Portal>