• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

visgl / luma.gl / 23357312823

20 Mar 2026 06:35PM UTC coverage: 58.158% (+5.9%) from 52.213%
23357312823

Pull #2555

github

web-flow
Merge 71b78bbe2 into fc5791b65
Pull Request #2555: chore: Run tests on src instead of dist

3021 of 6029 branches covered (50.11%)

Branch coverage included in aggregate %.

7102 of 11377 relevant lines covered (62.42%)

243.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

46.3
/modules/engine/src/scenegraph/scenegraph-node.ts
1
// luma.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
import {Vector3, Matrix4, NumericArray} from '@math.gl/core';
6
import {uid} from '../utils/uid';
7

8
function assert(condition: boolean, message?: string): asserts condition {
9
  if (!condition) {
2!
10
    throw new Error(message);
×
11
  }
12
}
13

14
/** Properties for creating a new Scenegraph */
15
export type ScenegraphNodeProps = {
16
  id?: string;
17
  /** whether to display the object at all */
18
  display?: boolean;
19
  matrix?: NumericArray;
20
  position?: NumericArray;
21
  rotation?: NumericArray;
22
  scale?: NumericArray;
23
  update?: boolean;
24
};
25

26
export class ScenegraphNode {
27
  readonly id: string;
28
  matrix: Matrix4 = new Matrix4();
44✔
29

30
  display = true;
44✔
31
  position = new Vector3();
44✔
32
  rotation = new Vector3();
44✔
33
  scale = new Vector3(1, 1, 1);
44✔
34
  userData: Record<string, unknown> = {};
44✔
35

36
  props: ScenegraphNodeProps = {};
44✔
37

38
  constructor(props: ScenegraphNodeProps = {}) {
44✔
39
    const {id} = props;
44✔
40

41
    this.id = id || uid(this.constructor.name);
44✔
42

43
    this._setScenegraphNodeProps(props);
44✔
44
  }
45

46
  getBounds(): [number[], number[]] | null {
47
    return null;
×
48
  }
49

50
  destroy(): void {}
51

52
  /** @deprecated use .destroy() */
53
  delete(): void {
54
    this.destroy();
×
55
  }
56
  setProps(props: ScenegraphNodeProps): this {
57
    this._setScenegraphNodeProps(props);
7✔
58
    return this;
7✔
59
  }
60

61
  toString(): string {
62
    return `{type: ScenegraphNode, id: ${this.id})}`;
×
63
  }
64

65
  setPosition(position: any): this {
66
    assert(position.length === 3, 'setPosition requires vector argument');
×
67
    this.position = position;
×
68
    return this;
×
69
  }
70

71
  setRotation(rotation: any): this {
72
    assert(rotation.length === 3 || rotation.length === 4, 'setRotation requires vector argument');
2✔
73
    this.rotation = rotation;
2✔
74
    return this;
2✔
75
  }
76

77
  setScale(scale: any): this {
78
    assert(scale.length === 3, 'setScale requires vector argument');
×
79
    this.scale = scale;
×
80
    return this;
×
81
  }
82

83
  setMatrix(matrix: any, copyMatrix: boolean = true): void {
5✔
84
    if (copyMatrix) {
5!
85
      this.matrix.copy(matrix);
5✔
86
    } else {
87
      this.matrix = matrix;
×
88
    }
89
  }
90

91
  setMatrixComponents(components: {
92
    position?: any;
93
    rotation?: any;
94
    scale?: any;
95
    update?: boolean;
96
  }): this {
97
    const {position, rotation, scale, update = true} = components;
×
98
    if (position) {
×
99
      this.setPosition(position);
×
100
    }
101
    if (rotation) {
×
102
      this.setRotation(rotation);
×
103
    }
104
    if (scale) {
×
105
      this.setScale(scale);
×
106
    }
107
    if (update) {
×
108
      this.updateMatrix();
×
109
    }
110
    return this;
×
111
  }
112

113
  updateMatrix(): this {
114
    this.matrix.identity();
51✔
115
    this.matrix.translate(this.position);
51✔
116
    if (this.rotation.length === 4) {
51✔
117
      const rotationMatrix = new Matrix4().fromQuaternion(this.rotation);
2✔
118
      this.matrix.multiplyRight(rotationMatrix);
2✔
119
    } else {
120
      this.matrix.rotateXYZ(this.rotation);
49✔
121
    }
122
    this.matrix.scale(this.scale);
51✔
123

124
    return this;
51✔
125
  }
126

127
  update({position, rotation, scale}: {position?: any; rotation?: any; scale?: any} = {}): this {
×
128
    if (position) {
×
129
      this.setPosition(position);
×
130
    }
131
    if (rotation) {
×
132
      this.setRotation(rotation);
×
133
    }
134
    if (scale) {
×
135
      this.setScale(scale);
×
136
    }
137

138
    this.updateMatrix();
×
139

140
    return this;
×
141
  }
142

143
  getCoordinateUniforms(
144
    viewMatrix: any,
145
    modelMatrix?: any
146
  ): {
147
    viewMatrix: any;
148
    modelMatrix: any;
149
    objectMatrix: any;
150
    worldMatrix: any;
151
    worldInverseMatrix: any;
152
    worldInverseTransposeMatrix: any;
153
  } {
154
    // TODO - solve multiple class problem
155
    // assert(viewMatrix instanceof Matrix4);
156
    // assert(viewMatrix);
157
    modelMatrix = modelMatrix || this.matrix;
×
158
    const worldMatrix = new Matrix4(viewMatrix).multiplyRight(modelMatrix);
×
159
    const worldInverse = worldMatrix.invert();
×
160
    const worldInverseTranspose = worldInverse.transpose();
×
161

162
    return {
×
163
      viewMatrix,
164
      modelMatrix,
165
      objectMatrix: modelMatrix,
166
      worldMatrix,
167
      worldInverseMatrix: worldInverse,
168
      worldInverseTransposeMatrix: worldInverseTranspose
169
    };
170
  }
171

172
  // TODO - copied code, not yet vetted
173
  /*
174
  transform() {
175
    if (!this.parent) {
176
      this.endPosition.set(this.position);
177
      this.endRotation.set(this.rotation);
178
      this.endScale.set(this.scale);
179
    } else {
180
      const parent = this.parent;
181
      this.endPosition.set(this.position.add(parent.endPosition));
182
      this.endRotation.set(this.rotation.add(parent.endRotation));
183
      this.endScale.set(this.scale.add(parent.endScale));
184
    }
185

186
    const ch = this.children;
187
    for (let i = 0; i < ch.length; ++i) {
188
      ch[i].transform();
189
    }
190

191
    return this;
192
  }
193
  */
194

195
  _setScenegraphNodeProps(props: ScenegraphNodeProps): void {
196
    // if ('display' in props) {
197
    //   this.display = props.display;
198
    // }
199

200
    if (props?.position) {
51!
201
      this.setPosition(props.position);
×
202
    }
203
    if (props?.rotation) {
51✔
204
      this.setRotation(props.rotation);
2✔
205
    }
206
    if (props?.scale) {
51!
207
      this.setScale(props.scale);
×
208
    }
209

210
    this.updateMatrix();
51✔
211

212
    // Matrix overwrites other props
213
    if (props?.matrix) {
51✔
214
      this.setMatrix(props.matrix);
5✔
215
    }
216

217
    Object.assign(this.props, props);
51✔
218
  }
219
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc