@treasuryspatial/viewer-kit 0.2.39 → 0.2.41

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.
@@ -20,6 +20,7 @@ export declare class ViewerEngine {
20
20
  private lastWidth;
21
21
  private lastHeight;
22
22
  private maxPixelRatio;
23
+ private hasDominantGroundPlane;
23
24
  constructor(options: ViewerCreateOptions);
24
25
  getHandle(): ViewerHandle;
25
26
  private invalidate;
@@ -1 +1 @@
1
- {"version":3,"file":"ViewerEngine.d.ts","sourceRoot":"","sources":["../../src/engine/ViewerEngine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,WAAW,EAAiB,sBAAsB,EAAE,mBAAmB,EAAmB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAQrK,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAiB;IAE1D,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,WAAW,CAA2B;IAE9C,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,iBAAiB,CAAU;IAEnC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;gBAElB,OAAO,EAAE,mBAAmB;IAwDxC,SAAS,IAAI,YAAY;IA0BzB,OAAO,CAAC,UAAU;IAKlB,KAAK,IAAI,IAAI;IAiBb,IAAI,IAAI,IAAI;IAQZ,MAAM,IAAI,IAAI;IAcd,OAAO,IAAI,IAAI;IAef,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIjC,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAStD,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAoDjC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;IAuB5C,cAAc,IAAI,WAAW;IAUvB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAmCjC,WAAW,IAAI,cAAc;IAe7B,OAAO,CAAC,YAAY;IAuCpB,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,aAAa;CAKtB"}
1
+ {"version":3,"file":"ViewerEngine.d.ts","sourceRoot":"","sources":["../../src/engine/ViewerEngine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,WAAW,EAAiB,sBAAsB,EAAE,mBAAmB,EAAmB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAQrK,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAiB;IAE1D,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,WAAW,CAA2B;IAE9C,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,iBAAiB,CAAU;IAEnC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAS;IAE9B,OAAO,CAAC,sBAAsB;gBAiClB,OAAO,EAAE,mBAAmB;IAwDxC,SAAS,IAAI,YAAY;IA0BzB,OAAO,CAAC,UAAU;IAKlB,KAAK,IAAI,IAAI;IAiBb,IAAI,IAAI,IAAI;IAQZ,MAAM,IAAI,IAAI;IAcd,OAAO,IAAI,IAAI;IAef,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIjC,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,IAAI;IAStD,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IA8DjC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI;IAuB5C,cAAc,IAAI,WAAW;IAUvB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAmCjC,WAAW,IAAI,cAAc;IAe7B,OAAO,CAAC,YAAY;IAuCpB,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,aAAa;CAKtB"}
@@ -27,6 +27,41 @@ export class ViewerEngine {
27
27
  lastWidth;
28
28
  lastHeight;
29
29
  maxPixelRatio;
30
+ hasDominantGroundPlane(root, bounds) {
31
+ if (!bounds || bounds.isEmpty())
32
+ return false;
33
+ const size = new THREE.Vector3();
34
+ bounds.getSize(size);
35
+ const planSpan = Math.max(size.x, size.z);
36
+ const minY = bounds.min.y;
37
+ const heightThreshold = Math.max(0.05, size.y * 0.02);
38
+ const planThreshold = planSpan * 0.7;
39
+ let detected = false;
40
+ root.updateMatrixWorld(true);
41
+ root.traverse((object) => {
42
+ if (detected)
43
+ return;
44
+ const mesh = object;
45
+ if (!mesh.isMesh || !mesh.geometry)
46
+ return;
47
+ const geometry = mesh.geometry;
48
+ geometry.computeBoundingBox();
49
+ const bbox = geometry.boundingBox?.clone();
50
+ if (!bbox)
51
+ return;
52
+ bbox.applyMatrix4(mesh.matrixWorld);
53
+ const spanX = bbox.max.x - bbox.min.x;
54
+ const spanZ = bbox.max.z - bbox.min.z;
55
+ const spanY = bbox.max.y - bbox.min.y;
56
+ const nearFloor = Math.abs(bbox.min.y - minY) <= heightThreshold * 1.5;
57
+ const flat = spanY <= heightThreshold;
58
+ const large = spanX >= planThreshold && spanZ >= planThreshold;
59
+ if (nearFloor && flat && large) {
60
+ detected = true;
61
+ }
62
+ });
63
+ return detected;
64
+ }
30
65
  constructor(options) {
31
66
  this.container = options.container;
32
67
  const basePresets = options.presets ?? DEFAULT_PRESETS;
@@ -205,7 +240,17 @@ export class ViewerEngine {
205
240
  // Re-apply scene extras (ground/grid) to match updated bounds.
206
241
  try {
207
242
  const preset = this.resolvePreset(this.presetId);
208
- this.debugSystem.apply(preset, this.sceneBounds);
243
+ const disableGround = this.hasDominantGroundPlane(this.rootGroup, this.sceneBounds);
244
+ const debugPreset = disableGround
245
+ ? {
246
+ ...preset,
247
+ sceneExtras: {
248
+ ...(preset.sceneExtras ?? {}),
249
+ ground: false,
250
+ },
251
+ }
252
+ : preset;
253
+ this.debugSystem.apply(debugPreset, this.sceneBounds);
209
254
  }
210
255
  catch {
211
256
  // ignore debug system failures
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export type { ViewerCreateOptions, ViewerHandle, ViewerRuntime, ViewerSnapshot,
2
2
  export type { CameraFrameConfig, CameraFrameMode, CameraNormalizationConfig, CameraNormalizationResult, } from "./camera";
3
3
  export { createViewer } from "./engine/createViewer";
4
4
  export { computeCameraFrame, normalizeObject3d } from "./camera";
5
+ export type { CameraRigConfig, SceneStats, ApplyGroupToViewerOptions, ApplyGroupToViewerResult, RoomHeights, } from "./scene";
6
+ export { DEFAULT_CAMERA_RIG, applyGroupToViewer, computeSceneStats, resolveRoomHeights, setCameraToBounds, setCameraTopDown, } from "./scene";
5
7
  export { DEFAULT_PRESET_ID, DEFAULT_PRESETS } from "./presets/defaults";
6
8
  export { SCIENCE_PRESETS, SCIENCE_PRESET_SUMMARIES, SCIENCE_DEFAULT_PRESET_ID, buildViewerPresets, buildSciencePresets, } from "./presets/sciencePresets";
7
9
  export { listScienceSkyOptions, getScienceSkyOption } from "./sky/scienceSky";
@@ -10,6 +12,8 @@ export type { MaterialCatalogue, MaterialDefinition, MaterialId, MaterialColor,
10
12
  export { getMaterialCatalogue, findMaterial, listMaterialsByCategory } from "./materials/catalogue";
11
13
  export { getRenderMaterialMetadata } from "./materials/renderMetadata";
12
14
  export { BASELINE_MATERIAL_PRESET_ID, MATERIAL_PRESET_DATA, listMaterialPresets, getMaterialPreset, resolveMaterialSlot, resolveMaterialPresetMaterials, } from "./materials/presets";
15
+ export type { MaterialOverrides, MaterialResolveOptions } from "./materials/resolve";
16
+ export { resolveMaterialConfig } from "./materials/resolve";
13
17
  export { applyMaterialsToGroup, buildSurfaceMaterial, buildCatalogMaterial, setTextureBaseUrl, } from "./materials/architectural";
14
18
  export { EnvironmentSystem } from "./systems/environmentSystem";
15
19
  export { LightingSystem } from "./systems/lightingSystem";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,WAAW,EACX,sBAAsB,EACtB,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACnE,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,WAAW,EACX,sBAAsB,EACtB,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACjE,YAAY,EACV,eAAe,EACf,UAAU,EACV,yBAAyB,EACzB,wBAAwB,EACxB,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC9E,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,qBAAqB,EACrB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACpG,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,mBAAmB,EACnB,8BAA8B,GAC/B,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACnE,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  export { createViewer } from "./engine/createViewer";
2
2
  export { computeCameraFrame, normalizeObject3d } from "./camera";
3
+ export { DEFAULT_CAMERA_RIG, applyGroupToViewer, computeSceneStats, resolveRoomHeights, setCameraToBounds, setCameraTopDown, } from "./scene";
3
4
  export { DEFAULT_PRESET_ID, DEFAULT_PRESETS } from "./presets/defaults";
4
5
  export { SCIENCE_PRESETS, SCIENCE_PRESET_SUMMARIES, SCIENCE_DEFAULT_PRESET_ID, buildViewerPresets, buildSciencePresets, } from "./presets/sciencePresets";
5
6
  export { listScienceSkyOptions, getScienceSkyOption } from "./sky/scienceSky";
6
7
  export { getMaterialCatalogue, findMaterial, listMaterialsByCategory } from "./materials/catalogue";
7
8
  export { getRenderMaterialMetadata } from "./materials/renderMetadata";
8
9
  export { BASELINE_MATERIAL_PRESET_ID, MATERIAL_PRESET_DATA, listMaterialPresets, getMaterialPreset, resolveMaterialSlot, resolveMaterialPresetMaterials, } from "./materials/presets";
10
+ export { resolveMaterialConfig } from "./materials/resolve";
9
11
  export { applyMaterialsToGroup, buildSurfaceMaterial, buildCatalogMaterial, setTextureBaseUrl, } from "./materials/architectural";
10
12
  export { EnvironmentSystem } from "./systems/environmentSystem";
11
13
  export { LightingSystem } from "./systems/lightingSystem";
@@ -0,0 +1,13 @@
1
+ import type { MaterialsConfig, SurfaceMaterialConfig } from "./types";
2
+ export type MaterialOverrides = {
3
+ walls?: Partial<SurfaceMaterialConfig>;
4
+ floor?: Partial<SurfaceMaterialConfig>;
5
+ ceiling?: Partial<SurfaceMaterialConfig>;
6
+ };
7
+ export type MaterialResolveOptions = {
8
+ payload?: Record<string, unknown> | null;
9
+ presetId?: string | null;
10
+ overrides?: MaterialOverrides | null;
11
+ };
12
+ export declare function resolveMaterialConfig(options: MaterialResolveOptions): MaterialsConfig | null;
13
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/materials/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGtE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CACtC,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,GAAG,IAAI,CAyB7F"}
@@ -0,0 +1,28 @@
1
+ import { getMaterialPreset, resolveMaterialPresetMaterials } from "./presets";
2
+ export function resolveMaterialConfig(options) {
3
+ const { payload, presetId, overrides } = options;
4
+ if (presetId) {
5
+ try {
6
+ const preset = getMaterialPreset(presetId);
7
+ const base = resolveMaterialPresetMaterials(preset);
8
+ return {
9
+ walls: { ...base.walls, ...(overrides?.walls ?? {}) },
10
+ floor: { ...base.floor, ...(overrides?.floor ?? {}) },
11
+ ceiling: { ...base.ceiling, ...(overrides?.ceiling ?? {}) },
12
+ };
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ const record = payload;
19
+ const directMaterials = record?.materials ?? record?.room?.materials;
20
+ if (directMaterials?.walls && directMaterials?.floor && directMaterials?.ceiling) {
21
+ return {
22
+ walls: { ...directMaterials.walls, ...(overrides?.walls ?? {}) },
23
+ floor: { ...directMaterials.floor, ...(overrides?.floor ?? {}) },
24
+ ceiling: { ...directMaterials.ceiling, ...(overrides?.ceiling ?? {}) },
25
+ };
26
+ }
27
+ return null;
28
+ }
@@ -0,0 +1,43 @@
1
+ import * as THREE from "three";
2
+ import type { ViewerHandle } from "./engine/types";
3
+ import type { CameraFrameConfig, CameraNormalizationConfig, CameraNormalizationResult } from "./camera";
4
+ import type { MaterialsConfig } from "./materials/types";
5
+ export type CameraRigConfig = CameraFrameConfig & CameraNormalizationConfig;
6
+ export declare const DEFAULT_CAMERA_RIG: CameraRigConfig;
7
+ export type SceneStats = {
8
+ meshCount: number;
9
+ vertexCount: number;
10
+ triangleCount: number;
11
+ size: {
12
+ x: number;
13
+ y: number;
14
+ z: number;
15
+ };
16
+ };
17
+ export declare function computeSceneStats(root?: THREE.Object3D | null): SceneStats;
18
+ export declare const setCameraToBounds: (handle: ViewerHandle, bounds: THREE.Box3, config?: CameraFrameConfig) => void;
19
+ export declare const setCameraTopDown: (handle: ViewerHandle, bounds: THREE.Box3) => void;
20
+ export type ApplyGroupToViewerOptions = {
21
+ viewer?: ViewerHandle | null;
22
+ group: THREE.Group;
23
+ cameraRig?: CameraRigConfig;
24
+ viewMode?: "2d" | "3d" | "auto";
25
+ frameConfig?: CameraFrameConfig;
26
+ materialsConfig?: MaterialsConfig | null;
27
+ floorLevel?: number;
28
+ ceilingHeight?: number;
29
+ };
30
+ export type ApplyGroupToViewerResult = {
31
+ bounds: THREE.Box3;
32
+ stats: SceneStats;
33
+ normalization: CameraNormalizationResult;
34
+ resolvedFloor: number;
35
+ resolvedHeight: number;
36
+ };
37
+ export type RoomHeights = {
38
+ floorLevel?: number;
39
+ ceilingHeight?: number;
40
+ };
41
+ export declare const resolveRoomHeights: (payload: Record<string, unknown>) => RoomHeights;
42
+ export declare function applyGroupToViewer(options: ApplyGroupToViewerOptions): ApplyGroupToViewerResult | null;
43
+ //# sourceMappingURL=scene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAExG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG,yBAAyB,CAAC;AAE5E,eAAO,MAAM,kBAAkB,EAAE,eAMhC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,UAAU,CA0C1E;AAED,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,YAAY,EACpB,QAAQ,KAAK,CAAC,IAAI,EAClB,SAAS,iBAAiB,SA0B3B,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,QAAQ,YAAY,EAAE,QAAQ,KAAK,CAAC,IAAI,SA0BxE,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IACnB,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,aAAa,EAAE,yBAAyB,CAAC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1E,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,WAYrE,CAAC;AAEF,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,yBAAyB,GACjC,wBAAwB,GAAG,IAAI,CA2CjC"}
package/dist/scene.js ADDED
@@ -0,0 +1,148 @@
1
+ import * as THREE from "three";
2
+ import { computeCameraFrame, normalizeObject3d } from "./camera";
3
+ import { applyMaterialsToGroup } from "./materials/architectural";
4
+ export const DEFAULT_CAMERA_RIG = {
5
+ recenter: true,
6
+ floorToZero: true,
7
+ padding: 1.22,
8
+ direction: [1, 0.7, 1],
9
+ mode: "iso",
10
+ };
11
+ export function computeSceneStats(root) {
12
+ let meshCount = 0;
13
+ let vertexCount = 0;
14
+ let triangleCount = 0;
15
+ if (!root || typeof root.traverse !== "function") {
16
+ return {
17
+ meshCount,
18
+ vertexCount,
19
+ triangleCount,
20
+ size: { x: 0, y: 0, z: 0 },
21
+ };
22
+ }
23
+ root.traverse((child) => {
24
+ const mesh = child;
25
+ if (mesh.isMesh) {
26
+ meshCount += 1;
27
+ const geometry = mesh.geometry;
28
+ const position = geometry.getAttribute("position");
29
+ if (position) {
30
+ vertexCount += position.count;
31
+ }
32
+ const index = geometry.getIndex();
33
+ if (index) {
34
+ triangleCount += index.count / 3;
35
+ }
36
+ else if (position) {
37
+ triangleCount += position.count / 3;
38
+ }
39
+ }
40
+ });
41
+ const bounds = new THREE.Box3().setFromObject(root);
42
+ const size = new THREE.Vector3();
43
+ bounds.getSize(size);
44
+ return {
45
+ meshCount,
46
+ vertexCount,
47
+ triangleCount: Math.round(triangleCount),
48
+ size: { x: size.x, y: size.y, z: size.z },
49
+ };
50
+ }
51
+ export const setCameraToBounds = (handle, bounds, config) => {
52
+ if (bounds.isEmpty())
53
+ return;
54
+ const fov = handle.getCameraState().fov ?? 60;
55
+ const { position, target } = computeCameraFrame(bounds, fov, config);
56
+ if (![position.x, position.y, position.z, target.x, target.y, target.z].every(Number.isFinite)) {
57
+ return;
58
+ }
59
+ const sphere = new THREE.Sphere();
60
+ bounds.getBoundingSphere(sphere);
61
+ const distance = position.distanceTo(target);
62
+ const safetyFar = 1.15;
63
+ const safetyNear = 1.6;
64
+ let near = Math.max(0.01, distance - sphere.radius * safetyNear);
65
+ const maxNear = distance * 0.1;
66
+ if (Number.isFinite(maxNear) && maxNear > 0) {
67
+ near = Math.min(near, maxNear);
68
+ }
69
+ const minSkyFar = 350;
70
+ const far = Math.max(distance + sphere.radius * safetyFar, near + sphere.radius * 2, minSkyFar);
71
+ handle.setCamera({
72
+ position: [position.x, position.y, position.z],
73
+ target: [target.x, target.y, target.z],
74
+ near,
75
+ far,
76
+ });
77
+ };
78
+ export const setCameraTopDown = (handle, bounds) => {
79
+ if (bounds.isEmpty())
80
+ return;
81
+ const center = bounds.getCenter(new THREE.Vector3());
82
+ const size = bounds.getSize(new THREE.Vector3());
83
+ const span = Math.max(size.x, size.z, 1);
84
+ const height = span * 1.5;
85
+ const position = new THREE.Vector3(center.x, center.y + height, center.z);
86
+ const target = center.clone();
87
+ const sphere = new THREE.Sphere();
88
+ bounds.getBoundingSphere(sphere);
89
+ const distance = position.distanceTo(target);
90
+ const safetyFar = 1.2;
91
+ const safetyNear = 1.8;
92
+ let near = Math.max(0.01, distance - sphere.radius * safetyNear);
93
+ const maxNear = distance * 0.1;
94
+ if (Number.isFinite(maxNear) && maxNear > 0) {
95
+ near = Math.min(near, maxNear);
96
+ }
97
+ const minSkyFar = 350;
98
+ const far = Math.max(distance + sphere.radius * safetyFar, near + sphere.radius * 2, minSkyFar);
99
+ handle.setCamera({
100
+ position: [position.x, position.y, position.z],
101
+ target: [target.x, target.y, target.z],
102
+ near,
103
+ far,
104
+ });
105
+ };
106
+ export const resolveRoomHeights = (payload) => {
107
+ const record = payload;
108
+ const floorLevel = typeof record?.floorLevel === "number" ? record.floorLevel : undefined;
109
+ const roomHeight = typeof record?.roomHeight === "number"
110
+ ? record.roomHeight
111
+ : typeof record?.room?.rectilinear?.height === "number"
112
+ ? record.room.rectilinear.height
113
+ : typeof record?.room?.curvilinear?.height === "number"
114
+ ? record.room.curvilinear.height
115
+ : undefined;
116
+ return { floorLevel, ceilingHeight: roomHeight };
117
+ };
118
+ export function applyGroupToViewer(options) {
119
+ const { viewer, group, cameraRig, viewMode = "auto", frameConfig, materialsConfig, floorLevel, ceilingHeight, } = options;
120
+ if (!group)
121
+ return null;
122
+ const normalization = normalizeObject3d(group, cameraRig);
123
+ const bounds = normalization.bounds;
124
+ const resolvedFloor = cameraRig?.floorToZero
125
+ ? 0
126
+ : typeof floorLevel === "number"
127
+ ? floorLevel * normalization.scale + normalization.offset.y
128
+ : bounds.min.y;
129
+ const resolvedHeight = typeof ceilingHeight === "number"
130
+ ? ceilingHeight * normalization.scale
131
+ : Math.max(0.1, bounds.max.y - bounds.min.y);
132
+ if (materialsConfig) {
133
+ applyMaterialsToGroup(group, materialsConfig, resolvedFloor, resolvedHeight);
134
+ viewer?.invalidate?.();
135
+ }
136
+ const stats = computeSceneStats(group);
137
+ if (viewer) {
138
+ viewer.setSceneRoot(group);
139
+ const shouldTopDown = viewMode === "2d" || (viewMode === "auto" && stats.meshCount === 0);
140
+ if (shouldTopDown) {
141
+ setCameraTopDown(viewer, bounds);
142
+ }
143
+ else {
144
+ setCameraToBounds(viewer, bounds, frameConfig);
145
+ }
146
+ }
147
+ return { bounds, stats, normalization, resolvedFloor, resolvedHeight };
148
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treasuryspatial/viewer-kit",
3
- "version": "0.2.39",
3
+ "version": "0.2.41",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "main": "./dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "dist"
16
16
  ],
17
17
  "dependencies": {
18
- "@treasuryspatial/rhino-bridge": "^0.1.6"
18
+ "@treasuryspatial/rhino-bridge": "^0.1.7"
19
19
  },
20
20
  "publishConfig": {
21
21
  "access": "public"