remove community
This commit is contained in:
@@ -9,7 +9,7 @@ import { NodeRenderer } from '../node-renderer'
|
||||
// - Back face (looking up at ceiling from below): solid
|
||||
// - Front face (looking down at ceiling from above): 30% opacity
|
||||
const ceilingTopMaterial = new MeshBasicNodeMaterial({
|
||||
color: 0xb5a78d,
|
||||
color: 0xb5_a7_8d,
|
||||
transparent: true,
|
||||
depthWrite: false,
|
||||
side: FrontSide,
|
||||
@@ -18,7 +18,7 @@ const ceilingTopMaterial = new MeshBasicNodeMaterial({
|
||||
})
|
||||
|
||||
const ceilingBottomMaterial = new MeshBasicNodeMaterial({
|
||||
color: 0x999999,
|
||||
color: 0x99_99_99,
|
||||
transparent: true,
|
||||
side: BackSide,
|
||||
})
|
||||
@@ -52,10 +52,16 @@ export const CeilingRenderer = ({ node }: { node: CeilingNode }) => {
|
||||
const handlers = useNodeEvents(node, 'ceiling')
|
||||
|
||||
return (
|
||||
<mesh ref={ref} material={ceilingBottomMaterial}>
|
||||
<mesh material={ceilingBottomMaterial} ref={ref}>
|
||||
{/* CeilingSystem will replace this geometry in the next frame */}
|
||||
<boxGeometry args={[0, 0, 0]} />
|
||||
<mesh name="ceiling-grid" material={ceilingTopMaterial} {...handlers} visible={false} scale={0}>
|
||||
<mesh
|
||||
material={ceilingTopMaterial}
|
||||
name="ceiling-grid"
|
||||
{...handlers}
|
||||
scale={0}
|
||||
visible={false}
|
||||
>
|
||||
<boxGeometry args={[0, 0, 0]} />
|
||||
</mesh>
|
||||
{node.children.map((childId) => (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useRegistry, type DoorNode } from '@pascal-app/core'
|
||||
import { type DoorNode, useRegistry } from '@pascal-app/core'
|
||||
import { useRef } from 'react'
|
||||
import type { Mesh } from 'three'
|
||||
import { useNodeEvents } from '../../../hooks/use-node-events'
|
||||
@@ -12,12 +12,12 @@ export const DoorRenderer = ({ node }: { node: DoorNode }) => {
|
||||
|
||||
return (
|
||||
<mesh
|
||||
ref={ref}
|
||||
castShadow
|
||||
receiveShadow
|
||||
visible={node.visible}
|
||||
position={node.position}
|
||||
receiveShadow
|
||||
ref={ref}
|
||||
rotation={node.rotation}
|
||||
visible={node.visible}
|
||||
{...(isTransient ? {} : handlers)}
|
||||
>
|
||||
{/* DoorSystem replaces this geometry each time the node is dirty */}
|
||||
|
||||
@@ -15,10 +15,15 @@ export const GuideRenderer = ({ node }: { node: GuideNode }) => {
|
||||
const resolvedUrl = useAssetUrl(node.url)
|
||||
|
||||
return (
|
||||
<group ref={ref} visible={showGuides} position={node.position} rotation={[0, node.rotation[1], 0]}>
|
||||
<group
|
||||
position={node.position}
|
||||
ref={ref}
|
||||
rotation={[0, node.rotation[1], 0]}
|
||||
visible={showGuides}
|
||||
>
|
||||
{resolvedUrl && (
|
||||
<Suspense>
|
||||
<GuidePlane url={resolvedUrl} scale={node.scale} opacity={node.opacity} />
|
||||
<GuidePlane opacity={node.opacity} scale={node.scale} url={resolvedUrl} />
|
||||
</Suspense>
|
||||
)}
|
||||
</group>
|
||||
@@ -53,10 +58,10 @@ const GuidePlane = ({ url, scale, opacity }: { url: string; scale: number; opaci
|
||||
|
||||
return (
|
||||
<mesh
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
frustumCulled={false}
|
||||
material={material}
|
||||
raycast={() => {}}
|
||||
frustumCulled={false}
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
>
|
||||
<planeGeometry args={[width, height]} boundingBox={null} boundingSphere={null} />
|
||||
</mesh>
|
||||
|
||||
@@ -24,7 +24,7 @@ import { NodeRenderer } from '../node-renderer'
|
||||
|
||||
// Shared materials to avoid creating new instances for every mesh
|
||||
const defaultMaterial = new MeshStandardNodeMaterial({
|
||||
color: 0xffffff,
|
||||
color: 0xff_ff_ff,
|
||||
roughness: 1,
|
||||
metalness: 0,
|
||||
})
|
||||
@@ -53,7 +53,7 @@ export const ItemRenderer = ({ node }: { node: ItemNode }) => {
|
||||
useRegistry(node.id, node.type, ref)
|
||||
|
||||
return (
|
||||
<group position={node.position} rotation={node.rotation} ref={ref} visible={node.visible}>
|
||||
<group position={node.position} ref={ref} rotation={node.rotation} visible={node.visible}>
|
||||
<Suspense fallback={<PreviewModel node={node} />}>
|
||||
<ModelRenderer node={node} />
|
||||
</Suspense>
|
||||
@@ -78,7 +78,7 @@ previewMaterial.transparent = true
|
||||
|
||||
const PreviewModel = ({ node }: { node: ItemNode }) => {
|
||||
return (
|
||||
<mesh position-y={node.asset.dimensions[1] / 2} material={previewMaterial}>
|
||||
<mesh material={previewMaterial} position-y={node.asset.dimensions[1] / 2}>
|
||||
<boxGeometry
|
||||
args={[node.asset.dimensions[0], node.asset.dimensions[1], node.asset.dimensions[2]]}
|
||||
/>
|
||||
@@ -150,24 +150,24 @@ const ModelRenderer = ({ node }: { node: ItemNode }) => {
|
||||
return (
|
||||
<>
|
||||
<Clone
|
||||
ref={ref}
|
||||
object={scene}
|
||||
scale={multiplyScales(node.asset.scale || [1, 1, 1], node.scale || [1, 1, 1])}
|
||||
position={node.asset.offset}
|
||||
ref={ref}
|
||||
rotation={node.asset.rotation}
|
||||
scale={multiplyScales(node.asset.scale || [1, 1, 1], node.scale || [1, 1, 1])}
|
||||
{...handlers}
|
||||
/>
|
||||
{animations.length > 0 && (
|
||||
<ItemAnimation
|
||||
nodeId={node.id}
|
||||
animEffect={animEffect}
|
||||
interactive={interactive ?? null}
|
||||
actions={actions}
|
||||
animations={animations}
|
||||
animEffect={animEffect}
|
||||
interactive={interactive ?? null}
|
||||
nodeId={node.id}
|
||||
/>
|
||||
)}
|
||||
{lightEffects.map((effect, i) => (
|
||||
<ItemLight key={i} nodeId={node.id} effect={effect} interactive={interactive!} />
|
||||
<ItemLight effect={effect} interactive={interactive!} key={i} nodeId={node.id} />
|
||||
))}
|
||||
</>
|
||||
)
|
||||
@@ -287,12 +287,12 @@ const ItemLight = ({
|
||||
|
||||
return (
|
||||
<pointLight
|
||||
ref={lightRef}
|
||||
color={effect.color}
|
||||
intensity={effect.intensityRange[0]}
|
||||
distance={effect.distance ?? 0}
|
||||
position={effect.offset}
|
||||
castShadow={false}
|
||||
color={effect.color}
|
||||
distance={effect.distance ?? 0}
|
||||
intensity={effect.intensityRange[0]}
|
||||
position={effect.offset}
|
||||
ref={lightRef}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ export const RoofRenderer = ({ node }: { node: RoofNode }) => {
|
||||
|
||||
return (
|
||||
<mesh
|
||||
ref={ref}
|
||||
castShadow
|
||||
receiveShadow
|
||||
position={node.position}
|
||||
receiveShadow
|
||||
ref={ref}
|
||||
rotation-y={node.rotation}
|
||||
visible={node.visible}
|
||||
{...handlers}
|
||||
|
||||
@@ -14,15 +14,15 @@ export const ScanRenderer = ({ node }: { node: ScanNode }) => {
|
||||
|
||||
return (
|
||||
<group
|
||||
ref={ref}
|
||||
visible={showScans}
|
||||
position={node.position}
|
||||
ref={ref}
|
||||
rotation={node.rotation}
|
||||
scale={[node.scale, node.scale, node.scale]}
|
||||
visible={showScans}
|
||||
>
|
||||
{resolvedUrl && (
|
||||
<Suspense>
|
||||
<ScanModel url={resolvedUrl} opacity={node.opacity} />
|
||||
<ScanModel opacity={node.opacity} url={resolvedUrl} />
|
||||
</Suspense>
|
||||
)}
|
||||
</group>
|
||||
@@ -41,11 +41,11 @@ const ScanModel = ({ url, opacity }: { url: string; opacity: number }) => {
|
||||
if (isTransparent) {
|
||||
material.transparent = true
|
||||
material.opacity = normalizedOpacity
|
||||
material.depthWrite = false;
|
||||
material.depthWrite = false
|
||||
} else {
|
||||
material.transparent = false
|
||||
material.opacity = 1
|
||||
material.depthWrite = true;
|
||||
material.depthWrite = true
|
||||
}
|
||||
material.needsUpdate = true
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"use client";
|
||||
'use client'
|
||||
|
||||
import { useScene } from "@pascal-app/core";
|
||||
import { NodeRenderer } from "./node-renderer";
|
||||
import { useScene } from '@pascal-app/core'
|
||||
import { NodeRenderer } from './node-renderer'
|
||||
|
||||
export const SceneRenderer = () => {
|
||||
const rootNodes = useScene((state) => state.rootNodeIds);
|
||||
const rootNodes = useScene((state) => state.rootNodeIds)
|
||||
|
||||
return (
|
||||
<group name="scene-renderer">
|
||||
@@ -12,5 +12,5 @@ export const SceneRenderer = () => {
|
||||
<NodeRenderer key={nodeId} nodeId={nodeId} />
|
||||
))}
|
||||
</group>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export const SiteRenderer = ({ node }: { node: SiteNode }) => {
|
||||
|
||||
const handlers = useNodeEvents(node, 'site')
|
||||
|
||||
if (!node || !floorShape || !lineGeometry) {
|
||||
if (!(node && floorShape && lineGeometry)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -76,17 +76,16 @@ export const SiteRenderer = ({ node }: { node: SiteNode }) => {
|
||||
))}
|
||||
|
||||
{/* Transparent floor fill */}
|
||||
<mesh position={[0, Y_OFFSET - 0.005, 0]} rotation={[-Math.PI / 2, 0, 0]} receiveShadow>
|
||||
<mesh position={[0, Y_OFFSET - 0.005, 0]} receiveShadow rotation={[-Math.PI / 2, 0, 0]}>
|
||||
<shapeGeometry args={[floorShape]} />
|
||||
<shadowMaterial transparent opacity={0.75} />
|
||||
<shadowMaterial opacity={0.75} transparent />
|
||||
</mesh>
|
||||
|
||||
{/* Simple boundary line */}
|
||||
{/* @ts-ignore */}
|
||||
<line geometry={lineGeometry} frustumCulled={false} renderOrder={9}>
|
||||
<lineBasicMaterial color="#f59e0b" linewidth={2} transparent opacity={0.6} />
|
||||
<line frustumCulled={false} geometry={lineGeometry} renderOrder={9}>
|
||||
<lineBasicMaterial color="#f59e0b" linewidth={2} opacity={0.6} transparent />
|
||||
</line>
|
||||
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export const SlabRenderer = ({ node }: { node: SlabNode }) => {
|
||||
const handlers = useNodeEvents(node, 'slab')
|
||||
|
||||
return (
|
||||
<mesh ref={ref} castShadow receiveShadow {...handlers} visible={node.visible}>
|
||||
<mesh castShadow receiveShadow ref={ref} {...handlers} visible={node.visible}>
|
||||
{/* SlabSystem will replace this geometry in the next frame */}
|
||||
<boxGeometry args={[0, 0, 0]} />
|
||||
<meshStandardMaterial color="#e5e5e5" />
|
||||
|
||||
@@ -12,7 +12,7 @@ export const WallRenderer = ({ node }: { node: WallNode }) => {
|
||||
const handlers = useNodeEvents(node, 'wall')
|
||||
|
||||
return (
|
||||
<mesh ref={ref} castShadow receiveShadow visible={node.visible}>
|
||||
<mesh castShadow receiveShadow ref={ref} visible={node.visible}>
|
||||
{/* WallSystem will replace this geometry in the next frame */}
|
||||
<boxGeometry args={[0, 0, 0]} />
|
||||
{/* Collision mesh: full-wall geometry (no cutouts) for pointer events */}
|
||||
|
||||
@@ -12,12 +12,12 @@ export const WindowRenderer = ({ node }: { node: WindowNode }) => {
|
||||
|
||||
return (
|
||||
<mesh
|
||||
ref={ref}
|
||||
castShadow
|
||||
receiveShadow
|
||||
visible={node.visible}
|
||||
position={node.position}
|
||||
receiveShadow
|
||||
ref={ref}
|
||||
rotation={node.rotation}
|
||||
visible={node.visible}
|
||||
{...(isTransient ? {} : handlers)}
|
||||
>
|
||||
{/* WindowSystem replaces this geometry each time the node is dirty */}
|
||||
|
||||
@@ -173,80 +173,83 @@ export const ZoneRenderer = ({ node }: { node: ZoneNode }) => {
|
||||
|
||||
const handlers = useNodeEvents(node, 'zone')
|
||||
|
||||
if (!node || !floorShape || !wallGeometry || !floorMaterial || !wallMaterial) {
|
||||
if (!(node && floorShape && wallGeometry && floorMaterial && wallMaterial)) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<group ref={ref} {...handlers} userData={{ labelPosition: [centroid[0], 1, centroid[1]] }}>
|
||||
<Html
|
||||
name="label"
|
||||
position={[centroid[0], 1, centroid[1]]}
|
||||
style={{ pointerEvents: 'none', }}
|
||||
style={{ pointerEvents: 'none' }}
|
||||
zIndexRange={[10, 0]}
|
||||
>
|
||||
<div id={`${node.id}-label`} style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
transform: 'translate3d(-50%, -50%, 0)',
|
||||
opacity: 0,
|
||||
transition: 'opacity 0.3s ease-in-out',
|
||||
}}>
|
||||
<div
|
||||
style={{
|
||||
width: 'max-content',
|
||||
color: 'white',
|
||||
textShadow: `-1px -1px 0 ${node.color}, 1px -1px 0 ${node.color}, -1px 1px 0 ${node.color}, 1px 1px 0 ${node.color}`,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
<span>{node.name}</span>
|
||||
</div>
|
||||
<div
|
||||
className="label-pin"
|
||||
id={`${node.id}-label`}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginTop: '2px',
|
||||
transform: 'translate3d(-50%, -50%, 0)',
|
||||
opacity: 0,
|
||||
transition: 'opacity 0.5s ease-in-out',
|
||||
transition: 'opacity 0.3s ease-in-out',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: '2px',
|
||||
height: '40px',
|
||||
backgroundColor: node.color,
|
||||
}}/>
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: node.color,
|
||||
border: `1px solid white`,
|
||||
width: 'max-content',
|
||||
color: 'white',
|
||||
textShadow: `-1px -1px 0 ${node.color}, 1px -1px 0 ${node.color}, -1px 1px 0 ${node.color}, 1px 1px 0 ${node.color}`,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
/>
|
||||
>
|
||||
<span>{node.name}</span>
|
||||
</div>
|
||||
<div
|
||||
className="label-pin"
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginTop: '2px',
|
||||
opacity: 0,
|
||||
transition: 'opacity 0.5s ease-in-out',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: '2px',
|
||||
height: '40px',
|
||||
backgroundColor: node.color,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
width: '10px',
|
||||
height: '10px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor: node.color,
|
||||
border: '1px solid white',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Html>
|
||||
|
||||
{/* Floor fill */}
|
||||
<mesh
|
||||
position={[0, Y_OFFSET, 0]}
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
layers={ZONE_LAYER}
|
||||
material={floorMaterial}
|
||||
name="floor"
|
||||
layers={ZONE_LAYER}
|
||||
position={[0, Y_OFFSET, 0]}
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
>
|
||||
<shapeGeometry args={[floorShape]} />
|
||||
</mesh>
|
||||
|
||||
{/* Wall borders with gradient */}
|
||||
<mesh geometry={wallGeometry} material={wallMaterial} name="walls" layers={ZONE_LAYER} />
|
||||
<mesh geometry={wallGeometry} layers={ZONE_LAYER} material={wallMaterial} name="walls" />
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user