@codefluss/plugin-configurator-3d 0.0.1-alpha.1
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/README.md +377 -0
- package/dist/components/configurator-3d-component.d.ts +14 -0
- package/dist/components/configurator-3d-component.d.ts.map +1 -0
- package/dist/components/configurator-renderer.d.ts +20 -0
- package/dist/components/configurator-renderer.d.ts.map +1 -0
- package/dist/components/model-viewer.d.ts +3 -0
- package/dist/components/model-viewer.d.ts.map +1 -0
- package/dist/configurator-3d-config.d.ts +13 -0
- package/dist/configurator-3d-config.d.ts.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +14 -0
- package/dist/index.mjs.map +1 -0
- package/dist/locales/index.d.ts +329 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/model-viewer-Bh6JoFYA.mjs +24 -0
- package/dist/model-viewer-Bh6JoFYA.mjs.map +1 -0
- package/dist/model-viewer-DQiZ9csY.js +2 -0
- package/dist/model-viewer-DQiZ9csY.js.map +1 -0
- package/dist/renderer.d.ts +7 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/store/configurator-store.d.ts +9 -0
- package/dist/store/configurator-store.d.ts.map +1 -0
- package/dist/types/index.d.ts +129 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
en: {
|
|
3
|
+
plugin: {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
};
|
|
7
|
+
properties: {
|
|
8
|
+
"model.url": {
|
|
9
|
+
label: string;
|
|
10
|
+
placeholder: string;
|
|
11
|
+
description: string;
|
|
12
|
+
};
|
|
13
|
+
"model.scale": {
|
|
14
|
+
label: string;
|
|
15
|
+
description: string;
|
|
16
|
+
};
|
|
17
|
+
"model.position": {
|
|
18
|
+
label: string;
|
|
19
|
+
placeholder: string;
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
"model.rotation": {
|
|
23
|
+
label: string;
|
|
24
|
+
placeholder: string;
|
|
25
|
+
description: string;
|
|
26
|
+
};
|
|
27
|
+
"pois.enabled": {
|
|
28
|
+
label: string;
|
|
29
|
+
description: string;
|
|
30
|
+
};
|
|
31
|
+
"camera.fov": {
|
|
32
|
+
label: string;
|
|
33
|
+
description: string;
|
|
34
|
+
};
|
|
35
|
+
"camera.enableOrbit": {
|
|
36
|
+
label: string;
|
|
37
|
+
description: string;
|
|
38
|
+
};
|
|
39
|
+
"camera.enableZoom": {
|
|
40
|
+
label: string;
|
|
41
|
+
description: string;
|
|
42
|
+
};
|
|
43
|
+
"camera.enablePan": {
|
|
44
|
+
label: string;
|
|
45
|
+
description: string;
|
|
46
|
+
};
|
|
47
|
+
"camera.near": {
|
|
48
|
+
label: string;
|
|
49
|
+
description: string;
|
|
50
|
+
};
|
|
51
|
+
"camera.far": {
|
|
52
|
+
label: string;
|
|
53
|
+
description: string;
|
|
54
|
+
};
|
|
55
|
+
"lighting.ambientIntensity": {
|
|
56
|
+
label: string;
|
|
57
|
+
description: string;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
categories: {
|
|
61
|
+
content: string;
|
|
62
|
+
style: string;
|
|
63
|
+
layout: string;
|
|
64
|
+
advanced: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
de: {
|
|
68
|
+
plugin: {
|
|
69
|
+
name: string;
|
|
70
|
+
description: string;
|
|
71
|
+
};
|
|
72
|
+
properties: {
|
|
73
|
+
"model.url": {
|
|
74
|
+
label: string;
|
|
75
|
+
placeholder: string;
|
|
76
|
+
description: string;
|
|
77
|
+
};
|
|
78
|
+
"model.scale": {
|
|
79
|
+
label: string;
|
|
80
|
+
description: string;
|
|
81
|
+
};
|
|
82
|
+
"model.position": {
|
|
83
|
+
label: string;
|
|
84
|
+
placeholder: string;
|
|
85
|
+
description: string;
|
|
86
|
+
};
|
|
87
|
+
"model.rotation": {
|
|
88
|
+
label: string;
|
|
89
|
+
placeholder: string;
|
|
90
|
+
description: string;
|
|
91
|
+
};
|
|
92
|
+
"pois.enabled": {
|
|
93
|
+
label: string;
|
|
94
|
+
description: string;
|
|
95
|
+
};
|
|
96
|
+
"camera.fov": {
|
|
97
|
+
label: string;
|
|
98
|
+
description: string;
|
|
99
|
+
};
|
|
100
|
+
"camera.enableOrbit": {
|
|
101
|
+
label: string;
|
|
102
|
+
description: string;
|
|
103
|
+
};
|
|
104
|
+
"camera.enableZoom": {
|
|
105
|
+
label: string;
|
|
106
|
+
description: string;
|
|
107
|
+
};
|
|
108
|
+
"camera.enablePan": {
|
|
109
|
+
label: string;
|
|
110
|
+
description: string;
|
|
111
|
+
};
|
|
112
|
+
"camera.near": {
|
|
113
|
+
label: string;
|
|
114
|
+
description: string;
|
|
115
|
+
};
|
|
116
|
+
"camera.far": {
|
|
117
|
+
label: string;
|
|
118
|
+
description: string;
|
|
119
|
+
};
|
|
120
|
+
"lighting.ambientIntensity": {
|
|
121
|
+
label: string;
|
|
122
|
+
description: string;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
categories: {
|
|
126
|
+
content: string;
|
|
127
|
+
style: string;
|
|
128
|
+
layout: string;
|
|
129
|
+
advanced: string;
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
fr: {
|
|
133
|
+
plugin: {
|
|
134
|
+
name: string;
|
|
135
|
+
description: string;
|
|
136
|
+
};
|
|
137
|
+
properties: {
|
|
138
|
+
"model.url": {
|
|
139
|
+
label: string;
|
|
140
|
+
placeholder: string;
|
|
141
|
+
description: string;
|
|
142
|
+
};
|
|
143
|
+
"model.scale": {
|
|
144
|
+
label: string;
|
|
145
|
+
description: string;
|
|
146
|
+
};
|
|
147
|
+
"model.position": {
|
|
148
|
+
label: string;
|
|
149
|
+
placeholder: string;
|
|
150
|
+
description: string;
|
|
151
|
+
};
|
|
152
|
+
"model.rotation": {
|
|
153
|
+
label: string;
|
|
154
|
+
placeholder: string;
|
|
155
|
+
description: string;
|
|
156
|
+
};
|
|
157
|
+
"pois.enabled": {
|
|
158
|
+
label: string;
|
|
159
|
+
description: string;
|
|
160
|
+
};
|
|
161
|
+
"camera.fov": {
|
|
162
|
+
label: string;
|
|
163
|
+
description: string;
|
|
164
|
+
};
|
|
165
|
+
"camera.enableOrbit": {
|
|
166
|
+
label: string;
|
|
167
|
+
description: string;
|
|
168
|
+
};
|
|
169
|
+
"camera.enableZoom": {
|
|
170
|
+
label: string;
|
|
171
|
+
description: string;
|
|
172
|
+
};
|
|
173
|
+
"camera.enablePan": {
|
|
174
|
+
label: string;
|
|
175
|
+
description: string;
|
|
176
|
+
};
|
|
177
|
+
"camera.near": {
|
|
178
|
+
label: string;
|
|
179
|
+
description: string;
|
|
180
|
+
};
|
|
181
|
+
"camera.far": {
|
|
182
|
+
label: string;
|
|
183
|
+
description: string;
|
|
184
|
+
};
|
|
185
|
+
"lighting.ambientIntensity": {
|
|
186
|
+
label: string;
|
|
187
|
+
description: string;
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
categories: {
|
|
191
|
+
content: string;
|
|
192
|
+
style: string;
|
|
193
|
+
layout: string;
|
|
194
|
+
advanced: string;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
es: {
|
|
198
|
+
plugin: {
|
|
199
|
+
name: string;
|
|
200
|
+
description: string;
|
|
201
|
+
};
|
|
202
|
+
properties: {
|
|
203
|
+
"model.url": {
|
|
204
|
+
label: string;
|
|
205
|
+
placeholder: string;
|
|
206
|
+
description: string;
|
|
207
|
+
};
|
|
208
|
+
"model.scale": {
|
|
209
|
+
label: string;
|
|
210
|
+
description: string;
|
|
211
|
+
};
|
|
212
|
+
"model.position": {
|
|
213
|
+
label: string;
|
|
214
|
+
placeholder: string;
|
|
215
|
+
description: string;
|
|
216
|
+
};
|
|
217
|
+
"model.rotation": {
|
|
218
|
+
label: string;
|
|
219
|
+
placeholder: string;
|
|
220
|
+
description: string;
|
|
221
|
+
};
|
|
222
|
+
"pois.enabled": {
|
|
223
|
+
label: string;
|
|
224
|
+
description: string;
|
|
225
|
+
};
|
|
226
|
+
"camera.fov": {
|
|
227
|
+
label: string;
|
|
228
|
+
description: string;
|
|
229
|
+
};
|
|
230
|
+
"camera.enableOrbit": {
|
|
231
|
+
label: string;
|
|
232
|
+
description: string;
|
|
233
|
+
};
|
|
234
|
+
"camera.enableZoom": {
|
|
235
|
+
label: string;
|
|
236
|
+
description: string;
|
|
237
|
+
};
|
|
238
|
+
"camera.enablePan": {
|
|
239
|
+
label: string;
|
|
240
|
+
description: string;
|
|
241
|
+
};
|
|
242
|
+
"camera.near": {
|
|
243
|
+
label: string;
|
|
244
|
+
description: string;
|
|
245
|
+
};
|
|
246
|
+
"camera.far": {
|
|
247
|
+
label: string;
|
|
248
|
+
description: string;
|
|
249
|
+
};
|
|
250
|
+
"lighting.ambientIntensity": {
|
|
251
|
+
label: string;
|
|
252
|
+
description: string;
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
categories: {
|
|
256
|
+
content: string;
|
|
257
|
+
style: string;
|
|
258
|
+
layout: string;
|
|
259
|
+
advanced: string;
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
it: {
|
|
263
|
+
plugin: {
|
|
264
|
+
name: string;
|
|
265
|
+
description: string;
|
|
266
|
+
};
|
|
267
|
+
properties: {
|
|
268
|
+
"model.url": {
|
|
269
|
+
label: string;
|
|
270
|
+
placeholder: string;
|
|
271
|
+
description: string;
|
|
272
|
+
};
|
|
273
|
+
"model.scale": {
|
|
274
|
+
label: string;
|
|
275
|
+
description: string;
|
|
276
|
+
};
|
|
277
|
+
"model.position": {
|
|
278
|
+
label: string;
|
|
279
|
+
placeholder: string;
|
|
280
|
+
description: string;
|
|
281
|
+
};
|
|
282
|
+
"model.rotation": {
|
|
283
|
+
label: string;
|
|
284
|
+
placeholder: string;
|
|
285
|
+
description: string;
|
|
286
|
+
};
|
|
287
|
+
"pois.enabled": {
|
|
288
|
+
label: string;
|
|
289
|
+
description: string;
|
|
290
|
+
};
|
|
291
|
+
"camera.fov": {
|
|
292
|
+
label: string;
|
|
293
|
+
description: string;
|
|
294
|
+
};
|
|
295
|
+
"camera.enableOrbit": {
|
|
296
|
+
label: string;
|
|
297
|
+
description: string;
|
|
298
|
+
};
|
|
299
|
+
"camera.enableZoom": {
|
|
300
|
+
label: string;
|
|
301
|
+
description: string;
|
|
302
|
+
};
|
|
303
|
+
"camera.enablePan": {
|
|
304
|
+
label: string;
|
|
305
|
+
description: string;
|
|
306
|
+
};
|
|
307
|
+
"camera.near": {
|
|
308
|
+
label: string;
|
|
309
|
+
description: string;
|
|
310
|
+
};
|
|
311
|
+
"camera.far": {
|
|
312
|
+
label: string;
|
|
313
|
+
description: string;
|
|
314
|
+
};
|
|
315
|
+
"lighting.ambientIntensity": {
|
|
316
|
+
label: string;
|
|
317
|
+
description: string;
|
|
318
|
+
};
|
|
319
|
+
};
|
|
320
|
+
categories: {
|
|
321
|
+
content: string;
|
|
322
|
+
style: string;
|
|
323
|
+
layout: string;
|
|
324
|
+
advanced: string;
|
|
325
|
+
};
|
|
326
|
+
};
|
|
327
|
+
};
|
|
328
|
+
export default _default;
|
|
329
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/locales/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,wBAME"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import{jsxs as e,jsx as t,Fragment as r}from"react/jsx-runtime";import{useState as a,useEffect as n,useRef as i}from"react";import{Canvas as o,useFrame as s,useThree as l}from"@react-three/fiber";import{Environment as c,OrbitControls as d}from"@react-three/drei";import{useStore as m}from"zustand";import{InstanceProvider as h,POIMarker as f}from"@codefluss/threejs-shared";import{createConfiguratorInstance as u}from"./index.mjs";import*as g from"three";const p=/* @__PURE__ */new Map;function b({instanceId:r,data:i,isEditorMode:s}){const[l]=a(()=>{const e=u(r);return p.set(r,e),e}),d=m(l,e=>e.isReady),f=m(l,e=>e.isLoading),g=m(l,e=>e.loadingProgress);return n(()=>{if(i.model?.url){const e=l.getState();if(e.gltf)return;e.loadModel(i.model.url)}else{l.getState().setFallbackGeometry(i.model?.fallbackGeometry||"box")}},[i.model?.url,i.model?.fallbackGeometry,l]),n(()=>()=>{l.getState().dispose(),p.delete(r)},[r,l]),/* @__PURE__ */e("div",{style:{width:"100%",height:"100%",position:"relative"},children:[f&&/* @__PURE__ */t(w,{progress:g}),
|
|
2
|
+
/* @__PURE__ */t(h,{instanceId:r,createStore:()=>l,children:/* @__PURE__ */e(o,{shadows:!0,camera:{position:[5,5,5],fov:i.camera?.fov||50,near:i.camera?.near||.1,far:i.camera?.far||2e3},frameloop:"demand",gl:{preserveDrawingBuffer:!0,antialias:!0,powerPreference:"high-performance"},children:[
|
|
3
|
+
/* @__PURE__ */t("color",{attach:"background",args:["#f0f0f0"]}),
|
|
4
|
+
/* @__PURE__ */t("ambientLight",{intensity:i.lighting?.ambientIntensity||.5}),
|
|
5
|
+
/* @__PURE__ */t("directionalLight",{position:i.lighting?.directionalPosition||[10,10,5],intensity:i.lighting?.directionalIntensity||1,castShadow:i.lighting?.enableShadows}),d&&/* @__PURE__ */t(y,{store:l,data:i}),d&&i.pois?.enabled&&/* @__PURE__ */t(v,{store:l}),
|
|
6
|
+
/* @__PURE__ */t(x,{store:l,enabled:!1!==i.camera?.enableOrbit,enableZoom:!1!==i.camera?.enableZoom,enablePan:!1!==i.camera?.enablePan}),
|
|
7
|
+
/* @__PURE__ */t(c,{preset:"city"})]},r)}),s&&d&&/* @__PURE__ */t(M,{instanceId:r,store:l})]})}function y({store:r,data:a}){const o=m(r,e=>e.gltf),l=m(r,e=>e.fallbackGeometry),c=i(null);if(s(({invalidate:e})=>{c.current&&a.model&&(c.current.position.set(...a.model.position||[0,0,0]),c.current.rotation.set(...a.model.rotation||[0,0,0]),c.current.scale.setScalar(a.model.scale||1),e())}),n(()=>{if(!o||!c.current)return;const e=(new g.Box3).setFromObject(c.current),t=e.getCenter(new g.Vector3),n=e.getSize(new g.Vector3),i=Math.max(n.x,n.y,n.z),s=(a.camera?.fov||50)*Math.PI/180,l=2.5*(i/(2*Math.tan(s/2)));r.setState({cameraTarget:[t.x,t.y,t.z],cameraDistance:l})},[o,a.camera?.fov,r]),!o)return null;if(o?.scene)/* @__PURE__ */
|
|
8
|
+
return t("primitive",{ref:c,object:o.scene});const d=l||"box",h=/* @__PURE__ */t("meshStandardMaterial",{color:"#4a90e2",metalness:.3,roughness:.4});switch(d){case"box":default:/* @__PURE__ */
|
|
9
|
+
return e("mesh",{ref:c,children:[
|
|
10
|
+
/* @__PURE__ */t("boxGeometry",{args:[2,2,2]}),h]});case"sphere":/* @__PURE__ */
|
|
11
|
+
return e("mesh",{ref:c,children:[
|
|
12
|
+
/* @__PURE__ */t("sphereGeometry",{args:[1.5,32,32]}),h]});case"cylinder":/* @__PURE__ */
|
|
13
|
+
return e("mesh",{ref:c,children:[
|
|
14
|
+
/* @__PURE__ */t("cylinderGeometry",{args:[1,1,2,32]}),h]});case"torus":/* @__PURE__ */
|
|
15
|
+
return e("mesh",{ref:c,children:[
|
|
16
|
+
/* @__PURE__ */t("torusGeometry",{args:[1,.4,16,32]}),h]})}}function x({store:e,enabled:r,enableZoom:a,enablePan:o}){const s=i(null),{camera:c,invalidate:h}=l(),f=m(e,e=>e.cameraTarget),u=m(e,e=>e.cameraDistance);return n(()=>{if(!f||!u)return;const e=Math.PI/4,t=Math.PI/6,r=f[0]+u*Math.cos(t)*Math.cos(e),a=f[1]+u*Math.sin(t),n=f[2]+u*Math.cos(t)*Math.sin(e);c.position.set(r,a,n),c.lookAt(f[0],f[1],f[2]),s.current&&(s.current.target.set(...f),s.current.update()),h()},[f,u,c,h]),/* @__PURE__ */t(d,{ref:s,enabled:r,enableZoom:a,enablePan:o,onChange:()=>h()})}function v({store:e}){const a=m(e,e=>e.pois);/* @__PURE__ */
|
|
17
|
+
return t(r,{children:a.map(e=>/* @__PURE__ */t(f,{...e},e.id))})}function w({progress:r}){/* @__PURE__ */
|
|
18
|
+
return t("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,0.5)",zIndex:10},children:/* @__PURE__ */e("div",{style:{textAlign:"center",color:"white"},children:[
|
|
19
|
+
/* @__PURE__ */t("div",{style:{width:200,height:4,background:"#333",borderRadius:2,overflow:"hidden"},children:/* @__PURE__ */t("div",{style:{width:`${r}%`,height:"100%",background:"#4CAF50",transition:"width 0.3s"}})}),
|
|
20
|
+
/* @__PURE__ */e("p",{style:{marginTop:10,fontSize:14},children:[Math.round(r),"%"]})]})})}function M({instanceId:r,store:a}){const n=m(a,e=>e.setMaterialVariant),i=m(a,e=>e.setCameraPreset),o=m(a,e=>e.materialVariants),s=m(a,e=>e.cameraPresets);/* @__PURE__ */
|
|
21
|
+
return e("div",{style:{position:"absolute",top:10,left:10,background:"white",padding:10,borderRadius:8,boxShadow:"0 2px 10px rgba(0,0,0,0.1)"},children:[o.length>0&&/* @__PURE__ */e("div",{style:{marginBottom:10},children:[
|
|
22
|
+
/* @__PURE__ */t("label",{style:{fontSize:12,fontWeight:"bold"},children:"Materials:"}),o.map(e=>/* @__PURE__ */t("button",{onClick:()=>n(e.id),style:{display:"block",padding:"4px 8px",margin:"4px 0",fontSize:11},children:e.name},e.id))]}),s.length>0&&/* @__PURE__ */e("div",{children:[
|
|
23
|
+
/* @__PURE__ */t("label",{style:{fontSize:12,fontWeight:"bold"},children:"Camera:"}),s.map(e=>/* @__PURE__ */t("button",{onClick:()=>i(e.id),style:{display:"block",padding:"4px 8px",margin:"4px 0",fontSize:11},children:e.name},e.id))]})]})}export{b as default};
|
|
24
|
+
//# sourceMappingURL=model-viewer-Bh6JoFYA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-viewer-Bh6JoFYA.mjs","sources":["../src/components/model-viewer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from 'react';\nimport { Canvas, useFrame, useThree } from '@react-three/fiber';\nimport { OrbitControls, Environment } from '@react-three/drei';\nimport { useStore } from 'zustand';\nimport { InstanceProvider, POIMarker } from '@codefluss/threejs-shared';\nimport { createConfiguratorInstance } from '../store/configurator-store';\nimport type { ModelViewerProps } from '../types';\nimport type { StoreApi } from 'zustand/vanilla';\nimport type { ConfiguratorStore } from '../types';\nimport * as THREE from 'three';\n\nconst configuratorStores = new Map<string, StoreApi<ConfiguratorStore>>();\n\nexport default function ModelViewer({ instanceId, data, isEditorMode }: ModelViewerProps) {\n const [store] = useState(() => {\n // Always create a fresh store for this instance\n const newStore = createConfiguratorInstance(instanceId);\n configuratorStores.set(instanceId, newStore);\n return newStore;\n });\n\n const isReady = useStore(store, (state) => state.isReady);\n const isLoading = useStore(store, (state) => state.isLoading);\n const loadingProgress = useStore(store, (state) => state.loadingProgress);\n\n // Load model\n useEffect(() => {\n if (data.model?.url) {\n const state = store.getState();\n if (state.gltf) return; // Already loaded\n\n state.loadModel(data.model.url);\n } else {\n // Fallback to built-in geometry\n const state = store.getState();\n state.setFallbackGeometry(data.model?.fallbackGeometry || 'box');\n }\n }, [data.model?.url, data.model?.fallbackGeometry, store]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n const state = store.getState();\n state.dispose();\n configuratorStores.delete(instanceId);\n };\n }, [instanceId, store]);\n\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {isLoading && <LoadingOverlay progress={loadingProgress} />}\n\n <InstanceProvider instanceId={instanceId} createStore={() => store}>\n <Canvas\n key={instanceId}\n shadows\n camera={{\n position: [5, 5, 5],\n fov: data.camera?.fov || 50,\n near: data.camera?.near || 0.1,\n far: data.camera?.far || 2000\n }}\n frameloop=\"demand\"\n gl={{\n preserveDrawingBuffer: true,\n antialias: true,\n powerPreference: \"high-performance\"\n }}\n >\n <color attach=\"background\" args={['#f0f0f0']} />\n\n <ambientLight intensity={data.lighting?.ambientIntensity || 0.5} />\n <directionalLight\n position={data.lighting?.directionalPosition || [10, 10, 5]}\n intensity={data.lighting?.directionalIntensity || 1}\n castShadow={data.lighting?.enableShadows}\n />\n\n {isReady && <Model store={store} data={data} />}\n {isReady && data.pois?.enabled && <POIMarkers store={store} />}\n\n <CameraController\n store={store}\n enabled={data.camera?.enableOrbit !== false}\n enableZoom={data.camera?.enableZoom !== false}\n enablePan={data.camera?.enablePan !== false}\n />\n <Environment preset=\"city\" />\n </Canvas>\n </InstanceProvider>\n\n {isEditorMode && isReady && <EditorControls instanceId={instanceId} store={store} />}\n </div>\n );\n}\n\nfunction Model({ store, data }: { store: StoreApi<ConfiguratorStore>; data: ModelViewerProps['data'] }) {\n const gltf = useStore(store, (state) => state.gltf);\n const fallbackGeometry = useStore(store, (state) => state.fallbackGeometry);\n const ref = useRef<THREE.Group>(null);\n\n useFrame(({ invalidate }) => {\n if (!ref.current || !data.model) return;\n ref.current.position.set(...(data.model.position || [0, 0, 0]));\n ref.current.rotation.set(...(data.model.rotation || [0, 0, 0]));\n ref.current.scale.setScalar(data.model.scale || 1);\n invalidate(); // Trigger re-render for frameloop=\"demand\"\n });\n\n // Auto-focus and auto-zoom on model load\n useEffect(() => {\n if (!gltf || !ref.current) return;\n\n // Calculate bounding box\n const box = new THREE.Box3().setFromObject(ref.current);\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n\n // Get the max dimension to determine zoom\n const maxDim = Math.max(size.x, size.y, size.z);\n const fov = data.camera?.fov || 50;\n const fovRad = (fov * Math.PI) / 180;\n\n // Calculate camera distance to fit the object\n const cameraDistance = maxDim / (2 * Math.tan(fovRad / 2));\n\n // Add padding (2.5x for better framing and full visibility)\n const finalDistance = cameraDistance * 2.5;\n\n // Store camera info for OrbitControls\n store.setState({\n cameraTarget: [center.x, center.y, center.z] as [number, number, number],\n cameraDistance: finalDistance\n });\n }, [gltf, data.camera?.fov, store]);\n\n if (!gltf) return null;\n\n if (gltf?.scene) {\n return <primitive ref={ref} object={gltf.scene} />;\n }\n\n // Fallback geometry when no GLTF model is loaded\n const geometry = fallbackGeometry || 'box';\n const material = (\n <meshStandardMaterial\n color=\"#4a90e2\"\n metalness={0.3}\n roughness={0.4}\n />\n );\n\n switch (geometry) {\n case 'box':\n return (\n <mesh ref={ref}>\n <boxGeometry args={[2, 2, 2]} />\n {material}\n </mesh>\n );\n case 'sphere':\n return (\n <mesh ref={ref}>\n <sphereGeometry args={[1.5, 32, 32]} />\n {material}\n </mesh>\n );\n case 'cylinder':\n return (\n <mesh ref={ref}>\n <cylinderGeometry args={[1, 1, 2, 32]} />\n {material}\n </mesh>\n );\n case 'torus':\n return (\n <mesh ref={ref}>\n <torusGeometry args={[1, 0.4, 16, 32]} />\n {material}\n </mesh>\n );\n default:\n return (\n <mesh ref={ref}>\n <boxGeometry args={[2, 2, 2]} />\n {material}\n </mesh>\n );\n }\n}\n\nfunction CameraController({\n store,\n enabled,\n enableZoom,\n enablePan\n}: {\n store: StoreApi<ConfiguratorStore>;\n enabled: boolean;\n enableZoom: boolean;\n enablePan: boolean;\n}) {\n const controlsRef = useRef<any>(null);\n const { camera, invalidate } = useThree();\n const cameraTarget = useStore(store, (state) => state.cameraTarget);\n const cameraDistance = useStore(store, (state) => state.cameraDistance);\n\n useEffect(() => {\n if (!cameraTarget || !cameraDistance) return;\n\n // Calculate camera position (angle: 45 degrees horizontal, 30 degrees vertical)\n const angleH = Math.PI / 4; // 45 degrees\n const angleV = Math.PI / 6; // 30 degrees\n\n const x = cameraTarget[0] + cameraDistance * Math.cos(angleV) * Math.cos(angleH);\n const y = cameraTarget[1] + cameraDistance * Math.sin(angleV);\n const z = cameraTarget[2] + cameraDistance * Math.cos(angleV) * Math.sin(angleH);\n\n camera.position.set(x, y, z);\n camera.lookAt(cameraTarget[0], cameraTarget[1], cameraTarget[2]);\n\n // Update OrbitControls target\n if (controlsRef.current) {\n controlsRef.current.target.set(...cameraTarget);\n controlsRef.current.update();\n }\n\n invalidate();\n }, [cameraTarget, cameraDistance, camera, invalidate]);\n\n return (\n <OrbitControls\n ref={controlsRef}\n enabled={enabled}\n enableZoom={enableZoom}\n enablePan={enablePan}\n onChange={() => invalidate()}\n />\n );\n}\n\nfunction POIMarkers({ store }: { store: StoreApi<ConfiguratorStore> }) {\n const pois = useStore(store, (state) => state.pois);\n\n return (\n <>\n {pois.map((poi) => (\n <POIMarker key={poi.id} {...poi} />\n ))}\n </>\n );\n}\n\nfunction LoadingOverlay({ progress }: { progress: number }) {\n return (\n <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.5)', zIndex: 10 }}>\n <div style={{ textAlign: 'center', color: 'white' }}>\n <div style={{ width: 200, height: 4, background: '#333', borderRadius: 2, overflow: 'hidden' }}>\n <div style={{ width: `${progress}%`, height: '100%', background: '#4CAF50', transition: 'width 0.3s' }} />\n </div>\n <p style={{ marginTop: 10, fontSize: 14 }}>{Math.round(progress)}%</p>\n </div>\n </div>\n );\n}\n\nfunction EditorControls({ instanceId: _, store }: { instanceId: string; store: StoreApi<ConfiguratorStore> }) {\n const setMaterialVariant = useStore(store, (s) => s.setMaterialVariant);\n const setCameraPreset = useStore(store, (s) => s.setCameraPreset);\n const materialVariants = useStore(store, (s) => s.materialVariants);\n const cameraPresets = useStore(store, (s) => s.cameraPresets);\n\n return (\n <div style={{ position: 'absolute', top: 10, left: 10, background: 'white', padding: 10, borderRadius: 8, boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}>\n {materialVariants.length > 0 && (\n <div style={{ marginBottom: 10 }}>\n <label style={{ fontSize: 12, fontWeight: 'bold' }}>Materials:</label>\n {materialVariants.map(v => (\n <button key={v.id} onClick={() => setMaterialVariant(v.id)} style={{ display: 'block', padding: '4px 8px', margin: '4px 0', fontSize: 11 }}>\n {v.name}\n </button>\n ))}\n </div>\n )}\n {cameraPresets.length > 0 && (\n <div>\n <label style={{ fontSize: 12, fontWeight: 'bold' }}>Camera:</label>\n {cameraPresets.map(p => (\n <button key={p.id} onClick={() => setCameraPreset(p.id)} style={{ display: 'block', padding: '4px 8px', margin: '4px 0', fontSize: 11 }}>\n {p.name}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"names":["configuratorStores","Map","ModelViewer","instanceId","data","isEditorMode","store","useState","newStore","createConfiguratorInstance","set","isReady","useStore","state","isLoading","loadingProgress","useEffect","model","url","getState","gltf","loadModel","setFallbackGeometry","fallbackGeometry","dispose","delete","jsxs","style","width","height","position","children","jsx","LoadingOverlay","progress","InstanceProvider","createStore","Canvas","shadows","camera","fov","near","far","frameloop","gl","preserveDrawingBuffer","antialias","powerPreference","attach","args","intensity","lighting","ambientIntensity","directionalPosition","directionalIntensity","castShadow","enableShadows","Model","pois","enabled","POIMarkers","CameraController","enableOrbit","enableZoom","enablePan","Environment","preset","EditorControls","ref","useRef","useFrame","invalidate","current","rotation","scale","setScalar","box","THREE","Box3","setFromObject","center","getCenter","Vector3","size","getSize","maxDim","Math","max","x","y","z","fovRad","PI","finalDistance","tan","setState","cameraTarget","cameraDistance","scene","object","geometry","material","color","metalness","roughness","controlsRef","useThree","angleH","angleV","cos","sin","lookAt","target","update","OrbitControls","onChange","Fragment","map","poi","POIMarker","id","inset","display","alignItems","justifyContent","background","zIndex","textAlign","borderRadius","overflow","transition","marginTop","fontSize","round","_","setMaterialVariant","s","setCameraPreset","materialVariants","cameraPresets","top","left","padding","boxShadow","length","marginBottom","fontWeight","v","onClick","margin","name","p"],"mappings":"ucAaA,MAAMA,qBAAyBC,IAE/B,SAAwBC,GAAYC,WAAEA,EAAAC,KAAYA,EAAAC,aAAMA,IACtD,MAAOC,GAASC,EAAS,KAEvB,MAAMC,EAAWC,EAA2BN,GAE5C,OADAH,EAAmBU,IAAIP,EAAYK,GAC5BA,IAGHG,EAAUC,EAASN,EAAQO,GAAUA,EAAMF,SAC3CG,EAAYF,EAASN,EAAQO,GAAUA,EAAMC,WAC7CC,EAAkBH,EAASN,EAAQO,GAAUA,EAAME,iBAyBzD,OAtBAC,EAAU,KACR,GAAIZ,EAAKa,OAAOC,IAAK,CACnB,MAAML,EAAQP,EAAMa,WACpB,GAAIN,EAAMO,KAAM,OAEhBP,EAAMQ,UAAUjB,EAAKa,MAAMC,IAC7B,KAAO,CAESZ,EAAMa,WACdG,oBAAoBlB,EAAKa,OAAOM,kBAAoB,MAC5D,GACC,CAACnB,EAAKa,OAAOC,IAAKd,EAAKa,OAAOM,iBAAkBjB,IAGnDU,EAAU,IACD,KACSV,EAAMa,WACdK,UACNxB,EAAmByB,OAAOtB,IAE3B,CAACA,EAAYG,mBAGdoB,EAAC,MAAA,CAAIC,MAAO,CAAEC,MAAO,OAAQC,OAAQ,OAAQC,SAAU,YACpDC,SAAA,CAAAjB,kBAAakB,EAACC,EAAA,CAAeC,SAAUnB;iBAEvCoB,EAAA,CAAiBhC,aAAwBiC,YAAa,IAAM9B,EAC3DyB,wBAAAL,EAACW,EAAA,CAECC,SAAO,EACPC,OAAQ,CACNT,SAAU,CAAC,EAAG,EAAG,GACjBU,IAAKpC,EAAKmC,QAAQC,KAAO,GACzBC,KAAMrC,EAAKmC,QAAQE,MAAQ,GAC3BC,IAAKtC,EAAKmC,QAAQG,KAAO,KAE3BC,UAAU,SACVC,GAAI,CACFC,uBAAuB,EACvBC,WAAW,EACXC,gBAAiB,oBAGnBhB,SAAA;eAAAC,EAAC,SAAMgB,OAAO,aAAaC,KAAM,CAAC;iBAEjC,eAAA,CAAaC,UAAW9C,EAAK+C,UAAUC,kBAAoB;eAC5DpB,EAAC,mBAAA,CACCF,SAAU1B,EAAK+C,UAAUE,qBAAuB,CAAC,GAAI,GAAI,GACzDH,UAAW9C,EAAK+C,UAAUG,sBAAwB,EAClDC,WAAYnD,EAAK+C,UAAUK,gBAG5B7C,kBAAWqB,EAACyB,EAAA,CAAMnD,QAAcF,SAChCO,GAAWP,EAAKsD,MAAMC,0BAAYC,GAAWtD;eAE9C0B,EAAC6B,EAAA,CACCvD,QACAqD,SAAsC,IAA7BvD,EAAKmC,QAAQuB,YACtBC,YAAwC,IAA5B3D,EAAKmC,QAAQwB,WACzBC,WAAsC,IAA3B5D,EAAKmC,QAAQyB;eAE1BhC,EAACiC,EAAA,CAAYC,OAAO,WAjCf/D,KAqCRE,GAAgBM,kBAAWqB,EAACmC,EAAA,CAAehE,aAAwBG,YAG1E,CAEA,SAASmD,GAAMnD,MAAEA,EAAAF,KAAOA,IACtB,MAAMgB,EAAOR,EAASN,EAAQO,GAAUA,EAAMO,MACxCG,EAAmBX,EAASN,EAAQO,GAAUA,EAAMU,kBACpD6C,EAAMC,EAAoB,MAqChC,GAnCAC,EAAS,EAAGC,iBACLH,EAAII,SAAYpE,EAAKa,QAC1BmD,EAAII,QAAQ1C,SAASpB,OAAQN,EAAKa,MAAMa,UAAY,CAAC,EAAG,EAAG,IAC3DsC,EAAII,QAAQC,SAAS/D,OAAQN,EAAKa,MAAMwD,UAAY,CAAC,EAAG,EAAG,IAC3DL,EAAII,QAAQE,MAAMC,UAAUvE,EAAKa,MAAMyD,OAAS,GAChDH,OAIFvD,EAAU,KACR,IAAKI,IAASgD,EAAII,QAAS,OAG3B,MAAMI,GAAM,IAAIC,EAAMC,MAAOC,cAAcX,EAAII,SACzCQ,EAASJ,EAAIK,UAAU,IAAIJ,EAAMK,SACjCC,EAAOP,EAAIQ,QAAQ,IAAIP,EAAMK,SAG7BG,EAASC,KAAKC,IAAIJ,EAAKK,EAAGL,EAAKM,EAAGN,EAAKO,GAEvCC,GADMvF,EAAKmC,QAAQC,KAAO,IACV8C,KAAKM,GAAM,IAM3BC,EAAiC,KAHhBR,GAAU,EAAIC,KAAKQ,IAAIH,EAAS,KAMvDrF,EAAMyF,SAAS,CACbC,aAAc,CAAChB,EAAOQ,EAAGR,EAAOS,EAAGT,EAAOU,GAC1CO,eAAgBJ,KAEjB,CAACzE,EAAMhB,EAAKmC,QAAQC,IAAKlC,KAEvBc,EAAM,OAAO,KAElB,GAAIA,GAAM8E;AACR,SAAQ,YAAA,CAAU9B,MAAU+B,OAAQ/E,EAAK8E,QAI3C,MAAME,EAAW7E,GAAoB,MAC/B8E,iBACJrE,EAAC,uBAAA,CACCsE,MAAM,UACNC,UAAW,GACXC,UAAW,KAIf,OAAQJ,GACN,IAAK,MA4BL;AACE,OACE1E,EAAC,QAAK0C,MACJrC,SAAA;eAAAC,EAAC,eAAYiB,KAAM,CAAC,EAAG,EAAG,KACzBoD,KAzBP,IAAK;AACH,OACE3E,EAAC,QAAK0C,MACJrC,SAAA;eAAAC,EAAC,kBAAeiB,KAAM,CAAC,IAAK,GAAI,MAC/BoD,KAGP,IAAK;AACH,OACE3E,EAAC,QAAK0C,MACJrC,SAAA;eAAAC,EAAC,oBAAiBiB,KAAM,CAAC,EAAG,EAAG,EAAG,MACjCoD,KAGP,IAAK;AACH,OACE3E,EAAC,QAAK0C,MACJrC,SAAA;eAAAC,EAAC,iBAAciB,KAAM,CAAC,EAAG,GAAK,GAAI,MACjCoD,KAWX,CAEA,SAASxC,GAAiBvD,MACxBA,EAAAqD,QACAA,EAAAI,WACAA,EAAAC,UACAA,IAOA,MAAMyC,EAAcpC,EAAY,OAC1B9B,OAAEA,EAAAgC,WAAQA,GAAemC,IACzBV,EAAepF,EAASN,EAAQO,GAAUA,EAAMmF,cAChDC,EAAiBrF,EAASN,EAAQO,GAAUA,EAAMoF,gBAyBxD,OAvBAjF,EAAU,KACR,IAAKgF,IAAiBC,EAAgB,OAGtC,MAAMU,EAASrB,KAAKM,GAAK,EACnBgB,EAAStB,KAAKM,GAAK,EAEnBJ,EAAIQ,EAAa,GAAKC,EAAiBX,KAAKuB,IAAID,GAAUtB,KAAKuB,IAAIF,GACnElB,EAAIO,EAAa,GAAKC,EAAiBX,KAAKwB,IAAIF,GAChDlB,EAAIM,EAAa,GAAKC,EAAiBX,KAAKuB,IAAID,GAAUtB,KAAKwB,IAAIH,GAEzEpE,EAAOT,SAASpB,IAAI8E,EAAGC,EAAGC,GAC1BnD,EAAOwE,OAAOf,EAAa,GAAIA,EAAa,GAAIA,EAAa,IAGzDS,EAAYjC,UACdiC,EAAYjC,QAAQwC,OAAOtG,OAAOsF,GAClCS,EAAYjC,QAAQyC,UAGtB1C,KACC,CAACyB,EAAcC,EAAgB1D,EAAQgC,mBAGxCvC,EAACkF,EAAA,CACC9C,IAAKqC,EACL9C,UACAI,aACAC,YACAmD,SAAU,IAAM5C,KAGtB,CAEA,SAASX,GAAWtD,MAAEA,IACpB,MAAMoD,EAAO9C,EAASN,EAAQO,GAAUA,EAAM6C;AAE9C,SACE0D,EAAA,CACGrF,SAAA2B,EAAK2D,IAAKC,kBACTtF,EAACuF,EAAA,IAA2BD,GAAZA,EAAIE,MAI5B,CAEA,SAASvF,GAAeC,SAAEA;AACxB,OACEF,EAAC,MAAA,CAAIL,MAAO,CAAEG,SAAU,WAAY2F,MAAO,EAAGC,QAAS,OAAQC,WAAY,SAAUC,eAAgB,SAAUC,WAAY,kBAAmBC,OAAQ,IACpJ/F,0BAAC,MAAA,CAAIJ,MAAO,CAAEoG,UAAW,SAAUzB,MAAO,SACxCvE,SAAA;eAAAC,EAAC,MAAA,CAAIL,MAAO,CAAEC,MAAO,IAAKC,OAAQ,EAAGgG,WAAY,OAAQG,aAAc,EAAGC,SAAU,UAClFlG,wBAAAC,EAAC,MAAA,CAAIL,MAAO,CAAEC,MAAO,GAAGM,KAAaL,OAAQ,OAAQgG,WAAY,UAAWK,WAAY;eAE1FxG,EAAC,KAAEC,MAAO,CAAEwG,UAAW,GAAIC,SAAU,IAAOrG,SAAA,CAAAuD,KAAK+C,MAAMnG,GAAU,WAIzE,CAEA,SAASiC,GAAiBhE,WAAYmI,EAAAhI,MAAGA,IACvC,MAAMiI,EAAqB3H,EAASN,EAAQkI,GAAMA,EAAED,oBAC9CE,EAAkB7H,EAASN,EAAQkI,GAAMA,EAAEC,iBAC3CC,EAAmB9H,EAASN,EAAQkI,GAAMA,EAAEE,kBAC5CC,EAAgB/H,EAASN,EAAQkI,GAAMA,EAAEG;AAE/C,SACG,MAAA,CAAIhH,MAAO,CAAEG,SAAU,WAAY8G,IAAK,GAAIC,KAAM,GAAIhB,WAAY,QAASiB,QAAS,GAAId,aAAc,EAAGe,UAAW,8BAClHhH,SAAA,CAAA2G,EAAiBM,OAAS,kBACzBtH,EAAC,MAAA,CAAIC,MAAO,CAAEsH,aAAc,IAC1BlH,SAAA;eAAAC,EAAC,QAAA,CAAML,MAAO,CAAEyG,SAAU,GAAIc,WAAY,QAAUnH,SAAA,eACnD2G,EAAiBrB,IAAI8B,kBACpBnH,EAAC,SAAA,CAAkBoH,QAAS,IAAMb,EAAmBY,EAAE3B,IAAK7F,MAAO,CAAE+F,QAAS,QAASoB,QAAS,UAAWO,OAAQ,QAASjB,SAAU,IACnIrG,SAAAoH,EAAEG,MADQH,EAAE3B,QAMpBmB,EAAcK,OAAS,kBACtBtH,EAAC,MAAA,CACCK,SAAA;eAAAC,EAAC,QAAA,CAAML,MAAO,CAAEyG,SAAU,GAAIc,WAAY,QAAUnH,SAAA,YACnD4G,EAActB,IAAIkC,kBACjBvH,EAAC,SAAA,CAAkBoH,QAAS,IAAMX,EAAgBc,EAAE/B,IAAK7F,MAAO,CAAE+F,QAAS,QAASoB,QAAS,UAAWO,OAAQ,QAASjB,SAAU,IAChIrG,SAAAwH,EAAED,MADQC,EAAE/B,UAQ3B"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),t=require("react"),r=require("@react-three/fiber"),n=require("@react-three/drei"),s=require("zustand"),a=require("@codefluss/threejs-shared"),o=require("./index.js");function i(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const r in e)if("default"!==r){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}return t.default=e,Object.freeze(t)}const l=i(require("three")),c=new Map;function d({store:n,data:a}){const o=s.useStore(n,e=>e.gltf),i=s.useStore(n,e=>e.fallbackGeometry),c=t.useRef(null);if(r.useFrame(({invalidate:e})=>{c.current&&a.model&&(c.current.position.set(...a.model.position||[0,0,0]),c.current.rotation.set(...a.model.rotation||[0,0,0]),c.current.scale.setScalar(a.model.scale||1),e())}),t.useEffect(()=>{if(!o||!c.current)return;const e=(new l.Box3).setFromObject(c.current),t=e.getCenter(new l.Vector3),r=e.getSize(new l.Vector3),s=Math.max(r.x,r.y,r.z),i=(a.camera?.fov||50)*Math.PI/180,d=2.5*(s/(2*Math.tan(i/2)));n.setState({cameraTarget:[t.x,t.y,t.z],cameraDistance:d})},[o,a.camera?.fov,n]),!o)return null;if(o?.scene)return e.jsx("primitive",{ref:c,object:o.scene});const d=i||"box",u=e.jsx("meshStandardMaterial",{color:"#4a90e2",metalness:.3,roughness:.4});switch(d){case"box":default:return e.jsxs("mesh",{ref:c,children:[e.jsx("boxGeometry",{args:[2,2,2]}),u]});case"sphere":return e.jsxs("mesh",{ref:c,children:[e.jsx("sphereGeometry",{args:[1.5,32,32]}),u]});case"cylinder":return e.jsxs("mesh",{ref:c,children:[e.jsx("cylinderGeometry",{args:[1,1,2,32]}),u]});case"torus":return e.jsxs("mesh",{ref:c,children:[e.jsx("torusGeometry",{args:[1,.4,16,32]}),u]})}}function u({store:a,enabled:o,enableZoom:i,enablePan:l}){const c=t.useRef(null),{camera:d,invalidate:u}=r.useThree(),h=s.useStore(a,e=>e.cameraTarget),f=s.useStore(a,e=>e.cameraDistance);return t.useEffect(()=>{if(!h||!f)return;const e=Math.PI/4,t=Math.PI/6,r=h[0]+f*Math.cos(t)*Math.cos(e),n=h[1]+f*Math.sin(t),s=h[2]+f*Math.cos(t)*Math.sin(e);d.position.set(r,n,s),d.lookAt(h[0],h[1],h[2]),c.current&&(c.current.target.set(...h),c.current.update()),u()},[h,f,d,u]),e.jsx(n.OrbitControls,{ref:c,enabled:o,enableZoom:i,enablePan:l,onChange:()=>u()})}function h({store:t}){const r=s.useStore(t,e=>e.pois);return e.jsx(e.Fragment,{children:r.map(t=>e.jsx(a.POIMarker,{...t},t.id))})}function f({progress:t}){return e.jsx("div",{style:{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",background:"rgba(0,0,0,0.5)",zIndex:10},children:e.jsxs("div",{style:{textAlign:"center",color:"white"},children:[e.jsx("div",{style:{width:200,height:4,background:"#333",borderRadius:2,overflow:"hidden"},children:e.jsx("div",{style:{width:`${t}%`,height:"100%",background:"#4CAF50",transition:"width 0.3s"}})}),e.jsxs("p",{style:{marginTop:10,fontSize:14},children:[Math.round(t),"%"]})]})})}function m({instanceId:t,store:r}){const n=s.useStore(r,e=>e.setMaterialVariant),a=s.useStore(r,e=>e.setCameraPreset),o=s.useStore(r,e=>e.materialVariants),i=s.useStore(r,e=>e.cameraPresets);return e.jsxs("div",{style:{position:"absolute",top:10,left:10,background:"white",padding:10,borderRadius:8,boxShadow:"0 2px 10px rgba(0,0,0,0.1)"},children:[o.length>0&&e.jsxs("div",{style:{marginBottom:10},children:[e.jsx("label",{style:{fontSize:12,fontWeight:"bold"},children:"Materials:"}),o.map(t=>e.jsx("button",{onClick:()=>n(t.id),style:{display:"block",padding:"4px 8px",margin:"4px 0",fontSize:11},children:t.name},t.id))]}),i.length>0&&e.jsxs("div",{children:[e.jsx("label",{style:{fontSize:12,fontWeight:"bold"},children:"Camera:"}),i.map(t=>e.jsx("button",{onClick:()=>a(t.id),style:{display:"block",padding:"4px 8px",margin:"4px 0",fontSize:11},children:t.name},t.id))]})]})}exports.default=function({instanceId:i,data:l,isEditorMode:g}){const[x]=t.useState(()=>{const e=o.createConfiguratorInstance(i);return c.set(i,e),e}),b=s.useStore(x,e=>e.isReady),p=s.useStore(x,e=>e.isLoading),j=s.useStore(x,e=>e.loadingProgress);return t.useEffect(()=>{if(l.model?.url){const e=x.getState();if(e.gltf)return;e.loadModel(l.model.url)}else{x.getState().setFallbackGeometry(l.model?.fallbackGeometry||"box")}},[l.model?.url,l.model?.fallbackGeometry,x]),t.useEffect(()=>()=>{x.getState().dispose(),c.delete(i)},[i,x]),e.jsxs("div",{style:{width:"100%",height:"100%",position:"relative"},children:[p&&e.jsx(f,{progress:j}),e.jsx(a.InstanceProvider,{instanceId:i,createStore:()=>x,children:e.jsxs(r.Canvas,{shadows:!0,camera:{position:[5,5,5],fov:l.camera?.fov||50,near:l.camera?.near||.1,far:l.camera?.far||2e3},frameloop:"demand",gl:{preserveDrawingBuffer:!0,antialias:!0,powerPreference:"high-performance"},children:[e.jsx("color",{attach:"background",args:["#f0f0f0"]}),e.jsx("ambientLight",{intensity:l.lighting?.ambientIntensity||.5}),e.jsx("directionalLight",{position:l.lighting?.directionalPosition||[10,10,5],intensity:l.lighting?.directionalIntensity||1,castShadow:l.lighting?.enableShadows}),b&&e.jsx(d,{store:x,data:l}),b&&l.pois?.enabled&&e.jsx(h,{store:x}),e.jsx(u,{store:x,enabled:!1!==l.camera?.enableOrbit,enableZoom:!1!==l.camera?.enableZoom,enablePan:!1!==l.camera?.enablePan}),e.jsx(n.Environment,{preset:"city"})]},i)}),g&&b&&e.jsx(m,{instanceId:i,store:x})]})};
|
|
2
|
+
//# sourceMappingURL=model-viewer-DQiZ9csY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-viewer-DQiZ9csY.js","sources":["../src/components/model-viewer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from 'react';\nimport { Canvas, useFrame, useThree } from '@react-three/fiber';\nimport { OrbitControls, Environment } from '@react-three/drei';\nimport { useStore } from 'zustand';\nimport { InstanceProvider, POIMarker } from '@codefluss/threejs-shared';\nimport { createConfiguratorInstance } from '../store/configurator-store';\nimport type { ModelViewerProps } from '../types';\nimport type { StoreApi } from 'zustand/vanilla';\nimport type { ConfiguratorStore } from '../types';\nimport * as THREE from 'three';\n\nconst configuratorStores = new Map<string, StoreApi<ConfiguratorStore>>();\n\nexport default function ModelViewer({ instanceId, data, isEditorMode }: ModelViewerProps) {\n const [store] = useState(() => {\n // Always create a fresh store for this instance\n const newStore = createConfiguratorInstance(instanceId);\n configuratorStores.set(instanceId, newStore);\n return newStore;\n });\n\n const isReady = useStore(store, (state) => state.isReady);\n const isLoading = useStore(store, (state) => state.isLoading);\n const loadingProgress = useStore(store, (state) => state.loadingProgress);\n\n // Load model\n useEffect(() => {\n if (data.model?.url) {\n const state = store.getState();\n if (state.gltf) return; // Already loaded\n\n state.loadModel(data.model.url);\n } else {\n // Fallback to built-in geometry\n const state = store.getState();\n state.setFallbackGeometry(data.model?.fallbackGeometry || 'box');\n }\n }, [data.model?.url, data.model?.fallbackGeometry, store]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n const state = store.getState();\n state.dispose();\n configuratorStores.delete(instanceId);\n };\n }, [instanceId, store]);\n\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {isLoading && <LoadingOverlay progress={loadingProgress} />}\n\n <InstanceProvider instanceId={instanceId} createStore={() => store}>\n <Canvas\n key={instanceId}\n shadows\n camera={{\n position: [5, 5, 5],\n fov: data.camera?.fov || 50,\n near: data.camera?.near || 0.1,\n far: data.camera?.far || 2000\n }}\n frameloop=\"demand\"\n gl={{\n preserveDrawingBuffer: true,\n antialias: true,\n powerPreference: \"high-performance\"\n }}\n >\n <color attach=\"background\" args={['#f0f0f0']} />\n\n <ambientLight intensity={data.lighting?.ambientIntensity || 0.5} />\n <directionalLight\n position={data.lighting?.directionalPosition || [10, 10, 5]}\n intensity={data.lighting?.directionalIntensity || 1}\n castShadow={data.lighting?.enableShadows}\n />\n\n {isReady && <Model store={store} data={data} />}\n {isReady && data.pois?.enabled && <POIMarkers store={store} />}\n\n <CameraController\n store={store}\n enabled={data.camera?.enableOrbit !== false}\n enableZoom={data.camera?.enableZoom !== false}\n enablePan={data.camera?.enablePan !== false}\n />\n <Environment preset=\"city\" />\n </Canvas>\n </InstanceProvider>\n\n {isEditorMode && isReady && <EditorControls instanceId={instanceId} store={store} />}\n </div>\n );\n}\n\nfunction Model({ store, data }: { store: StoreApi<ConfiguratorStore>; data: ModelViewerProps['data'] }) {\n const gltf = useStore(store, (state) => state.gltf);\n const fallbackGeometry = useStore(store, (state) => state.fallbackGeometry);\n const ref = useRef<THREE.Group>(null);\n\n useFrame(({ invalidate }) => {\n if (!ref.current || !data.model) return;\n ref.current.position.set(...(data.model.position || [0, 0, 0]));\n ref.current.rotation.set(...(data.model.rotation || [0, 0, 0]));\n ref.current.scale.setScalar(data.model.scale || 1);\n invalidate(); // Trigger re-render for frameloop=\"demand\"\n });\n\n // Auto-focus and auto-zoom on model load\n useEffect(() => {\n if (!gltf || !ref.current) return;\n\n // Calculate bounding box\n const box = new THREE.Box3().setFromObject(ref.current);\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n\n // Get the max dimension to determine zoom\n const maxDim = Math.max(size.x, size.y, size.z);\n const fov = data.camera?.fov || 50;\n const fovRad = (fov * Math.PI) / 180;\n\n // Calculate camera distance to fit the object\n const cameraDistance = maxDim / (2 * Math.tan(fovRad / 2));\n\n // Add padding (2.5x for better framing and full visibility)\n const finalDistance = cameraDistance * 2.5;\n\n // Store camera info for OrbitControls\n store.setState({\n cameraTarget: [center.x, center.y, center.z] as [number, number, number],\n cameraDistance: finalDistance\n });\n }, [gltf, data.camera?.fov, store]);\n\n if (!gltf) return null;\n\n if (gltf?.scene) {\n return <primitive ref={ref} object={gltf.scene} />;\n }\n\n // Fallback geometry when no GLTF model is loaded\n const geometry = fallbackGeometry || 'box';\n const material = (\n <meshStandardMaterial\n color=\"#4a90e2\"\n metalness={0.3}\n roughness={0.4}\n />\n );\n\n switch (geometry) {\n case 'box':\n return (\n <mesh ref={ref}>\n <boxGeometry args={[2, 2, 2]} />\n {material}\n </mesh>\n );\n case 'sphere':\n return (\n <mesh ref={ref}>\n <sphereGeometry args={[1.5, 32, 32]} />\n {material}\n </mesh>\n );\n case 'cylinder':\n return (\n <mesh ref={ref}>\n <cylinderGeometry args={[1, 1, 2, 32]} />\n {material}\n </mesh>\n );\n case 'torus':\n return (\n <mesh ref={ref}>\n <torusGeometry args={[1, 0.4, 16, 32]} />\n {material}\n </mesh>\n );\n default:\n return (\n <mesh ref={ref}>\n <boxGeometry args={[2, 2, 2]} />\n {material}\n </mesh>\n );\n }\n}\n\nfunction CameraController({\n store,\n enabled,\n enableZoom,\n enablePan\n}: {\n store: StoreApi<ConfiguratorStore>;\n enabled: boolean;\n enableZoom: boolean;\n enablePan: boolean;\n}) {\n const controlsRef = useRef<any>(null);\n const { camera, invalidate } = useThree();\n const cameraTarget = useStore(store, (state) => state.cameraTarget);\n const cameraDistance = useStore(store, (state) => state.cameraDistance);\n\n useEffect(() => {\n if (!cameraTarget || !cameraDistance) return;\n\n // Calculate camera position (angle: 45 degrees horizontal, 30 degrees vertical)\n const angleH = Math.PI / 4; // 45 degrees\n const angleV = Math.PI / 6; // 30 degrees\n\n const x = cameraTarget[0] + cameraDistance * Math.cos(angleV) * Math.cos(angleH);\n const y = cameraTarget[1] + cameraDistance * Math.sin(angleV);\n const z = cameraTarget[2] + cameraDistance * Math.cos(angleV) * Math.sin(angleH);\n\n camera.position.set(x, y, z);\n camera.lookAt(cameraTarget[0], cameraTarget[1], cameraTarget[2]);\n\n // Update OrbitControls target\n if (controlsRef.current) {\n controlsRef.current.target.set(...cameraTarget);\n controlsRef.current.update();\n }\n\n invalidate();\n }, [cameraTarget, cameraDistance, camera, invalidate]);\n\n return (\n <OrbitControls\n ref={controlsRef}\n enabled={enabled}\n enableZoom={enableZoom}\n enablePan={enablePan}\n onChange={() => invalidate()}\n />\n );\n}\n\nfunction POIMarkers({ store }: { store: StoreApi<ConfiguratorStore> }) {\n const pois = useStore(store, (state) => state.pois);\n\n return (\n <>\n {pois.map((poi) => (\n <POIMarker key={poi.id} {...poi} />\n ))}\n </>\n );\n}\n\nfunction LoadingOverlay({ progress }: { progress: number }) {\n return (\n <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.5)', zIndex: 10 }}>\n <div style={{ textAlign: 'center', color: 'white' }}>\n <div style={{ width: 200, height: 4, background: '#333', borderRadius: 2, overflow: 'hidden' }}>\n <div style={{ width: `${progress}%`, height: '100%', background: '#4CAF50', transition: 'width 0.3s' }} />\n </div>\n <p style={{ marginTop: 10, fontSize: 14 }}>{Math.round(progress)}%</p>\n </div>\n </div>\n );\n}\n\nfunction EditorControls({ instanceId: _, store }: { instanceId: string; store: StoreApi<ConfiguratorStore> }) {\n const setMaterialVariant = useStore(store, (s) => s.setMaterialVariant);\n const setCameraPreset = useStore(store, (s) => s.setCameraPreset);\n const materialVariants = useStore(store, (s) => s.materialVariants);\n const cameraPresets = useStore(store, (s) => s.cameraPresets);\n\n return (\n <div style={{ position: 'absolute', top: 10, left: 10, background: 'white', padding: 10, borderRadius: 8, boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}>\n {materialVariants.length > 0 && (\n <div style={{ marginBottom: 10 }}>\n <label style={{ fontSize: 12, fontWeight: 'bold' }}>Materials:</label>\n {materialVariants.map(v => (\n <button key={v.id} onClick={() => setMaterialVariant(v.id)} style={{ display: 'block', padding: '4px 8px', margin: '4px 0', fontSize: 11 }}>\n {v.name}\n </button>\n ))}\n </div>\n )}\n {cameraPresets.length > 0 && (\n <div>\n <label style={{ fontSize: 12, fontWeight: 'bold' }}>Camera:</label>\n {cameraPresets.map(p => (\n <button key={p.id} onClick={() => setCameraPreset(p.id)} style={{ display: 'block', padding: '4px 8px', margin: '4px 0', fontSize: 11 }}>\n {p.name}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"names":["configuratorStores","Map","Model","store","data","gltf","useStore","state","fallbackGeometry","ref","useRef","useFrame","invalidate","current","model","position","set","rotation","scale","setScalar","useEffect","box","THREE","Box3","setFromObject","center","getCenter","Vector3","size","getSize","maxDim","Math","max","x","y","z","fovRad","camera","fov","PI","finalDistance","tan","setState","cameraTarget","cameraDistance","scene","jsx","object","geometry","material","color","metalness","roughness","jsxs","children","args","CameraController","enabled","enableZoom","enablePan","controlsRef","useThree","angleH","angleV","cos","sin","lookAt","target","update","OrbitControls","onChange","POIMarkers","pois","Fragment","map","poi","POIMarker","id","LoadingOverlay","progress","style","inset","display","alignItems","justifyContent","background","zIndex","textAlign","width","height","borderRadius","overflow","transition","marginTop","fontSize","round","EditorControls","instanceId","_","setMaterialVariant","s","setCameraPreset","materialVariants","cameraPresets","top","left","padding","boxShadow","length","marginBottom","fontWeight","v","onClick","margin","name","p","isEditorMode","useState","newStore","createConfiguratorInstance","isReady","isLoading","loadingProgress","url","getState","loadModel","setFallbackGeometry","dispose","delete","InstanceProvider","createStore","Canvas","shadows","near","far","frameloop","gl","preserveDrawingBuffer","antialias","powerPreference","attach","intensity","lighting","ambientIntensity","directionalPosition","directionalIntensity","castShadow","enableShadows","enableOrbit","Environment","preset"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configurator 3D Plugin - SSR Renderer Exports
|
|
3
|
+
*/
|
|
4
|
+
export { ConfiguratorRenderer } from './components/configurator-renderer';
|
|
5
|
+
export type { ConfiguratorRendererProps } from './components/configurator-renderer';
|
|
6
|
+
export type { Configurator3DData, CameraPreset, MaterialVariant, } from './types';
|
|
7
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,YAAY,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAEpF,YAAY,EACX,kBAAkB,EAClB,YAAY,EACZ,eAAe,GACf,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ConfiguratorStore } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Configurator Store Factory
|
|
4
|
+
*
|
|
5
|
+
* Creates isolated 3D configurator instance per plugin instance
|
|
6
|
+
* Handles GLTF loading, POI system, material variants, and camera presets
|
|
7
|
+
*/
|
|
8
|
+
export declare function createConfiguratorInstance(instanceId: string): import('zustand').StoreApi<ConfiguratorStore>;
|
|
9
|
+
//# sourceMappingURL=configurator-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configurator-store.d.ts","sourceRoot":"","sources":["../../src/store/configurator-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAiC,MAAM,UAAU,CAAC;AAGjF;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,iDAiQ5D"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { GLTF } from 'three/addons/loaders/GLTFLoader.js';
|
|
2
|
+
import { POI } from '@codefluss/threejs-shared';
|
|
3
|
+
/**
|
|
4
|
+
* Camera Preset Interface
|
|
5
|
+
*/
|
|
6
|
+
export interface CameraPreset {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
position: [number, number, number];
|
|
10
|
+
target: [number, number, number];
|
|
11
|
+
fov?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Material Variant Interface
|
|
15
|
+
*/
|
|
16
|
+
export interface MaterialVariant {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
materialName: string;
|
|
20
|
+
properties: {
|
|
21
|
+
color?: string;
|
|
22
|
+
metalness?: number;
|
|
23
|
+
roughness?: number;
|
|
24
|
+
emissive?: string;
|
|
25
|
+
emissiveIntensity?: number;
|
|
26
|
+
map?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Configurator 3D Data Interface
|
|
31
|
+
*/
|
|
32
|
+
export interface Configurator3DData {
|
|
33
|
+
model?: {
|
|
34
|
+
url?: string;
|
|
35
|
+
scale?: number;
|
|
36
|
+
position?: [number, number, number];
|
|
37
|
+
rotation?: [number, number, number];
|
|
38
|
+
fallbackGeometry?: 'box' | 'sphere' | 'cylinder' | 'torus';
|
|
39
|
+
description?: string;
|
|
40
|
+
keywords?: string[];
|
|
41
|
+
};
|
|
42
|
+
pois?: {
|
|
43
|
+
enabled?: boolean;
|
|
44
|
+
markers?: POI[];
|
|
45
|
+
};
|
|
46
|
+
materials?: {
|
|
47
|
+
enabled?: boolean;
|
|
48
|
+
variants?: MaterialVariant[];
|
|
49
|
+
activeVariant?: string;
|
|
50
|
+
};
|
|
51
|
+
camera?: {
|
|
52
|
+
presets?: CameraPreset[];
|
|
53
|
+
activePreset?: string;
|
|
54
|
+
enableOrbit?: boolean;
|
|
55
|
+
enableZoom?: boolean;
|
|
56
|
+
enablePan?: boolean;
|
|
57
|
+
fov?: number;
|
|
58
|
+
near?: number;
|
|
59
|
+
far?: number;
|
|
60
|
+
};
|
|
61
|
+
lighting?: {
|
|
62
|
+
ambientIntensity?: number;
|
|
63
|
+
directionalIntensity?: number;
|
|
64
|
+
directionalPosition?: [number, number, number];
|
|
65
|
+
enableShadows?: boolean;
|
|
66
|
+
};
|
|
67
|
+
layout?: {
|
|
68
|
+
height?: string;
|
|
69
|
+
position?: 'relative' | 'absolute' | 'fixed' | 'sticky';
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Configurator Store Interface
|
|
74
|
+
*/
|
|
75
|
+
export interface ConfiguratorStore {
|
|
76
|
+
instanceId: string;
|
|
77
|
+
gltf: GLTF | null;
|
|
78
|
+
fallbackGeometry?: 'box' | 'sphere' | 'cylinder' | 'torus';
|
|
79
|
+
isLoading: boolean;
|
|
80
|
+
loadingProgress: number;
|
|
81
|
+
error: string | null;
|
|
82
|
+
isReady: boolean;
|
|
83
|
+
pois: POI[];
|
|
84
|
+
activePOI: string | null;
|
|
85
|
+
materialVariants: MaterialVariant[];
|
|
86
|
+
activeMaterialVariant: string | null;
|
|
87
|
+
cameraPresets: CameraPreset[];
|
|
88
|
+
activeCameraPreset: string | null;
|
|
89
|
+
cameraTarget?: [number, number, number];
|
|
90
|
+
cameraDistance?: number;
|
|
91
|
+
loadModel: (url: string, onProgress?: (progress: number) => void) => Promise<GLTF>;
|
|
92
|
+
setFallbackGeometry: (geometry: 'box' | 'sphere' | 'cylinder' | 'torus') => void;
|
|
93
|
+
addPOI: (poi: Omit<POI, 'id'>) => string;
|
|
94
|
+
updatePOI: (id: string, updates: Partial<POI>) => void;
|
|
95
|
+
removePOI: (id: string) => void;
|
|
96
|
+
setActivePOI: (id: string | null) => void;
|
|
97
|
+
setMaterialVariant: (variantId: string) => void;
|
|
98
|
+
addMaterialVariant: (variant: MaterialVariant) => void;
|
|
99
|
+
setCameraPreset: (presetId: string) => void;
|
|
100
|
+
addCameraPreset: (preset: CameraPreset) => void;
|
|
101
|
+
dispose: () => void;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Component Props
|
|
105
|
+
*/
|
|
106
|
+
export interface Configurator3DComponentProps {
|
|
107
|
+
data: Configurator3DData;
|
|
108
|
+
elementId: string;
|
|
109
|
+
isEditorMode?: boolean;
|
|
110
|
+
dependencies: any;
|
|
111
|
+
}
|
|
112
|
+
export interface ModelViewerProps {
|
|
113
|
+
instanceId: string;
|
|
114
|
+
data: Configurator3DData;
|
|
115
|
+
isEditorMode: boolean;
|
|
116
|
+
}
|
|
117
|
+
export interface POIEditorProps {
|
|
118
|
+
instanceId: string;
|
|
119
|
+
onPOISelect?: (poiId: string) => void;
|
|
120
|
+
}
|
|
121
|
+
export interface MaterialEditorProps {
|
|
122
|
+
instanceId: string;
|
|
123
|
+
onVariantSelect?: (variantId: string) => void;
|
|
124
|
+
}
|
|
125
|
+
export interface CameraEditorProps {
|
|
126
|
+
instanceId: string;
|
|
127
|
+
onPresetSelect?: (presetId: string) => void;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|