@mapcomponents/three 1.7.2 → 1.7.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.
Files changed (73) hide show
  1. package/dist/README.md +54 -0
  2. package/dist/assets/3D/godzilla_simple.glb +0 -0
  3. package/dist/assets/splats/output.splat +0 -0
  4. package/dist/components/MlThreeGizmo.d.ts +12 -0
  5. package/dist/components/MlThreeGizmo.d.ts.map +1 -0
  6. package/dist/components/MlThreeModelLayer/MlThreeModelLayer.cy.d.ts +2 -0
  7. package/dist/components/MlThreeModelLayer/MlThreeModelLayer.cy.d.ts.map +1 -0
  8. package/dist/components/MlThreeModelLayer/MlThreeModelLayer.d.ts +12 -0
  9. package/dist/components/MlThreeModelLayer/MlThreeModelLayer.d.ts.map +1 -0
  10. package/dist/components/MlThreeObjectControls.d.ts +41 -0
  11. package/dist/components/MlThreeObjectControls.d.ts.map +1 -0
  12. package/dist/components/MlThreeSplatLayer/MlThreeSplatLayer.cy.d.ts +2 -0
  13. package/dist/components/MlThreeSplatLayer/MlThreeSplatLayer.cy.d.ts.map +1 -0
  14. package/dist/components/MlThreeSplatLayer/MlThreeSplatLayer.d.ts +12 -0
  15. package/dist/components/MlThreeSplatLayer/MlThreeSplatLayer.d.ts.map +1 -0
  16. package/dist/contexts/ThreeContext.d.ts +15 -0
  17. package/dist/contexts/ThreeContext.d.ts.map +1 -0
  18. package/dist/contexts/ThreeProvider.d.ts +18 -0
  19. package/dist/contexts/ThreeProvider.d.ts.map +1 -0
  20. package/dist/cypress/support/commands.d.ts +1 -0
  21. package/dist/cypress/support/commands.d.ts.map +1 -0
  22. package/dist/cypress/support/component.d.ts +9 -0
  23. package/dist/cypress/support/component.d.ts.map +1 -0
  24. package/dist/decorators/ThreejsContextDecorator.d.ts +3 -0
  25. package/dist/decorators/ThreejsContextDecorator.d.ts.map +1 -0
  26. package/dist/hooks/useThreeModel.d.ts +34 -0
  27. package/dist/hooks/useThreeModel.d.ts.map +1 -0
  28. package/dist/html2canvas.esm-CUkZERmf.js +22 -0
  29. package/dist/html2canvas.esm-Dmi1NfiH.mjs +4871 -0
  30. package/dist/index-CnnmRv4J.mjs +90875 -0
  31. package/dist/index-DbqgNSpy.js +5442 -0
  32. package/dist/index.css +1 -0
  33. package/dist/index.d.ts +10 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.es-BPSzkkDP.mjs +6674 -0
  36. package/dist/index.es-ajYPKLNS.js +18 -0
  37. package/dist/index.js +1 -0
  38. package/dist/index.mjs +10 -0
  39. package/dist/lib/ThreejsSceneHelper.d.ts +16 -0
  40. package/dist/lib/ThreejsSceneHelper.d.ts.map +1 -0
  41. package/dist/lib/ThreejsSceneRenderer.d.ts +18 -0
  42. package/dist/lib/ThreejsSceneRenderer.d.ts.map +1 -0
  43. package/dist/lib/ThreejsUtils.d.ts +14 -0
  44. package/dist/lib/ThreejsUtils.d.ts.map +1 -0
  45. package/dist/lib/splats/GaussianSplattingMesh.d.ts +104 -0
  46. package/dist/lib/splats/GaussianSplattingMesh.d.ts.map +1 -0
  47. package/dist/lib/splats/GaussianSplattingShaders.d.ts +10 -0
  48. package/dist/lib/splats/GaussianSplattingShaders.d.ts.map +1 -0
  49. package/dist/lib/splats/loaders/PlySplatLoader.d.ts +81 -0
  50. package/dist/lib/splats/loaders/PlySplatLoader.d.ts.map +1 -0
  51. package/dist/lib/splats/loaders/SplatLoader.d.ts +10 -0
  52. package/dist/lib/splats/loaders/SplatLoader.d.ts.map +1 -0
  53. package/dist/lib/utils/coroutine.d.ts +17 -0
  54. package/dist/lib/utils/coroutine.d.ts.map +1 -0
  55. package/dist/package.json +26 -0
  56. package/dist/purify.es-D1I7B1hP.js +2 -0
  57. package/dist/purify.es-DHbHSKL1.mjs +528 -0
  58. package/package.json +8 -6
  59. package/src/components/{MlTransformControls.tsx → MlThreeGizmo.tsx} +4 -4
  60. package/src/components/MlThreeModelLayer/MlThreeModelLayer.cy.tsx +2 -3
  61. package/src/components/MlThreeModelLayer/MlThreeModelLayer.stories.tsx +14 -55
  62. package/src/components/MlThreeModelLayer/MlThreeModelLayer.tsx +30 -133
  63. package/src/components/MlThreeObjectControls.tsx +289 -0
  64. package/src/components/MlThreeSplatLayer/MlThreeSplatLayer.cy.tsx +2 -3
  65. package/src/components/MlThreeSplatLayer/MlThreeSplatLayer.stories.tsx +14 -58
  66. package/src/components/MlThreeSplatLayer/MlThreeSplatLayer.tsx +26 -138
  67. package/src/decorators/ThreejsContextDecorator.tsx +1 -1
  68. package/src/hooks/useThreeModel.tsx +179 -0
  69. package/src/index.ts +4 -2
  70. package/vite.config.ts +2 -2
  71. package/src/components/ThreeObjectControls.tsx +0 -197
  72. /package/src/{components → contexts}/ThreeContext.tsx +0 -0
  73. /package/src/{components → contexts}/ThreeProvider.tsx +0 -0
@@ -5,10 +5,7 @@ import Link from '@mui/material/Link';
5
5
  import MlThreeSplatLayer from './MlThreeSplatLayer';
6
6
  import { useMap, TopToolbar, Sidebar } from '@mapcomponents/react-maplibre';
7
7
  import MlThreeJsContextDecorator from '../../decorators/ThreejsContextDecorator';
8
- import { ThreeObjectControls } from '../ThreeObjectControls';
9
- import { useThree } from '../ThreeContext';
10
- import ThreejsUtils from '../../lib/ThreejsUtils';
11
- import * as THREE from 'three';
8
+ import { MlThreeObjectControls } from '../MlThreeObjectControls';
12
9
 
13
10
  const storyoptions = {
14
11
  title: 'MapComponents/MlThreeSplatLayer',
@@ -25,17 +22,14 @@ const storyoptions = {
25
22
  export default storyoptions;
26
23
 
27
24
  const Template: any = () => {
28
- const { worldMatrix } = useThree();
29
25
  const [showLayer, setShowLayer] = useState(true);
30
26
  const [scale, setScale] = useState(100);
31
27
  const [rotation, setRotation] = useState({ x: 270, y: 0, z: 5 });
32
- const [useMapCoords, setUseMapCoords] = useState(true);
33
28
  const [mapPosition, setMapPosition] = useState({ lng: 7.0968, lat: 50.736 });
34
- const [altitude, setAltitude] = useState(30);
35
- const [position, setPosition] = useState({ x: 0, y: 0, z: 100 });
29
+ const [position, setPosition] = useState({ x: 0, y: 0, z: 30 });
30
+ const [sidebarOpen, setSidebarOpen] = useState(true);
36
31
  const [enableTransformControls, setEnableTransformControls] = useState(false);
37
32
  const [transformMode, setTransformMode] = useState<'translate' | 'rotate' | 'scale'>('translate');
38
- const [sidebarOpen, setSidebarOpen] = useState(true);
39
33
 
40
34
  const mapHook = useMap({ mapId: 'map_1' });
41
35
  useEffect(() => {
@@ -45,57 +39,23 @@ const Template: any = () => {
45
39
  mapHook.map?.setCenter([7.096614581535903, 50.736500960686556]);
46
40
  }, [mapHook.map]);
47
41
 
48
- // Center map on position when switching coordinate modes
49
- useEffect(() => {
50
- if (!mapHook.map) return;
51
- if (useMapCoords) {
52
- mapHook.map.setCenter([mapPosition.lng, mapPosition.lat]);
53
- }
54
- // eslint-disable-next-line react-hooks/exhaustive-deps
55
- }, [useMapCoords, mapHook.map]);
56
-
57
- const handleTransformChange = (object: THREE.Object3D) => {
58
- setRotation({
59
- x: (object.rotation.x * 180) / Math.PI,
60
- y: (object.rotation.y * 180) / Math.PI,
61
- z: (object.rotation.z * 180) / Math.PI,
62
- });
63
- setScale(object.scale.x);
64
-
65
- if (useMapCoords && worldMatrix) {
66
- const [lng, lat, alt] = ThreejsUtils.toMapPosition(worldMatrix, object.position);
67
- setMapPosition({ lng, lat });
68
- setAltitude(parseFloat(alt.toFixed(2)));
69
- } else {
70
- setPosition({ x: object.position.x, y: object.position.y, z: object.position.z });
71
- }
72
- };
73
-
74
42
  return (
75
43
  <>
76
44
  {showLayer && (
77
45
  <MlThreeSplatLayer
78
46
  url="assets/splats/output.splat"
79
- rotation={{
80
- x: (rotation.x * Math.PI) / 180,
81
- y: (rotation.y * Math.PI) / 180,
82
- z: (rotation.z * Math.PI) / 180,
47
+ position={[mapPosition.lng, mapPosition.lat]}
48
+ transform={{
49
+ rotation: {
50
+ x: (rotation.x * Math.PI) / 180,
51
+ y: (rotation.y * Math.PI) / 180,
52
+ z: (rotation.z * Math.PI) / 180,
53
+ },
54
+ scale: scale,
55
+ position: position,
83
56
  }}
84
- scale={scale}
85
- enableTransformControls={enableTransformControls}
86
- transformMode={transformMode}
87
- onTransformChange={handleTransformChange}
88
- {...(useMapCoords
89
- ? {
90
- mapPosition: [mapPosition.lng, mapPosition.lat],
91
- altitude: altitude,
92
- }
93
- : {
94
- position: position,
95
- })}
96
57
  />
97
58
  )}
98
-
99
59
  <TopToolbar
100
60
  unmovableButtons={
101
61
  <Button
@@ -107,26 +67,22 @@ const Template: any = () => {
107
67
  }
108
68
  />
109
69
  <Sidebar open={sidebarOpen} setOpen={setSidebarOpen} name="Splat Config">
110
- <ThreeObjectControls
70
+ <MlThreeObjectControls
111
71
  showLayer={showLayer}
112
72
  setShowLayer={setShowLayer}
113
73
  scale={scale}
114
74
  setScale={setScale}
115
75
  rotation={rotation}
116
76
  setRotation={setRotation}
117
- useMapCoords={useMapCoords}
118
- setUseMapCoords={setUseMapCoords}
119
77
  mapPosition={mapPosition}
120
78
  setMapPosition={setMapPosition}
121
- altitude={altitude}
122
- setAltitude={setAltitude}
123
79
  position={position}
124
80
  setPosition={setPosition}
81
+ layerName="Splat"
125
82
  enableTransformControls={enableTransformControls}
126
83
  setEnableTransformControls={setEnableTransformControls}
127
84
  transformMode={transformMode}
128
85
  setTransformMode={setTransformMode}
129
- layerName="Splat"
130
86
  />
131
87
  <Typography
132
88
  variant="body2"
@@ -1,157 +1,45 @@
1
- import { useEffect, useRef, useState } from 'react';
2
- import * as THREE from 'three';
3
- import { LngLatLike } from 'maplibre-gl';
4
- import { useThree } from '../ThreeContext';
1
+ import { useMemo } from 'react';
5
2
  import { SplatLoader } from '../../lib/splats/loaders/SplatLoader';
6
3
  import { PlySplatLoader } from '../../lib/splats/loaders/PlySplatLoader';
7
- import ThreejsUtils from '../../lib/ThreejsUtils';
8
- import MlTransformControls from '../MlTransformControls';
4
+ import { useThreeModel, UseThreeModelProps, ModelLoader } from '../../hooks/useThreeModel';
9
5
 
10
6
  /**
11
- * Renders splat 3D Models on the MapLibreMap referenced by props.mapId
7
+ * Renders splat 3D Models on the MapLibreMap
12
8
  *
13
9
  * @component
14
10
  */
15
11
 
16
- export interface MlThreeSplatLayerProps {
12
+ export type MlThreeSplatLayerProps = Omit<UseThreeModelProps, 'loaders'> & {
17
13
  mapId?: string;
18
- url: string;
19
- position?: { x: number; y: number; z: number };
20
- mapPosition?: LngLatLike;
21
- altitude?: number;
22
- rotation?: { x: number; y: number; z: number };
23
- scale?: { x: number; y: number; z: number } | number;
24
- enableTransformControls?: boolean;
25
- transformMode?: 'translate' | 'rotate' | 'scale';
26
- onTransformChange?: (object: THREE.Object3D) => void;
27
- init?: () => void;
28
- onDone?: () => void;
29
- }
14
+ };
30
15
 
31
16
  const MlThreeSplatLayer = (props: MlThreeSplatLayerProps) => {
32
- const {
17
+ const { url, position, transform, init, onDone, customLoaders } = props;
18
+
19
+ const loaders = useMemo<Record<string, ModelLoader>>(
20
+ () => ({
21
+ splat: (url, onLoad) => {
22
+ const loader = new SplatLoader();
23
+ loader.load(url, (splatMesh) => onLoad(splatMesh));
24
+ },
25
+ ply: (url, onLoad) => {
26
+ const loader = new PlySplatLoader();
27
+ loader.load(url, (splatMesh) => onLoad(splatMesh));
28
+ },
29
+ }),
30
+ []
31
+ );
32
+
33
+ useThreeModel({
33
34
  url,
34
35
  position,
35
- mapPosition,
36
- altitude,
37
- rotation,
38
- scale,
39
- enableTransformControls,
40
- transformMode,
41
- onTransformChange,
36
+ transform,
42
37
  init,
43
38
  onDone,
44
- } = props;
45
- const { scene, worldMatrixInv } = useThree();
46
- const modelRef = useRef<THREE.Object3D | undefined>(undefined);
47
- const [model, setModel] = useState<THREE.Object3D | undefined>(undefined);
48
-
49
- // Use refs for callbacks to avoid re-triggering the effect when they change
50
- const initRef = useRef(init);
51
- const onDoneRef = useRef(onDone);
52
- initRef.current = init;
53
- onDoneRef.current = onDone;
54
-
55
- const transformRef = useRef({ position, mapPosition, altitude, rotation, scale });
56
- transformRef.current = { position, mapPosition, altitude, rotation, scale };
57
- const worldMatrixInvRef = useRef(worldMatrixInv);
58
- worldMatrixInvRef.current = worldMatrixInv;
59
-
60
- useEffect(() => {
61
- if (!scene) return;
62
-
63
- if (typeof initRef.current === 'function') {
64
- initRef.current();
65
- }
66
-
67
- const extension = url.split('.').pop()?.toLowerCase();
68
-
69
- const onLoad = (object: THREE.Object3D) => {
70
- const { position, mapPosition, altitude, rotation, scale } = transformRef.current;
71
- const worldMatrixInv = worldMatrixInvRef.current;
72
-
73
- if (mapPosition && worldMatrixInv) {
74
- const scenePos = ThreejsUtils.toScenePosition(worldMatrixInv, mapPosition, altitude);
75
- object.position.set(scenePos.x, scenePos.y, scenePos.z);
76
- } else if (position) {
77
- object.position.set(position.x, position.y, position.z);
78
- }
79
-
80
- if (rotation) {
81
- object.rotation.set(rotation.x, rotation.y, rotation.z);
82
- }
83
- if (scale) {
84
- if (typeof scale === 'number') {
85
- object.scale.set(scale, scale, scale);
86
- } else {
87
- object.scale.set(scale.x, scale.y, scale.z);
88
- }
89
- }
90
- object.updateMatrixWorld(true);
91
-
92
- modelRef.current = object;
93
- scene.add(object);
94
- setModel(object);
95
- if (typeof onDoneRef.current === 'function') {
96
- onDoneRef.current();
97
- }
98
- };
99
-
100
- if (extension === 'splat') {
101
- const loader = new SplatLoader();
102
- loader.load(url, (splatMesh) => {
103
- onLoad(splatMesh);
104
- });
105
- } else if (extension === 'ply') {
106
- const loader = new PlySplatLoader();
107
- loader.load(url, (splatMesh) => {
108
- onLoad(splatMesh);
109
- });
110
- } else {
111
- console.warn('MlThreeSplatLayer: Unsupported file extension', extension);
112
- }
113
-
114
- return () => {
115
- if (modelRef.current) {
116
- scene.remove(modelRef.current);
117
- if ('dispose' in modelRef.current && typeof modelRef.current.dispose === 'function') {
118
- (modelRef.current as any).dispose();
119
- }
120
- modelRef.current = undefined;
121
- setModel(undefined);
122
- }
123
- };
124
- }, [scene, url]);
125
-
126
- useEffect(() => {
127
- if (!model) return;
128
-
129
- // Handle position: mapPosition takes precedence over position
130
- if (mapPosition && worldMatrixInv) {
131
- const scenePos = ThreejsUtils.toScenePosition(worldMatrixInv, mapPosition, altitude);
132
- model.position.set(scenePos.x, scenePos.y, scenePos.z);
133
- } else if (position) {
134
- model.position.set(position.x, position.y, position.z);
135
- }
136
-
137
- if (rotation) {
138
- model.rotation.set(rotation.x, rotation.y, rotation.z);
139
- }
140
- if (scale) {
141
- if (typeof scale === 'number') {
142
- model.scale.set(scale, scale, scale);
143
- } else {
144
- model.scale.set(scale.x, scale.y, scale.z);
145
- }
146
- }
147
- model.updateMatrixWorld(true);
148
- }, [model, position, mapPosition, altitude, rotation, scale, worldMatrixInv]);
39
+ loaders,
40
+ customLoaders,
41
+ });
149
42
 
150
- if (enableTransformControls && model) {
151
- return (
152
- <MlTransformControls target={model} mode={transformMode} onObjectChange={onTransformChange} />
153
- );
154
- }
155
43
  return null;
156
44
  };
157
45
 
@@ -1,5 +1,5 @@
1
1
  import React, { useMemo } from 'react';
2
- import { ThreeProvider } from '../components/ThreeProvider';
2
+ import { ThreeProvider } from '../contexts/ThreeProvider';
3
3
  import {
4
4
  MapComponentsProvider,
5
5
  MapLibreMap,
@@ -0,0 +1,179 @@
1
+ import { useEffect, useRef, useState, useCallback, useMemo } from 'react';
2
+ import * as THREE from 'three';
3
+ import { LngLatLike } from 'maplibre-gl';
4
+ import { useThree } from '../contexts/ThreeContext';
5
+ import ThreejsUtils from '../lib/ThreejsUtils';
6
+
7
+ export interface ThreeModelTransform {
8
+ rotation?: { x: number; y: number; z: number };
9
+ scale?: { x: number; y: number; z: number } | number;
10
+ position?: { x: number; y: number; z: number };
11
+ }
12
+
13
+ export type ModelLoader = (url: string, onSuccess: (object: THREE.Object3D) => void) => void;
14
+
15
+ export interface UseThreeModelProps {
16
+ url: string;
17
+ position: LngLatLike;
18
+ transform?: ThreeModelTransform;
19
+ init?: () => void;
20
+ onDone?: () => void;
21
+ loaders: Record<string, ModelLoader>;
22
+ customLoaders?: Record<string, ModelLoader>;
23
+ }
24
+
25
+ /**
26
+ * Recursively dispose of Three.js object resources to prevent memory leaks.
27
+ */
28
+ const disposeObject = (obj: THREE.Object3D): void => {
29
+ if ((obj as any).geometry) {
30
+ (obj as any).geometry.dispose();
31
+ }
32
+
33
+ if ((obj as any).material) {
34
+ const material = (obj as any).material;
35
+ if (Array.isArray(material)) {
36
+ material.forEach((m) => m.dispose());
37
+ } else {
38
+ material.dispose();
39
+ }
40
+ }
41
+
42
+ if ('dispose' in obj && typeof (obj as any).dispose === 'function') {
43
+ (obj as any).dispose();
44
+ }
45
+ };
46
+
47
+ /**
48
+ * Hook to manage loading, transforming, and rendering a 3D model in the MapLibre/Three.js context.
49
+ */
50
+ export const useThreeModel = (props: UseThreeModelProps) => {
51
+ const { url, position, transform, init, onDone, loaders, customLoaders } = props;
52
+ const { scene, worldMatrixInv } = useThree();
53
+ const [model, setModel] = useState<THREE.Object3D | undefined>(undefined);
54
+ const modelRef = useRef<THREE.Object3D | undefined>(undefined);
55
+
56
+ const initRef = useRef(init);
57
+ const onDoneRef = useRef(onDone);
58
+ initRef.current = init;
59
+ onDoneRef.current = onDone;
60
+
61
+ const transformRef = useRef({ position, transform });
62
+ transformRef.current = { position, transform };
63
+ const worldMatrixInvRef = useRef(worldMatrixInv);
64
+ worldMatrixInvRef.current = worldMatrixInv;
65
+
66
+ const allLoaders = useMemo(() => ({ ...loaders, ...customLoaders }), [loaders, customLoaders]);
67
+
68
+ const updateModelTransform = useCallback(
69
+ (object: THREE.Object3D, currentWorldMatrixInv: THREE.Matrix4 | undefined) => {
70
+ const { position: currentPosition, transform: currentTransform } = transformRef.current;
71
+
72
+ if (currentPosition && currentWorldMatrixInv) {
73
+ const scenePos = ThreejsUtils.toScenePosition(currentWorldMatrixInv, currentPosition, 0);
74
+ object.position.set(scenePos.x, scenePos.y, scenePos.z);
75
+
76
+ if (currentTransform?.position) {
77
+ object.position.x += currentTransform.position.x;
78
+ object.position.y += currentTransform.position.y;
79
+ object.position.z += currentTransform.position.z;
80
+ }
81
+ }
82
+
83
+ if (currentTransform?.rotation) {
84
+ object.rotation.set(
85
+ currentTransform.rotation.x,
86
+ currentTransform.rotation.y,
87
+ currentTransform.rotation.z
88
+ );
89
+ }
90
+
91
+ if (currentTransform?.scale) {
92
+ if (typeof currentTransform.scale === 'number') {
93
+ object.scale.set(currentTransform.scale, currentTransform.scale, currentTransform.scale);
94
+ } else {
95
+ object.scale.set(
96
+ currentTransform.scale.x,
97
+ currentTransform.scale.y,
98
+ currentTransform.scale.z
99
+ );
100
+ }
101
+ }
102
+
103
+ object.updateMatrixWorld(true);
104
+ },
105
+ []
106
+ );
107
+
108
+ const cleanup = useCallback(() => {
109
+ if (modelRef.current && scene) {
110
+ scene.remove(modelRef.current);
111
+ modelRef.current.traverse(disposeObject);
112
+ disposeObject(modelRef.current);
113
+ modelRef.current = undefined;
114
+ setModel(undefined);
115
+ }
116
+ }, [scene]);
117
+
118
+ useEffect(() => {
119
+ if (!scene) return;
120
+
121
+ if (typeof initRef.current === 'function') {
122
+ initRef.current();
123
+ }
124
+
125
+ let extension = '';
126
+ try {
127
+ const urlObj = new URL(url, window.location.origin);
128
+ extension = urlObj.pathname.split('.').pop()?.toLowerCase() || '';
129
+ } catch (e) {
130
+ extension = url.split('.').pop()?.toLowerCase() || '';
131
+ }
132
+
133
+ const loader = allLoaders[extension];
134
+ if (!loader) {
135
+ console.warn(
136
+ `useThreeModel: No loader found for file extension "${extension}". Supported extensions: ${Object.keys(allLoaders).join(', ')}`
137
+ );
138
+ return;
139
+ }
140
+
141
+ let isCanceled = false;
142
+
143
+ const handleLoad = (object: THREE.Object3D) => {
144
+ if (isCanceled) {
145
+ object.traverse(disposeObject);
146
+ disposeObject(object);
147
+ return;
148
+ }
149
+
150
+ if (modelRef.current) {
151
+ cleanup();
152
+ }
153
+
154
+ modelRef.current = object;
155
+ updateModelTransform(object, worldMatrixInvRef.current);
156
+ scene.add(object);
157
+ setModel(object);
158
+
159
+ if (typeof onDoneRef.current === 'function') {
160
+ onDoneRef.current();
161
+ }
162
+ };
163
+
164
+ loader(url, handleLoad);
165
+
166
+ return () => {
167
+ isCanceled = true;
168
+ cleanup();
169
+ };
170
+ }, [url, scene, allLoaders, cleanup, updateModelTransform]);
171
+
172
+ useEffect(() => {
173
+ if (model) {
174
+ updateModelTransform(model, worldMatrixInv);
175
+ }
176
+ }, [model, position, transform, worldMatrixInv, updateModelTransform]);
177
+
178
+ return model;
179
+ };
package/src/index.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export * from './lib/ThreejsUtils';
2
2
  export * from './lib/ThreejsSceneHelper';
3
3
  export * from './lib/ThreejsSceneRenderer';
4
- export * from './components/ThreeContext';
5
- export * from './components/ThreeProvider';
4
+ export * from './contexts/ThreeContext';
5
+ export * from './contexts/ThreeProvider';
6
6
  export { default as MlThreeModelLayer } from './components/MlThreeModelLayer/MlThreeModelLayer';
7
7
  export { default as MlThreeSplatLayer } from './components/MlThreeSplatLayer/MlThreeSplatLayer';
8
+ export { default as MlThreeGizmo } from './components/MlThreeGizmo';
9
+ export { MlThreeObjectControls } from './components/MlThreeObjectControls';
package/vite.config.ts CHANGED
@@ -26,7 +26,7 @@ export default defineConfig(() => ({
26
26
  // Configuration for building your library.
27
27
  // See: https://vitejs.dev/guide/build.html#library-mode
28
28
  build: {
29
- outDir: '../../dist/packages/three',
29
+ outDir: 'dist',
30
30
  emptyOutDir: true,
31
31
  reportCompressedSize: true,
32
32
  commonjsOptions: {
@@ -39,7 +39,7 @@ export default defineConfig(() => ({
39
39
  fileName: 'index',
40
40
  // Change this to the formats you want to support.
41
41
  // Don't forget to update your package.json as well.
42
- formats: ['es' as const],
42
+ formats: ['es' as const, 'cjs' as const],
43
43
  },
44
44
  rollupOptions: {
45
45
  // External packages that should not be bundled into your library.