@viamrobotics/motion-tools 1.18.0 → 1.19.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.
@@ -2,3 +2,5 @@ import { BufferGeometry } from 'three';
2
2
  import type { Metadata } from './metadata';
3
3
  export declare const createBufferGeometry: (positions: Float32Array, metadata?: Metadata) => BufferGeometry<import("three").NormalBufferAttributes, import("three").BufferGeometryEventMap>;
4
4
  export declare const updateBufferGeometry: (geometry: BufferGeometry, positions: Float32Array, metadata: Metadata) => void;
5
+ export declare const preAllocateBufferGeometry: (total: number, size: number, metadata: Metadata) => BufferGeometry;
6
+ export declare const writeBufferGeometryRange: (geometry: BufferGeometry, positions: Float32Array, start: number, metadata: Metadata) => void;
package/dist/attribute.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BufferAttribute, BufferGeometry } from 'three';
2
- import { colorStride } from './buffer';
2
+ import { colorStride, STRIDE } from './buffer';
3
3
  export const createBufferGeometry = (positions, metadata) => {
4
4
  const geometry = new BufferGeometry();
5
5
  geometry.setAttribute('position', new BufferAttribute(positions, 3));
@@ -44,3 +44,49 @@ export const updateBufferGeometry = (geometry, positions, metadata) => {
44
44
  }
45
45
  }
46
46
  };
47
+ export const preAllocateBufferGeometry = (total, size, metadata) => {
48
+ const geometry = new BufferGeometry();
49
+ const posAttr = new BufferAttribute(new Float32Array(total * size), size);
50
+ geometry.setAttribute('position', posAttr);
51
+ if (metadata.colors) {
52
+ const stride = colorStride(metadata.colorFormat) || STRIDE.COLORS_RGB;
53
+ const colorAttr = new BufferAttribute(new Uint8Array(total * stride), stride, true);
54
+ geometry.setAttribute('color', colorAttr);
55
+ }
56
+ if (metadata.opacities) {
57
+ const opacityAttr = new BufferAttribute(new Uint8Array(total), 1, true);
58
+ geometry.setAttribute('opacity', opacityAttr);
59
+ }
60
+ geometry.setDrawRange(0, 0);
61
+ return geometry;
62
+ };
63
+ export const writeBufferGeometryRange = (geometry, positions, start, metadata) => {
64
+ const chunkElements = positions.length / 3;
65
+ const posAttr = geometry.getAttribute('position');
66
+ posAttr.array.set(positions, start * 3);
67
+ posAttr.addUpdateRange(start * 3, chunkElements * 3);
68
+ posAttr.needsUpdate = true;
69
+ if (metadata.colors) {
70
+ const colorAttr = geometry.getAttribute('color');
71
+ if (colorAttr) {
72
+ const stride = colorAttr.itemSize;
73
+ colorAttr.array.set(metadata.colors, start * stride);
74
+ colorAttr.addUpdateRange(start * stride, chunkElements * stride);
75
+ colorAttr.needsUpdate = true;
76
+ }
77
+ }
78
+ if (metadata.opacities) {
79
+ const opacityAttr = geometry.getAttribute('opacity');
80
+ if (opacityAttr) {
81
+ ;
82
+ opacityAttr.array.set(metadata.opacities, start);
83
+ opacityAttr.addUpdateRange(start, chunkElements);
84
+ opacityAttr.needsUpdate = true;
85
+ }
86
+ }
87
+ const endPoint = start + chunkElements;
88
+ const currentEnd = geometry.drawRange.count;
89
+ if (endPoint > currentEnd) {
90
+ geometry.setDrawRange(0, endPoint);
91
+ }
92
+ };
@@ -15,6 +15,39 @@ export declare enum ColorFormat {
15
15
  */
16
16
  RGB = 1
17
17
  }
18
+ /**
19
+ * Chunks describes how a large entity is chunked for progressive delivery.
20
+ *
21
+ * @generated from message draw.v1.Chunks
22
+ */
23
+ export declare class Chunks extends Message<Chunks> {
24
+ /**
25
+ * The number of elements per chunk.
26
+ *
27
+ * @generated from field: uint32 chunk_size = 1;
28
+ */
29
+ chunkSize: number;
30
+ /**
31
+ * The total number of elements across all chunks.
32
+ *
33
+ * @generated from field: uint32 total = 2;
34
+ */
35
+ total: number;
36
+ /**
37
+ * The number of bytes per element (e.g. 12 for float32 xyz positions).
38
+ *
39
+ * @generated from field: uint32 stride = 3;
40
+ */
41
+ stride: number;
42
+ constructor(data?: PartialMessage<Chunks>);
43
+ static readonly runtime: typeof proto3;
44
+ static readonly typeName = "draw.v1.Chunks";
45
+ static readonly fields: FieldList;
46
+ static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Chunks;
47
+ static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Chunks;
48
+ static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Chunks;
49
+ static equals(a: Chunks | PlainMessage<Chunks> | undefined, b: Chunks | PlainMessage<Chunks> | undefined): boolean;
50
+ }
18
51
  /**
19
52
  * @generated from message draw.v1.Metadata
20
53
  */
@@ -53,6 +86,12 @@ export declare class Metadata extends Message<Metadata> {
53
86
  * @generated from field: optional bool invisible = 5;
54
87
  */
55
88
  invisible?: boolean;
89
+ /**
90
+ * When present, indicates this drawing uses chunked delivery.
91
+ *
92
+ * @generated from field: optional draw.v1.Chunks chunks = 6;
93
+ */
94
+ chunks?: Chunks;
56
95
  constructor(data?: PartialMessage<Metadata>);
57
96
  static readonly runtime: typeof proto3;
58
97
  static readonly typeName = "draw.v1.Metadata";
@@ -24,6 +24,54 @@ proto3.util.setEnumType(ColorFormat, "draw.v1.ColorFormat", [
24
24
  { no: 0, name: "COLOR_FORMAT_UNSPECIFIED" },
25
25
  { no: 1, name: "COLOR_FORMAT_RGB" },
26
26
  ]);
27
+ /**
28
+ * Chunks describes how a large entity is chunked for progressive delivery.
29
+ *
30
+ * @generated from message draw.v1.Chunks
31
+ */
32
+ export class Chunks extends Message {
33
+ /**
34
+ * The number of elements per chunk.
35
+ *
36
+ * @generated from field: uint32 chunk_size = 1;
37
+ */
38
+ chunkSize = 0;
39
+ /**
40
+ * The total number of elements across all chunks.
41
+ *
42
+ * @generated from field: uint32 total = 2;
43
+ */
44
+ total = 0;
45
+ /**
46
+ * The number of bytes per element (e.g. 12 for float32 xyz positions).
47
+ *
48
+ * @generated from field: uint32 stride = 3;
49
+ */
50
+ stride = 0;
51
+ constructor(data) {
52
+ super();
53
+ proto3.util.initPartial(data, this);
54
+ }
55
+ static runtime = proto3;
56
+ static typeName = "draw.v1.Chunks";
57
+ static fields = proto3.util.newFieldList(() => [
58
+ { no: 1, name: "chunk_size", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
59
+ { no: 2, name: "total", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
60
+ { no: 3, name: "stride", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
61
+ ]);
62
+ static fromBinary(bytes, options) {
63
+ return new Chunks().fromBinary(bytes, options);
64
+ }
65
+ static fromJson(jsonValue, options) {
66
+ return new Chunks().fromJson(jsonValue, options);
67
+ }
68
+ static fromJsonString(jsonString, options) {
69
+ return new Chunks().fromJsonString(jsonString, options);
70
+ }
71
+ static equals(a, b) {
72
+ return proto3.util.equals(Chunks, a, b);
73
+ }
74
+ }
27
75
  /**
28
76
  * @generated from message draw.v1.Metadata
29
77
  */
@@ -62,6 +110,12 @@ export class Metadata extends Message {
62
110
  * @generated from field: optional bool invisible = 5;
63
111
  */
64
112
  invisible;
113
+ /**
114
+ * When present, indicates this drawing uses chunked delivery.
115
+ *
116
+ * @generated from field: optional draw.v1.Chunks chunks = 6;
117
+ */
118
+ chunks;
65
119
  constructor(data) {
66
120
  super();
67
121
  proto3.util.initPartial(data, this);
@@ -74,6 +128,7 @@ export class Metadata extends Message {
74
128
  { no: 3, name: "opacities", kind: "scalar", T: 12 /* ScalarType.BYTES */, opt: true },
75
129
  { no: 4, name: "show_axes_helper", kind: "scalar", T: 8 /* ScalarType.BOOL */, opt: true },
76
130
  { no: 5, name: "invisible", kind: "scalar", T: 8 /* ScalarType.BOOL */, opt: true },
131
+ { no: 6, name: "chunks", kind: "message", T: Chunks, opt: true },
77
132
  ]);
78
133
  static fromBinary(bytes, options) {
79
134
  return new Metadata().fromBinary(bytes, options);
@@ -0,0 +1,26 @@
1
+ import type { Entity, World } from 'koota';
2
+ import { ColorFormat } from './buf/draw/v1/metadata_pb';
3
+ import { type Metadata } from './metadata';
4
+ export interface EntityChunk {
5
+ /** Element offset (in points) where this chunk should be written. */
6
+ start: number;
7
+ /** Flat `[x, y, z, ...]` positions in meters. */
8
+ positions: Float32Array;
9
+ /** Optional colors aligned with `positions`. */
10
+ colors?: Uint8Array;
11
+ /** Optional per-vertex opacities aligned with `positions`. */
12
+ opacities?: Uint8Array;
13
+ /** `true` when the server has no more chunks for this entity. */
14
+ done: boolean;
15
+ }
16
+ export type ChunkFetcher = (uuid: string, start: number, signal: AbortSignal) => Promise<EntityChunk | null>;
17
+ export interface ChunkLoaderOptions {
18
+ world: World;
19
+ invalidate: () => void;
20
+ fetchChunk: ChunkFetcher;
21
+ colorFormat?: ColorFormat;
22
+ }
23
+ export declare const createChunkLoader: ({ world, invalidate, fetchChunk, colorFormat, }: ChunkLoaderOptions) => {
24
+ start(uuid: string, entity: Entity, metadata: Metadata): void;
25
+ dispose(): void;
26
+ };
@@ -0,0 +1,59 @@
1
+ import { writeBufferGeometryRange } from './attribute';
2
+ import { ColorFormat } from './buf/draw/v1/metadata_pb';
3
+ import { traits } from './ecs';
4
+ import {} from './metadata';
5
+ export const createChunkLoader = ({ world, invalidate, fetchChunk, colorFormat = ColorFormat.RGB, }) => {
6
+ const active = new Set();
7
+ const controller = new AbortController();
8
+ const pull = async (uuid, entity, total, firstChunkEnd) => {
9
+ if (active.has(uuid))
10
+ return;
11
+ active.add(uuid);
12
+ const { signal } = controller;
13
+ let nextStart = firstChunkEnd;
14
+ try {
15
+ while (!signal.aborted) {
16
+ const chunk = await fetchChunk(uuid, nextStart, signal);
17
+ if (signal.aborted || !chunk)
18
+ break;
19
+ const buffer = entity.get(traits.BufferGeometry);
20
+ if (!buffer)
21
+ break;
22
+ writeBufferGeometryRange(buffer, chunk.positions, chunk.start, {
23
+ colorFormat,
24
+ colors: chunk.colors,
25
+ opacities: chunk.opacities,
26
+ });
27
+ const chunkElements = chunk.positions.length / 3;
28
+ nextStart = chunk.start + chunkElements;
29
+ entity.set(traits.ChunkProgress, { loaded: nextStart, total });
30
+ invalidate();
31
+ if (chunk.done)
32
+ break;
33
+ }
34
+ }
35
+ catch (error) {
36
+ if (!signal.aborted) {
37
+ console.error(`Chunk pull failed for entity ${uuid}:`, error);
38
+ }
39
+ }
40
+ finally {
41
+ active.delete(uuid);
42
+ if (world.has(entity)) {
43
+ entity.remove(traits.ChunkProgress);
44
+ }
45
+ }
46
+ };
47
+ return {
48
+ start(uuid, entity, metadata) {
49
+ const chunks = metadata.chunks;
50
+ if (!chunks || chunks.total <= 0)
51
+ return;
52
+ entity.add(traits.ChunkProgress({ loaded: chunks.chunkSize, total: chunks.total }));
53
+ void pull(uuid, entity, chunks.total, chunks.chunkSize);
54
+ },
55
+ dispose() {
56
+ controller.abort();
57
+ },
58
+ };
59
+ };
package/dist/color.d.ts CHANGED
@@ -8,6 +8,7 @@ import { Color, type ColorRepresentation, type RGB } from 'three';
8
8
  */
9
9
  export declare const darkenColor: (value: ColorRepresentation, percent: number) => Color;
10
10
  export declare const resourceNameToColor: (resourceName?: ResourceName) => Color | undefined;
11
+ export declare const subtypeToColor: (subtype?: string) => Color | undefined;
11
12
  export declare const colors: {
12
13
  readonly default: string;
13
14
  };
package/dist/color.js CHANGED
@@ -55,9 +55,17 @@ export const darkenColor = (value, percent) => {
55
55
  return new Color().setHSL(hsl.h, hsl.s, hsl.l);
56
56
  };
57
57
  export const resourceNameToColor = (resourceName) => {
58
- return resourceName
59
- ? new Color(resourceColors[resourceName.subtype])
60
- : undefined;
58
+ if (!resourceName)
59
+ return undefined;
60
+ return subtypeToColor(resourceName.subtype);
61
+ };
62
+ export const subtypeToColor = (subtype) => {
63
+ if (!subtype)
64
+ return undefined;
65
+ const colorValue = resourceColors[subtype];
66
+ if (!colorValue)
67
+ return undefined;
68
+ return new Color(colorValue);
61
69
  };
62
70
  const darkness = '600';
63
71
  export const colors = {
@@ -48,7 +48,7 @@
48
48
  is={arrows.headMesh}
49
49
  bvh={{ enabled: false }}
50
50
  raycast={() => null}
51
- visible={invisible.current}
51
+ visible={invisible.current !== true}
52
52
  />
53
53
  <T
54
54
  is={arrows.shaftMesh}
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { T, type Props as ThrelteProps, useThrelte } from '@threlte/core'
6
6
  import { type Snippet } from 'svelte'
7
- import { BufferGeometry, Color, DoubleSide, FrontSide, Mesh } from 'three'
7
+ import { BufferGeometry, Color, DoubleSide, FrontSide, Material, Mesh } from 'three'
8
8
 
9
9
  import { asColor } from '../../buffer'
10
10
  import { colors, darkenColor } from '../../color'
@@ -56,8 +56,19 @@
56
56
 
57
57
  const currentOpacity = $derived(opacity.current ?? 0.7)
58
58
 
59
- const mesh = new Mesh()
59
+ let material = $state.raw<Material>(new Material())
60
+ $effect(() => {
61
+ const isTransparent = currentOpacity < 1
62
+ material.depthWrite = !isTransparent
63
+ material.opacity = currentOpacity
64
+ if (material.transparent !== isTransparent) {
65
+ material.transparent = isTransparent
66
+ material.needsUpdate = true
67
+ invalidate()
68
+ }
69
+ })
60
70
 
71
+ const mesh = new Mesh()
61
72
  $effect.pre(() => {
62
73
  if (center) {
63
74
  poseToObject3d(center, mesh)
@@ -66,6 +77,11 @@
66
77
  })
67
78
 
68
79
  let geo = $state.raw<BufferGeometry>()
80
+ $effect.pre(() => {
81
+ if (!box.current && !sphere.current && !capsule.current && !bufferGeometry.current) {
82
+ geo = undefined
83
+ }
84
+ })
69
85
 
70
86
  const oncreate = (bufferGeometry: BufferGeometry) => {
71
87
  geo = bufferGeometry
@@ -108,10 +124,10 @@
108
124
  <T.MeshToonMaterial
109
125
  {color}
110
126
  side={bufferGeometry.current ? DoubleSide : FrontSide}
111
- transparent={currentOpacity < 1}
112
- depthWrite={currentOpacity === 1}
113
- opacity={currentOpacity}
114
127
  depthTest={materialProps.current?.depthTest ?? true}
128
+ oncreate={(m) => {
129
+ material = m
130
+ }}
115
131
  />
116
132
 
117
133
  <!--
@@ -4,6 +4,7 @@
4
4
  import type { Snippet } from 'svelte'
5
5
 
6
6
  import { traits, useTrait } from '../../ecs'
7
+ import { usePartConfig } from '../../hooks/usePartConfig.svelte'
7
8
  import { usePose } from '../../hooks/usePose.svelte'
8
9
  import { matrixToPose, poseToMatrix } from '../../transform'
9
10
 
@@ -13,6 +14,7 @@
13
14
  }
14
15
  let { entity, children }: Props = $props()
15
16
 
17
+ const partConfig = usePartConfig()
16
18
  const name = useTrait(() => entity, traits.Name)
17
19
  const parent = useTrait(() => entity, traits.Parent)
18
20
  const editedPose = useTrait(() => entity, traits.EditedPose)
@@ -24,7 +26,7 @@
24
26
  )
25
27
 
26
28
  const resolvedPose = $derived.by(() => {
27
- if (pose.current === undefined) {
29
+ if (pose.current === undefined || partConfig.hasPendingSave) {
28
30
  return editedPose.current
29
31
  }
30
32
 
@@ -20,10 +20,13 @@
20
20
 
21
21
  const world = useWorld()
22
22
 
23
- let entity: Entity
24
-
25
23
  $effect(() => {
24
+ let entity: Entity | undefined
25
+ let cancelled = false
26
+
26
27
  parsePcdInWorker(data).then(({ positions, colors }) => {
28
+ if (cancelled) return
29
+
27
30
  const geometry = createBufferGeometry(positions, { colors, colorFormat: ColorFormat.RGB })
28
31
 
29
32
  const entityTraits: ConfigurableTrait[] = [
@@ -45,6 +48,7 @@
45
48
  })
46
49
 
47
50
  return () => {
51
+ cancelled = true
48
52
  if (entity && world.has(entity)) {
49
53
  entity.destroy()
50
54
  }
@@ -99,7 +99,6 @@
99
99
  {/if}
100
100
 
101
101
  <T.Group attach={focusedObject ? false : undefined}>
102
- <PortalTarget id="world" />
103
102
  <PortalTarget />
104
103
 
105
104
  <Entities />
@@ -46,6 +46,7 @@
46
46
  traits.LinePositions(new Float32Array([x, y, 0])),
47
47
  selectionTraits.StartPoint({ x, y }),
48
48
  traits.LineWidth(1.5),
49
+ traits.ScreenSpace,
49
50
  traits.RenderOrder(999),
50
51
  traits.Material({ depthTest: false }),
51
52
  traits.Color({ r: 1, g: 0, b: 0 }),
@@ -404,6 +404,8 @@
404
404
  value: parent.current ?? 'world',
405
405
  options: configFrames.getParentFrameOptions(name.current ?? ''),
406
406
  onChange: (value) => {
407
+ if (value === parent.current) return
408
+ traits.setParentTrait(entity, value)
407
409
  detailConfigUpdater.setFrameParent(entity, value)
408
410
  },
409
411
  })}
@@ -20,11 +20,33 @@
20
20
 
21
21
  const name = useTrait(() => node.entity, traits.Name)
22
22
  const invisible = useTrait(() => node.entity, traits.Invisible)
23
+ const chunkProgress = useTrait(() => node.entity, traits.ChunkProgress)
24
+ const loading = $derived(chunkProgress.current !== undefined)
25
+ const progress = $derived(
26
+ chunkProgress.current && chunkProgress.current.total > 0
27
+ ? chunkProgress.current.loaded / chunkProgress.current.total
28
+ : 0
29
+ )
23
30
 
24
31
  const nodeProps = $derived({ indexPath, node })
25
32
  const nodeState = $derived(api.getNodeState(nodeProps))
26
33
  </script>
27
34
 
35
+ {#snippet progressIndicator()}
36
+ {#if loading}
37
+ <span
38
+ role="progressbar"
39
+ aria-label="Loading {Math.round(progress * 100)}%"
40
+ aria-valuenow={Math.round(progress * 100)}
41
+ aria-valuemin={0}
42
+ aria-valuemax={100}
43
+ class="border-gray-6 size-3 rounded-full border"
44
+ style:background="conic-gradient(var(--color-gray-6, #9c9ca4) {progress * 100}%, transparent {progress *
45
+ 100}%)"
46
+ ></span>
47
+ {/if}
48
+ {/snippet}
49
+
28
50
  {#if nodeState.isBranch}
29
51
  {@const { expanded } = nodeState}
30
52
  {@const { children = [] } = node}
@@ -52,25 +74,28 @@
52
74
  >
53
75
  {name.current}
54
76
  </span>
55
-
56
- <button
57
- class="text-gray-6"
58
- onclick={(event) => {
59
- event.stopPropagation()
60
-
61
- if (node.entity.has(traits.Invisible)) {
62
- node.entity.remove(traits.Invisible)
63
- } else {
64
- node.entity.add(traits.Invisible)
65
- }
66
- }}
67
- >
68
- {#if invisible.current}
69
- <EyeOff size={14} />
70
- {:else}
71
- <Eye size={14} />
72
- {/if}
73
- </button>
77
+ <div class="flex items-center justify-end gap-1">
78
+ {@render progressIndicator()}
79
+
80
+ <button
81
+ class="text-gray-6"
82
+ onclick={(event) => {
83
+ event.stopPropagation()
84
+
85
+ if (node.entity.has(traits.Invisible)) {
86
+ node.entity.remove(traits.Invisible)
87
+ } else {
88
+ node.entity.add(traits.Invisible)
89
+ }
90
+ }}
91
+ >
92
+ {#if invisible.current}
93
+ <EyeOff size={14} />
94
+ {:else}
95
+ <Eye size={14} />
96
+ {/if}
97
+ </button>
98
+ </div>
74
99
  </div>
75
100
  <div {...api.getBranchContentProps(nodeProps)}>
76
101
  <div {...api.getBranchIndentGuideProps(nodeProps)}></div>
@@ -113,23 +138,27 @@
113
138
  {node.entity.get(traits.Name)}
114
139
  </span>
115
140
 
116
- <button
117
- class="text-gray-6"
118
- onclick={(event) => {
119
- event.stopPropagation()
120
- if (node.entity.has(traits.Invisible)) {
121
- node.entity.remove(traits.Invisible)
122
- } else {
123
- node.entity.add(traits.Invisible)
124
- }
125
- }}
126
- >
127
- {#if invisible.current}
128
- <EyeOff size={14} />
129
- {:else}
130
- <Eye size={14} />
131
- {/if}
132
- </button>
141
+ <div class="flex items-center gap-1">
142
+ {@render progressIndicator()}
143
+
144
+ <button
145
+ class="text-gray-6"
146
+ onclick={(event) => {
147
+ event.stopPropagation()
148
+ if (node.entity.has(traits.Invisible)) {
149
+ node.entity.remove(traits.Invisible)
150
+ } else {
151
+ node.entity.add(traits.Invisible)
152
+ }
153
+ }}
154
+ >
155
+ {#if invisible.current}
156
+ <EyeOff size={14} />
157
+ {:else}
158
+ <Eye size={14} />
159
+ {/if}
160
+ </button>
161
+ </div>
133
162
  </div>
134
163
  {/if}
135
164
 
package/dist/draw.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { TransformWithUUID } from '@viamrobotics/sdk';
2
2
  import type { Entity, Trait, World } from 'koota';
3
3
  import type { Transform as TransformProto } from './buf/common/v1/common_pb';
4
4
  import type { Drawing } from './buf/draw/v1/drawing_pb';
5
+ import { type Metadata } from './metadata';
5
6
  export type Transform = TransformWithUUID | TransformProto;
6
7
  type Options = {
7
8
  removable?: boolean;
@@ -9,5 +10,10 @@ type Options = {
9
10
  export declare const drawTransform: (world: World, { referenceFrame, poseInObserverFrame, physicalObject, metadata }: Transform, api: Trait, options?: Options) => Entity;
10
11
  export declare const drawDrawing: (world: World, drawing: Drawing, api: Trait, options?: Options) => Entity[];
11
12
  export declare const updateTransform: (entity: Entity, { poseInObserverFrame, physicalObject, metadata }: Transform, options?: Options) => void;
13
+ export declare const updateMetadata: (entity: Entity, metadata: Metadata, { pointCloud }?: {
14
+ pointCloud?: boolean;
15
+ }) => void;
12
16
  export declare const updateDrawing: (world: World, entities: Entity[], drawing: Drawing, api: Trait, options?: Options) => Entity[];
17
+ export declare const addColorTraits: (entity: Entity, colors: Uint8Array) => void;
18
+ export declare const setColorTraits: (entity: Entity, colors: Uint8Array) => void;
13
19
  export {};