3d-spinner 0.9.4 → 0.9.6

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 (54) hide show
  1. package/dist/animations/charged-orb.js +4 -2
  2. package/dist/animations/ghost-train.d.ts +1 -1
  3. package/dist/animations/ghost-train.js +3 -1
  4. package/dist/animations/grid-assembly.d.ts +1 -1
  5. package/dist/animations/spin.d.ts +3 -1
  6. package/dist/animations/spin.js +6 -1
  7. package/dist/cjs/animations/charged-orb.cjs +177 -30
  8. package/dist/cjs/animations/grid-assembly.cjs +171 -28
  9. package/dist/cjs/animations/object-motion.cjs +163 -26
  10. package/dist/cjs/animations/particles.cjs +181 -30
  11. package/dist/cjs/animations/spin.cjs +176 -29
  12. package/dist/cjs/engines/little-3d-engine/little-3d-engine.cjs +200 -47
  13. package/dist/cjs/engines/little-3d-engine/loaders/obj.cjs +51 -13
  14. package/dist/cjs/engines/little-3d-engine/renderers/canvas2d-textured.cjs +56 -6
  15. package/dist/cjs/engines/little-3d-engine/renderers/webgl-textured.cjs +69 -10
  16. package/dist/cjs/engines/little-3d-engine/renderers/webgpu-textured.cjs +64 -11
  17. package/dist/cjs/prefabs/prefabs.cjs +200 -44
  18. package/dist/engines/little-3d-engine/core/geometry.d.ts +15 -2
  19. package/dist/engines/little-3d-engine/core/geometry.js +25 -3
  20. package/dist/engines/little-3d-engine/core/light.d.ts +28 -4
  21. package/dist/engines/little-3d-engine/core/light.js +48 -7
  22. package/dist/engines/little-3d-engine/core/mesh.d.ts +33 -0
  23. package/dist/engines/little-3d-engine/core/mesh.js +12 -0
  24. package/dist/engines/little-3d-engine/little-3d-engine.d.ts +2 -2
  25. package/dist/engines/little-3d-engine/little-3d-engine.js +1 -1
  26. package/dist/engines/little-3d-engine/loaders/obj.d.ts +8 -7
  27. package/dist/engines/little-3d-engine/loaders/obj.js +74 -20
  28. package/dist/engines/little-3d-engine/renderers/canvas2d.js +23 -1
  29. package/dist/engines/little-3d-engine/renderers/webgl-textured.js +8 -3
  30. package/dist/engines/little-3d-engine/renderers/webgl.js +41 -7
  31. package/dist/engines/little-3d-engine/renderers/webgpu.js +43 -10
  32. package/dist/engines/little-3d-engine/shapes/complex/plane.d.ts +8 -3
  33. package/dist/engines/little-3d-engine/shapes/complex/plane.js +10 -4
  34. package/dist/engines/little-3d-engine/shapes/primitives/cube.d.ts +3 -2
  35. package/dist/engines/little-3d-engine/shapes/primitives/cube.js +4 -2
  36. package/dist/engines/little-3d-engine/shapes/primitives/octahedron.d.ts +3 -2
  37. package/dist/engines/little-3d-engine/shapes/primitives/octahedron.js +4 -2
  38. package/dist/engines/little-3d-engine/shapes/primitives/pyramid.d.ts +3 -2
  39. package/dist/engines/little-3d-engine/shapes/primitives/pyramid.js +4 -2
  40. package/dist/engines/little-3d-engine/shapes/primitives/quad.d.ts +3 -2
  41. package/dist/engines/little-3d-engine/shapes/primitives/quad.js +4 -2
  42. package/dist/engines/little-3d-engine/shapes/primitives/spheres/cube-sphere.d.ts +3 -2
  43. package/dist/engines/little-3d-engine/shapes/primitives/spheres/cube-sphere.js +4 -2
  44. package/dist/engines/little-3d-engine/shapes/primitives/spheres/icosphere.d.ts +3 -2
  45. package/dist/engines/little-3d-engine/shapes/primitives/spheres/icosphere.js +4 -2
  46. package/dist/engines/little-3d-engine/shapes/primitives/spheres/octa-sphere.d.ts +3 -2
  47. package/dist/engines/little-3d-engine/shapes/primitives/spheres/octa-sphere.js +4 -2
  48. package/dist/engines/little-3d-engine/shapes/primitives/spheres/uv-sphere.d.ts +3 -2
  49. package/dist/engines/little-3d-engine/shapes/primitives/spheres/uv-sphere.js +4 -2
  50. package/dist/engines/little-3d-engine/shapes/primitives/tetrahedron.d.ts +3 -2
  51. package/dist/engines/little-3d-engine/shapes/primitives/tetrahedron.js +4 -2
  52. package/dist/umd/spinner.global.js +271 -67
  53. package/dist/umd/spinner.global.min.js +58 -17
  54. package/package.json +1 -1
@@ -136,7 +136,10 @@ function expandToTriangles(mesh) {
136
136
  const positions = new Float32Array(triangles * 9);
137
137
  const normals = new Float32Array(triangles * 9);
138
138
  const colors = new Float32Array(triangles * 9);
139
+ const emissives = new Float32Array(triangles * 9);
140
+ const speculars = new Float32Array(triangles * 12);
139
141
  let o = 0;
142
+ let so = 0;
140
143
  for (const face of mesh.faces) {
141
144
  const v0 = mesh.vertices[face.indices[0]];
142
145
  const v1 = mesh.vertices[face.indices[1]];
@@ -146,6 +149,15 @@ function expandToTriangles(mesh) {
146
149
  const cr = r / 255;
147
150
  const cg = g / 255;
148
151
  const cb = b / 255;
152
+ const emissive = face.material?.emissive;
153
+ const er = emissive ? emissive[0] : 0;
154
+ const eg = emissive ? emissive[1] : 0;
155
+ const eb = emissive ? emissive[2] : 0;
156
+ const specular = face.material?.specular;
157
+ const sr = specular ? specular[0] : 0;
158
+ const sg = specular ? specular[1] : 0;
159
+ const sb = specular ? specular[2] : 0;
160
+ const sn = specular ? face.material?.shininess ?? 32 : 1;
149
161
  for (let k = 1; k < face.indices.length - 1; k++) {
150
162
  const tri = [face.indices[0], face.indices[k], face.indices[k + 1]];
151
163
  for (const index of tri) {
@@ -159,11 +171,19 @@ function expandToTriangles(mesh) {
159
171
  colors[o] = cr;
160
172
  colors[o + 1] = cg;
161
173
  colors[o + 2] = cb;
174
+ emissives[o] = er;
175
+ emissives[o + 1] = eg;
176
+ emissives[o + 2] = eb;
177
+ speculars[so] = sr;
178
+ speculars[so + 1] = sg;
179
+ speculars[so + 2] = sb;
180
+ speculars[so + 3] = sn;
162
181
  o += 3;
182
+ so += 4;
163
183
  }
164
184
  }
165
185
  }
166
- return { positions, normals, colors, count: positions.length / 3 };
186
+ return { positions, normals, colors, emissives, speculars, count: positions.length / 3 };
167
187
  }
168
188
  var init_geometry = __esm({
169
189
  "src/engines/little-3d-engine/core/geometry.ts"() {
@@ -176,13 +196,42 @@ var init_geometry = __esm({
176
196
  function clamp01(value) {
177
197
  return Math.min(1, Math.max(0, value));
178
198
  }
179
- function shadeColor(normal, color, light) {
199
+ function clamp255(value) {
200
+ return Math.round(Math.min(255, Math.max(0, value)));
201
+ }
202
+ function shade(normal, color, light, surface) {
180
203
  const lambert = Math.max(0, dot(normal, light.toLight));
181
204
  const brightness = clamp01(light.ambient + light.intensity * lambert);
182
- const [r, g, b] = parseColor(color);
183
- return `rgb(${Math.round(r * brightness)}, ${Math.round(g * brightness)}, ${Math.round(
184
- b * brightness
185
- )})`;
205
+ const [baseR, baseG, baseB] = parseColor(color);
206
+ let r = baseR * brightness;
207
+ let g = baseG * brightness;
208
+ let b = baseB * brightness;
209
+ const material = surface?.material;
210
+ const specular = material?.specular;
211
+ const viewDir = surface?.viewDir;
212
+ if (specular && viewDir && lambert > 0) {
213
+ const half = normalize({
214
+ x: light.toLight.x + viewDir.x,
215
+ y: light.toLight.y + viewDir.y,
216
+ z: light.toLight.z + viewDir.z
217
+ });
218
+ const shininess = material?.shininess ?? 32;
219
+ const highlight = Math.pow(Math.max(0, dot(normal, half)), shininess) * light.intensity * 255;
220
+ r += highlight * specular[0];
221
+ g += highlight * specular[1];
222
+ b += highlight * specular[2];
223
+ }
224
+ const emissive = material?.emissive;
225
+ if (emissive) {
226
+ r += emissive[0] * 255;
227
+ g += emissive[1] * 255;
228
+ b += emissive[2] * 255;
229
+ }
230
+ return [clamp255(r), clamp255(g), clamp255(b)];
231
+ }
232
+ function shadeColor(normal, color, light, surface) {
233
+ const [r, g, b] = shade(normal, color, light, surface);
234
+ return `rgb(${r}, ${g}, ${b})`;
186
235
  }
187
236
  var DEFAULTS2, Light;
188
237
  var init_light = __esm({
@@ -205,8 +254,8 @@ var init_light = __esm({
205
254
  };
206
255
  }
207
256
  /** Convenience wrapper around {@link shadeColor} using this light. */
208
- shade(normal, color) {
209
- return shadeColor(normal, color, this.params);
257
+ shade(normal, color, surface) {
258
+ return shadeColor(normal, color, this.params, surface);
210
259
  }
211
260
  };
212
261
  }
@@ -246,28 +295,51 @@ var init_webgl = __esm({
246
295
  in vec3 aPos;
247
296
  in vec3 aNormal;
248
297
  in vec3 aColor;
298
+ in vec3 aEmissive;
299
+ in vec4 aSpecular;
249
300
  uniform mat4 uViewProj;
250
301
  uniform mat4 uModel;
251
302
  out vec3 vNormal;
252
303
  out vec3 vColor;
304
+ out vec3 vEmissive;
305
+ out vec4 vSpecular;
306
+ out vec3 vWorldPos;
253
307
  void main() {
254
308
  vNormal = mat3(uModel) * aNormal;
255
309
  vColor = aColor;
256
- gl_Position = uViewProj * uModel * vec4(aPos, 1.0);
310
+ vEmissive = aEmissive;
311
+ vSpecular = aSpecular;
312
+ vec4 world = uModel * vec4(aPos, 1.0);
313
+ vWorldPos = world.xyz;
314
+ gl_Position = uViewProj * world;
257
315
  }`;
258
316
  FRAGMENT_SHADER = `#version 300 es
259
317
  precision mediump float;
260
318
  in vec3 vNormal;
261
319
  in vec3 vColor;
320
+ in vec3 vEmissive;
321
+ in vec4 vSpecular;
322
+ in vec3 vWorldPos;
262
323
  uniform vec3 uToLight;
324
+ uniform vec3 uEye;
263
325
  uniform float uIntensity;
264
326
  uniform float uAmbient;
265
327
  uniform float uOpacity;
266
328
  out vec4 fragColor;
267
329
  void main() {
268
- float lambert = max(dot(normalize(vNormal), normalize(uToLight)), 0.0);
330
+ vec3 normal = normalize(vNormal);
331
+ vec3 toLight = normalize(uToLight);
332
+ float lambert = max(dot(normal, toLight), 0.0);
269
333
  float brightness = clamp(uAmbient + uIntensity * lambert, 0.0, 1.0);
270
- fragColor = vec4(vColor * brightness, uOpacity);
334
+ vec3 lit = vColor * brightness;
335
+ if (lambert > 0.0) {
336
+ vec3 viewDir = normalize(uEye - vWorldPos);
337
+ vec3 halfVec = normalize(toLight + viewDir);
338
+ float highlight = pow(max(dot(normal, halfVec), 0.0), vSpecular.w) * uIntensity;
339
+ lit += highlight * vSpecular.xyz;
340
+ }
341
+ lit += vEmissive;
342
+ fragColor = vec4(lit, uOpacity);
271
343
  }`;
272
344
  WebGLRenderer = class {
273
345
  constructor(options = {}) {
@@ -288,9 +360,12 @@ void main() {
288
360
  aPos: gl.getAttribLocation(this.program, "aPos"),
289
361
  aNormal: gl.getAttribLocation(this.program, "aNormal"),
290
362
  aColor: gl.getAttribLocation(this.program, "aColor"),
363
+ aEmissive: gl.getAttribLocation(this.program, "aEmissive"),
364
+ aSpecular: gl.getAttribLocation(this.program, "aSpecular"),
291
365
  uViewProj: gl.getUniformLocation(this.program, "uViewProj"),
292
366
  uModel: gl.getUniformLocation(this.program, "uModel"),
293
367
  uToLight: gl.getUniformLocation(this.program, "uToLight"),
368
+ uEye: gl.getUniformLocation(this.program, "uEye"),
294
369
  uIntensity: gl.getUniformLocation(this.program, "uIntensity"),
295
370
  uAmbient: gl.getUniformLocation(this.program, "uAmbient"),
296
371
  uOpacity: gl.getUniformLocation(this.program, "uOpacity")
@@ -314,19 +389,23 @@ void main() {
314
389
  const data = expandToTriangles(mesh);
315
390
  const vao = gl.createVertexArray();
316
391
  gl.bindVertexArray(vao);
317
- const attribute = (location, array) => {
392
+ const buffers = [];
393
+ const attribute = (location, array, size = 3) => {
318
394
  if (location < 0) return;
319
395
  const buffer = gl.createBuffer();
396
+ buffers.push(buffer);
320
397
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
321
398
  gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
322
399
  gl.enableVertexAttribArray(location);
323
- gl.vertexAttribPointer(location, 3, gl.FLOAT, false, 0, 0);
400
+ gl.vertexAttribPointer(location, size, gl.FLOAT, false, 0, 0);
324
401
  };
325
402
  attribute(loc.aPos, data.positions);
326
403
  attribute(loc.aNormal, data.normals);
327
404
  attribute(loc.aColor, data.colors);
405
+ attribute(loc.aEmissive, data.emissives);
406
+ attribute(loc.aSpecular, data.speculars, 4);
328
407
  gl.bindVertexArray(null);
329
- const result = { vao, count: data.count };
408
+ const result = { vao, buffers, count: data.count };
330
409
  this.cache.set(mesh, result);
331
410
  return result;
332
411
  }
@@ -339,6 +418,7 @@ void main() {
339
418
  gl.useProgram(this.program);
340
419
  gl.uniformMatrix4fv(loc.uViewProj, false, new Float32Array(frame.viewProjection));
341
420
  gl.uniform3f(loc.uToLight, frame.light.toLight.x, frame.light.toLight.y, frame.light.toLight.z);
421
+ gl.uniform3f(loc.uEye, frame.eye.x, frame.eye.y, frame.eye.z);
342
422
  gl.uniform1f(loc.uIntensity, frame.light.intensity);
343
423
  gl.uniform1f(loc.uAmbient, frame.light.ambient);
344
424
  gl.disable(gl.BLEND);
@@ -383,7 +463,10 @@ void main() {
383
463
  destroy() {
384
464
  const gl = this.gl;
385
465
  if (gl) {
386
- for (const mesh of this.cache.values()) gl.deleteVertexArray(mesh.vao);
466
+ for (const mesh of this.cache.values()) {
467
+ gl.deleteVertexArray(mesh.vao);
468
+ for (const buffer of mesh.buffers) gl.deleteBuffer(buffer);
469
+ }
387
470
  if (this.program) gl.deleteProgram(this.program);
388
471
  }
389
472
  this.cache.clear();
@@ -413,6 +496,7 @@ struct Uniforms {
413
496
  model: mat4x4<f32>,
414
497
  toLight: vec4<f32>,
415
498
  params: vec4<f32>,
499
+ eye: vec4<f32>,
416
500
  };
417
501
  @group(0) @binding(0) var<uniform> u: Uniforms;
418
502
 
@@ -420,23 +504,40 @@ struct VSOut {
420
504
  @builtin(position) position: vec4<f32>,
421
505
  @location(0) normal: vec3<f32>,
422
506
  @location(1) color: vec3<f32>,
507
+ @location(2) emissive: vec3<f32>,
508
+ @location(3) specular: vec4<f32>,
509
+ @location(4) worldPos: vec3<f32>,
423
510
  };
424
511
 
425
512
  @vertex
426
- fn vs(@location(0) pos: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) color: vec3<f32>) -> VSOut {
513
+ fn vs(@location(0) pos: vec3<f32>, @location(1) normal: vec3<f32>, @location(2) color: vec3<f32>, @location(3) emissive: vec3<f32>, @location(4) specular: vec4<f32>) -> VSOut {
427
514
  var out: VSOut;
428
515
  let m = mat3x3<f32>(u.model[0].xyz, u.model[1].xyz, u.model[2].xyz);
429
516
  out.normal = m * normal;
430
517
  out.color = color;
431
- out.position = u.viewProj * u.model * vec4<f32>(pos, 1.0);
518
+ out.emissive = emissive;
519
+ out.specular = specular;
520
+ let world = u.model * vec4<f32>(pos, 1.0);
521
+ out.worldPos = world.xyz;
522
+ out.position = u.viewProj * world;
432
523
  return out;
433
524
  }
434
525
 
435
526
  @fragment
436
527
  fn fs(in: VSOut) -> @location(0) vec4<f32> {
437
- let lambert = max(dot(normalize(in.normal), normalize(u.toLight.xyz)), 0.0);
528
+ let normal = normalize(in.normal);
529
+ let toLight = normalize(u.toLight.xyz);
530
+ let lambert = max(dot(normal, toLight), 0.0);
438
531
  let brightness = clamp(u.params.y + u.params.x * lambert, 0.0, 1.0);
439
- return vec4<f32>(in.color * brightness, u.params.z);
532
+ var lit = in.color * brightness;
533
+ if (lambert > 0.0) {
534
+ let viewDir = normalize(u.eye.xyz - in.worldPos);
535
+ let halfVec = normalize(toLight + viewDir);
536
+ let highlight = pow(max(dot(normal, halfVec), 0.0), in.specular.w) * u.params.x;
537
+ lit = lit + highlight * in.specular.xyz;
538
+ }
539
+ lit = lit + in.emissive;
540
+ return vec4<f32>(lit, u.params.z);
440
541
  }
441
542
  `;
442
543
  CLIP_Z_FIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 1];
@@ -477,13 +578,15 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
477
578
  {
478
579
  binding: 0,
479
580
  visibility: stage.VERTEX | stage.FRAGMENT,
480
- buffer: { type: "uniform", hasDynamicOffset: true, minBindingSize: 160 }
581
+ buffer: { type: "uniform", hasDynamicOffset: true, minBindingSize: 176 }
481
582
  }
482
583
  ]
483
584
  });
484
- const vertexBuffer = (location) => ({
485
- arrayStride: 12,
486
- attributes: [{ shaderLocation: location, offset: 0, format: "float32x3" }]
585
+ const vertexBuffer = (location, components = 3) => ({
586
+ arrayStride: components * 4,
587
+ attributes: [
588
+ { shaderLocation: location, offset: 0, format: `float32x${components}` }
589
+ ]
487
590
  });
488
591
  const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [layout] });
489
592
  const blend = {
@@ -499,7 +602,13 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
499
602
  vertex: {
500
603
  module: module2,
501
604
  entryPoint: "vs",
502
- buffers: [vertexBuffer(0), vertexBuffer(1), vertexBuffer(2)]
605
+ buffers: [
606
+ vertexBuffer(0),
607
+ vertexBuffer(1),
608
+ vertexBuffer(2),
609
+ vertexBuffer(3),
610
+ vertexBuffer(4, 4)
611
+ ]
503
612
  },
504
613
  fragment: {
505
614
  module: module2,
@@ -552,6 +661,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
552
661
  position: upload(data.positions),
553
662
  normal: upload(data.normals),
554
663
  color: upload(data.colors),
664
+ emissive: upload(data.emissives),
665
+ specular: upload(data.speculars),
555
666
  count: data.count
556
667
  };
557
668
  this.cache.set(mesh, result);
@@ -603,7 +714,7 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
603
714
  const bindGroup = this.device.createBindGroup({
604
715
  layout,
605
716
  entries: [
606
- { binding: 0, resource: { buffer: this.uniformBuffer, offset: 0, size: 160 } }
717
+ { binding: 0, resource: { buffer: this.uniformBuffer, offset: 0, size: 176 } }
607
718
  ]
608
719
  });
609
720
  draws.forEach((draw, i) => {
@@ -612,6 +723,7 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
612
723
  data.set(draw.item.model, 16);
613
724
  data.set([frame.light.toLight.x, frame.light.toLight.y, frame.light.toLight.z, 0], 32);
614
725
  data.set([frame.light.intensity, frame.light.ambient, draw.opacity, 0], 36);
726
+ data.set([frame.eye.x, frame.eye.y, frame.eye.z, 0], 40);
615
727
  this.device.queue.writeBuffer(this.uniformBuffer, i * UNIFORM_STRIDE, data);
616
728
  });
617
729
  const encoder = this.device.createCommandEncoder();
@@ -638,6 +750,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
638
750
  pass.setVertexBuffer(0, mesh.position);
639
751
  pass.setVertexBuffer(1, mesh.normal);
640
752
  pass.setVertexBuffer(2, mesh.color);
753
+ pass.setVertexBuffer(3, mesh.emissive);
754
+ pass.setVertexBuffer(4, mesh.specular);
641
755
  pass.draw(mesh.count);
642
756
  });
643
757
  pass.end();
@@ -649,6 +763,8 @@ fn fs(in: VSOut) -> @location(0) vec4<f32> {
649
763
  mesh.position.destroy?.();
650
764
  mesh.normal.destroy?.();
651
765
  mesh.color.destroy?.();
766
+ mesh.emissive.destroy?.();
767
+ mesh.specular.destroy?.();
652
768
  }
653
769
  this.cache.clear();
654
770
  this.uniformBuffer?.destroy?.();
@@ -731,9 +847,30 @@ var init_canvas2d = __esm({
731
847
  depth += dot(d, d);
732
848
  }
733
849
  depth /= face.indices.length;
850
+ let surface;
851
+ const material = face.material;
852
+ if (material) {
853
+ if (material.specular) {
854
+ let cx = 0;
855
+ let cy = 0;
856
+ let cz = 0;
857
+ for (const i of face.indices) {
858
+ cx += world[i].x;
859
+ cy += world[i].y;
860
+ cz += world[i].z;
861
+ }
862
+ const inv = 1 / face.indices.length;
863
+ const viewDir = normalize(
864
+ subtract(frame.eye, { x: cx * inv, y: cy * inv, z: cz * inv })
865
+ );
866
+ surface = { material, viewDir };
867
+ } else {
868
+ surface = { material };
869
+ }
870
+ }
734
871
  polygons.push({
735
872
  points,
736
- color: shadeColor(normal, face.color, frame.light),
873
+ color: shadeColor(normal, face.color, frame.light, surface),
737
874
  depth,
738
875
  opacity: faceOpacity
739
876
  });
@@ -863,6 +1000,12 @@ init_light();
863
1000
  init_math();
864
1001
 
865
1002
  // src/engines/little-3d-engine/core/mesh.ts
1003
+ function attachMaterial(mesh, material) {
1004
+ if (material) {
1005
+ for (const face of mesh.faces) face.material = material;
1006
+ }
1007
+ return mesh;
1008
+ }
866
1009
  function transform(init) {
867
1010
  return {
868
1011
  position: init?.position ?? { x: 0, y: 0, z: 0 },
@@ -877,7 +1020,7 @@ init_light();
877
1020
 
878
1021
  // src/engines/little-3d-engine/shapes/primitives/cube.ts
879
1022
  var DEFAULT_COLORS = ["#3b82f6", "#8b5cf6", "#ec4899", "#f59e0b", "#10b981", "#ef4444"];
880
- function cube(size = 1, colors = DEFAULT_COLORS) {
1023
+ function cube(size = 1, colors = DEFAULT_COLORS, material) {
881
1024
  const h = size / 2;
882
1025
  const vertices = [
883
1026
  { x: -h, y: -h, z: h },
@@ -897,7 +1040,7 @@ function cube(size = 1, colors = DEFAULT_COLORS) {
897
1040
  { indices: [1, 5, 6, 2], color: colors[4 % colors.length] },
898
1041
  { indices: [4, 0, 3, 7], color: colors[5 % colors.length] }
899
1042
  ];
900
- return { vertices, faces };
1043
+ return attachMaterial({ vertices, faces }, material);
901
1044
  }
902
1045
 
903
1046
  // src/engines/little-3d-engine/shapes/primitives/spheres/icosphere.ts
@@ -1225,10 +1368,14 @@ function applyColor(mesh, color) {
1225
1368
  const pick = Array.isArray(color) ? (i) => color[i % color.length] : () => color;
1226
1369
  return { vertices: mesh.vertices, faces: mesh.faces.map((f, i) => ({ ...f, color: pick(i) })) };
1227
1370
  }
1371
+ function applyMaterial(mesh, material) {
1372
+ if (!material) return mesh;
1373
+ return { vertices: mesh.vertices, faces: mesh.faces.map((f) => ({ ...f, material })) };
1374
+ }
1228
1375
  var SpinAnimation = class {
1229
1376
  constructor(options = {}) {
1230
1377
  this.exited = false;
1231
- this.mesh = applyColor(resolveMesh(options.shape), options.color);
1378
+ this.mesh = applyMaterial(applyColor(resolveMesh(options.shape), options.color), options.material);
1232
1379
  this.spinX = options.spinX ?? 7e-4;
1233
1380
  this.spinY = options.spinY ?? 11e-4;
1234
1381
  this.backend = options.backend;