Updated Physics.

This commit is contained in:
Michael Mainguy 2023-07-31 16:01:06 -05:00
parent 2df01efdcc
commit cdefd3bb70
8 changed files with 250 additions and 119 deletions

32
package-lock.json generated
View File

@ -10,10 +10,10 @@
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@auth0/auth0-spa-js": "^2.0.8", "@auth0/auth0-spa-js": "^2.0.8",
"@babylonjs/core": "^6.12.3", "@babylonjs/core": "^6.14.0",
"@babylonjs/gui": "^6.12.3", "@babylonjs/gui": "^6.14.0",
"@babylonjs/havok": "^1.1.0", "@babylonjs/havok": "1.1.1",
"@babylonjs/inspector": "^6.12.3", "@babylonjs/inspector": "^6.14.0",
"@maptiler/client": "^1.5.0", "@maptiler/client": "^1.5.0",
"axios": "^1.4.0", "axios": "^1.4.0",
"dexie": "^3.2.4", "dexie": "^3.2.4",
@ -53,14 +53,14 @@
} }
}, },
"node_modules/@babylonjs/core": { "node_modules/@babylonjs/core": {
"version": "6.12.3", "version": "6.14.0",
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.12.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.14.0.tgz",
"integrity": "sha512-p1di605M2Pa5+YiHbydGJ3PA4nUWSlmu79agL3mcsq7s8zC5VN/HaK1uNSicYI9LhVfPF6bDsVGHqCXxEkRsFQ==" "integrity": "sha512-ciIfWMMtV5jsnqxqTn+v/CS65yji6CXTP2drmvLlzk+k+IZjE8RfkpMqZgZozN/KNkOmIVn2Li7qRMjg4ZUGlw=="
}, },
"node_modules/@babylonjs/gui": { "node_modules/@babylonjs/gui": {
"version": "6.12.3", "version": "6.14.0",
"resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.12.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.14.0.tgz",
"integrity": "sha512-Yh9rVWwAymjy23g8dC5PMjeI2c71HWMZ6Lw2G0yjTZS9gf0st2A/OLsv/4ofK51u0fqvHZFBTfFTL5ZOFYNMow==", "integrity": "sha512-rkqPEVDaeza4agyd5xSLSjnWgI1spqcNI/kmNke4gREmweEcZZFxNxjGQd5m/JQMbx7qrj9jtEp8COZ7wNSiWw==",
"peerDependencies": { "peerDependencies": {
"@babylonjs/core": "^6.0.0" "@babylonjs/core": "^6.0.0"
} }
@ -78,17 +78,17 @@
} }
}, },
"node_modules/@babylonjs/havok": { "node_modules/@babylonjs/havok": {
"version": "1.1.0", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.1.1.tgz",
"integrity": "sha512-BNo2d+gfkoCbbEGYOVZgdPWG6NRdo5Tjvd9rpjMs0sWV/EaKQ6kL8hnJUn+HVZx4hdyKrTkq8ThTGFt/nTediA==", "integrity": "sha512-QIygEnKPYYPCE8QuJDxDLYPMj+W5Yha6NOdUfpvcVfZwtjVDE+eOa2Y5el7muQD563OdeJS+Kzmhyg+5qAZHBA==",
"dependencies": { "dependencies": {
"@types/emscripten": "^1.39.6" "@types/emscripten": "^1.39.6"
} }
}, },
"node_modules/@babylonjs/inspector": { "node_modules/@babylonjs/inspector": {
"version": "6.12.3", "version": "6.14.0",
"resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.12.3.tgz", "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.14.0.tgz",
"integrity": "sha512-REW+BF4LQhOK0cRRTVfSaOGnjh1LVE1lgwel7BBjjWeRcIjCVBimAprPY8rE0K+EAGMmPlxt9rDIpGoA0PUTqQ==", "integrity": "sha512-8wntNbVb9Yhj0q8Ll4kFGDDJPHk7IeosqVwXTPToTfDYC67pwkVQFXFViEXr1R0HrG0l1FmZzPVLY6szbFSwrw==",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.0", "@fortawesome/fontawesome-svg-core": "^6.1.0",
"@fortawesome/free-regular-svg-icons": "^6.0.0", "@fortawesome/free-regular-svg-icons": "^6.0.0",

View File

@ -12,10 +12,10 @@
"postinstall": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps" "postinstall": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
}, },
"dependencies": { "dependencies": {
"@babylonjs/core": "^6.12.3", "@babylonjs/core": "^6.14.0",
"@babylonjs/gui": "^6.12.3", "@babylonjs/gui": "^6.14.0",
"@babylonjs/havok": "^1.1.0", "@babylonjs/havok": "1.1.1",
"@babylonjs/inspector": "^6.12.3", "@babylonjs/inspector": "^6.14.0",
"express": "^4.18.2", "express": "^4.18.2",
"@auth0/auth0-spa-js": "^2.0.8", "@auth0/auth0-spa-js": "^2.0.8",
"ring-client-api": "^11.8.0", "ring-client-api": "^11.8.0",

View File

@ -40,7 +40,7 @@ export class App {
constructor() { constructor() {
const config = AppConfig.config; const config = AppConfig.config;
log.setLevel('debug'); log.setLevel('warn');
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
canvas.style.width = "100%"; canvas.style.width = "100%";
canvas.style.height = "100%"; canvas.style.height = "100%";

View File

@ -1,6 +1,11 @@
import { import {
AbstractMesh, AbstractMesh,
HavokPlugin,
PhysicsAggregate,
PhysicsMotionType,
PhysicsShapeType,
Scene, Scene,
TransformNode,
Vector3, Vector3,
WebXRControllerComponent, WebXRControllerComponent,
WebXRDefaultExperience, WebXRDefaultExperience,
@ -20,7 +25,8 @@ export class Base {
protected speedFactor = 4; protected speedFactor = 4;
protected readonly scene: Scene; protected readonly scene: Scene;
protected grabbedMesh: AbstractMesh = null; protected grabbedMesh: AbstractMesh = null;
protected previousParent: string = null; protected grabbedMeshParentId: string = null;
protected previousParentId: string = null;
protected previousRotation: Vector3 = null; protected previousRotation: Vector3 = null;
protected previousScaling: Vector3 = null; protected previousScaling: Vector3 = null;
protected previousPosition: Vector3 = null; protected previousPosition: Vector3 = null;
@ -28,6 +34,8 @@ export class Base {
protected readonly xr: WebXRDefaultExperience; protected readonly xr: WebXRDefaultExperience;
protected readonly diagramManager: DiagramManager; protected readonly diagramManager: DiagramManager;
private logger: log.Logger; private logger: log.Logger;
private lastPosition: Vector3 = null;
constructor(controller: WebXRInputSource, constructor(controller: WebXRInputSource,
scene: Scene, scene: Scene,
xr: WebXRDefaultExperience, xr: WebXRDefaultExperience,
@ -36,8 +44,33 @@ export class Base {
this.controller = controller; this.controller = controller;
this.scene = scene; this.scene = scene;
this.scene.onAfterRenderObservable.add(() => {
}, -1, false, this);
this.scene.onBeforeRenderObservable.add(() => {
if (this?.grabbedMesh?.physicsBody) {
const hk = (this.scene.getPhysicsEngine().getPhysicsPlugin() as HavokPlugin);
this.lastPosition = this?.grabbedMesh?.physicsBody?.transformNode.absolutePosition.clone();
if (this.grabbedMeshParentId) {
const parent = this.scene.getTransformNodeById(this.grabbedMeshParentId);
if (parent) {
hk.setPhysicsBodyTransformation(this.grabbedMesh.physicsBody, parent);
hk.sync(this.grabbedMesh.physicsBody);
} else {
this.logger.error("parent not found for " + this.grabbedMeshParentId);
}
} else {
this.logger.warn("no parent id");
}
}
}, -1, false, this);
this.xr = xr; this.xr = xr;
this.diagramManager = diagramManager; this.diagramManager = diagramManager;
this.controller.onMotionControllerInitObservable.add((init) => { this.controller.onMotionControllerInitObservable.add((init) => {
if (init.components['xr-standard-trigger']) { if (init.components['xr-standard-trigger']) {
init.components['xr-standard-trigger'] init.components['xr-standard-trigger']
@ -69,11 +102,12 @@ export class Base {
this.controller.pointer.setEnabled(true); this.controller.pointer.setEnabled(true);
} }
private initGrip(grip: WebXRControllerComponent) { private buildTransformNode() {
grip.onButtonStateChangedObservable.add(() => {
if (grip.changes.pressed) { }
if (grip.pressed) {
let mesh = this.scene.meshUnderPointer; private grab(mesh) {
if (this.xr.pointerSelection.getMeshUnderPointer) { if (this.xr.pointerSelection.getMeshUnderPointer) {
mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId); mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId);
} }
@ -81,7 +115,7 @@ export class Base {
return; return;
} }
if (!mesh?.metadata?.template) { if (!mesh?.metadata?.template) {
if (mesh.id == "handle") { if (mesh?.id == "handle") {
mesh && mesh.setParent(this.controller.motionController.rootMesh); mesh && mesh.setParent(this.controller.motionController.rootMesh);
this.grabbedMesh = mesh; this.grabbedMesh = mesh;
} else { } else {
@ -89,81 +123,155 @@ export class Base {
} }
} }
this.previousParent = mesh?.parent?.id; this.previousParentId = mesh?.parent?.id;
this.previousRotation = mesh?.rotation.clone(); this.previousRotation = mesh?.rotation.clone();
this.previousScaling = mesh?.scaling.clone(); this.previousScaling = mesh?.scaling.clone();
this.previousPosition = mesh?.position.clone(); this.previousPosition = mesh?.position.clone();
if ("toolbox" != mesh?.parent?.parent?.id) { if ("toolbox" != mesh?.parent?.parent?.id) {
mesh && mesh.setParent(this.controller.motionController.rootMesh); if (mesh.physicsBody) {
const transformNode = new TransformNode("grabAnchor, this.scene");
transformNode.id = "grabAnchor";
transformNode.position = mesh.position.clone();
transformNode.rotationQuaternion = mesh.rotationQuaternion.clone();
transformNode.setParent(this.controller.motionController.rootMesh);
mesh.physicsBody.setMotionType(PhysicsMotionType.STATIC);
//mesh.setParent(transformNode);
this.grabbedMeshParentId = transformNode.id;
} else {
mesh.setParent(this.controller.motionController.rootMesh);
}
this.grabbedMesh = mesh; this.grabbedMesh = mesh;
} else { } else {
const config = AppConfig.config; const config = AppConfig.config;
const newMesh = this.diagramManager.createCopy(mesh); const newMesh = this.diagramManager.createCopy(mesh);
newMesh.position = mesh.absolutePosition.clone(); newMesh.position = mesh.absolutePosition.clone();
if (mesh.absoluteRotationQuaternion) {
newMesh.rotation = mesh.absoluteRotationQuaternion.toEulerAngles().clone(); newMesh.rotation = mesh.absoluteRotationQuaternion.toEulerAngles().clone();
} else {
newMesh.rotation = mesh.absoluteRotation.clone();
}
newMesh.scaling = config.createSnapVal; newMesh.scaling = config.createSnapVal;
newMesh.material = mesh.material; newMesh.material = mesh.material;
newMesh.metadata = mesh.metadata; newMesh.metadata = mesh.metadata;
newMesh && newMesh.setParent(this.controller.motionController.rootMesh); const transformNode = new TransformNode("grabAnchor, this.scene");
transformNode.id = "grabAnchor";
transformNode.position = newMesh.position.clone();
if (newMesh.rotationQuaternion) {
transformNode.rotationQuaternion = newMesh.rotationQuaternion.clone();
} else {
transformNode.rotation = newMesh.rotation.clone();
}
transformNode.setParent(this.controller.motionController.rootMesh);
//newMesh?.physicsBody?.setMotionType(PhysicsMotionType.STATIC);
//mesh.setParent(transformNode);
this.grabbedMeshParentId = transformNode.id;
const aggregate = new PhysicsAggregate(newMesh,
PhysicsShapeType.BOX, {mass: 10, restitution: .1, friction: .9}, this.scene);
aggregate.body.setMotionType(PhysicsMotionType.STATIC);
//newMesh && newMesh.setParent(this.controller.motionController.rootMesh);
this.grabbedMesh = newMesh;
this.previousParentId = null;
const event: DiagramEvent = { const event: DiagramEvent = {
type: DiagramEventType.ADD, type: DiagramEventType.ADD,
entity: MeshConverter.toDiagramEntity(newMesh) entity: MeshConverter.toDiagramEntity(newMesh)
} }
this.diagramManager.onDiagramEventObservable.notifyObservers(event); this.diagramManager.onDiagramEventObservable.notifyObservers(event);
this.grabbedMesh = newMesh;
this.previousParent = null;
} }
} else {
let mesh = this.scene.meshUnderPointer;
if (this.xr.pointerSelection.getMeshUnderPointer) {
mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId);
} }
if (!this.grabbedMesh) {
log.debug("controllers", "no grabbed mesh"); private handleGrabbed(mesh: AbstractMesh): boolean {
return; if (!mesh?.metadata?.template
} && mesh?.id == "handle") {
if (mesh?.id != this?.grabbedMesh?.id) { //mesh && mesh.setParent(null);
log.debug("controllers", "not the same mesh");
}
mesh = this.grabbedMesh;
if (!mesh?.metadata?.template) {
if (mesh.id == "handle") {
mesh && mesh.setParent(null);
this.grabbedMesh = null; this.grabbedMesh = null;
this.previousParent = null; this.previousParentId = null;
return; mesh.setParent(null);
return true;
} else {
return false;
} }
} }
private reparent(mesh: AbstractMesh) {
const config = AppConfig.config; const config = AppConfig.config;
const snappedRotation = config.snapRotateVal(mesh.absoluteRotationQuaternion.toEulerAngles().clone()); const snappedRotation = config.snapRotateVal(mesh.absoluteRotationQuaternion.toEulerAngles().clone());
const snappedPosition = config.snapGridVal(mesh.absolutePosition.clone()); const snappedPosition = config.snapGridVal(mesh.absolutePosition.clone());
if (this.previousParent) {
const p = this.scene.getMeshById(this.previousParent); if (this.previousParentId) {
if (p) { const parent = this.scene.getMeshById(this.previousParentId);
mesh && mesh.setParent(this.scene.getMeshById(this.previousParent)); if (parent) {
//mesh && mesh.setParent(this.scene.getMeshById(this.previousParentId));
log.getLogger("Base").warn("Base", "Have not implemented snapping to parent yet"); log.getLogger("Base").warn("Base", "Have not implemented snapping to parent yet");
//@note: this is not implemented yet //@note: this is not implemented yet
} else { } else {
mesh && mesh.setParent(null); //mesh.setParent(null);
mesh.rotation = snappedRotation; mesh.rotation = snappedRotation;
mesh.position = snappedPosition; mesh.position = snappedPosition;
mesh?.physicsBody?.setMotionType(PhysicsMotionType.DYNAMIC);
} }
} else { } else {
mesh && mesh.setParent(null); const parent = this.scene.getTransformNodeById(this.grabbedMeshParentId);
mesh.rotation = snappedRotation; if (parent) {
mesh.position = snappedPosition; parent.rotation = snappedRotation;
parent.position = snappedPosition;
this.grabbedMeshParentId = null;
parent.dispose();
} }
}
}
private drop() {
const mesh = this.grabbedMesh;
if (!mesh) {
return;
}
if (this.handleGrabbed(mesh)) {
return;
}
this.reparent(mesh);
this.previousParentId = null;
this.previousScaling = null;
this.previousRotation = null;
this.previousPosition = null;
this.grabbedMesh = null;
const entity = MeshConverter.toDiagramEntity(mesh); const entity = MeshConverter.toDiagramEntity(mesh);
const event: DiagramEvent = { const event: DiagramEvent = {
type: DiagramEventType.DROP, type: DiagramEventType.DROP,
entity: entity entity: entity
} }
this.previousParent = null;
this.previousScaling = null;
this.previousRotation = null;
this.previousPosition = null;
this.diagramManager.onDiagramEventObservable.notifyObservers(event); this.diagramManager.onDiagramEventObservable.notifyObservers(event);
const body = mesh?.physicsBody;
if (body) {
body.setMotionType(PhysicsMotionType.DYNAMIC);
this.logger.debug(body.transformNode.absolutePosition);
this.logger.debug(this.lastPosition);
if (this.lastPosition) {
body.setLinearVelocity(body.transformNode.absolutePosition.subtract(this.lastPosition).scale(20));
//body.setLinearVelocity(this.lastPosition.subtract(body.transformNode.absolutePosition).scale(20));
this.logger.debug(this.lastPosition.subtract(body.transformNode.absolutePosition).scale(20));
}
}
}
private initGrip(grip: WebXRControllerComponent) {
grip.onButtonStateChangedObservable.add(() => {
if (grip.changes.pressed) {
if (grip.pressed) {
this.grab(this.scene.meshUnderPointer);
} else {
this.drop();
} }
} }
}); });

View File

@ -35,6 +35,7 @@ export class Rigplatform {
private camera: Camera; private camera: Camera;
private turning: boolean = false; private turning: boolean = false;
private velocity: Vector3 = Vector3.Zero(); private velocity: Vector3 = Vector3.Zero();
private logger = log.getLogger('Rigplatform');
private readonly diagramManager: DiagramManager; private readonly diagramManager: DiagramManager;
constructor(scene: Scene, xr: WebXRDefaultExperience, diagramManager: DiagramManager) { constructor(scene: Scene, xr: WebXRDefaultExperience, diagramManager: DiagramManager) {
@ -74,7 +75,10 @@ export class Rigplatform {
} }
private registerVelocityObserver() { private registerVelocityObserver() {
this.scene.onBeforeRenderObservable.add(() => { this.scene.onBeforeRenderObservable.add(() => {
const vel = this.velocity.applyRotationQuaternion(this.camera.absoluteRotation); const vel = this.velocity.applyRotationQuaternion(this.scene.activeCamera.absoluteRotation);
if (vel.length() > 0) {
this.logger.debug('Velocity', this.velocity, vel, this.scene.activeCamera.absoluteRotation);
}
this.body.setLinearVelocity(vel); this.body.setLinearVelocity(vel);
}); });
} }

View File

@ -6,6 +6,9 @@ import {
InstancedMesh, InstancedMesh,
Mesh, Mesh,
Observable, Observable,
PhysicsAggregate,
PhysicsMotionType,
PhysicsShapeType,
PlaySoundAction, PlaySoundAction,
Scene, Scene,
WebXRExperienceHelper WebXRExperienceHelper
@ -88,6 +91,9 @@ export class DiagramManager {
if (event.parent) { if (event.parent) {
mesh.parent = this.scene.getMeshById(event.parent); mesh.parent = this.scene.getMeshById(event.parent);
} }
const body = new PhysicsAggregate(mesh, PhysicsShapeType.BOX, {mass: 10, restitution: .1}, this.scene);
body.body.setMotionType(PhysicsMotionType.DYNAMIC);
} }
private onDiagramEvent(event: DiagramEvent) { private onDiagramEvent(event: DiagramEvent) {
@ -97,6 +103,8 @@ export class DiagramManager {
if (entity) { if (entity) {
mesh = this.scene.getMeshById(entity.id); mesh = this.scene.getMeshById(entity.id);
} }
//const body = mesh?.physicsBody;
switch (event.type) { switch (event.type) {
case DiagramEventType.CLEAR: case DiagramEventType.CLEAR:
break; break;
@ -105,9 +113,11 @@ export class DiagramManager {
case DiagramEventType.DROP: case DiagramEventType.DROP:
this.getPersistenceManager()?.modify(mesh); this.getPersistenceManager()?.modify(mesh);
MeshConverter.updateTextNode(mesh, entity.text); MeshConverter.updateTextNode(mesh, entity.text);
break; break;
case DiagramEventType.ADD: case DiagramEventType.ADD:
this.getPersistenceManager()?.add(mesh); this.getPersistenceManager()?.add(mesh);
break; break;
case DiagramEventType.MODIFY: case DiagramEventType.MODIFY:
this.getPersistenceManager()?.modify(mesh); this.getPersistenceManager()?.modify(mesh);
@ -134,7 +144,9 @@ export class DiagramManager {
case DiagramEventType.REMOVE: case DiagramEventType.REMOVE:
if (mesh) { if (mesh) {
this.getPersistenceManager()?.remove(mesh) this.getPersistenceManager()?.remove(mesh)
mesh?.physicsBody?.dispose();
mesh.dispose(); mesh.dispose();
DiaSounds.instance.exit.play();
} }
break; break;
} }

View File

@ -16,6 +16,7 @@ import log from "loglevel";
import {InputTextView} from "../information/inputTextView"; import {InputTextView} from "../information/inputTextView";
import {Right} from "../controllers/right"; import {Right} from "../controllers/right";
import {Left} from "../controllers/left"; import {Left} from "../controllers/left";
import {DiaSounds} from "../util/diaSounds";
export class EditMenu { export class EditMenu {
private state: BmenuState = BmenuState.NONE; private state: BmenuState = BmenuState.NONE;
@ -180,9 +181,12 @@ export class EditMenu {
toggle() { toggle() {
//console.log(mesh.name); //console.log(mesh.name);
if (this.manager) { if (this.manager) {
DiaSounds.instance.exit.play();
this.manager.dispose(); this.manager.dispose();
this.manager = null; this.manager = null;
} else { } else {
DiaSounds.instance.enter.play();
this.manager = new GUI3DManager(this.scene); this.manager = new GUI3DManager(this.scene);
const panel = new StackPanel3D(); const panel = new StackPanel3D();
this.manager.addControl(panel); this.manager.addControl(panel);
@ -196,6 +200,7 @@ export class EditMenu {
this.scene.activeCamera.globalPosition.add(offset); this.scene.activeCamera.globalPosition.add(offset);
panel.node.lookAt(this.scene.activeCamera.globalPosition); panel.node.lookAt(this.scene.activeCamera.globalPosition);
panel.node.rotation.y = panel.node.rotation.y + Math.PI; panel.node.rotation.y = panel.node.rotation.y + Math.PI;
} }
} }

View File

@ -51,16 +51,18 @@ export class Toolbox {
this.manager.addControl(this.addPanel); this.manager.addControl(this.addPanel);
this.node = new TransformNode("toolbox", this.scene); this.node = new TransformNode("toolbox", this.scene);
const handle = MeshBuilder.CreateCapsule("handle", { const handle = MeshBuilder.CreateCapsule("handle", {
radius: .01, radius: .05,
orientation: Vector3.Right(), orientation: Vector3.Right(),
height: .3 height: .4
}, this.scene); }, this.scene);
handle.id = "handle"; handle.id = "handle";
const handleMaterial = new StandardMaterial("handle-material", this.scene); const handleMaterial = new StandardMaterial("handle-material", this.scene);
handleMaterial.diffuseColor = Color3.FromHexString("#EEEEFF"); handleMaterial.diffuseColor = Color3.FromHexString("#EEEEFF");
handleMaterial.alpha = .5;
handle.material = handleMaterial; handle.material = handleMaterial;
handle.position = CameraHelper.getFrontPosition(2, this.scene); handle.position = CameraHelper.getFrontPosition(2, this.scene);
handle.position.y = 1.6; handle.position.y = 1.6;
this.node.parent = handle; this.node.parent = handle;
this.xr = xr; this.xr = xr;
if (!this.scene.activeCamera) { if (!this.scene.activeCamera) {
@ -73,14 +75,14 @@ export class Toolbox {
} }
private buildToolbox() { private buildToolbox() {
this.node.position.y = -.2; this.node.position.y = .1;
this.node.scaling= new Vector3(0.5, 0.5, 0.5); this.node.scaling = new Vector3(0.6, 0.6, 0.6);
const color = "#7777FF"; const color = "#7777FF";
this.buildColor(Color3.FromHexString(color)); this.buildColor(Color3.FromHexString(color));
const addButton= new Button3D("add-button"); const addButton = new Button3D("add-button");
const text = new TextBlock("add-button-text", "Add Color"); const text = new TextBlock("add-button-text", "Add Color");
text.color="white"; text.color = "white";
text.fontSize = "48px"; text.fontSize = "48px";
text.text = "Add Color"; text.text = "Add Color";
addButton.content = text; addButton.content = text;