@react-arch/renderer-3d 0.1.0
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/LICENSE +21 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +358 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 React Arch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { BuildingDocument, EntityRef } from "@react-arch/core";
|
|
2
|
+
|
|
3
|
+
//#region src/Building3D.d.ts
|
|
4
|
+
interface Building3DProps {
|
|
5
|
+
document: BuildingDocument;
|
|
6
|
+
floorIds: string[] | "all";
|
|
7
|
+
selected?: EntityRef | null;
|
|
8
|
+
onSelect?: (ref: EntityRef | null) => void;
|
|
9
|
+
exploded?: boolean;
|
|
10
|
+
explodeGap?: number;
|
|
11
|
+
wireframe?: boolean;
|
|
12
|
+
xray?: boolean;
|
|
13
|
+
showSlabs?: boolean;
|
|
14
|
+
className?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function Building3D(props: Building3DProps): import("react").JSX.Element;
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/scene3d.d.ts
|
|
19
|
+
/**
|
|
20
|
+
* Plan→world mapping: plan X → world X, plan Y → world Z, height → world Y.
|
|
21
|
+
* All records below carry positions/rotations/sizes ready to drop onto meshes.
|
|
22
|
+
*/
|
|
23
|
+
interface BoxMesh {
|
|
24
|
+
key: string;
|
|
25
|
+
entityId: string;
|
|
26
|
+
floorId: string;
|
|
27
|
+
kind: "wall";
|
|
28
|
+
position: [number, number, number];
|
|
29
|
+
rotationY: number;
|
|
30
|
+
size: [number, number, number];
|
|
31
|
+
materialId?: string;
|
|
32
|
+
}
|
|
33
|
+
interface SlabMesh {
|
|
34
|
+
key: string;
|
|
35
|
+
entityId: string;
|
|
36
|
+
floorId: string;
|
|
37
|
+
kind: "slab";
|
|
38
|
+
position: [number, number, number];
|
|
39
|
+
size: [number, number, number];
|
|
40
|
+
}
|
|
41
|
+
interface PanelMesh {
|
|
42
|
+
key: string;
|
|
43
|
+
entityId: string;
|
|
44
|
+
floorId: string;
|
|
45
|
+
kind: "door" | "window" | "opening";
|
|
46
|
+
position: [number, number, number];
|
|
47
|
+
rotationY: number;
|
|
48
|
+
size: [number, number, number];
|
|
49
|
+
}
|
|
50
|
+
interface ObjectMesh {
|
|
51
|
+
key: string;
|
|
52
|
+
entityId: string;
|
|
53
|
+
floorId: string;
|
|
54
|
+
kind: "object";
|
|
55
|
+
objectType: string;
|
|
56
|
+
position: [number, number, number];
|
|
57
|
+
rotationY: number;
|
|
58
|
+
size: [number, number, number];
|
|
59
|
+
}
|
|
60
|
+
interface Scene3D {
|
|
61
|
+
boxes: BoxMesh[];
|
|
62
|
+
slabs: SlabMesh[];
|
|
63
|
+
panels: PanelMesh[];
|
|
64
|
+
objects: ObjectMesh[];
|
|
65
|
+
center: [number, number, number];
|
|
66
|
+
radius: number;
|
|
67
|
+
}
|
|
68
|
+
interface Build3DOptions {
|
|
69
|
+
floorIds: string[] | "all";
|
|
70
|
+
exploded?: boolean;
|
|
71
|
+
explodeGap?: number;
|
|
72
|
+
showSlabs?: boolean;
|
|
73
|
+
}
|
|
74
|
+
declare function build3DScene(doc: BuildingDocument, opts: Build3DOptions): Scene3D;
|
|
75
|
+
//#endregion
|
|
76
|
+
export { type Build3DOptions, Building3D, type Building3DProps, type Scene3D, build3DScene };
|
|
77
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/Building3D.tsx","../src/scene3d.ts"],"mappings":";;;UAOiB,eAAA;EACf,QAAA,EAAU,gBAAA;EACV,QAAA;EACA,QAAA,GAAW,SAAA;EACX,QAAA,IAAY,GAAA,EAAK,SAAA;EACjB,QAAA;EACA,UAAA;EACA,SAAA;EACA,IAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,iBA8Bc,UAAA,CAAW,KAAA,EAAO,eAAe,mBAAA,GAAA,CAAA,OAAA;;;;;AAxCjD;;UCEiB,OAAA;EACf,GAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA;EACA,QAAA;EACA,SAAA;EACA,IAAA;EACA,UAAA;AAAA;AAAA,UAEe,QAAA;EACf,GAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA;EACA,QAAA;EACA,IAAA;AAAA;AAAA,UAEe,SAAA;EACf,GAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA;EACA,QAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,UAGe,UAAA;EACf,GAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA;EACA,UAAA;EACA,QAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,UAGe,OAAA;EACf,KAAA,EAAO,OAAA;EACP,KAAA,EAAO,QAAA;EACP,MAAA,EAAQ,SAAA;EACR,OAAA,EAAS,UAAA;EACT,MAAA;EACA,MAAA;AAAA;AAAA,UAGe,cAAA;EACf,QAAA;EACA,QAAA;EACA,UAAA;EACA,SAAA;AAAA;AAAA,iBAQc,YAAA,CAAa,GAAA,EAAK,gBAAA,EAAkB,IAAA,EAAM,cAAA,GAAiB,OAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { Canvas, useThree } from "@react-three/fiber";
|
|
3
|
+
import { OrbitControls } from "@react-three/drei";
|
|
4
|
+
import { allFloors, furnitureColor, furnitureDims } from "@react-arch/core";
|
|
5
|
+
import { bounds, wallBoxes, wallDirection } from "@react-arch/geometry";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/scene3d.ts
|
|
8
|
+
const SLAB_THICKNESS = .14;
|
|
9
|
+
/** Drop the slab top slightly below the floor line to avoid sharing a plane
|
|
10
|
+
* with the wall-tops of the floor below (prevents z-fighting). 2 cm, invisible. */
|
|
11
|
+
const SLAB_TOP_GAP = .02;
|
|
12
|
+
function build3DScene(doc, opts) {
|
|
13
|
+
const ordered = [...allFloors(doc)].sort((a, b) => a.elevation - b.elevation);
|
|
14
|
+
const gap = opts.explodeGap ?? 3;
|
|
15
|
+
const boxes = [];
|
|
16
|
+
const slabs = [];
|
|
17
|
+
const panels = [];
|
|
18
|
+
const objects = [];
|
|
19
|
+
const allPts = [];
|
|
20
|
+
let minY = Infinity;
|
|
21
|
+
let maxY = -Infinity;
|
|
22
|
+
ordered.forEach((floor, index) => {
|
|
23
|
+
if (!(opts.floorIds === "all" ? floor.visible : opts.floorIds.includes(floor.id))) return;
|
|
24
|
+
const elevation = floor.elevation + (opts.exploded ? index * gap : 0);
|
|
25
|
+
minY = Math.min(minY, elevation);
|
|
26
|
+
maxY = Math.max(maxY, elevation + floor.height);
|
|
27
|
+
const wallById = new Map(floor.walls.map((w) => [w.id, w]));
|
|
28
|
+
const openingsByWall = /* @__PURE__ */ new Map();
|
|
29
|
+
for (const o of floor.openings) {
|
|
30
|
+
const arr = openingsByWall.get(o.wallId) ?? [];
|
|
31
|
+
arr.push(o);
|
|
32
|
+
openingsByWall.set(o.wallId, arr);
|
|
33
|
+
}
|
|
34
|
+
for (const wall of floor.walls) {
|
|
35
|
+
allPts.push(wall.start, wall.end);
|
|
36
|
+
const dir = wallDirection(wall);
|
|
37
|
+
const theta = Math.atan2(dir[1], dir[0]);
|
|
38
|
+
wallBoxes(wall, (openingsByWall.get(wall.id) ?? []).map((o) => ({
|
|
39
|
+
offset: o.offset,
|
|
40
|
+
width: o.width,
|
|
41
|
+
height: o.height,
|
|
42
|
+
sillHeight: o.sillHeight
|
|
43
|
+
})), wall.height, wall.thickness / 2).forEach((s, i) => {
|
|
44
|
+
const along = (s.along0 + s.along1) / 2;
|
|
45
|
+
const px = wall.start[0] + dir[0] * along;
|
|
46
|
+
const py = wall.start[1] + dir[1] * along;
|
|
47
|
+
boxes.push({
|
|
48
|
+
key: `${wall.id}-${i}`,
|
|
49
|
+
entityId: wall.id,
|
|
50
|
+
floorId: floor.id,
|
|
51
|
+
kind: "wall",
|
|
52
|
+
position: [
|
|
53
|
+
px,
|
|
54
|
+
elevation + (s.z0 + s.z1) / 2,
|
|
55
|
+
py
|
|
56
|
+
],
|
|
57
|
+
rotationY: -theta,
|
|
58
|
+
size: [
|
|
59
|
+
Math.max(s.along1 - s.along0, .001),
|
|
60
|
+
Math.max(s.z1 - s.z0, .001),
|
|
61
|
+
wall.thickness
|
|
62
|
+
],
|
|
63
|
+
materialId: wall.materialId
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
for (const o of floor.openings) {
|
|
68
|
+
const wall = wallById.get(o.wallId);
|
|
69
|
+
if (!wall) continue;
|
|
70
|
+
const dir = wallDirection(wall);
|
|
71
|
+
const theta = Math.atan2(dir[1], dir[0]);
|
|
72
|
+
const px = wall.start[0] + dir[0] * o.offset;
|
|
73
|
+
const py = wall.start[1] + dir[1] * o.offset;
|
|
74
|
+
const depth = o.type === "window" ? .05 : wall.thickness * .6;
|
|
75
|
+
panels.push({
|
|
76
|
+
key: o.id,
|
|
77
|
+
entityId: o.id,
|
|
78
|
+
floorId: floor.id,
|
|
79
|
+
kind: o.type,
|
|
80
|
+
position: [
|
|
81
|
+
px,
|
|
82
|
+
elevation + o.sillHeight + o.height / 2,
|
|
83
|
+
py
|
|
84
|
+
],
|
|
85
|
+
rotationY: -theta,
|
|
86
|
+
size: [
|
|
87
|
+
Math.max(o.width - .04, .05),
|
|
88
|
+
Math.max(o.height - .04, .05),
|
|
89
|
+
depth
|
|
90
|
+
]
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
for (const ob of floor.objects) {
|
|
94
|
+
const d = furnitureDims(ob.type, ob.scale);
|
|
95
|
+
objects.push({
|
|
96
|
+
key: ob.id,
|
|
97
|
+
entityId: ob.id,
|
|
98
|
+
floorId: floor.id,
|
|
99
|
+
kind: "object",
|
|
100
|
+
objectType: ob.type,
|
|
101
|
+
position: [
|
|
102
|
+
ob.position[0],
|
|
103
|
+
elevation + ob.position[2] + d.height / 2,
|
|
104
|
+
ob.position[1]
|
|
105
|
+
],
|
|
106
|
+
rotationY: -ob.rotation[2],
|
|
107
|
+
size: [
|
|
108
|
+
d.width,
|
|
109
|
+
d.height,
|
|
110
|
+
d.depth
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
if (opts.showSlabs !== false && floor.walls.length > 0) {
|
|
115
|
+
const b = bounds(floor.walls.flatMap((w) => [w.start, w.end]));
|
|
116
|
+
slabs.push({
|
|
117
|
+
key: `slab-${floor.id}`,
|
|
118
|
+
entityId: floor.id,
|
|
119
|
+
floorId: floor.id,
|
|
120
|
+
kind: "slab",
|
|
121
|
+
position: [
|
|
122
|
+
(b.min[0] + b.max[0]) / 2,
|
|
123
|
+
elevation - SLAB_TOP_GAP - SLAB_THICKNESS / 2,
|
|
124
|
+
(b.min[1] + b.max[1]) / 2
|
|
125
|
+
],
|
|
126
|
+
size: [
|
|
127
|
+
b.width + .4,
|
|
128
|
+
SLAB_THICKNESS,
|
|
129
|
+
b.height + .4
|
|
130
|
+
]
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
const b = bounds(allPts);
|
|
135
|
+
const cx = (b.min[0] + b.max[0]) / 2;
|
|
136
|
+
const cz = (b.min[1] + b.max[1]) / 2;
|
|
137
|
+
const cy = Number.isFinite(minY) ? (minY + maxY) / 2 : 1.5;
|
|
138
|
+
const radius = Math.max(b.width, b.height, maxY - minY, 4) * .75;
|
|
139
|
+
return {
|
|
140
|
+
boxes,
|
|
141
|
+
slabs,
|
|
142
|
+
panels,
|
|
143
|
+
objects,
|
|
144
|
+
center: [
|
|
145
|
+
cx,
|
|
146
|
+
cy,
|
|
147
|
+
cz
|
|
148
|
+
],
|
|
149
|
+
radius
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/Building3D.tsx
|
|
154
|
+
const ACCENT = "#4c8eff";
|
|
155
|
+
function colorFor(doc, materialId, fallback) {
|
|
156
|
+
if (!materialId) return fallback;
|
|
157
|
+
return doc.materials.find((m) => m.id === materialId)?.baseColor ?? fallback;
|
|
158
|
+
}
|
|
159
|
+
function CameraRig({ scene }) {
|
|
160
|
+
const { camera } = useThree();
|
|
161
|
+
const controls = useRef(null);
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
const [cx, cy, cz] = scene.center;
|
|
164
|
+
const r = scene.radius;
|
|
165
|
+
camera.position.set(cx + r * 1.4, cy + r * 1.3, cz + r * 1.6);
|
|
166
|
+
camera.near = Math.max(.05, r * .02);
|
|
167
|
+
camera.far = r * 8 + 40;
|
|
168
|
+
camera.updateProjectionMatrix();
|
|
169
|
+
if (controls.current) {
|
|
170
|
+
controls.current.target.set(cx, cy, cz);
|
|
171
|
+
controls.current.update();
|
|
172
|
+
}
|
|
173
|
+
}, [scene, camera]);
|
|
174
|
+
return /* @__PURE__ */ jsx(OrbitControls, {
|
|
175
|
+
ref: controls,
|
|
176
|
+
makeDefault: true,
|
|
177
|
+
enableDamping: true,
|
|
178
|
+
dampingFactor: .1
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function Building3D(props) {
|
|
182
|
+
const { document: doc, floorIds } = props;
|
|
183
|
+
const scene = useMemo(() => build3DScene(doc, {
|
|
184
|
+
floorIds,
|
|
185
|
+
exploded: props.exploded,
|
|
186
|
+
explodeGap: props.explodeGap,
|
|
187
|
+
showSlabs: props.showSlabs
|
|
188
|
+
}), [
|
|
189
|
+
doc,
|
|
190
|
+
floorIds,
|
|
191
|
+
props.exploded,
|
|
192
|
+
props.explodeGap,
|
|
193
|
+
props.showSlabs
|
|
194
|
+
]);
|
|
195
|
+
const wallColor = colorFor(doc, void 0, "#e8e6e1");
|
|
196
|
+
const isSelected = (id) => props.selected?.id === id;
|
|
197
|
+
return /* @__PURE__ */ jsx("div", {
|
|
198
|
+
className: props.className,
|
|
199
|
+
style: {
|
|
200
|
+
width: "100%",
|
|
201
|
+
height: "100%",
|
|
202
|
+
background: "#0f1115"
|
|
203
|
+
},
|
|
204
|
+
children: /* @__PURE__ */ jsxs(Canvas, {
|
|
205
|
+
shadows: true,
|
|
206
|
+
dpr: [1, 2],
|
|
207
|
+
camera: {
|
|
208
|
+
position: [
|
|
209
|
+
12,
|
|
210
|
+
10,
|
|
211
|
+
14
|
|
212
|
+
],
|
|
213
|
+
fov: 45
|
|
214
|
+
},
|
|
215
|
+
gl: { antialias: true },
|
|
216
|
+
onPointerMissed: () => props.onSelect?.(null),
|
|
217
|
+
children: [
|
|
218
|
+
/* @__PURE__ */ jsx("color", {
|
|
219
|
+
attach: "background",
|
|
220
|
+
args: ["#0f1115"]
|
|
221
|
+
}),
|
|
222
|
+
/* @__PURE__ */ jsx("hemisphereLight", {
|
|
223
|
+
intensity: .55,
|
|
224
|
+
groundColor: "#1a1c22"
|
|
225
|
+
}),
|
|
226
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: .35 }),
|
|
227
|
+
/* @__PURE__ */ jsx("directionalLight", {
|
|
228
|
+
position: [
|
|
229
|
+
scene.center[0] + 20,
|
|
230
|
+
scene.center[1] + 35,
|
|
231
|
+
scene.center[2] + 15
|
|
232
|
+
],
|
|
233
|
+
intensity: 1.1,
|
|
234
|
+
castShadow: true,
|
|
235
|
+
"shadow-mapSize": [2048, 2048]
|
|
236
|
+
}),
|
|
237
|
+
/* @__PURE__ */ jsx("gridHelper", {
|
|
238
|
+
args: [
|
|
239
|
+
200,
|
|
240
|
+
200,
|
|
241
|
+
"#2a2d35",
|
|
242
|
+
"#1c1e24"
|
|
243
|
+
],
|
|
244
|
+
position: [
|
|
245
|
+
scene.center[0],
|
|
246
|
+
-.01,
|
|
247
|
+
scene.center[2]
|
|
248
|
+
]
|
|
249
|
+
}),
|
|
250
|
+
scene.slabs.map((s) => /* @__PURE__ */ jsxs("mesh", {
|
|
251
|
+
position: s.position,
|
|
252
|
+
receiveShadow: true,
|
|
253
|
+
onClick: (e) => {
|
|
254
|
+
e.stopPropagation();
|
|
255
|
+
props.onSelect?.({
|
|
256
|
+
kind: "floor",
|
|
257
|
+
id: s.floorId
|
|
258
|
+
});
|
|
259
|
+
},
|
|
260
|
+
children: [/* @__PURE__ */ jsx("boxGeometry", { args: s.size }), /* @__PURE__ */ jsx("meshStandardMaterial", {
|
|
261
|
+
color: isSelected(s.floorId) ? ACCENT : "#3a3d44",
|
|
262
|
+
roughness: .95,
|
|
263
|
+
polygonOffset: true,
|
|
264
|
+
polygonOffsetFactor: 1,
|
|
265
|
+
polygonOffsetUnits: 1
|
|
266
|
+
})]
|
|
267
|
+
}, s.key)),
|
|
268
|
+
scene.boxes.map((b) => {
|
|
269
|
+
const sel = isSelected(b.entityId);
|
|
270
|
+
return /* @__PURE__ */ jsxs("mesh", {
|
|
271
|
+
position: b.position,
|
|
272
|
+
rotation: [
|
|
273
|
+
0,
|
|
274
|
+
b.rotationY,
|
|
275
|
+
0
|
|
276
|
+
],
|
|
277
|
+
castShadow: true,
|
|
278
|
+
receiveShadow: true,
|
|
279
|
+
onClick: (e) => {
|
|
280
|
+
e.stopPropagation();
|
|
281
|
+
props.onSelect?.({
|
|
282
|
+
kind: "wall",
|
|
283
|
+
id: b.entityId
|
|
284
|
+
});
|
|
285
|
+
},
|
|
286
|
+
children: [/* @__PURE__ */ jsx("boxGeometry", { args: b.size }), /* @__PURE__ */ jsx("meshStandardMaterial", {
|
|
287
|
+
color: sel ? ACCENT : colorFor(doc, b.materialId, wallColor),
|
|
288
|
+
roughness: .9,
|
|
289
|
+
wireframe: props.wireframe,
|
|
290
|
+
transparent: props.xray,
|
|
291
|
+
opacity: props.xray ? .25 : 1
|
|
292
|
+
})]
|
|
293
|
+
}, b.key);
|
|
294
|
+
}),
|
|
295
|
+
scene.panels.map((p) => {
|
|
296
|
+
const sel = isSelected(p.entityId);
|
|
297
|
+
const isGlass = p.kind === "window";
|
|
298
|
+
return /* @__PURE__ */ jsxs("mesh", {
|
|
299
|
+
position: p.position,
|
|
300
|
+
rotation: [
|
|
301
|
+
0,
|
|
302
|
+
p.rotationY,
|
|
303
|
+
0
|
|
304
|
+
],
|
|
305
|
+
castShadow: true,
|
|
306
|
+
onClick: (e) => {
|
|
307
|
+
e.stopPropagation();
|
|
308
|
+
props.onSelect?.({
|
|
309
|
+
kind: "opening",
|
|
310
|
+
id: p.entityId
|
|
311
|
+
});
|
|
312
|
+
},
|
|
313
|
+
children: [/* @__PURE__ */ jsx("boxGeometry", { args: p.size }), /* @__PURE__ */ jsx("meshStandardMaterial", {
|
|
314
|
+
color: sel ? ACCENT : isGlass ? "#bcd6e6" : "#6b4b2f",
|
|
315
|
+
roughness: isGlass ? .05 : .6,
|
|
316
|
+
metalness: isGlass ? .1 : 0,
|
|
317
|
+
transparent: isGlass || props.xray,
|
|
318
|
+
opacity: isGlass ? .4 : props.xray ? .3 : 1,
|
|
319
|
+
wireframe: props.wireframe
|
|
320
|
+
})]
|
|
321
|
+
}, p.key);
|
|
322
|
+
}),
|
|
323
|
+
scene.objects.map((o) => {
|
|
324
|
+
const sel = isSelected(o.entityId);
|
|
325
|
+
return /* @__PURE__ */ jsxs("mesh", {
|
|
326
|
+
position: o.position,
|
|
327
|
+
rotation: [
|
|
328
|
+
0,
|
|
329
|
+
o.rotationY,
|
|
330
|
+
0
|
|
331
|
+
],
|
|
332
|
+
castShadow: true,
|
|
333
|
+
receiveShadow: true,
|
|
334
|
+
onClick: (e) => {
|
|
335
|
+
e.stopPropagation();
|
|
336
|
+
props.onSelect?.({
|
|
337
|
+
kind: "object",
|
|
338
|
+
id: o.entityId
|
|
339
|
+
});
|
|
340
|
+
},
|
|
341
|
+
children: [/* @__PURE__ */ jsx("boxGeometry", { args: o.size }), /* @__PURE__ */ jsx("meshStandardMaterial", {
|
|
342
|
+
color: sel ? ACCENT : furnitureColor(o.objectType),
|
|
343
|
+
roughness: .7,
|
|
344
|
+
wireframe: props.wireframe,
|
|
345
|
+
transparent: props.xray,
|
|
346
|
+
opacity: props.xray ? .35 : 1
|
|
347
|
+
})]
|
|
348
|
+
}, o.key);
|
|
349
|
+
}),
|
|
350
|
+
/* @__PURE__ */ jsx(CameraRig, { scene })
|
|
351
|
+
]
|
|
352
|
+
})
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
356
|
+
export { Building3D, build3DScene };
|
|
357
|
+
|
|
358
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/scene3d.ts","../src/Building3D.tsx"],"sourcesContent":["import type { BuildingDocument } from \"@react-arch/core\";\nimport { allFloors, furnitureDims } from \"@react-arch/core\";\nimport { bounds, wallBoxes, wallDirection, wallLength, type Vec2 } from \"@react-arch/geometry\";\n\n/**\n * Plan→world mapping: plan X → world X, plan Y → world Z, height → world Y.\n * All records below carry positions/rotations/sizes ready to drop onto meshes.\n */\n\nexport interface BoxMesh {\n key: string;\n entityId: string;\n floorId: string;\n kind: \"wall\";\n position: [number, number, number];\n rotationY: number;\n size: [number, number, number];\n materialId?: string;\n}\nexport interface SlabMesh {\n key: string;\n entityId: string;\n floorId: string;\n kind: \"slab\";\n position: [number, number, number];\n size: [number, number, number];\n}\nexport interface PanelMesh {\n key: string;\n entityId: string;\n floorId: string;\n kind: \"door\" | \"window\" | \"opening\";\n position: [number, number, number];\n rotationY: number;\n size: [number, number, number];\n}\n\nexport interface ObjectMesh {\n key: string;\n entityId: string;\n floorId: string;\n kind: \"object\";\n objectType: string;\n position: [number, number, number];\n rotationY: number;\n size: [number, number, number];\n}\n\nexport interface Scene3D {\n boxes: BoxMesh[];\n slabs: SlabMesh[];\n panels: PanelMesh[];\n objects: ObjectMesh[];\n center: [number, number, number];\n radius: number;\n}\n\nexport interface Build3DOptions {\n floorIds: string[] | \"all\";\n exploded?: boolean;\n explodeGap?: number;\n showSlabs?: boolean;\n}\n\nconst SLAB_THICKNESS = 0.14;\n/** Drop the slab top slightly below the floor line to avoid sharing a plane\n * with the wall-tops of the floor below (prevents z-fighting). 2 cm, invisible. */\nconst SLAB_TOP_GAP = 0.02;\n\nexport function build3DScene(doc: BuildingDocument, opts: Build3DOptions): Scene3D {\n const floors = allFloors(doc);\n const ordered = [...floors].sort((a, b) => a.elevation - b.elevation);\n const gap = opts.explodeGap ?? 3;\n\n const boxes: BoxMesh[] = [];\n const slabs: SlabMesh[] = [];\n const panels: PanelMesh[] = [];\n const objects: ObjectMesh[] = [];\n const allPts: Vec2[] = [];\n let minY = Infinity;\n let maxY = -Infinity;\n\n ordered.forEach((floor, index) => {\n const visible = opts.floorIds === \"all\" ? floor.visible : opts.floorIds.includes(floor.id);\n if (!visible) return;\n const elevation = floor.elevation + (opts.exploded ? index * gap : 0);\n minY = Math.min(minY, elevation);\n maxY = Math.max(maxY, elevation + floor.height);\n\n const wallById = new Map(floor.walls.map((w) => [w.id, w]));\n const openingsByWall = new Map<string, typeof floor.openings>();\n for (const o of floor.openings) {\n const arr = openingsByWall.get(o.wallId) ?? [];\n arr.push(o);\n openingsByWall.set(o.wallId, arr);\n }\n\n for (const wall of floor.walls) {\n allPts.push(wall.start, wall.end);\n const dir = wallDirection(wall);\n const theta = Math.atan2(dir[1], dir[0]);\n const wallOpenings = (openingsByWall.get(wall.id) ?? []).map((o) => ({\n offset: o.offset,\n width: o.width,\n height: o.height,\n sillHeight: o.sillHeight,\n }));\n // Extend each end by half-thickness so walls overlap and fill corners.\n const segs = wallBoxes(wall, wallOpenings, wall.height, wall.thickness / 2);\n segs.forEach((s, i) => {\n const along = (s.along0 + s.along1) / 2;\n const px = wall.start[0] + dir[0] * along;\n const py = wall.start[1] + dir[1] * along;\n boxes.push({\n key: `${wall.id}-${i}`,\n entityId: wall.id,\n floorId: floor.id,\n kind: \"wall\",\n position: [px, elevation + (s.z0 + s.z1) / 2, py],\n rotationY: -theta,\n size: [Math.max(s.along1 - s.along0, 0.001), Math.max(s.z1 - s.z0, 0.001), wall.thickness],\n materialId: wall.materialId,\n });\n });\n }\n\n for (const o of floor.openings) {\n const wall = wallById.get(o.wallId);\n if (!wall) continue;\n const dir = wallDirection(wall);\n const theta = Math.atan2(dir[1], dir[0]);\n const px = wall.start[0] + dir[0] * o.offset;\n const py = wall.start[1] + dir[1] * o.offset;\n const depth = o.type === \"window\" ? 0.05 : wall.thickness * 0.6;\n panels.push({\n key: o.id,\n entityId: o.id,\n floorId: floor.id,\n kind: o.type,\n position: [px, elevation + o.sillHeight + o.height / 2, py],\n rotationY: -theta,\n size: [Math.max(o.width - 0.04, 0.05), Math.max(o.height - 0.04, 0.05), depth],\n });\n }\n\n for (const ob of floor.objects) {\n const d = furnitureDims(ob.type, ob.scale);\n objects.push({\n key: ob.id,\n entityId: ob.id,\n floorId: floor.id,\n kind: \"object\",\n objectType: ob.type,\n position: [ob.position[0], elevation + ob.position[2] + d.height / 2, ob.position[1]],\n rotationY: -ob.rotation[2],\n size: [d.width, d.height, d.depth],\n });\n }\n\n if (opts.showSlabs !== false && floor.walls.length > 0) {\n const b = bounds(floor.walls.flatMap((w) => [w.start, w.end]));\n slabs.push({\n key: `slab-${floor.id}`,\n entityId: floor.id,\n floorId: floor.id,\n kind: \"slab\",\n // Sit the slab top SLAB_TOP_GAP below the floor line so it is never\n // coplanar with the tops of the walls of the floor below (which reach\n // exactly this elevation) — the root cause of the z-fighting seam.\n position: [(b.min[0] + b.max[0]) / 2, elevation - SLAB_TOP_GAP - SLAB_THICKNESS / 2, (b.min[1] + b.max[1]) / 2],\n size: [b.width + 0.4, SLAB_THICKNESS, b.height + 0.4],\n });\n }\n });\n\n const b = bounds(allPts);\n const cx = (b.min[0] + b.max[0]) / 2;\n const cz = (b.min[1] + b.max[1]) / 2;\n const cy = Number.isFinite(minY) ? (minY + maxY) / 2 : 1.5;\n const radius = Math.max(b.width, b.height, maxY - minY, 4) * 0.75;\n return { boxes, slabs, panels, objects, center: [cx, cy, cz], radius };\n}\n","import { useEffect, useMemo, useRef } from \"react\";\nimport { Canvas, useThree } from \"@react-three/fiber\";\nimport { OrbitControls } from \"@react-three/drei\";\nimport type { BuildingDocument, EntityRef } from \"@react-arch/core\";\nimport { furnitureColor } from \"@react-arch/core\";\nimport { build3DScene, type Scene3D } from \"./scene3d.js\";\n\nexport interface Building3DProps {\n document: BuildingDocument;\n floorIds: string[] | \"all\";\n selected?: EntityRef | null;\n onSelect?: (ref: EntityRef | null) => void;\n exploded?: boolean;\n explodeGap?: number;\n wireframe?: boolean;\n xray?: boolean;\n showSlabs?: boolean;\n className?: string;\n}\n\nconst ACCENT = \"#4c8eff\";\n\nfunction colorFor(doc: BuildingDocument, materialId: string | undefined, fallback: string): string {\n if (!materialId) return fallback;\n return doc.materials.find((m) => m.id === materialId)?.baseColor ?? fallback;\n}\n\nfunction CameraRig({ scene }: { scene: Scene3D }) {\n const { camera } = useThree();\n const controls = useRef<any>(null);\n useEffect(() => {\n const [cx, cy, cz] = scene.center;\n const r = scene.radius;\n camera.position.set(cx + r * 1.4, cy + r * 1.3, cz + r * 1.6);\n // Keep the near/far range tight for good depth-buffer precision (reduces\n // z-fighting between stacked floors that share a plane).\n camera.near = Math.max(0.05, r * 0.02);\n camera.far = r * 8 + 40;\n camera.updateProjectionMatrix();\n if (controls.current) {\n controls.current.target.set(cx, cy, cz);\n controls.current.update();\n }\n }, [scene, camera]);\n return <OrbitControls ref={controls} makeDefault enableDamping dampingFactor={0.1} />;\n}\n\nexport function Building3D(props: Building3DProps) {\n const { document: doc, floorIds } = props;\n const scene = useMemo(\n () => build3DScene(doc, { floorIds, exploded: props.exploded, explodeGap: props.explodeGap, showSlabs: props.showSlabs }),\n [doc, floorIds, props.exploded, props.explodeGap, props.showSlabs],\n );\n\n const wallColor = colorFor(doc, undefined, \"#e8e6e1\");\n const isSelected = (id: string) => props.selected?.id === id;\n\n return (\n <div className={props.className} style={{ width: \"100%\", height: \"100%\", background: \"#0f1115\" }}>\n <Canvas\n shadows\n dpr={[1, 2]}\n camera={{ position: [12, 10, 14], fov: 45 }}\n gl={{ antialias: true }}\n onPointerMissed={() => props.onSelect?.(null)}\n >\n <color attach=\"background\" args={[\"#0f1115\"]} />\n <hemisphereLight intensity={0.55} groundColor=\"#1a1c22\" />\n <ambientLight intensity={0.35} />\n <directionalLight\n position={[scene.center[0] + 20, scene.center[1] + 35, scene.center[2] + 15]}\n intensity={1.1}\n castShadow\n shadow-mapSize={[2048, 2048]}\n />\n\n {/* Ground reference grid */}\n <gridHelper args={[200, 200, \"#2a2d35\", \"#1c1e24\"]} position={[scene.center[0], -0.01, scene.center[2]]} />\n\n {scene.slabs.map((s) => (\n <mesh key={s.key} position={s.position} receiveShadow\n onClick={(e) => { e.stopPropagation(); props.onSelect?.({ kind: \"floor\", id: s.floorId }); }}>\n <boxGeometry args={s.size} />\n {/* polygonOffset pushes the slab slightly back in depth so it never\n ties with a coplanar wall-top from the floor below. */}\n <meshStandardMaterial\n color={isSelected(s.floorId) ? ACCENT : \"#3a3d44\"}\n roughness={0.95}\n polygonOffset\n polygonOffsetFactor={1}\n polygonOffsetUnits={1}\n />\n </mesh>\n ))}\n\n {scene.boxes.map((b) => {\n const sel = isSelected(b.entityId);\n return (\n <mesh key={b.key} position={b.position} rotation={[0, b.rotationY, 0]} castShadow receiveShadow\n onClick={(e) => { e.stopPropagation(); props.onSelect?.({ kind: \"wall\", id: b.entityId }); }}>\n <boxGeometry args={b.size} />\n <meshStandardMaterial\n color={sel ? ACCENT : colorFor(doc, b.materialId, wallColor)}\n roughness={0.9}\n wireframe={props.wireframe}\n transparent={props.xray}\n opacity={props.xray ? 0.25 : 1}\n />\n </mesh>\n );\n })}\n\n {scene.panels.map((p) => {\n const sel = isSelected(p.entityId);\n const isGlass = p.kind === \"window\";\n return (\n <mesh key={p.key} position={p.position} rotation={[0, p.rotationY, 0]} castShadow\n onClick={(e) => { e.stopPropagation(); props.onSelect?.({ kind: \"opening\", id: p.entityId }); }}>\n <boxGeometry args={p.size} />\n <meshStandardMaterial\n color={sel ? ACCENT : isGlass ? \"#bcd6e6\" : \"#6b4b2f\"}\n roughness={isGlass ? 0.05 : 0.6}\n metalness={isGlass ? 0.1 : 0}\n transparent={isGlass || props.xray}\n opacity={isGlass ? 0.4 : props.xray ? 0.3 : 1}\n wireframe={props.wireframe}\n />\n </mesh>\n );\n })}\n\n {scene.objects.map((o) => {\n const sel = isSelected(o.entityId);\n return (\n <mesh key={o.key} position={o.position} rotation={[0, o.rotationY, 0]} castShadow receiveShadow\n onClick={(e) => { e.stopPropagation(); props.onSelect?.({ kind: \"object\", id: o.entityId }); }}>\n <boxGeometry args={o.size} />\n <meshStandardMaterial\n color={sel ? ACCENT : furnitureColor(o.objectType)}\n roughness={0.7}\n wireframe={props.wireframe}\n transparent={props.xray}\n opacity={props.xray ? 0.35 : 1}\n />\n </mesh>\n );\n })}\n\n <CameraRig scene={scene} />\n </Canvas>\n </div>\n );\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@react-arch/renderer-3d",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@react-arch/core": "0.1.0",
|
|
16
|
+
"@react-arch/shared": "0.1.0",
|
|
17
|
+
"@react-arch/geometry": "0.1.0"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"@react-three/drei": ">=9",
|
|
21
|
+
"@react-three/fiber": ">=8",
|
|
22
|
+
"react": "^18.3.0",
|
|
23
|
+
"three": ">=0.160"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@react-three/drei": "^9.114.0",
|
|
27
|
+
"@react-three/fiber": "^8.17.10",
|
|
28
|
+
"@types/react": "^18.3.12",
|
|
29
|
+
"@types/three": "^0.169.0",
|
|
30
|
+
"react": "^18.3.1",
|
|
31
|
+
"three": "^0.169.0",
|
|
32
|
+
"typescript": "^5.7.2"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist"
|
|
36
|
+
],
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/react-arch/react-arch.git",
|
|
43
|
+
"directory": "packages/renderer-3d"
|
|
44
|
+
},
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"scripts": {
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"test": "vitest run --passWithNoTests",
|
|
49
|
+
"lint": "oxlint src",
|
|
50
|
+
"build": "tsdown"
|
|
51
|
+
}
|
|
52
|
+
}
|