@pascal-app/viewer 0.1.12 → 0.1.13

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.
@@ -1 +1 @@
1
- {"version":3,"file":"item-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/item/item-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAyB,MAAM,kBAAkB,CAAA;AAmCvF,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAYxD,CAAA"}
1
+ {"version":3,"file":"item-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/item/item-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,QAAQ,EAAyB,MAAM,kBAAkB,CAAA;AAoCvF,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAexD,CAAA"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useRegistry, useScene } from '@pascal-app/core';
3
3
  import { Clone } from '@react-three/drei/core/Clone';
4
4
  import { useGLTF } from '@react-three/drei/core/Gltf';
@@ -7,6 +7,7 @@ import { positionLocal, smoothstep, time } from 'three/tsl';
7
7
  import { DoubleSide, MeshStandardNodeMaterial } from 'three/webgpu';
8
8
  import { useNodeEvents } from '../../../hooks/use-node-events';
9
9
  import { resolveCdnUrl } from '../../../lib/asset-url';
10
+ import { NodeRenderer } from '../node-renderer';
10
11
  // Shared materials to avoid creating new instances for every mesh
11
12
  const defaultMaterial = new MeshStandardNodeMaterial({
12
13
  color: 0xffffff,
@@ -32,7 +33,7 @@ const getMaterialForOriginal = (original) => {
32
33
  export const ItemRenderer = ({ node }) => {
33
34
  const ref = useRef(null);
34
35
  useRegistry(node.id, node.type, ref);
35
- return (_jsx("group", { position: node.position, rotation: node.rotation, ref: ref, visible: node.visible, children: _jsx(Suspense, { fallback: _jsx(PreviewModel, { node: node }), children: _jsx(ModelRenderer, { node: node }) }) }));
36
+ return (_jsxs("group", { position: node.position, rotation: node.rotation, ref: ref, visible: node.visible, children: [_jsx(Suspense, { fallback: _jsx(PreviewModel, { node: node }), children: _jsx(ModelRenderer, { node: node }) }), node.children?.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId)))] }));
36
37
  };
37
38
  const previewMaterial = new MeshStandardNodeMaterial({
38
39
  color: '#cccccc',
@@ -1 +1 @@
1
- {"version":3,"file":"node-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/renderers/node-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAY,MAAM,kBAAkB,CAAA;AAazD,eAAO,MAAM,YAAY,GAAI,YAAY;IAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,mDAoBjE,CAAA"}
1
+ {"version":3,"file":"node-renderer.d.ts","sourceRoot":"","sources":["../../../src/components/renderers/node-renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,OAAO,EAAY,MAAM,kBAAkB,CAAA;AAczD,eAAO,MAAM,YAAY,GAAI,YAAY;IAAE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,mDAqBjE,CAAA"}
@@ -11,10 +11,11 @@ import { ScanRenderer } from './scan/scan-renderer';
11
11
  import { SiteRenderer } from './site/site-renderer';
12
12
  import { SlabRenderer } from './slab/slab-renderer';
13
13
  import { WallRenderer } from './wall/wall-renderer';
14
+ import { WindowRenderer } from './window/window-renderer';
14
15
  import { ZoneRenderer } from './zone/zone-renderer';
15
16
  export const NodeRenderer = ({ nodeId }) => {
16
17
  const node = useScene((state) => state.nodes[nodeId]);
17
18
  if (!node)
18
19
  return null;
19
- return (_jsxs(_Fragment, { children: [node.type === 'site' && _jsx(SiteRenderer, { node: node }), node.type === 'building' && _jsx(BuildingRenderer, { node: node }), node.type === 'ceiling' && _jsx(CeilingRenderer, { node: node }), node.type === 'level' && _jsx(LevelRenderer, { node: node }), node.type === 'item' && _jsx(ItemRenderer, { node: node }), node.type === 'slab' && _jsx(SlabRenderer, { node: node }), node.type === 'wall' && _jsx(WallRenderer, { node: node }), node.type === 'zone' && _jsx(ZoneRenderer, { node: node }), node.type === 'roof' && _jsx(RoofRenderer, { node: node }), node.type === 'scan' && _jsx(ScanRenderer, { node: node }), node.type === 'guide' && _jsx(GuideRenderer, { node: node })] }));
20
+ return (_jsxs(_Fragment, { children: [node.type === 'site' && _jsx(SiteRenderer, { node: node }), node.type === 'building' && _jsx(BuildingRenderer, { node: node }), node.type === 'ceiling' && _jsx(CeilingRenderer, { node: node }), node.type === 'level' && _jsx(LevelRenderer, { node: node }), node.type === 'item' && _jsx(ItemRenderer, { node: node }), node.type === 'slab' && _jsx(SlabRenderer, { node: node }), node.type === 'wall' && _jsx(WallRenderer, { node: node }), node.type === 'window' && _jsx(WindowRenderer, { node: node }), node.type === 'zone' && _jsx(ZoneRenderer, { node: node }), node.type === 'roof' && _jsx(RoofRenderer, { node: node }), node.type === 'scan' && _jsx(ScanRenderer, { node: node }), node.type === 'guide' && _jsx(GuideRenderer, { node: node })] }));
20
21
  };
@@ -1 +1 @@
1
- {"version":3,"file":"site-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/site/site-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAe,MAAM,kBAAkB,CAAA;AAiC7D,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,mDAmGxD,CAAA"}
1
+ {"version":3,"file":"site-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/site/site-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAe,MAAM,kBAAkB,CAAA;AAiC7D,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,mDAwFxD,CAAA"}
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useRegistry } from '@pascal-app/core';
3
3
  import { Html } from '@react-three/drei';
4
4
  import { useMemo, useRef } from 'react';
5
- import { BufferGeometry, DoubleSide, Float32BufferAttribute, Shape } from 'three';
5
+ import { BufferGeometry, Float32BufferAttribute, Shape } from 'three';
6
6
  import { useNodeEvents } from '../../../hooks/use-node-events';
7
7
  import { NodeRenderer } from '../node-renderer';
8
8
  const Y_OFFSET = 0.01;
@@ -67,5 +67,5 @@ export const SiteRenderer = ({ node }) => {
67
67
  if (!node || !floorShape || !lineGeometry) {
68
68
  return null;
69
69
  }
70
- return (_jsxs("group", { ref: ref, ...handlers, children: [node.children.map((child) => (_jsx(NodeRenderer, { nodeId: typeof child === 'string' ? child : child.id }, typeof child === 'string' ? child : child.id))), _jsxs("mesh", { position: [0, Y_OFFSET - 0.005, 0], rotation: [-Math.PI / 2, 0, 0], children: [_jsx("shapeGeometry", { args: [floorShape] }), _jsx("meshBasicMaterial", { color: "#f59e0b", transparent: true, opacity: 0.05, side: DoubleSide, depthWrite: false })] }), _jsx("line", { geometry: lineGeometry, frustumCulled: false, renderOrder: 9, children: _jsx("lineBasicMaterial", { color: "#f59e0b", linewidth: 2, transparent: true, opacity: 0.6 }) }), edges.map((edge, i) => (_jsx(Html, { center: true, position: [edge.midX, 0.5, edge.midZ], style: { pointerEvents: 'none', userSelect: 'none' }, zIndexRange: [10, 0], occlude: true, children: _jsxs("div", { className: "whitespace-nowrap rounded bg-black/75 px-1.5 py-0.5 font-mono text-white text-xs backdrop-blur-sm", children: [edge.dist.toFixed(2), "m"] }) }, `edge-${i}`)))] }));
70
+ return (_jsxs("group", { ref: ref, ...handlers, children: [node.children.map((child) => (_jsx(NodeRenderer, { nodeId: typeof child === 'string' ? child : child.id }, typeof child === 'string' ? child : child.id))), _jsxs("mesh", { position: [0, Y_OFFSET - 0.005, 0], rotation: [-Math.PI / 2, 0, 0], receiveShadow: true, children: [_jsx("shapeGeometry", { args: [floorShape] }), _jsx("shadowMaterial", { transparent: true, opacity: 0.75 })] }), _jsx("line", { geometry: lineGeometry, frustumCulled: false, renderOrder: 9, children: _jsx("lineBasicMaterial", { color: "#f59e0b", linewidth: 2, transparent: true, opacity: 0.6 }) }), edges.map((edge, i) => (_jsx(Html, { center: true, position: [edge.midX, 0.5, edge.midZ], style: { pointerEvents: 'none', userSelect: 'none' }, zIndexRange: [10, 0], occlude: true, children: _jsxs("div", { className: "whitespace-nowrap rounded bg-black/75 px-1.5 py-0.5 font-mono text-white text-xs backdrop-blur-sm", children: [edge.dist.toFixed(2), "m"] }) }, `edge-${i}`)))] }));
71
71
  };
@@ -0,0 +1,5 @@
1
+ import { type WindowNode } from '@pascal-app/core';
2
+ export declare const WindowRenderer: ({ node }: {
3
+ node: WindowNode;
4
+ }) => import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=window-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/window/window-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAK/D,eAAO,MAAM,cAAc,GAAI,UAAU;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,4CAqB5D,CAAA"}
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useRegistry } from '@pascal-app/core';
3
+ import { useRef } from 'react';
4
+ import { useNodeEvents } from '../../../hooks/use-node-events';
5
+ export const WindowRenderer = ({ node }) => {
6
+ const ref = useRef(null);
7
+ useRegistry(node.id, 'window', ref);
8
+ const handlers = useNodeEvents(node, 'window');
9
+ return (_jsxs("mesh", { ref: ref, castShadow: true, receiveShadow: true, visible: node.visible, position: node.position, rotation: node.rotation, ...handlers, children: [_jsx("boxGeometry", { args: [0, 0, 0] }), _jsx("meshStandardMaterial", { color: "#d1d5db" })] }));
10
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC5E,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAYrC,OAAO,QAAQ,oBAAoB,CAAC;IAClC,UAAU,aAAc,SAAQ,kBAAkB,CAAC,OAAO,KAAK,CAAC;KAAG;CACpE;AAID,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,gBAAgB,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;CACxC;AAED,QAAA,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA8CjC,CAAA;AAED,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/index.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC5E,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAYrC,OAAO,QAAQ,oBAAoB,CAAC;IAClC,UAAU,aAAc,SAAQ,kBAAkB,CAAC,OAAO,KAAK,CAAC;KAAG;CACpE;AAID,UAAU,WAAW;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,gBAAgB,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;CACxC;AAED,QAAA,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CA+CjC,CAAA;AAED,eAAe,MAAM,CAAA"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { CeilingSystem, ItemSystem, RoofSystem, SlabSystem, WallSystem } from '@pascal-app/core';
3
+ import { CeilingSystem, ItemSystem, RoofSystem, SlabSystem, WallSystem, WindowSystem } from '@pascal-app/core';
4
4
  import { Bvh } from '@react-three/drei';
5
5
  import { Canvas, extend } from '@react-three/fiber';
6
6
  import * as THREE from 'three/webgpu';
@@ -25,6 +25,6 @@ const Viewer = ({ children, selectionManager = 'default' }) => {
25
25
  }, shadows: {
26
26
  type: THREE.PCFShadowMap,
27
27
  enabled: true,
28
- }, camera: { position: [50, 50, 50], fov: 50 }, children: [_jsx("color", { attach: "background", args: ['#fafafa'] }), _jsx(ViewerCamera, {}), _jsx(Lights, {}), _jsx(Bvh, { children: _jsx(SceneRenderer, {}) }), _jsx(LevelSystem, {}), _jsx(GuideSystem, {}), _jsx(ScanSystem, {}), _jsx(WallCutout, {}), _jsx(CeilingSystem, {}), _jsx(ItemSystem, {}), _jsx(RoofSystem, {}), _jsx(SlabSystem, {}), _jsx(WallSystem, {}), _jsx(ZoneSystem, {}), _jsx(PostProcessing, {}), selectionManager === 'default' && _jsx(SelectionManager, {}), children] }));
28
+ }, camera: { position: [50, 50, 50], fov: 50 }, children: [_jsx("color", { attach: "background", args: ['#fafafa'] }), _jsx(ViewerCamera, {}), _jsx(Lights, {}), _jsx(Bvh, { children: _jsx(SceneRenderer, {}) }), _jsx(LevelSystem, {}), _jsx(GuideSystem, {}), _jsx(ScanSystem, {}), _jsx(WallCutout, {}), _jsx(CeilingSystem, {}), _jsx(ItemSystem, {}), _jsx(RoofSystem, {}), _jsx(SlabSystem, {}), _jsx(WallSystem, {}), _jsx(WindowSystem, {}), _jsx(ZoneSystem, {}), _jsx(PostProcessing, {}), selectionManager === 'default' && _jsx(SelectionManager, {}), children] }));
29
29
  };
30
30
  export default Viewer;
@@ -10,7 +10,7 @@ import useViewer from '../../store/use-viewer';
10
10
  // SSGI Parameters - adjust these to fine-tune global illumination and ambient occlusion
11
11
  export const SSGI_PARAMS = {
12
12
  enabled: true,
13
- sliceCount: 1,
13
+ sliceCount: 2,
14
14
  stepCount: 8,
15
15
  radius: 1,
16
16
  expFactor: 1.5,
@@ -70,8 +70,6 @@ const PostProcessingPasses = () => {
70
70
  const ao = giPass.a;
71
71
  // Composite: scene * AO + diffuse * GI
72
72
  const compositePass = vec4(add(scenePassColor.rgb.mul(ao), scenePassDiffuse.rgb.mul(gi)), scenePassColor.a);
73
- // TRAA (Temporal Reprojection Anti-Aliasing)
74
- const traaPass = traa(compositePass, scenePassDepth, scenePassVelocity, camera);
75
73
  function generateSelectedOutlinePass() {
76
74
  const edgeStrength = uniform(3);
77
75
  const edgeGlow = uniform(0);
@@ -116,10 +114,12 @@ const PostProcessingPasses = () => {
116
114
  const postProcessing = new PostProcessing(renderer);
117
115
  const selectedOutlinePass = generateSelectedOutlinePass();
118
116
  const hoverOutlinePass = generateHoverOutlinePass();
119
- // Combine SSGI output with outlines
120
- const finalOutput = SSGI_PARAMS.enabled
121
- ? selectedOutlinePass.add(hoverOutlinePass).add(traaPass)
122
- : selectedOutlinePass.add(hoverOutlinePass).add(scenePassColor);
117
+ // Combine composite with outlines BEFORE applying TRAA
118
+ const compositeWithOutlines = SSGI_PARAMS.enabled
119
+ ? vec4(add(compositePass.rgb, selectedOutlinePass.add(hoverOutlinePass)), compositePass.a)
120
+ : vec4(add(scenePassColor.rgb, selectedOutlinePass.add(hoverOutlinePass)), scenePassColor.a);
121
+ // TRAA (Temporal Reprojection Anti-Aliasing) - applied AFTER combining everything
122
+ const finalOutput = traa(compositeWithOutlines, scenePassDepth, scenePassVelocity, camera);
123
123
  postProcessing.outputNode = finalOutput;
124
124
  postProcessingRef.current = postProcessing;
125
125
  return () => {
@@ -1 +1 @@
1
- {"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/selection-manager.tsx"],"names":[],"mappings":"AAkNA,eAAO,MAAM,gBAAgB,+CA0D5B,CAAA"}
1
+ {"version":3,"file":"selection-manager.d.ts","sourceRoot":"","sources":["../../../src/components/viewer/selection-manager.tsx"],"names":[],"mappings":"AAkOA,eAAO,MAAM,gBAAgB,+CAoE5B,CAAA"}
@@ -144,14 +144,16 @@ const getStrategy = () => {
144
144
  isValid: (node) => node.type === 'zone' && node.parentId === levelId,
145
145
  };
146
146
  }
147
- // Zone selected -> can select/hover contents (walls, items, slabs, ceilings, roofs)
147
+ // Zone selected -> can select/hover contents (walls, items, slabs, ceilings, roofs, windows)
148
148
  return {
149
- types: ['wall', 'item', 'slab', 'ceiling', 'roof'],
149
+ types: ['wall', 'item', 'slab', 'ceiling', 'roof', 'window'],
150
150
  handleClick: (node) => {
151
151
  const { selectedIds } = useViewer.getState().selection;
152
152
  // Toggle selection - if already selected, deselect; otherwise select
153
153
  if (selectedIds.includes(node.id)) {
154
- useViewer.getState().setSelection({ selectedIds: selectedIds.filter((id) => id !== node.id) });
154
+ useViewer
155
+ .getState()
156
+ .setSelection({ selectedIds: selectedIds.filter((id) => id !== node.id) });
155
157
  }
156
158
  else {
157
159
  useViewer.getState().setSelection({ selectedIds: [node.id] });
@@ -168,7 +170,7 @@ const getStrategy = () => {
168
170
  }
169
171
  },
170
172
  isValid: (node) => {
171
- const validTypes = ['wall', 'item', 'slab', 'ceiling', 'roof'];
173
+ const validTypes = ['wall', 'item', 'slab', 'ceiling', 'roof', 'window'];
172
174
  if (!validTypes.includes(node.type))
173
175
  return false;
174
176
  return isNodeInZone(node, levelId, zoneId);
@@ -210,7 +212,17 @@ export const SelectionManager = () => {
210
212
  useViewer.setState({ hoveredId: null });
211
213
  };
212
214
  // Subscribe to all node types
213
- const allTypes = ['building', 'level', 'zone', 'wall', 'item', 'slab', 'ceiling', 'roof'];
215
+ const allTypes = [
216
+ 'building',
217
+ 'level',
218
+ 'zone',
219
+ 'wall',
220
+ 'item',
221
+ 'slab',
222
+ 'ceiling',
223
+ 'roof',
224
+ 'window',
225
+ ];
214
226
  for (const type of allTypes) {
215
227
  emitter.on(`${type}:enter`, onEnter);
216
228
  emitter.on(`${type}:leave`, onLeave);
@@ -223,14 +235,16 @@ export const SelectionManager = () => {
223
235
  emitter.off(`${type}:click`, onClick);
224
236
  }
225
237
  };
226
- }, [selection]);
238
+ }, []);
227
239
  return (_jsxs(_Fragment, { children: [_jsx(PointerMissedHandler, { clickHandledRef: clickHandledRef }), _jsx(OutlinerSync, {})] }));
228
240
  };
229
- const PointerMissedHandler = ({ clickHandledRef }) => {
241
+ const PointerMissedHandler = ({ clickHandledRef, }) => {
230
242
  const gl = useThree((s) => s.gl);
231
243
  useEffect(() => {
232
244
  const handleClick = (event) => {
233
245
  // Only handle left clicks
246
+ if (useViewer.getState().cameraDragging)
247
+ return;
234
248
  if (event.button !== 0)
235
249
  return;
236
250
  // Use requestAnimationFrame to check after R3F event handlers
@@ -1,4 +1,4 @@
1
- import { type BuildingEvent, type BuildingNode, type CeilingEvent, type CeilingNode, type ItemEvent, type ItemNode, type LevelEvent, type LevelNode, type RoofEvent, type RoofNode, type SiteEvent, type SiteNode, type SlabEvent, type SlabNode, type WallEvent, type WallNode, type ZoneEvent, type ZoneNode } from '@pascal-app/core';
1
+ import { type BuildingEvent, type BuildingNode, type CeilingEvent, type CeilingNode, type ItemEvent, type ItemNode, type LevelEvent, type LevelNode, type RoofEvent, type RoofNode, type SiteEvent, type SiteNode, type SlabEvent, type SlabNode, type WallEvent, type WallNode, type WindowEvent, type WindowNode, type ZoneEvent, type ZoneNode } from '@pascal-app/core';
2
2
  import type { ThreeEvent } from '@react-three/fiber';
3
3
  type NodeConfig = {
4
4
  site: {
@@ -37,6 +37,10 @@ type NodeConfig = {
37
37
  node: RoofNode;
38
38
  event: RoofEvent;
39
39
  };
40
+ window: {
41
+ node: WindowNode;
42
+ event: WindowEvent;
43
+ };
40
44
  };
41
45
  type NodeType = keyof NodeConfig;
42
46
  export declare function useNodeEvents<T extends NodeType>(node: NodeConfig[T]['node'], type: T): {
@@ -1 +1 @@
1
- {"version":3,"file":"use-node-events.d.ts","sourceRoot":"","sources":["../../src/hooks/use-node-events.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAGhB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAEpD,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,QAAQ,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,CAAA;IACtD,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;IAC7C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,OAAO,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,CAAA;IACnD,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;CAC3C,CAAA;AAED,KAAK,QAAQ,GAAG,MAAM,UAAU,CAAA;AAEhC,wBAAgB,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;uBAiB/D,UAAU,CAAC,YAAY,CAAC;qBAI1B,UAAU,CAAC,YAAY,CAAC;iBAI5B,UAAU,CAAC,YAAY,CAAC;wBAIjB,UAAU,CAAC,YAAY,CAAC;wBACxB,UAAU,CAAC,YAAY,CAAC;uBACzB,UAAU,CAAC,YAAY,CAAC;uBACxB,UAAU,CAAC,YAAY,CAAC;uBACxB,UAAU,CAAC,YAAY,CAAC;EAE9C"}
1
+ {"version":3,"file":"use-node-events.d.ts","sourceRoot":"","sources":["../../src/hooks/use-node-events.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAGhB,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAGpD,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,QAAQ,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,aAAa,CAAA;KAAE,CAAA;IACtD,KAAK,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAA;IAC7C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,OAAO,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,CAAA;IACnD,IAAI,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,SAAS,CAAA;KAAE,CAAA;IAC1C,MAAM,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,CAAA;CACjD,CAAA;AAED,KAAK,QAAQ,GAAG,MAAM,UAAU,CAAA;AAEhC,wBAAgB,aAAa,CAAC,CAAC,SAAS,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;uBAiB/D,UAAU,CAAC,YAAY,CAAC;qBAK1B,UAAU,CAAC,YAAY,CAAC;iBAK5B,UAAU,CAAC,YAAY,CAAC;wBAKjB,UAAU,CAAC,YAAY,CAAC;wBAIxB,UAAU,CAAC,YAAY,CAAC;uBAIzB,UAAU,CAAC,YAAY,CAAC;uBAIxB,UAAU,CAAC,YAAY,CAAC;uBAIxB,UAAU,CAAC,YAAY,CAAC;EAK9C"}
@@ -1,4 +1,5 @@
1
1
  import { emitter, } from '@pascal-app/core';
2
+ import useViewer from '../store/use-viewer';
2
3
  export function useNodeEvents(node, type) {
3
4
  const emit = (suffix, e) => {
4
5
  const eventKey = `${type}:${suffix}`;
@@ -15,24 +16,50 @@ export function useNodeEvents(node, type) {
15
16
  };
16
17
  return {
17
18
  onPointerDown: (e) => {
19
+ if (useViewer.getState().cameraDragging)
20
+ return;
18
21
  if (e.button !== 0)
19
22
  return;
20
23
  emit('pointerdown', e);
21
24
  },
22
25
  onPointerUp: (e) => {
26
+ if (useViewer.getState().cameraDragging)
27
+ return;
23
28
  if (e.button !== 0)
24
29
  return;
25
30
  emit('pointerup', e);
26
31
  },
27
32
  onClick: (e) => {
33
+ if (useViewer.getState().cameraDragging)
34
+ return;
28
35
  if (e.button !== 0)
29
36
  return;
30
37
  emit('click', e);
31
38
  },
32
- onPointerEnter: (e) => emit('enter', e),
33
- onPointerLeave: (e) => emit('leave', e),
34
- onPointerMove: (e) => emit('move', e),
35
- onDoubleClick: (e) => emit('double-click', e),
36
- onContextMenu: (e) => emit('context-menu', e),
39
+ onPointerEnter: (e) => {
40
+ if (useViewer.getState().cameraDragging)
41
+ return;
42
+ emit('enter', e);
43
+ },
44
+ onPointerLeave: (e) => {
45
+ if (useViewer.getState().cameraDragging)
46
+ return;
47
+ emit('leave', e);
48
+ },
49
+ onPointerMove: (e) => {
50
+ if (useViewer.getState().cameraDragging)
51
+ return;
52
+ emit('move', e);
53
+ },
54
+ onDoubleClick: (e) => {
55
+ if (useViewer.getState().cameraDragging)
56
+ return;
57
+ emit('double-click', e);
58
+ },
59
+ onContextMenu: (e) => {
60
+ if (useViewer.getState().cameraDragging)
61
+ return;
62
+ emit('context-menu', e);
63
+ },
37
64
  };
38
65
  }
@@ -29,6 +29,8 @@ type ViewerState = {
29
29
  outliner: Outliner;
30
30
  exportScene: (() => Promise<void>) | null;
31
31
  setExportScene: (fn: (() => Promise<void>) | null) => void;
32
+ cameraDragging: boolean;
33
+ setCameraDragging: (dragging: boolean) => void;
32
34
  };
33
35
  declare const useViewer: import("zustand").UseBoundStore<import("zustand").StoreApi<ViewerState>>;
34
36
  export default useViewer;
@@ -1 +1 @@
1
- {"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAItC,KAAK,aAAa,GAAG;IACnB,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;CAC/B,CAAC;AAEF,KAAK,QAAQ,GAAG;IACd,eAAe,EAAE,QAAQ,EAAE,CAAC;IAC5B,cAAc,EAAE,QAAQ,EAAE,CAAC;CAC5B,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,aAAa,CAAA;IACxB,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,YAAY,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,CAAA;IAEjE,UAAU,EAAE,aAAa,GAAG,cAAc,CAAA;IAC1C,aAAa,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,KAAK,IAAI,CAAA;IAE7D,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAA;IACrD,YAAY,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,KAAK,IAAI,CAAA;IAExE,QAAQ,EAAE,IAAI,GAAG,SAAS,GAAG,MAAM,CAAA;IACnC,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,GAAG,MAAM,KAAK,IAAI,CAAA;IAEtD,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAErC,UAAU,EAAE,OAAO,CAAA;IACnB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAGtC,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,IAAI,CAAA;IACvD,cAAc,EAAE,MAAM,IAAI,CAAA;IAE1B,QAAQ,EAAE,QAAQ,CAAA;IAGlB,WAAW,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAA;IACzC,cAAc,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,IAAI,CAAA;CAC3D,CAAA;AAED,QAAA,MAAM,SAAS,0EAqDZ,CAAC;AAEJ,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAItC,KAAK,aAAa,GAAG;IACnB,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;CAC/B,CAAC;AAEF,KAAK,QAAQ,GAAG;IACd,eAAe,EAAE,QAAQ,EAAE,CAAC;IAC5B,cAAc,EAAE,QAAQ,EAAE,CAAC;CAC5B,CAAC;AAEF,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,aAAa,CAAA;IACxB,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,YAAY,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,CAAA;IAEjE,UAAU,EAAE,aAAa,GAAG,cAAc,CAAA;IAC1C,aAAa,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,KAAK,IAAI,CAAA;IAE7D,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAA;IACrD,YAAY,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,KAAK,IAAI,CAAA;IAExE,QAAQ,EAAE,IAAI,GAAG,SAAS,GAAG,MAAM,CAAA;IACnC,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,GAAG,MAAM,KAAK,IAAI,CAAA;IAEtD,SAAS,EAAE,OAAO,CAAA;IAClB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAErC,UAAU,EAAE,OAAO,CAAA;IACnB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAGtC,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,IAAI,CAAA;IACvD,cAAc,EAAE,MAAM,IAAI,CAAA;IAE1B,QAAQ,EAAE,QAAQ,CAAA;IAGlB,WAAW,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAA;IACzC,cAAc,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,IAAI,CAAA;IAE1D,cAAc,EAAE,OAAO,CAAA;IACvB,iBAAiB,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;CAC/C,CAAA;AAED,QAAA,MAAM,SAAS,0EAwDZ,CAAC;AAEJ,eAAe,SAAS,CAAC"}
@@ -42,5 +42,7 @@ const useViewer = create()((set, get) => ({
42
42
  outliner: { selectedObjects: [], hoveredObjects: [] },
43
43
  exportScene: null,
44
44
  setExportScene: (fn) => set({ exportScene: fn }),
45
+ cameraDragging: false,
46
+ setCameraDragging: (dragging) => set({ cameraDragging: dragging }),
45
47
  }));
46
48
  export default useViewer;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pascal-app/viewer",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "3D viewer component for Pascal building editor",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,8 +49,10 @@
49
49
  ],
50
50
  "repository": {
51
51
  "type": "git",
52
- "url": "https://github.com/your-username/pascal-editor.git",
52
+ "url": "https://github.com/pascalorg/editor.git",
53
53
  "directory": "packages/viewer"
54
54
  },
55
- "license": "MIT"
55
+ "license": "MIT",
56
+ "homepage": "https://github.com/pascalorg/editor/tree/main/packages/viewer#readme",
57
+ "bugs": "https://github.com/pascalorg/editor/issues"
56
58
  }
@@ -1,12 +0,0 @@
1
- import type { ThreeEvent } from "@react-three/fiber";
2
- export declare function useGridEvents(): {
3
- onPointerDown: (e: ThreeEvent<PointerEvent>) => void;
4
- onPointerUp: (e: ThreeEvent<PointerEvent>) => void;
5
- onClick: (e: ThreeEvent<PointerEvent>) => void;
6
- onPointerEnter: (e: ThreeEvent<PointerEvent>) => void;
7
- onPointerLeave: (e: ThreeEvent<PointerEvent>) => void;
8
- onPointerMove: (e: ThreeEvent<PointerEvent>) => void;
9
- onDoubleClick: (e: ThreeEvent<PointerEvent>) => void;
10
- onContextMenu: (e: ThreeEvent<PointerEvent>) => void;
11
- };
12
- //# sourceMappingURL=use-grid-events.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-grid-events.d.ts","sourceRoot":"","sources":["../../src/hooks/use-grid-events.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,wBAAgB,aAAa;uBAYN,UAAU,CAAC,YAAY,CAAC;qBAI1B,UAAU,CAAC,YAAY,CAAC;iBAI5B,UAAU,CAAC,YAAY,CAAC;wBAIjB,UAAU,CAAC,YAAY,CAAC;wBACxB,UAAU,CAAC,YAAY,CAAC;uBACzB,UAAU,CAAC,YAAY,CAAC;uBACxB,UAAU,CAAC,YAAY,CAAC;uBACxB,UAAU,CAAC,YAAY,CAAC;EAE9C"}
@@ -1,33 +0,0 @@
1
- import { emitter } from "@pascal-app/core";
2
- export function useGridEvents() {
3
- const emit = (suffix, e) => {
4
- const eventKey = `grid:${suffix}`;
5
- const payload = {
6
- position: [e.point.x, e.point.y, e.point.z],
7
- nativeEvent: e,
8
- };
9
- emitter.emit(eventKey, payload);
10
- };
11
- return {
12
- onPointerDown: (e) => {
13
- if (e.button !== 0)
14
- return;
15
- emit("pointerdown", e);
16
- },
17
- onPointerUp: (e) => {
18
- if (e.button !== 0)
19
- return;
20
- emit("pointerup", e);
21
- },
22
- onClick: (e) => {
23
- if (e.button !== 0)
24
- return;
25
- emit("click", e);
26
- },
27
- onPointerEnter: (e) => emit("enter", e),
28
- onPointerLeave: (e) => emit("leave", e),
29
- onPointerMove: (e) => emit("move", e),
30
- onDoubleClick: (e) => emit("double-click", e),
31
- onContextMenu: (e) => emit("context-menu", e),
32
- };
33
- }