@particle-academy/fancy-3d-babylon 0.1.1 → 0.1.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/README.md +8 -0
- package/dist/index.cjs +60 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -22
- package/dist/index.d.ts +4 -22
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +50 -41
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -1
- package/dist/react.d.ts +2 -1
- package/dist/react.js +10 -1
- package/dist/react.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @particle-academy/fancy-3d-babylon
|
|
2
2
|
|
|
3
|
+
[](https://particle.academy)
|
|
4
|
+
|
|
3
5
|
Babylon.js adapter for [`@particle-academy/fancy-3d`](https://www.npmjs.com/package/@particle-academy/fancy-3d).
|
|
4
6
|
|
|
5
7
|
`fancy-3d` ships an engine-agnostic core (Scene types + a `CanvasEngine` interface + a DOM/CSS-3D renderer). This package adds a full WebGL renderer on top, plus the React components that mount onto a Babylon `Scene`: `Stage`, `Monitor`, `Card3D`, `Screen`, primitives, and layout helpers (`placeOnGrid`, `placeOnArc`, `placeOnWall`, `placeOnSphere`, `placeOnPath`).
|
|
@@ -62,3 +64,9 @@ The core `fancy-3d` is engine-agnostic and lightweight (~80KB). Pulling in Babyl
|
|
|
62
64
|
## License
|
|
63
65
|
|
|
64
66
|
MIT
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## ⭐ Star Fancy UI
|
|
71
|
+
|
|
72
|
+
If this package is useful to you, a quick ⭐ on the repo really helps us build a better kit. Thank you!
|
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var math_color = require('@babylonjs/core/Maths/math.color');
|
|
4
|
+
var math_vector = require('@babylonjs/core/Maths/math.vector');
|
|
5
|
+
var dynamicTexture = require('@babylonjs/core/Materials/Textures/dynamicTexture');
|
|
6
|
+
var meshBuilder = require('@babylonjs/core/Meshes/meshBuilder');
|
|
7
|
+
var standardMaterial = require('@babylonjs/core/Materials/standardMaterial');
|
|
8
|
+
var mesh = require('@babylonjs/core/Meshes/mesh');
|
|
4
9
|
|
|
5
10
|
// src/index.ts
|
|
6
11
|
|
|
@@ -403,11 +408,11 @@ function autoPixelSize(worldWidth, worldHeight, density = DEFAULT_DENSITY) {
|
|
|
403
408
|
return { w, h };
|
|
404
409
|
}
|
|
405
410
|
function buildSurface(scene, name, surface, autoSize) {
|
|
406
|
-
const mat = new
|
|
407
|
-
mat.specularColor = new
|
|
411
|
+
const mat = new standardMaterial.StandardMaterial(`${name}-mat`, scene);
|
|
412
|
+
mat.specularColor = new math_color.Color3(0.05, 0.05, 0.05);
|
|
408
413
|
if (surface.type === "color") {
|
|
409
|
-
mat.diffuseColor =
|
|
410
|
-
mat.emissiveColor =
|
|
414
|
+
mat.diffuseColor = math_color.Color3.FromHexString(surface.color);
|
|
415
|
+
mat.emissiveColor = math_color.Color3.FromHexString(surface.color).scale(0.15);
|
|
411
416
|
return { material: mat, texture: null };
|
|
412
417
|
}
|
|
413
418
|
let w = surface.pixelWidth;
|
|
@@ -419,7 +424,7 @@ function buildSurface(scene, name, surface, autoSize) {
|
|
|
419
424
|
}
|
|
420
425
|
w = w ?? 512;
|
|
421
426
|
h = h ?? 512;
|
|
422
|
-
const tex = new
|
|
427
|
+
const tex = new dynamicTexture.DynamicTexture(`${name}-tex`, { width: w * TEX_SCALE, height: h * TEX_SCALE }, scene, true);
|
|
423
428
|
tex.vScale = -1;
|
|
424
429
|
tex.vOffset = 1;
|
|
425
430
|
if (surface.type === "paint" && surface.transparent) {
|
|
@@ -438,13 +443,13 @@ function buildSurface(scene, name, surface, autoSize) {
|
|
|
438
443
|
tex.update(false);
|
|
439
444
|
mat.diffuseTexture = tex;
|
|
440
445
|
mat.emissiveTexture = tex;
|
|
441
|
-
mat.emissiveColor = new
|
|
446
|
+
mat.emissiveColor = new math_color.Color3(0.6, 0.6, 0.6);
|
|
442
447
|
if (tex.hasAlpha) mat.useAlphaFromDiffuseTexture = true;
|
|
443
448
|
return { material: mat, texture: tex };
|
|
444
449
|
}
|
|
445
450
|
function createPanel(opts) {
|
|
446
451
|
const name = opts.name ?? "panel";
|
|
447
|
-
const m =
|
|
452
|
+
const m = meshBuilder.MeshBuilder.CreatePlane(name, { width: opts.width, height: opts.height, sideOrientation: opts.sideOrientation }, opts.scene);
|
|
448
453
|
const { material } = buildSurface(opts.scene, name, opts.surface, {
|
|
449
454
|
worldWidth: opts.width,
|
|
450
455
|
worldHeight: opts.height
|
|
@@ -455,7 +460,7 @@ function createPanel(opts) {
|
|
|
455
460
|
function createBillboard(opts) {
|
|
456
461
|
const m = createPanel({ ...opts, name: opts.name ?? "billboard" });
|
|
457
462
|
if (opts.faceCamera) {
|
|
458
|
-
m.billboardMode =
|
|
463
|
+
m.billboardMode = mesh.Mesh.BILLBOARDMODE_ALL;
|
|
459
464
|
}
|
|
460
465
|
return m;
|
|
461
466
|
}
|
|
@@ -463,7 +468,7 @@ var BOX_FACE_ORDER = ["front", "back", "right", "left", "top", "bottom"];
|
|
|
463
468
|
function createBuilding(opts) {
|
|
464
469
|
const name = opts.name ?? "building";
|
|
465
470
|
if (opts.surface && !opts.faces) {
|
|
466
|
-
const box2 =
|
|
471
|
+
const box2 = meshBuilder.MeshBuilder.CreateBox(name, { width: opts.width, height: opts.height, depth: opts.depth }, opts.scene);
|
|
467
472
|
const { material } = buildSurface(opts.scene, name, opts.surface, {
|
|
468
473
|
worldWidth: opts.width,
|
|
469
474
|
worldHeight: opts.height
|
|
@@ -475,7 +480,7 @@ function createBuilding(opts) {
|
|
|
475
480
|
const faceH = 256;
|
|
476
481
|
const atlasW = faceW * 3;
|
|
477
482
|
const atlasH = faceH * 2;
|
|
478
|
-
const tex = new
|
|
483
|
+
const tex = new dynamicTexture.DynamicTexture(`${name}-atlas`, { width: atlasW * TEX_SCALE, height: atlasH * TEX_SCALE }, opts.scene, true);
|
|
479
484
|
tex.vScale = -1;
|
|
480
485
|
tex.vOffset = 1;
|
|
481
486
|
const ctx = tex.getContext();
|
|
@@ -498,15 +503,15 @@ function createBuilding(opts) {
|
|
|
498
503
|
paintWidget(ctx, surface.widget, faceW, faceH, surface.selected ?? false);
|
|
499
504
|
}
|
|
500
505
|
ctx.restore();
|
|
501
|
-
faceUV.push(new
|
|
506
|
+
faceUV.push(new math_vector.Vector4(fx / atlasW, 1 - (fy + faceH) / atlasH, (fx + faceW) / atlasW, 1 - fy / atlasH));
|
|
502
507
|
});
|
|
503
508
|
tex.update(false);
|
|
504
|
-
const mat = new
|
|
509
|
+
const mat = new standardMaterial.StandardMaterial(`${name}-mat`, opts.scene);
|
|
505
510
|
mat.diffuseTexture = tex;
|
|
506
511
|
mat.emissiveTexture = tex;
|
|
507
|
-
mat.emissiveColor = new
|
|
508
|
-
mat.specularColor = new
|
|
509
|
-
const box =
|
|
512
|
+
mat.emissiveColor = new math_color.Color3(0.4, 0.4, 0.4);
|
|
513
|
+
mat.specularColor = new math_color.Color3(0.05, 0.05, 0.05);
|
|
514
|
+
const box = meshBuilder.MeshBuilder.CreateBox(name, {
|
|
510
515
|
width: opts.width,
|
|
511
516
|
height: opts.height,
|
|
512
517
|
depth: opts.depth,
|
|
@@ -528,7 +533,7 @@ function createPillar(opts) {
|
|
|
528
533
|
}
|
|
529
534
|
function createCylinder(opts) {
|
|
530
535
|
const name = opts.name ?? "cylinder";
|
|
531
|
-
const m =
|
|
536
|
+
const m = meshBuilder.MeshBuilder.CreateCylinder(name, {
|
|
532
537
|
diameter: opts.radius * 2,
|
|
533
538
|
height: opts.height,
|
|
534
539
|
tessellation: opts.tessellation ?? 48
|
|
@@ -545,13 +550,13 @@ function createCurvedPanel(opts) {
|
|
|
545
550
|
const radius = opts.width / opts.arc;
|
|
546
551
|
const tess = opts.tessellation ?? 48;
|
|
547
552
|
const fullCircleSegments = Math.max(8, Math.ceil(tess * (Math.PI * 2) / opts.arc));
|
|
548
|
-
const m =
|
|
553
|
+
const m = meshBuilder.MeshBuilder.CreateCylinder(name, {
|
|
549
554
|
diameter: radius * 2,
|
|
550
555
|
height: opts.height,
|
|
551
556
|
tessellation: fullCircleSegments,
|
|
552
557
|
arc: opts.arc / (Math.PI * 2),
|
|
553
|
-
cap:
|
|
554
|
-
sideOrientation:
|
|
558
|
+
cap: mesh.Mesh.NO_CAP,
|
|
559
|
+
sideOrientation: mesh.Mesh.DOUBLESIDE
|
|
555
560
|
}, opts.scene);
|
|
556
561
|
const { material } = buildSurface(opts.scene, name, opts.surface, {
|
|
557
562
|
worldWidth: opts.width,
|
|
@@ -562,7 +567,7 @@ function createCurvedPanel(opts) {
|
|
|
562
567
|
}
|
|
563
568
|
function createSphere(opts) {
|
|
564
569
|
const name = opts.name ?? "sphere";
|
|
565
|
-
const m =
|
|
570
|
+
const m = meshBuilder.MeshBuilder.CreateSphere(name, { diameter: opts.diameter, segments: opts.segments ?? 32 }, opts.scene);
|
|
566
571
|
const { material } = buildSurface(opts.scene, name, opts.surface, {
|
|
567
572
|
worldWidth: opts.diameter * Math.PI,
|
|
568
573
|
worldHeight: opts.diameter * Math.PI / 2
|
|
@@ -572,7 +577,7 @@ function createSphere(opts) {
|
|
|
572
577
|
}
|
|
573
578
|
function createDisc(opts) {
|
|
574
579
|
const name = opts.name ?? "disc";
|
|
575
|
-
const m =
|
|
580
|
+
const m = meshBuilder.MeshBuilder.CreateDisc(name, { radius: opts.radius, tessellation: opts.tessellation ?? 64 }, opts.scene);
|
|
576
581
|
const { material } = buildSurface(opts.scene, name, opts.surface, {
|
|
577
582
|
worldWidth: opts.radius * 2,
|
|
578
583
|
worldHeight: opts.radius * 2
|
|
@@ -605,7 +610,7 @@ function createSign(opts) {
|
|
|
605
610
|
const postHeight = opts.postHeight ?? 1.4;
|
|
606
611
|
const postThickness = opts.postThickness ?? 0.12;
|
|
607
612
|
const postColor = opts.postColor ?? "#1f2937";
|
|
608
|
-
const root = new
|
|
613
|
+
const root = new mesh.Mesh(`${name}-root`, opts.scene);
|
|
609
614
|
const panel = createBillboard({
|
|
610
615
|
scene: opts.scene,
|
|
611
616
|
name: `${name}-panel`,
|
|
@@ -613,16 +618,16 @@ function createSign(opts) {
|
|
|
613
618
|
height: opts.height,
|
|
614
619
|
surface: opts.surface
|
|
615
620
|
});
|
|
616
|
-
panel.position = new
|
|
621
|
+
panel.position = new math_vector.Vector3(0, postHeight + opts.height / 2, 0);
|
|
617
622
|
panel.parent = root;
|
|
618
|
-
const post =
|
|
623
|
+
const post = meshBuilder.MeshBuilder.CreateBox(`${name}-post`, {
|
|
619
624
|
width: postThickness,
|
|
620
625
|
height: postHeight,
|
|
621
626
|
depth: postThickness
|
|
622
627
|
}, opts.scene);
|
|
623
|
-
post.position = new
|
|
624
|
-
const postMat = new
|
|
625
|
-
postMat.diffuseColor =
|
|
628
|
+
post.position = new math_vector.Vector3(0, postHeight / 2, 0);
|
|
629
|
+
const postMat = new standardMaterial.StandardMaterial(`${name}-post-mat`, opts.scene);
|
|
630
|
+
postMat.diffuseColor = math_color.Color3.FromHexString(postColor);
|
|
626
631
|
post.material = postMat;
|
|
627
632
|
post.parent = root;
|
|
628
633
|
return { root, panel, post };
|
|
@@ -631,15 +636,15 @@ function createMonitor(opts) {
|
|
|
631
636
|
const name = opts.name ?? "monitor";
|
|
632
637
|
const depth = opts.depth ?? 0.18;
|
|
633
638
|
const bezelColor = opts.bezel ?? "#0b0f17";
|
|
634
|
-
const root = new
|
|
635
|
-
const body =
|
|
639
|
+
const root = new mesh.Mesh(`${name}-root`, opts.scene);
|
|
640
|
+
const body = meshBuilder.MeshBuilder.CreateBox(`${name}-body`, {
|
|
636
641
|
width: opts.width,
|
|
637
642
|
height: opts.height,
|
|
638
643
|
depth
|
|
639
644
|
}, opts.scene);
|
|
640
|
-
const bodyMat = new
|
|
641
|
-
bodyMat.diffuseColor =
|
|
642
|
-
bodyMat.specularColor = new
|
|
645
|
+
const bodyMat = new standardMaterial.StandardMaterial(`${name}-body-mat`, opts.scene);
|
|
646
|
+
bodyMat.diffuseColor = math_color.Color3.FromHexString(bezelColor);
|
|
647
|
+
bodyMat.specularColor = new math_color.Color3(0.08, 0.08, 0.08);
|
|
643
648
|
body.material = bodyMat;
|
|
644
649
|
body.parent = root;
|
|
645
650
|
const screenInset = 0.04;
|
|
@@ -654,16 +659,16 @@ function createMonitor(opts) {
|
|
|
654
659
|
front: opts.screen,
|
|
655
660
|
edge: { type: "color", color: bezelColor }
|
|
656
661
|
});
|
|
657
|
-
screen.position = new
|
|
662
|
+
screen.position = new math_vector.Vector3(0, 0, depth / 2 + 5e-3);
|
|
658
663
|
screen.parent = root;
|
|
659
664
|
let stand;
|
|
660
665
|
if (opts.standHeight && opts.standHeight > 0) {
|
|
661
|
-
stand =
|
|
666
|
+
stand = meshBuilder.MeshBuilder.CreateBox(`${name}-stand`, {
|
|
662
667
|
width: opts.width * 0.3,
|
|
663
668
|
height: opts.standHeight,
|
|
664
669
|
depth: depth * 1.5
|
|
665
670
|
}, opts.scene);
|
|
666
|
-
stand.position = new
|
|
671
|
+
stand.position = new math_vector.Vector3(0, -opts.height / 2 - opts.standHeight / 2, 0);
|
|
667
672
|
stand.material = bodyMat;
|
|
668
673
|
stand.parent = root;
|
|
669
674
|
}
|
|
@@ -671,9 +676,9 @@ function createMonitor(opts) {
|
|
|
671
676
|
}
|
|
672
677
|
function createDecal(opts) {
|
|
673
678
|
const name = opts.name ?? "decal";
|
|
674
|
-
const normal = opts.normal ?? new
|
|
675
|
-
const size = new
|
|
676
|
-
const decal =
|
|
679
|
+
const normal = opts.normal ?? new math_vector.Vector3(0, 0, -1);
|
|
680
|
+
const size = new math_vector.Vector3(opts.size.width, opts.size.height, opts.size.depth ?? 1);
|
|
681
|
+
const decal = meshBuilder.MeshBuilder.CreateDecal(name, opts.target, {
|
|
677
682
|
position: opts.position,
|
|
678
683
|
normal,
|
|
679
684
|
size,
|
|
@@ -690,7 +695,7 @@ function createDecal(opts) {
|
|
|
690
695
|
return decal;
|
|
691
696
|
}
|
|
692
697
|
function createWidgetTexture(scene, name, widget, pixelWidth, pixelHeight, selected = false) {
|
|
693
|
-
const tex = new
|
|
698
|
+
const tex = new dynamicTexture.DynamicTexture(name, { width: pixelWidth * TEX_SCALE, height: pixelHeight * TEX_SCALE }, scene, true);
|
|
694
699
|
tex.vScale = -1;
|
|
695
700
|
tex.vOffset = 1;
|
|
696
701
|
tex.hasAlpha = true;
|
|
@@ -711,11 +716,11 @@ function normalizedCenter(node, bounds) {
|
|
|
711
716
|
}
|
|
712
717
|
function placeOnGrid(node, mesh, bounds, opts = {}) {
|
|
713
718
|
const scale = opts.scale ?? 1 / 120;
|
|
714
|
-
const origin = opts.origin ?? new
|
|
719
|
+
const origin = opts.origin ?? new math_vector.Vector3(0, 0, 0);
|
|
715
720
|
const { w, h } = sizeOf(node);
|
|
716
721
|
const cx = node.position.x + w / 2 - (bounds.minX + bounds.maxX) / 2;
|
|
717
722
|
const cy = node.position.y + h / 2 - (bounds.minY + bounds.maxY) / 2;
|
|
718
|
-
mesh.position = new
|
|
723
|
+
mesh.position = new math_vector.Vector3(origin.x + cx * scale, origin.y - cy * scale, origin.z);
|
|
719
724
|
}
|
|
720
725
|
function placeOnWall(node, mesh, bounds, opts = {}) {
|
|
721
726
|
const spreadX = opts.spreadX ?? 10;
|
|
@@ -723,7 +728,7 @@ function placeOnWall(node, mesh, bounds, opts = {}) {
|
|
|
723
728
|
const centerY = opts.centerY ?? 1.5;
|
|
724
729
|
const z = opts.z ?? 0;
|
|
725
730
|
const { cx, cy } = normalizedCenter(node, bounds);
|
|
726
|
-
mesh.position = new
|
|
731
|
+
mesh.position = new math_vector.Vector3((cx - 0.5) * spreadX, centerY + (0.5 - cy) * spreadY, z);
|
|
727
732
|
mesh.rotation.y = 0;
|
|
728
733
|
}
|
|
729
734
|
function placeOnArc(node, mesh, bounds, opts = {}) {
|
|
@@ -733,19 +738,19 @@ function placeOnArc(node, mesh, bounds, opts = {}) {
|
|
|
733
738
|
const baseY = opts.baseY ?? 0;
|
|
734
739
|
const { cx, cy } = normalizedCenter(node, bounds);
|
|
735
740
|
const angle = (cx - 0.5) * arc;
|
|
736
|
-
mesh.position = new
|
|
741
|
+
mesh.position = new math_vector.Vector3(Math.sin(angle) * radius, baseY + (0.5 - cy) * height, Math.cos(angle) * radius);
|
|
737
742
|
mesh.rotation.y = angle;
|
|
738
743
|
}
|
|
739
744
|
function lerpPath(waypoints, t) {
|
|
740
|
-
if (waypoints.length === 0) return { pos: new
|
|
741
|
-
if (waypoints.length === 1) return { pos: waypoints[0].clone(), tangent: new
|
|
745
|
+
if (waypoints.length === 0) return { pos: new math_vector.Vector3(0, 0, 0), tangent: new math_vector.Vector3(0, 0, 1) };
|
|
746
|
+
if (waypoints.length === 1) return { pos: waypoints[0].clone(), tangent: new math_vector.Vector3(0, 0, 1) };
|
|
742
747
|
const segments = waypoints.length - 1;
|
|
743
748
|
const scaled = Math.max(0, Math.min(1, t)) * segments;
|
|
744
749
|
const i = Math.min(segments - 1, Math.floor(scaled));
|
|
745
750
|
const local = scaled - i;
|
|
746
751
|
const a = waypoints[i];
|
|
747
752
|
const b = waypoints[i + 1];
|
|
748
|
-
const pos =
|
|
753
|
+
const pos = math_vector.Vector3.Lerp(a, b, local);
|
|
749
754
|
const tangent = b.subtract(a).normalize();
|
|
750
755
|
return { pos, tangent };
|
|
751
756
|
}
|
|
@@ -768,7 +773,7 @@ function placeOnPath(node, mesh, bounds, opts) {
|
|
|
768
773
|
}
|
|
769
774
|
function placeOnSphere(node, mesh, bounds, opts = {}) {
|
|
770
775
|
const radius = opts.radius ?? 5;
|
|
771
|
-
const center = opts.center ?? new
|
|
776
|
+
const center = opts.center ?? new math_vector.Vector3(0, 0, 0);
|
|
772
777
|
const latSpan = opts.latSpan ?? Math.PI * 0.7;
|
|
773
778
|
const lonSpan = opts.lonSpan ?? Math.PI * 2;
|
|
774
779
|
const { cx, cy } = normalizedCenter(node, bounds);
|
|
@@ -778,7 +783,7 @@ function placeOnSphere(node, mesh, bounds, opts = {}) {
|
|
|
778
783
|
const x = r * Math.cos(lat) * Math.sin(lon);
|
|
779
784
|
const y = r * Math.sin(lat);
|
|
780
785
|
const z = r * Math.cos(lat) * Math.cos(lon);
|
|
781
|
-
mesh.position = new
|
|
786
|
+
mesh.position = new math_vector.Vector3(center.x + x, center.y + y, center.z + z);
|
|
782
787
|
mesh.rotation.y = lon;
|
|
783
788
|
}
|
|
784
789
|
|
|
@@ -788,7 +793,7 @@ function createBabylonAdapter(deps) {
|
|
|
788
793
|
return {
|
|
789
794
|
render(spec, ctx) {
|
|
790
795
|
const { w, h } = deps.sizeFor(spec);
|
|
791
|
-
const tex = new
|
|
796
|
+
const tex = new dynamicTexture.DynamicTexture(`tex-${ctx.nodeId}`, { width: w * TEX_SCALE, height: h * TEX_SCALE }, deps.scene3D, true);
|
|
792
797
|
tex.hasAlpha = true;
|
|
793
798
|
tex.vScale = -1;
|
|
794
799
|
tex.vOffset = 1;
|
|
@@ -796,13 +801,13 @@ function createBabylonAdapter(deps) {
|
|
|
796
801
|
c.scale(TEX_SCALE, TEX_SCALE);
|
|
797
802
|
paintWidget(c, spec, w, h, ctx.selected);
|
|
798
803
|
tex.update(false);
|
|
799
|
-
const mat = new
|
|
804
|
+
const mat = new standardMaterial.StandardMaterial(`mat-${ctx.nodeId}`, deps.scene3D);
|
|
800
805
|
mat.diffuseTexture = tex;
|
|
801
806
|
mat.emissiveTexture = tex;
|
|
802
|
-
mat.emissiveColor = new
|
|
807
|
+
mat.emissiveColor = new math_color.Color3(1, 1, 1);
|
|
803
808
|
mat.disableLighting = false;
|
|
804
809
|
mat.useAlphaFromDiffuseTexture = true;
|
|
805
|
-
const plane =
|
|
810
|
+
const plane = meshBuilder.MeshBuilder.CreatePlane(`node-${ctx.nodeId}`, { width: w * WORLD_SCALE, height: h * WORLD_SCALE }, deps.scene3D);
|
|
806
811
|
plane.material = mat;
|
|
807
812
|
plane.metadata = { nodeId: ctx.nodeId, kind: spec.kind };
|
|
808
813
|
return plane;
|
|
@@ -818,8 +823,8 @@ function placeOnCylinder(node, mesh, bounds, opts = {}) {
|
|
|
818
823
|
const cy = (node.position.y + (node.size?.h ?? 120) / 2 - bounds.minY) / rangeY;
|
|
819
824
|
const angle = (cx - 0.5) * arc;
|
|
820
825
|
const height = (0.5 - cy) * 6;
|
|
821
|
-
mesh.position = new
|
|
822
|
-
mesh.rotation = new
|
|
826
|
+
mesh.position = new math_vector.Vector3(Math.sin(angle) * radius, height, Math.cos(angle) * radius);
|
|
827
|
+
mesh.rotation = new math_vector.Vector3(0, angle, 0);
|
|
823
828
|
}
|
|
824
829
|
function sceneBounds(scene) {
|
|
825
830
|
const xs = scene.nodes.map((n) => n.position.x);
|