Skip to content

Commit af16f2e

Browse files
added hex house concept docs
1 parent 2b95f76 commit af16f2e

17 files changed

Lines changed: 2189 additions & 508 deletions

File tree

docs/learn/npm-packages/babylonjs/hex-house-concept.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ In this related video tutorial you can see how the results of this app look like
2929
</iframe>
3030
</div>
3131

32-
<Admonition type="info" title="Note on tutorial">
32+
<Admonition type="info" title="Note on video tutorial">
3333
<p>This tutorial originally used the Three.js game engine, but rest assured—the geometry creation logic maps directly (1:1) to what we've built in Babylon.js. See the StackBlitz example below for reference.</p>
3434
<p>
3535
While the original tutorial was based on a somewhat outdated app structure, we've provided a more modern and well-organized version here. You can also use this scaffold as a starting point for your own projects.

docs/learn/npm-packages/threejs/hex-house-concept.md

Lines changed: 609 additions & 0 deletions
Large diffs are not rendered by default.

examples/vite/threejs/hex-building/index.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>Bitbybit & ThreeJS CAD Example</title>
7+
<title>Bitbybit & ThreeJS Hex House Concept Demo</title>
88
</head>
99
<body>
1010
<a
@@ -18,8 +18,10 @@
1818
src="https://bitbybit.dev/assets/logo-gold-small.png"
1919
/>
2020
<div>bitbybit.dev</div>
21+
<br />
22+
<div>support the mission - subscribe</div>
2123
</a>
22-
<div id="app"></div>
24+
<canvas id="three-canvas"> </canvas>
2325
<script type="module" src="/src/main.ts"></script>
2426
</body>
2527
</html>

examples/vite/threejs/hex-building/package-lock.json

Lines changed: 1015 additions & 210 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import GUI from "lil-gui";
2+
import type { Current, Model } from "../models";
3+
import type { Mesh, MeshPhongMaterial } from "three";
4+
5+
export const createGui = (
6+
current: Current,
7+
model: Model,
8+
updateShape: () => void
9+
) => {
10+
model.update = () => updateShape();
11+
const gui = new GUI();
12+
current.gui = gui;
13+
gui.$title.innerHTML = "Pattern";
14+
15+
gui
16+
.add(model, "uHex", 5, 81, 4)
17+
.name("Hexagons U")
18+
.onFinishChange((value: number) => {
19+
model.uHex = value;
20+
updateShape();
21+
});
22+
23+
gui
24+
.add(model, "vHex", 5, 12, 1)
25+
.name("Hexagons V")
26+
.onFinishChange((value: number) => {
27+
model.vHex = value;
28+
updateShape();
29+
});
30+
31+
gui
32+
.add(model, "drawEdges")
33+
.name("Draw Edges")
34+
.onFinishChange((value: boolean) => {
35+
model.drawEdges = value;
36+
updateShape();
37+
});
38+
39+
gui
40+
.add(model, "drawFaces")
41+
.name("Draw Faces")
42+
.onFinishChange((value: boolean) => {
43+
model.drawFaces = value;
44+
updateShape();
45+
});
46+
47+
gui
48+
.addColor(model, "color")
49+
.name("Color")
50+
.onChange((value: string) => {
51+
let children: Mesh[] = [];
52+
if (current.groups) {
53+
children = current.groups[0].children[0].children as Mesh[];
54+
}
55+
[...children, current.ground].forEach((child) => {
56+
const material = (child as Mesh).material as MeshPhongMaterial;
57+
material.color.setHex(parseInt(value.replace("#", "0x")));
58+
});
59+
});
60+
61+
gui.add(model, "downloadSTL").name("Download STL");
62+
gui.add(model, "downloadStep").name("Download STEP");
63+
gui.add(model, "downloadGLB").name("Download GLTF");
64+
};

examples/vite/threejs/hex-building/src/create-shape.ts renamed to examples/vite/threejs/hex-building/src/helpers/create-shape.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import type { BitByBitBase } from '@bitbybit-dev/threejs';
2-
import { Color, MeshPhongMaterial, Scene } from 'three';
3-
import { Inputs } from '@bitbybit-dev/threejs';
4-
import type { Current } from './models/current';
5-
import type { Model } from './models/model';
1+
import type { BitByBitBase } from "@bitbybit-dev/threejs";
2+
import { Inputs } from "@bitbybit-dev/threejs";
3+
import { Color, MeshPhongMaterial, Scene } from "three";
4+
import type { Current, Model } from "../models";
65

76
export const createShape = async (
87
bitbybit: BitByBitBase | undefined,
@@ -115,14 +114,14 @@ export const createShape = async (
115114

116115
const roof = await createHexagonsRoof(
117116
faceRoof,
118-
model.uRec,
119-
model.vRec,
117+
model.uHex,
118+
model.vHex,
120119
bitbybit
121120
);
122121
const wall = await createHexagonsWalls(
123122
faceWall,
124-
model.uRec,
125-
Math.ceil(model.vRec / 2),
123+
model.uHex,
124+
Math.ceil(model.vHex / 2),
126125
bitbybit
127126
);
128127
const wallExtrude = await operations.extrude({
@@ -160,7 +159,7 @@ export const createShape = async (
160159
options.precision = 0.19;
161160
options.drawEdges = model.drawEdges;
162161
options.drawFaces = model.drawFaces;
163-
options.edgeColour = '#000000';
162+
options.edgeColour = "#000000";
164163

165164
const mat1 = new MeshPhongMaterial({ color: new Color(model.color) });
166165
mat1.polygonOffset = true;
@@ -173,7 +172,7 @@ export const createShape = async (
173172
options,
174173
});
175174

176-
const mat2 = new MeshPhongMaterial({ color: new Color(0x010012) });
175+
const mat2 = new MeshPhongMaterial({ color: new Color(0x0000ff) });
177176
mat2.polygonOffset = true;
178177
mat2.polygonOffsetFactor = 1;
179178
mat2.side = 2;
@@ -184,7 +183,7 @@ export const createShape = async (
184183
options,
185184
});
186185

187-
const mat3 = new MeshPhongMaterial({ color: new Color(0x010010) });
186+
const mat3 = new MeshPhongMaterial({ color: new Color(0x3300ff) });
188187
mat3.polygonOffset = true;
189188
mat3.polygonOffsetFactor = 1;
190189
mat3.side = 2;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import type { BitByBitBase, Inputs } from "@bitbybit-dev/threejs";
2+
import type { Scene } from "three";
3+
import { STLExporter } from "three/examples/jsm/exporters/STLExporter";
4+
import { GLTFExporter } from "three/examples/jsm/exporters/GLTFExporter";
5+
6+
export const downloadStep = async (
7+
bitbybit: BitByBitBase,
8+
finalShape: Inputs.OCCT.TopoDSShapePointer | undefined
9+
) => {
10+
if (bitbybit && finalShape) {
11+
// threejs is right handed - originally bitbybit was built on left handed system, thus this compensation is needed till
12+
// we improve support
13+
const exportShape = await bitbybit.occt.transforms.mirrorAlongNormal({
14+
shape: finalShape,
15+
origin: [0, 0, 0],
16+
normal: [0, 0, 1],
17+
});
18+
await bitbybit.occt.io.saveShapeSTEP({
19+
shape: exportShape,
20+
fileName: "shape",
21+
adjustYtoZ: true,
22+
tryDownload: true,
23+
});
24+
bitbybit.occt.deleteShape({ shape: exportShape });
25+
}
26+
};
27+
28+
export const downloadSTL = (scene: Scene) => {
29+
if (scene) {
30+
var exporter = new STLExporter();
31+
var str = exporter.parse(scene);
32+
var blob = new Blob([str], { type: "text/plain" });
33+
var link = document.createElement("a");
34+
link.style.display = "none";
35+
document.body.appendChild(link);
36+
link.href = URL.createObjectURL(blob);
37+
link.download = "Scene.stl";
38+
link.click();
39+
}
40+
};
41+
42+
export const downloadGLB = (scene: Scene) => {
43+
if (scene) {
44+
var exporter = new GLTFExporter();
45+
exporter.parse(
46+
scene,
47+
function (gltf: ArrayBuffer) {
48+
var blob = new Blob([gltf], { type: "application/octet-stream" });
49+
var link = document.createElement("a");
50+
link.style.display = "none";
51+
document.body.appendChild(link);
52+
link.href = URL.createObjectURL(blob);
53+
link.download = "Scene.glb";
54+
link.click();
55+
},
56+
function (error: string) {
57+
console.error("An error happened", error);
58+
},
59+
{ trs: false, onlyVisible: true, binary: true }
60+
);
61+
}
62+
};
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
export function disableGUI() {
2+
const lilGui = document.getElementsByClassName("lil-gui")[0] as HTMLElement;
3+
lilGui.style.pointerEvents = "none";
4+
lilGui.style.opacity = "0.5";
5+
}
6+
7+
export function enableGUI() {
8+
const lilGui = document.getElementsByClassName("lil-gui")[0] as HTMLElement;
9+
lilGui.style.pointerEvents = "all";
10+
lilGui.style.opacity = "1";
11+
}
12+
13+
export function showSpinner() {
14+
const element = document.createElement("div");
15+
element.id = "spinner";
16+
element.className = "lds-ellipsis";
17+
element.innerHTML = `
18+
<div></div>
19+
<div></div>
20+
<div></div>
21+
`;
22+
23+
document.body.appendChild(element);
24+
}
25+
26+
export function hideSpinner() {
27+
const el = document.getElementById("spinner");
28+
if (el) {
29+
el.remove();
30+
}
31+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export * from "./create-gui";
2+
export * from "./create-shape";
3+
export * from "./init-kernels";
4+
export * from "./init-threejs";
5+
export * from "./downloads";
6+
export * from "./gui-helper";
7+
export * from "./downloads";
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import type { BitByBitBase } from "@bitbybit-dev/threejs";
2+
import type { Scene } from "three";
3+
import type { KernelOptions } from "../models";
4+
import { first, firstValueFrom, tap } from "rxjs";
5+
import { OccStateEnum } from "@bitbybit-dev/occt-worker";
6+
import { JscadStateEnum } from "@bitbybit-dev/jscad-worker";
7+
import { ManifoldStateEnum } from "@bitbybit-dev/manifold-worker";
8+
9+
export async function initKernels(
10+
scene: Scene,
11+
bitbybit: BitByBitBase,
12+
options: KernelOptions
13+
): Promise<{ message: string }> {
14+
let occtWorkerInstance: Worker | undefined;
15+
let jscadWorkerInstance: Worker | undefined;
16+
let manifoldWorkerInstance: Worker | undefined;
17+
18+
// 1. Conditionally create worker instances
19+
if (options.enableOCCT) {
20+
occtWorkerInstance = new Worker(
21+
new URL("../workers/occt.worker.ts", import.meta.url),
22+
{ name: "OCC_WORKER", type: "module" }
23+
);
24+
}
25+
if (options.enableJSCAD) {
26+
jscadWorkerInstance = new Worker(
27+
new URL("../workers/jscad.worker.ts", import.meta.url),
28+
{ name: "JSCAD_WORKER", type: "module" }
29+
);
30+
}
31+
if (options.enableManifold) {
32+
manifoldWorkerInstance = new Worker(
33+
new URL("../workers/manifold.worker.ts", import.meta.url),
34+
{ name: "MANIFOLD_WORKER", type: "module" }
35+
);
36+
}
37+
38+
// 2. Initialize Bitbybit
39+
await bitbybit.init(
40+
scene,
41+
occtWorkerInstance,
42+
jscadWorkerInstance,
43+
manifoldWorkerInstance
44+
);
45+
46+
// 3. Collect promises for kernel initializations
47+
const initializationPromises: Promise<void>[] = [];
48+
let anyKernelSelectedForInit = false;
49+
50+
if (options.enableOCCT) {
51+
anyKernelSelectedForInit = true;
52+
if (bitbybit.occtWorkerManager) {
53+
initializationPromises.push(
54+
firstValueFrom(
55+
bitbybit.occtWorkerManager.occWorkerState$.pipe(
56+
first((s) => s.state === OccStateEnum.initialised),
57+
tap(() => console.log("OCCT Initialized"))
58+
)
59+
).then(() => {}) // Ensure the promise resolves to void for Promise.all
60+
);
61+
} else {
62+
console.warn(
63+
"OCCT enabled in options, but occtWorkerManager not found after init."
64+
);
65+
}
66+
}
67+
68+
if (options.enableJSCAD) {
69+
anyKernelSelectedForInit = true;
70+
if (bitbybit.jscadWorkerManager) {
71+
initializationPromises.push(
72+
firstValueFrom(
73+
bitbybit.jscadWorkerManager.jscadWorkerState$.pipe(
74+
first((s) => s.state === JscadStateEnum.initialised),
75+
tap(() => console.log("JSCAD Initialized"))
76+
)
77+
).then(() => {})
78+
);
79+
} else {
80+
console.warn(
81+
"JSCAD enabled in options, but jscadWorkerManager not found after init."
82+
);
83+
}
84+
}
85+
86+
if (options.enableManifold) {
87+
anyKernelSelectedForInit = true;
88+
if (bitbybit.manifoldWorkerManager) {
89+
initializationPromises.push(
90+
firstValueFrom(
91+
bitbybit.manifoldWorkerManager.manifoldWorkerState$.pipe(
92+
first((s) => s.state === ManifoldStateEnum.initialised),
93+
tap(() => console.log("Manifold Initialized"))
94+
)
95+
).then(() => {})
96+
);
97+
} else {
98+
console.warn(
99+
"Manifold enabled in options, but manifoldWorkerManager not found after init."
100+
);
101+
}
102+
}
103+
104+
// 4. Wait for selected & available kernels or handle no selection/availability
105+
if (!anyKernelSelectedForInit) {
106+
console.log("No kernels selected for initialization.");
107+
return { message: "No kernels selected for initialization." };
108+
}
109+
110+
if (initializationPromises.length === 0) {
111+
// Kernels were selected, but none were awaitable (e.g., managers missing for all selected)
112+
console.log(
113+
"Kernels were selected, but none had managers available for awaiting initialization."
114+
);
115+
return {
116+
message: "Selected kernels were not awaitable for initialization state.",
117+
};
118+
}
119+
120+
await Promise.all(initializationPromises);
121+
console.log("Selected and awaitable kernels initialized:", options);
122+
return {
123+
message: "Selected and awaitable kernels initialized successfully.",
124+
};
125+
}

0 commit comments

Comments
 (0)