@react-arch/renderer-3d 0.1.1 → 0.1.3
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/dist/index.js +27 -13
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -19,6 +19,9 @@ function build3DScene(doc, opts) {
|
|
|
19
19
|
const allPts = [];
|
|
20
20
|
let minY = Infinity;
|
|
21
21
|
let maxY = -Infinity;
|
|
22
|
+
const addPlanRect = (cx, cz, width, depth) => {
|
|
23
|
+
allPts.push([cx - width / 2, cz - depth / 2], [cx + width / 2, cz + depth / 2]);
|
|
24
|
+
};
|
|
22
25
|
ordered.forEach((floor, index) => {
|
|
23
26
|
if (!(opts.floorIds === "all" ? floor.visible : opts.floorIds.includes(floor.id))) return;
|
|
24
27
|
const elevation = floor.elevation + (opts.exploded ? index * gap : 0);
|
|
@@ -44,6 +47,14 @@ function build3DScene(doc, opts) {
|
|
|
44
47
|
const along = (s.along0 + s.along1) / 2;
|
|
45
48
|
const px = wall.start[0] + dir[0] * along;
|
|
46
49
|
const py = wall.start[1] + dir[1] * along;
|
|
50
|
+
const size = [
|
|
51
|
+
Math.max(s.along1 - s.along0, .001),
|
|
52
|
+
Math.max(s.z1 - s.z0, .001),
|
|
53
|
+
wall.thickness
|
|
54
|
+
];
|
|
55
|
+
addPlanRect(px, py, size[0], size[2]);
|
|
56
|
+
minY = Math.min(minY, elevation + s.z0);
|
|
57
|
+
maxY = Math.max(maxY, elevation + s.z1);
|
|
47
58
|
boxes.push({
|
|
48
59
|
key: `${wall.id}-${i}`,
|
|
49
60
|
entityId: wall.id,
|
|
@@ -55,16 +66,13 @@ function build3DScene(doc, opts) {
|
|
|
55
66
|
py
|
|
56
67
|
],
|
|
57
68
|
rotationY: -theta,
|
|
58
|
-
size
|
|
59
|
-
Math.max(s.along1 - s.along0, .001),
|
|
60
|
-
Math.max(s.z1 - s.z0, .001),
|
|
61
|
-
wall.thickness
|
|
62
|
-
],
|
|
69
|
+
size,
|
|
63
70
|
materialId: wall.materialId
|
|
64
71
|
});
|
|
65
72
|
});
|
|
66
73
|
}
|
|
67
74
|
for (const o of floor.openings) {
|
|
75
|
+
if (o.type === "opening") continue;
|
|
68
76
|
const wall = wallById.get(o.wallId);
|
|
69
77
|
if (!wall) continue;
|
|
70
78
|
const dir = wallDirection(wall);
|
|
@@ -72,6 +80,14 @@ function build3DScene(doc, opts) {
|
|
|
72
80
|
const px = wall.start[0] + dir[0] * o.offset;
|
|
73
81
|
const py = wall.start[1] + dir[1] * o.offset;
|
|
74
82
|
const depth = o.type === "window" ? .05 : wall.thickness * .6;
|
|
83
|
+
const size = [
|
|
84
|
+
Math.max(o.width - .04, .05),
|
|
85
|
+
Math.max(o.height - .04, .05),
|
|
86
|
+
depth
|
|
87
|
+
];
|
|
88
|
+
addPlanRect(px, py, size[0], size[2]);
|
|
89
|
+
minY = Math.min(minY, elevation + o.sillHeight);
|
|
90
|
+
maxY = Math.max(maxY, elevation + o.sillHeight + o.height);
|
|
75
91
|
panels.push({
|
|
76
92
|
key: o.id,
|
|
77
93
|
entityId: o.id,
|
|
@@ -83,15 +99,14 @@ function build3DScene(doc, opts) {
|
|
|
83
99
|
py
|
|
84
100
|
],
|
|
85
101
|
rotationY: -theta,
|
|
86
|
-
size
|
|
87
|
-
Math.max(o.width - .04, .05),
|
|
88
|
-
Math.max(o.height - .04, .05),
|
|
89
|
-
depth
|
|
90
|
-
]
|
|
102
|
+
size
|
|
91
103
|
});
|
|
92
104
|
}
|
|
93
105
|
for (const ob of floor.objects) {
|
|
94
106
|
const d = furnitureDims(ob.type, ob.scale);
|
|
107
|
+
addPlanRect(ob.position[0], ob.position[1], d.width, d.depth);
|
|
108
|
+
minY = Math.min(minY, elevation + ob.position[2]);
|
|
109
|
+
maxY = Math.max(maxY, elevation + ob.position[2] + d.height);
|
|
95
110
|
objects.push({
|
|
96
111
|
key: ob.id,
|
|
97
112
|
entityId: ob.id,
|
|
@@ -151,7 +166,7 @@ function build3DScene(doc, opts) {
|
|
|
151
166
|
}
|
|
152
167
|
//#endregion
|
|
153
168
|
//#region src/Building3D.tsx
|
|
154
|
-
const ACCENT = "#
|
|
169
|
+
const ACCENT = "#2563eb";
|
|
155
170
|
function colorFor(doc, materialId, fallback) {
|
|
156
171
|
if (!materialId) return fallback;
|
|
157
172
|
return doc.materials.find((m) => m.id === materialId)?.baseColor ?? fallback;
|
|
@@ -174,8 +189,7 @@ function CameraRig({ scene }) {
|
|
|
174
189
|
return /* @__PURE__ */ jsx(OrbitControls, {
|
|
175
190
|
ref: controls,
|
|
176
191
|
makeDefault: true,
|
|
177
|
-
enableDamping: true
|
|
178
|
-
dampingFactor: .1
|
|
192
|
+
enableDamping: true
|
|
179
193
|
});
|
|
180
194
|
}
|
|
181
195
|
function Building3D(props) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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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"}
|
|
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, 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 const addPlanRect = (cx: number, cz: number, width: number, depth: number) => {\n allPts.push([cx - width / 2, cz - depth / 2], [cx + width / 2, cz + depth / 2]);\n };\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 const size: [number, number, number] = [Math.max(s.along1 - s.along0, 0.001), Math.max(s.z1 - s.z0, 0.001), wall.thickness];\n addPlanRect(px, py, size[0], size[2]);\n minY = Math.min(minY, elevation + s.z0);\n maxY = Math.max(maxY, elevation + s.z1);\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,\n materialId: wall.materialId,\n });\n });\n }\n\n for (const o of floor.openings) {\n if (o.type === \"opening\") continue;\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 const size: [number, number, number] = [Math.max(o.width - 0.04, 0.05), Math.max(o.height - 0.04, 0.05), depth];\n addPlanRect(px, py, size[0], size[2]);\n minY = Math.min(minY, elevation + o.sillHeight);\n maxY = Math.max(maxY, elevation + o.sillHeight + o.height);\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,\n });\n }\n\n for (const ob of floor.objects) {\n const d = furnitureDims(ob.type, ob.scale);\n addPlanRect(ob.position[0], ob.position[1], d.width, d.depth);\n minY = Math.min(minY, elevation + ob.position[2]);\n maxY = Math.max(maxY, elevation + ob.position[2] + d.height);\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 = \"#2563eb\";\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 />;\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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-arch/renderer-3d",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@react-arch/core": "0.1.
|
|
16
|
-
"@react-arch/
|
|
17
|
-
"@react-arch/
|
|
15
|
+
"@react-arch/core": "0.1.3",
|
|
16
|
+
"@react-arch/geometry": "0.1.3",
|
|
17
|
+
"@react-arch/shared": "0.1.3"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@react-three/drei": ">=9",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"@types/three": "^0.169.0",
|
|
30
30
|
"react": "^18.3.1",
|
|
31
31
|
"three": "^0.169.0",
|
|
32
|
-
"typescript": "^5.7.2"
|
|
32
|
+
"typescript": "^5.7.2",
|
|
33
|
+
"vitest": "^2.1.8"
|
|
33
34
|
},
|
|
34
35
|
"files": [
|
|
35
36
|
"dist"
|