@vizij/render 0.0.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/dist/index.js ADDED
@@ -0,0 +1,2723 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ Controller: () => Controller,
34
+ EmptyModelError: () => EmptyModelError,
35
+ InnerVizij: () => InnerVizij,
36
+ ShapeMaterial: () => ShapeMaterial,
37
+ Vizij: () => Vizij,
38
+ VizijContext: () => VizijContext,
39
+ VizijSlice: () => VizijSlice,
40
+ createVizijStore: () => createVizijStore,
41
+ exportScene: () => exportScene,
42
+ loadGLTF: () => loadGLTF,
43
+ loadGLTFFromBlob: () => loadGLTFFromBlob,
44
+ loadGltfFromBlob: () => loadGltfFromBlob,
45
+ useDefaultVizijStore: () => useDefaultVizijStore,
46
+ useFeatures: () => useFeatures,
47
+ useVizijStore: () => useVizijStore,
48
+ useVizijStoreGetter: () => useVizijStoreGetter,
49
+ useVizijStoreSetter: () => useVizijStoreSetter,
50
+ useVizijStoreSubscription: () => useVizijStoreSubscription
51
+ });
52
+ module.exports = __toCommonJS(index_exports);
53
+
54
+ // src/controllers/controller.tsx
55
+ var import_react3 = require("react");
56
+ var import_shallow = require("zustand/react/shallow");
57
+ var import_clsx = require("clsx");
58
+ var import_utils = require("@vizij/utils");
59
+ var import_ui = require("@semio/ui");
60
+
61
+ // src/hooks/use-vizij-store.ts
62
+ var import_react2 = require("react");
63
+ var import_zustand = require("zustand");
64
+
65
+ // src/context.ts
66
+ var import_react = require("react");
67
+ var VizijContext = (0, import_react.createContext)(null);
68
+
69
+ // src/hooks/use-vizij-store.ts
70
+ function useVizijStore(selector) {
71
+ const store = (0, import_react2.useContext)(VizijContext);
72
+ if (!store) throw new Error("Missing VizijProvider in the tree");
73
+ return (0, import_zustand.useStore)(store, selector);
74
+ }
75
+
76
+ // src/controllers/controller.tsx
77
+ var import_jsx_runtime = require("react/jsx-runtime");
78
+ function InnerController({
79
+ animatableId,
80
+ namespace,
81
+ subfield,
82
+ className
83
+ }) {
84
+ const setValue = useVizijStore((0, import_shallow.useShallow)((state) => state.setValue));
85
+ const animatable = useVizijStore(
86
+ (0, import_shallow.useShallow)((state) => state.animatables[animatableId])
87
+ );
88
+ const lookupId = (0, import_utils.getLookup)(namespace ?? "default", animatableId);
89
+ const rawValue = useVizijStore(
90
+ (0, import_shallow.useShallow)((state) => state.values.get(lookupId))
91
+ );
92
+ if (animatable.type === "number") {
93
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.clsx)("flex flex-col w-full", className), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
94
+ import_ui.SliderNumberField,
95
+ {
96
+ size: import_ui.Size.Sm,
97
+ value: rawValue ?? animatable.default,
98
+ onChange: (v) => {
99
+ setValue(animatableId, namespace ?? "default", v);
100
+ },
101
+ min: animatable.constraints.min,
102
+ max: animatable.constraints.max
103
+ }
104
+ ) });
105
+ } else if (animatable.type === "vector3" && !subfield) {
106
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.clsx)("flex flex-col gap-2", className), children: ["x", "y", "z"].map((axis) => {
107
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
108
+ InnerController,
109
+ {
110
+ animatableId,
111
+ namespace,
112
+ subfield: axis
113
+ },
114
+ axis
115
+ );
116
+ }) });
117
+ } else if (animatable.type === "vector2" && !subfield) {
118
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.clsx)("flex flex-col gap-2", className), children: ["x", "y"].map((axis) => {
119
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
120
+ InnerController,
121
+ {
122
+ animatableId,
123
+ namespace,
124
+ subfield: axis
125
+ },
126
+ axis
127
+ );
128
+ }) });
129
+ } else if (animatable.type === "euler" && !subfield) {
130
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.clsx)("flex flex-col gap-2", className), children: ["x", "y", "z"].map((axis) => {
131
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
132
+ InnerController,
133
+ {
134
+ animatableId,
135
+ namespace,
136
+ subfield: axis
137
+ },
138
+ axis
139
+ );
140
+ }) });
141
+ } else if (animatable.type === "rgb" && !subfield) {
142
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: (0, import_clsx.clsx)("flex flex-col gap-2", className), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
143
+ import_ui.ColorPickerPopover,
144
+ {
145
+ value: rawValue ? convertRGBRange(rawValue, "255") : convertRGBRange(animatable.default, "255"),
146
+ onChange: (v) => {
147
+ setValue(
148
+ animatableId,
149
+ namespace ?? "default",
150
+ convertRGBRange(v, "1")
151
+ );
152
+ }
153
+ }
154
+ ) });
155
+ } else if (animatable.type === "vector3" && subfield && ["x", "y", "z"].includes(subfield)) {
156
+ const axis = subfield;
157
+ const currentVec = rawValue ?? animatable.default;
158
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
159
+ import_ui.SliderNumberField,
160
+ {
161
+ label: axis,
162
+ size: import_ui.Size.Sm,
163
+ value: currentVec[axis],
164
+ onChange: (v) => {
165
+ setValue(animatableId, namespace ?? "default", {
166
+ ...currentVec,
167
+ [axis]: v
168
+ });
169
+ },
170
+ min: animatable.constraints.min?.[vectorIndexLookup[axis]] ?? void 0,
171
+ max: animatable.constraints.max?.[vectorIndexLookup[axis]] ?? void 0
172
+ }
173
+ );
174
+ } else if (animatable.type === "vector2" && subfield && ["x", "y"].includes(subfield)) {
175
+ const axis = subfield;
176
+ const currentVec = rawValue ?? animatable.default;
177
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
178
+ import_ui.SliderNumberField,
179
+ {
180
+ label: axis,
181
+ size: import_ui.Size.Sm,
182
+ value: currentVec[axis],
183
+ onChange: (v) => {
184
+ setValue(animatableId, namespace ?? "default", {
185
+ ...currentVec,
186
+ [axis]: v
187
+ });
188
+ },
189
+ min: animatable.constraints.min?.[vectorIndexLookup[axis]] ?? void 0,
190
+ max: animatable.constraints.max?.[vectorIndexLookup[axis]] ?? void 0
191
+ }
192
+ );
193
+ } else if (animatable.type === "euler" && subfield && ["x", "y", "z"].includes(subfield)) {
194
+ const axis = subfield;
195
+ const currentVec = rawValue ?? animatable.default;
196
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
197
+ import_ui.SliderNumberField,
198
+ {
199
+ label: axis,
200
+ size: import_ui.Size.Sm,
201
+ value: currentVec[axis],
202
+ onChange: (v) => {
203
+ setValue(animatableId, namespace ?? "default", {
204
+ ...currentVec,
205
+ [axis]: v
206
+ });
207
+ },
208
+ min: animatable.constraints.min?.[vectorIndexLookup[axis]] ?? void 0,
209
+ max: animatable.constraints.max?.[vectorIndexLookup[axis]] ?? void 0
210
+ }
211
+ );
212
+ } else if (animatable.type === "rgb" && subfield && ["r", "g", "b"].includes(subfield)) {
213
+ const axis = subfield;
214
+ const currentVec = rawValue ?? animatable.default;
215
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
216
+ import_ui.SliderNumberField,
217
+ {
218
+ label: axis,
219
+ size: import_ui.Size.Sm,
220
+ value: currentVec[axis],
221
+ strictText: true,
222
+ strictSlider: true,
223
+ onChange: (v) => {
224
+ setValue(animatableId, namespace ?? "default", {
225
+ ...currentVec,
226
+ [axis]: v
227
+ });
228
+ },
229
+ min: animatable.constraints.min?.[vectorIndexLookup[axis]] ?? void 0,
230
+ max: animatable.constraints.max?.[vectorIndexLookup[axis]] ?? void 0
231
+ }
232
+ );
233
+ }
234
+ }
235
+ var Controller = (0, import_react3.memo)(InnerController);
236
+ var vectorIndexLookup = {
237
+ x: 0,
238
+ y: 1,
239
+ z: 2,
240
+ r: 0,
241
+ g: 1,
242
+ b: 2
243
+ };
244
+ var convertRGBRange = (color, to) => {
245
+ if (to === "255") {
246
+ return {
247
+ r: color.r * 255,
248
+ g: color.g * 255,
249
+ b: color.b * 255
250
+ };
251
+ } else if (to === "1") {
252
+ return {
253
+ r: color.r / 255,
254
+ g: color.g / 255,
255
+ b: color.b / 255
256
+ };
257
+ }
258
+ return color;
259
+ };
260
+
261
+ // src/vizij.tsx
262
+ var import_react11 = require("react");
263
+ var import_react_error_boundary = require("react-error-boundary");
264
+ var import_three = require("three");
265
+ var import_fiber = require("@react-three/fiber");
266
+ var import_drei3 = require("@react-three/drei");
267
+ var import_shallow8 = require("zustand/react/shallow");
268
+
269
+ // src/renderables/renderable.tsx
270
+ var import_react9 = require("react");
271
+ var import_shallow7 = require("zustand/react/shallow");
272
+
273
+ // src/renderables/group.tsx
274
+ var import_react5 = require("react");
275
+ var THREE = __toESM(require("three"));
276
+ var import_shallow3 = require("zustand/react/shallow");
277
+ var import_utils3 = require("@vizij/utils");
278
+
279
+ // src/hooks/use-features.ts
280
+ var import_react4 = require("react");
281
+ var import_shallow2 = require("zustand/shallow");
282
+ var import_utils2 = require("@vizij/utils");
283
+ function useFeatures(namespace, features, callbacks, debugInfo) {
284
+ const store = (0, import_react4.useContext)(VizijContext);
285
+ if (!store) throw new Error("Missing VizijProvider in the tree");
286
+ (0, import_react4.useEffect)(() => {
287
+ const unsubsribes = [];
288
+ Object.keys(callbacks).forEach((key) => {
289
+ if (!(key in features)) {
290
+ return;
291
+ }
292
+ const featureInfo = features[key];
293
+ if (!featureInfo.animated) {
294
+ callbacks[key](featureInfo.value);
295
+ } else {
296
+ const animatableValueInfo = store.getState().animatables[featureInfo.value];
297
+ if (!animatableValueInfo) {
298
+ console.error(
299
+ `Feature with id ${key} is animated but the animated value with id ${featureInfo.value} is not found`,
300
+ debugInfo
301
+ );
302
+ return;
303
+ }
304
+ const cb = (value) => {
305
+ if (value === void 0) {
306
+ callbacks[key](animatableValueInfo.default);
307
+ } else {
308
+ callbacks[key](value);
309
+ }
310
+ };
311
+ const defaultValue = animatableValueInfo.default;
312
+ const lookupKey = (0, import_utils2.getLookup)(namespace, animatableValueInfo.id);
313
+ const unsubscribe = store.subscribe(
314
+ (state) => state.values.get(lookupKey) ?? defaultValue,
315
+ cb,
316
+ { equalityFn: import_shallow2.shallow, fireImmediately: true }
317
+ );
318
+ unsubsribes.push(unsubscribe);
319
+ }
320
+ });
321
+ return () => {
322
+ unsubsribes.forEach((unsubscribe) => unsubscribe());
323
+ };
324
+ }, [features, callbacks, store, debugInfo, namespace]);
325
+ }
326
+
327
+ // src/functions/create-stored-data.ts
328
+ var import_lodash2 = require("lodash");
329
+
330
+ // src/functions/create-stored-features.ts
331
+ var import_lodash = require("lodash");
332
+ function createStoredFeatures(objectFeatures, animatableValues) {
333
+ return (0, import_lodash.mapValues)(objectFeatures, (feat) => {
334
+ if (feat.animated) {
335
+ const storedFeat = {
336
+ animated: true,
337
+ value: animatableValues[feat.value],
338
+ ...feat.label ? { label: feat.label } : {}
339
+ };
340
+ return storedFeat;
341
+ } else {
342
+ const staticFeature = feat;
343
+ return staticFeature.label ? { ...staticFeature } : staticFeature;
344
+ }
345
+ });
346
+ }
347
+
348
+ // src/functions/create-stored-data.ts
349
+ function createStoredRenderable(data, animatableValues) {
350
+ const d = (0, import_lodash2.omit)(data, "refs", "geometry");
351
+ const storedFeatures = createStoredFeatures(
352
+ data.features,
353
+ animatableValues
354
+ );
355
+ return { ...d, features: storedFeatures };
356
+ }
357
+
358
+ // src/renderables/group.tsx
359
+ var import_jsx_runtime2 = require("react/jsx-runtime");
360
+ THREE.Object3D.DEFAULT_UP.set(0, 0, 1);
361
+ function InnerRenderedGroup({
362
+ id,
363
+ namespace,
364
+ chain
365
+ }) {
366
+ const ref = (0, import_react5.useRef)();
367
+ const group = useVizijStore((0, import_shallow3.useShallow)((state) => state.world[id]));
368
+ const refIsNull = !group.refs[namespace]?.current;
369
+ const animatables = useVizijStore((0, import_shallow3.useShallow)((state) => state.animatables));
370
+ const setHoveredElement = useVizijStore(
371
+ (0, import_shallow3.useShallow)((state) => state.setHoveredElement)
372
+ );
373
+ const animatableValues = (0, import_react5.useMemo)(() => {
374
+ const av = {};
375
+ Object.values(group.features).forEach((feat) => {
376
+ if (feat.animated) {
377
+ const animatable = animatables[feat.value];
378
+ av[animatable.id] = animatable;
379
+ }
380
+ });
381
+ return av;
382
+ }, [group.features, animatables]);
383
+ const userData = {
384
+ gltfExtensions: {
385
+ RobotData: createStoredRenderable(group, animatableValues)
386
+ }
387
+ };
388
+ useFeatures(namespace, group.features, {
389
+ translation: (pos) => {
390
+ if (ref.current?.position && (0, import_utils3.instanceOfRawVector3)(pos)) {
391
+ ref.current.position.set(
392
+ pos.x,
393
+ pos.y,
394
+ pos.z
395
+ );
396
+ } else if (ref.current?.position && (0, import_utils3.instanceOfRawVector2)(pos)) {
397
+ const currentZ = ref.current.position.z;
398
+ ref.current.position.set(pos.x, pos.y, currentZ);
399
+ }
400
+ },
401
+ rotation: (rot) => {
402
+ if (ref.current?.rotation && (0, import_utils3.instanceOfRawEuler)(rot)) {
403
+ ref.current.rotation.set(rot.x, rot.y, rot.z, "ZYX");
404
+ } else if (ref.current?.rotation && (0, import_utils3.instanceOfRawNumber)(rot)) {
405
+ ref.current.rotation.set(0, 0, 0);
406
+ ref.current.rotateZ(rot);
407
+ }
408
+ },
409
+ scale: (scale) => {
410
+ if (ref.current?.scale && (0, import_utils3.instanceOfRawVector3)(scale)) {
411
+ if (scale.x === null || scale.y === null || scale.z === null) {
412
+ ref.current.scale.set(0.1, 0.1, 0.1);
413
+ return;
414
+ }
415
+ ref.current.scale.set(scale.x, scale.y, scale.z);
416
+ } else if (ref.current && (0, import_utils3.instanceOfRawNumber)(scale)) {
417
+ ref.current.scale.set(scale, scale, scale);
418
+ } else if (ref.current) {
419
+ ref.current.scale.set(1, 1, 1);
420
+ }
421
+ }
422
+ });
423
+ const setReference = useVizijStore(
424
+ (0, import_shallow3.useShallow)((state) => state.setReference)
425
+ );
426
+ (0, import_react5.useEffect)(() => {
427
+ if (ref.current && refIsNull) {
428
+ setReference(group.id, namespace, ref);
429
+ }
430
+ }, [group.id, namespace, ref, setReference, refIsNull]);
431
+ const handlePointerOver = (0, import_react5.useCallback)(
432
+ (event) => {
433
+ if (event.eventObject !== event.object) {
434
+ return;
435
+ }
436
+ setHoveredElement({ id, namespace, type: "group" });
437
+ },
438
+ [id, namespace, setHoveredElement]
439
+ );
440
+ const handlePointerOut = (0, import_react5.useCallback)(
441
+ (event) => {
442
+ if (event.eventObject !== event.object) {
443
+ return;
444
+ }
445
+ setHoveredElement(null);
446
+ },
447
+ [setHoveredElement]
448
+ );
449
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
450
+ "group",
451
+ {
452
+ ref,
453
+ uuid: `${namespace}.${group.id}`,
454
+ userData,
455
+ onPointerOver: handlePointerOver,
456
+ onPointerOut: handlePointerOut,
457
+ children: group.children.map((child) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
458
+ Renderable,
459
+ {
460
+ id: child,
461
+ namespace,
462
+ chain: [...chain, id]
463
+ },
464
+ child
465
+ ))
466
+ }
467
+ );
468
+ }
469
+ var RenderedGroup = (0, import_react5.memo)(InnerRenderedGroup);
470
+
471
+ // src/renderables/ellipse.tsx
472
+ var import_react6 = require("react");
473
+ var import_shallow4 = require("zustand/react/shallow");
474
+ var import_utils4 = require("@vizij/utils");
475
+ var import_drei = require("@react-three/drei");
476
+ var import_jsx_runtime3 = require("react/jsx-runtime");
477
+ function InnerRenderedEllipse({
478
+ id,
479
+ namespace,
480
+ chain
481
+ }) {
482
+ const ellipseRef = (0, import_react6.useRef)();
483
+ const materialRef = (0, import_react6.useRef)();
484
+ const lineRef = (0, import_react6.useRef)();
485
+ const strokeOffsetRef = (0, import_react6.useRef)(0);
486
+ const strokeWidthRef = (0, import_react6.useRef)(0);
487
+ const onElementClick = useVizijStore(
488
+ (0, import_shallow4.useShallow)((state) => state.onElementClick)
489
+ );
490
+ const setHoveredElement = useVizijStore(
491
+ (0, import_shallow4.useShallow)((state) => state.setHoveredElement)
492
+ );
493
+ const ellipse = useVizijStore(
494
+ (0, import_shallow4.useShallow)((state) => state.world[id])
495
+ );
496
+ const refIsNull = !ellipse.refs[namespace]?.current;
497
+ const animatables = useVizijStore((0, import_shallow4.useShallow)((state) => state.animatables));
498
+ const animatableValues = (0, import_react6.useMemo)(() => {
499
+ const av = {};
500
+ Object.values(ellipse.features).forEach((feat) => {
501
+ if (feat.animated) {
502
+ const animatable = animatables[feat.value];
503
+ av[animatable.id] = animatable;
504
+ }
505
+ });
506
+ return av;
507
+ }, [ellipse.features, animatables]);
508
+ const selectionData = (0, import_react6.useMemo)(
509
+ () => ({ id, namespace, type: "ellipse" }),
510
+ [id, namespace]
511
+ );
512
+ const userData = (0, import_react6.useMemo)(
513
+ () => ({
514
+ gltfExtensions: {
515
+ RobotData: createStoredRenderable(ellipse, animatableValues)
516
+ },
517
+ selection: selectionData
518
+ }),
519
+ [ellipse, animatableValues, selectionData]
520
+ );
521
+ useFeatures(namespace, ellipse.features, {
522
+ translation: (pos) => {
523
+ if (ellipseRef.current?.position && (0, import_utils4.instanceOfRawVector3)(pos)) {
524
+ ellipseRef.current.position.set(
525
+ pos.x,
526
+ pos.y,
527
+ pos.z
528
+ );
529
+ } else if (ellipseRef.current?.position && (0, import_utils4.instanceOfRawVector2)(pos)) {
530
+ const currentZ = ellipseRef.current.position.z;
531
+ ellipseRef.current.position.set(
532
+ pos.x,
533
+ pos.y,
534
+ currentZ
535
+ );
536
+ }
537
+ if (lineRef.current?.position && (0, import_utils4.instanceOfRawVector3)(pos)) {
538
+ lineRef.current.position.set(
539
+ pos.x,
540
+ pos.y,
541
+ pos.z
542
+ );
543
+ } else if (lineRef.current?.position && (0, import_utils4.instanceOfRawVector2)(pos)) {
544
+ const currentZ = lineRef.current.position.z;
545
+ lineRef.current.position.set(
546
+ pos.x,
547
+ pos.y,
548
+ currentZ
549
+ );
550
+ }
551
+ },
552
+ rotation: (rot) => {
553
+ if (ellipseRef.current?.rotation && (0, import_utils4.instanceOfRawEuler)(rot)) {
554
+ ellipseRef.current.rotation.set(rot.x, rot.y, rot.z, "ZYX");
555
+ } else if (ellipseRef.current?.rotation && (0, import_utils4.instanceOfRawNumber)(rot)) {
556
+ ellipseRef.current.rotation.set(0, 0, 0);
557
+ ellipseRef.current.rotateZ(rot);
558
+ }
559
+ if (lineRef.current?.rotation && (0, import_utils4.instanceOfRawEuler)(rot)) {
560
+ lineRef.current.rotation.set(rot.x, rot.y, rot.z, "ZYX");
561
+ } else if (lineRef.current?.rotation && (0, import_utils4.instanceOfRawNumber)(rot)) {
562
+ lineRef.current.rotation.set(0, 0, 0);
563
+ lineRef.current.rotateZ(rot);
564
+ }
565
+ },
566
+ fillOpacity: (op) => {
567
+ if (materialRef.current?.opacity !== void 0 && (0, import_utils4.instanceOfRawNumber)(op)) {
568
+ materialRef.current.opacity = op;
569
+ if (op < 1) {
570
+ materialRef.current.transparent = true;
571
+ } else {
572
+ materialRef.current.transparent = false;
573
+ }
574
+ materialRef.current.needsUpdate = true;
575
+ }
576
+ },
577
+ fillColor: (color) => {
578
+ if (materialRef.current?.color) {
579
+ if ((0, import_utils4.instanceOfRawRGB)(color)) {
580
+ materialRef.current.color.setRGB(color.r, color.g, color.b);
581
+ materialRef.current.needsUpdate = true;
582
+ } else if ((0, import_utils4.instanceOfRawHSL)(color)) {
583
+ materialRef.current.color.setHSL(color.h, color.s, color.l);
584
+ materialRef.current.needsUpdate = true;
585
+ }
586
+ }
587
+ },
588
+ height: (height) => {
589
+ if (ellipseRef.current && (0, import_utils4.instanceOfRawNumber)(height)) {
590
+ ellipseRef.current.scale.set(ellipseRef.current.scale.x, height, 1);
591
+ }
592
+ if (ellipseRef.current && lineRef.current && (0, import_utils4.instanceOfRawNumber)(height)) {
593
+ const offset = strokeOffsetRef.current * strokeWidthRef.current / 2 + strokeOffsetRef.current * -1;
594
+ lineRef.current.scale.set(
595
+ ellipseRef.current.scale.x + offset,
596
+ height + offset,
597
+ 1
598
+ );
599
+ }
600
+ },
601
+ width: (width) => {
602
+ if (ellipseRef.current && (0, import_utils4.instanceOfRawNumber)(width)) {
603
+ ellipseRef.current.scale.set(width, ellipseRef.current.scale.y, 1);
604
+ }
605
+ if (ellipseRef.current && lineRef.current && (0, import_utils4.instanceOfRawNumber)(width)) {
606
+ const offset = strokeOffsetRef.current * strokeWidthRef.current / 2 + strokeOffsetRef.current * -1;
607
+ lineRef.current.scale.set(
608
+ width + offset,
609
+ ellipseRef.current.scale.y + offset,
610
+ 1
611
+ );
612
+ }
613
+ },
614
+ strokeOpacity: (strokeOpacity) => {
615
+ if (lineRef.current?.material && (0, import_utils4.instanceOfRawNumber)(strokeOpacity)) {
616
+ lineRef.current.material.opacity = strokeOpacity;
617
+ if (strokeOpacity < 1) {
618
+ lineRef.current.material.transparent = true;
619
+ } else {
620
+ lineRef.current.material.transparent = false;
621
+ }
622
+ lineRef.current.material.needsUpdate = true;
623
+ }
624
+ },
625
+ strokeColor: (strokeColor) => {
626
+ if (lineRef.current?.material.color) {
627
+ if ((0, import_utils4.instanceOfRawRGB)(strokeColor)) {
628
+ lineRef.current.material.color.setRGB(
629
+ strokeColor.r,
630
+ strokeColor.g,
631
+ strokeColor.b
632
+ );
633
+ lineRef.current.material.needsUpdate = true;
634
+ } else if ((0, import_utils4.instanceOfRawHSL)(strokeColor)) {
635
+ lineRef.current.material.color.setHSL(
636
+ strokeColor.h,
637
+ strokeColor.s,
638
+ strokeColor.l
639
+ );
640
+ lineRef.current.material.needsUpdate = true;
641
+ }
642
+ }
643
+ },
644
+ strokeWidth: (strokeWidth) => {
645
+ if (lineRef.current?.material && ellipseRef.current) {
646
+ if ((0, import_utils4.instanceOfRawNumber)(strokeWidth)) {
647
+ strokeWidthRef.current = strokeWidth;
648
+ const offset = strokeWidth * strokeOffsetRef.current / 2 + strokeOffsetRef.current * -1;
649
+ lineRef.current.scale.set(
650
+ ellipseRef.current.scale.x + offset,
651
+ ellipseRef.current.scale.y + offset,
652
+ 1
653
+ );
654
+ lineRef.current.material.linewidth = strokeWidth;
655
+ lineRef.current.material.needsUpdate = true;
656
+ }
657
+ }
658
+ },
659
+ strokeOffset: (strokeOffset) => {
660
+ if (lineRef.current?.material && ellipseRef.current) {
661
+ if ((0, import_utils4.instanceOfRawNumber)(strokeOffset)) {
662
+ strokeOffsetRef.current = strokeOffset;
663
+ const offset = strokeOffset * strokeWidthRef.current / 2 + strokeOffset * -1;
664
+ lineRef.current.scale.set(
665
+ ellipseRef.current.scale.x + offset,
666
+ ellipseRef.current.scale.y + offset,
667
+ 1
668
+ );
669
+ }
670
+ }
671
+ }
672
+ });
673
+ const setReference = useVizijStore(
674
+ (0, import_shallow4.useShallow)((state) => state.setReference)
675
+ );
676
+ const points = (0, import_react6.useMemo)(() => {
677
+ const n = 600;
678
+ const p = [];
679
+ const angleStep = 2 * Math.PI / n;
680
+ for (let i = 0; i < n; i++) {
681
+ const angle = i * angleStep;
682
+ const x = Math.cos(angle);
683
+ const y = Math.sin(angle);
684
+ p.push([x, y, 0]);
685
+ }
686
+ return p;
687
+ }, []);
688
+ (0, import_react6.useEffect)(() => {
689
+ if (ellipseRef.current && refIsNull)
690
+ setReference(ellipse.id, namespace, ellipseRef);
691
+ }, [ellipse.id, namespace, ellipseRef, setReference, refIsNull]);
692
+ const handlePointerOver = (0, import_react6.useCallback)(
693
+ (event) => {
694
+ event.stopPropagation();
695
+ setHoveredElement({ id, namespace, type: "ellipse" });
696
+ },
697
+ [id, namespace, setHoveredElement]
698
+ );
699
+ const handlePointerOut = (0, import_react6.useCallback)(
700
+ (event) => {
701
+ event.stopPropagation();
702
+ setHoveredElement(null);
703
+ },
704
+ [setHoveredElement]
705
+ );
706
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
707
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
708
+ import_drei.Circle,
709
+ {
710
+ ref: ellipseRef,
711
+ userData,
712
+ args: [1, 100],
713
+ onPointerOver: handlePointerOver,
714
+ onPointerOut: handlePointerOut,
715
+ onClick: (e) => {
716
+ onElementClick({ id, type: "ellipse", namespace }, [...chain, id], e);
717
+ },
718
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("meshStandardMaterial", { attach: "material", ref: materialRef })
719
+ }
720
+ ),
721
+ showLine(ellipse) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
722
+ import_drei.Line,
723
+ {
724
+ ref: lineRef,
725
+ points,
726
+ onPointerOver: handlePointerOver,
727
+ onPointerOut: handlePointerOut
728
+ }
729
+ )
730
+ ] });
731
+ }
732
+ var RenderedEllipse = (0, import_react6.memo)(InnerRenderedEllipse);
733
+ var showLine = (ellipse) => {
734
+ if ("strokeOpacity" in ellipse.features) {
735
+ return true;
736
+ } else if ("strokeColor" in ellipse.features) {
737
+ return true;
738
+ } else if ("strokeWidth" in ellipse.features) {
739
+ return true;
740
+ } else if ("strokeOffset" in ellipse.features) {
741
+ return true;
742
+ }
743
+ return false;
744
+ };
745
+
746
+ // src/renderables/rectangle.tsx
747
+ var import_react7 = require("react");
748
+ var import_shallow5 = require("zustand/react/shallow");
749
+ var import_utils5 = require("@vizij/utils");
750
+ var import_drei2 = require("@react-three/drei");
751
+ var import_jsx_runtime4 = require("react/jsx-runtime");
752
+ function InnerRenderedRectangle({
753
+ id,
754
+ namespace,
755
+ chain
756
+ }) {
757
+ const rectangleRef = (0, import_react7.useRef)();
758
+ const materialRef = (0, import_react7.useRef)();
759
+ const lineRef = (0, import_react7.useRef)();
760
+ const strokeOffsetRef = (0, import_react7.useRef)(0);
761
+ const strokeWidthRef = (0, import_react7.useRef)(0);
762
+ const onElementClick = useVizijStore(
763
+ (0, import_shallow5.useShallow)((state) => state.onElementClick)
764
+ );
765
+ const setHoveredElement = useVizijStore(
766
+ (0, import_shallow5.useShallow)((state) => state.setHoveredElement)
767
+ );
768
+ const rectangle = useVizijStore(
769
+ (0, import_shallow5.useShallow)((state) => state.world[id])
770
+ );
771
+ const refIsNull = !rectangle.refs[namespace]?.current;
772
+ const animatables = useVizijStore((0, import_shallow5.useShallow)((state) => state.animatables));
773
+ const animatableValues = (0, import_react7.useMemo)(() => {
774
+ const av = {};
775
+ Object.values(rectangle.features).forEach((feat) => {
776
+ if (feat.animated) {
777
+ const animatable = animatables[feat.value];
778
+ av[animatable.id] = animatable;
779
+ }
780
+ });
781
+ return av;
782
+ }, [rectangle.features, animatables]);
783
+ const selectionData = (0, import_react7.useMemo)(
784
+ () => ({ id, namespace, type: "rectangle" }),
785
+ [id, namespace]
786
+ );
787
+ const userData = (0, import_react7.useMemo)(
788
+ () => ({
789
+ gltfExtensions: {
790
+ RobotData: createStoredRenderable(rectangle, animatableValues)
791
+ },
792
+ selection: selectionData
793
+ }),
794
+ [rectangle, animatableValues, selectionData]
795
+ );
796
+ useFeatures(namespace, rectangle.features, {
797
+ translation: (pos) => {
798
+ if (rectangleRef.current?.position && (0, import_utils5.instanceOfRawVector3)(pos)) {
799
+ rectangleRef.current.position.set(
800
+ pos.x,
801
+ pos.y,
802
+ pos.z
803
+ );
804
+ } else if (rectangleRef.current?.position && (0, import_utils5.instanceOfRawVector2)(pos)) {
805
+ const currentZ = rectangleRef.current.position.z;
806
+ rectangleRef.current.position.set(
807
+ pos.x,
808
+ pos.y,
809
+ currentZ
810
+ );
811
+ }
812
+ if (lineRef.current?.position && (0, import_utils5.instanceOfRawVector3)(pos)) {
813
+ lineRef.current.position.set(
814
+ pos.x,
815
+ pos.y,
816
+ pos.z
817
+ );
818
+ } else if (lineRef.current?.position && (0, import_utils5.instanceOfRawVector2)(pos)) {
819
+ const currentZ = lineRef.current.position.z;
820
+ lineRef.current.position.set(
821
+ pos.x,
822
+ pos.y,
823
+ currentZ
824
+ );
825
+ }
826
+ },
827
+ rotation: (rot) => {
828
+ if (rectangleRef.current?.rotation && (0, import_utils5.instanceOfRawEuler)(rot)) {
829
+ rectangleRef.current.rotation.set(rot.x, rot.y, rot.z, "ZYX");
830
+ } else if (rectangleRef.current?.rotation && (0, import_utils5.instanceOfRawNumber)(rot)) {
831
+ rectangleRef.current.rotation.set(0, 0, 0);
832
+ rectangleRef.current.rotateZ(rot);
833
+ }
834
+ if (lineRef.current?.rotation && (0, import_utils5.instanceOfRawEuler)(rot)) {
835
+ lineRef.current.rotation.set(rot.x, rot.y, rot.z, "ZYX");
836
+ } else if (lineRef.current?.rotation && (0, import_utils5.instanceOfRawNumber)(rot)) {
837
+ lineRef.current.rotation.set(0, 0, 0);
838
+ lineRef.current.rotateZ(rot);
839
+ }
840
+ },
841
+ fillOpacity: (op) => {
842
+ if (materialRef.current?.opacity !== void 0 && (0, import_utils5.instanceOfRawNumber)(op)) {
843
+ materialRef.current.opacity = op;
844
+ if (op < 1) {
845
+ materialRef.current.transparent = true;
846
+ } else {
847
+ materialRef.current.transparent = false;
848
+ }
849
+ materialRef.current.needsUpdate = true;
850
+ }
851
+ },
852
+ fillColor: (color) => {
853
+ if (materialRef.current?.color) {
854
+ if ((0, import_utils5.instanceOfRawRGB)(color)) {
855
+ materialRef.current.color.setRGB(color.r, color.g, color.b);
856
+ materialRef.current.needsUpdate = true;
857
+ } else if ((0, import_utils5.instanceOfRawHSL)(color)) {
858
+ materialRef.current.color.setHSL(color.h, color.s, color.l);
859
+ materialRef.current.needsUpdate = true;
860
+ }
861
+ }
862
+ },
863
+ height: (height) => {
864
+ if (rectangleRef.current && (0, import_utils5.instanceOfRawNumber)(height)) {
865
+ rectangleRef.current.scale.set(rectangleRef.current.scale.x, height, 1);
866
+ }
867
+ if (rectangleRef.current && lineRef.current && (0, import_utils5.instanceOfRawNumber)(height)) {
868
+ const offset = strokeOffsetRef.current * strokeWidthRef.current / 2 + strokeOffsetRef.current * -1;
869
+ lineRef.current.scale.set(
870
+ rectangleRef.current.scale.x + offset,
871
+ height + offset,
872
+ 1
873
+ );
874
+ }
875
+ },
876
+ width: (width) => {
877
+ if (rectangleRef.current && (0, import_utils5.instanceOfRawNumber)(width)) {
878
+ rectangleRef.current.scale.set(width, rectangleRef.current.scale.y, 1);
879
+ }
880
+ if (rectangleRef.current && lineRef.current && (0, import_utils5.instanceOfRawNumber)(width)) {
881
+ const offset = strokeOffsetRef.current * strokeWidthRef.current / 2 + strokeOffsetRef.current * -1;
882
+ lineRef.current.scale.set(
883
+ width + offset,
884
+ rectangleRef.current.scale.y + offset,
885
+ 1
886
+ );
887
+ }
888
+ },
889
+ strokeOpacity: (strokeOpacity) => {
890
+ if (lineRef.current?.material && (0, import_utils5.instanceOfRawNumber)(strokeOpacity)) {
891
+ lineRef.current.material.opacity = strokeOpacity;
892
+ if (strokeOpacity < 1) {
893
+ lineRef.current.material.transparent = true;
894
+ } else {
895
+ lineRef.current.material.transparent = false;
896
+ }
897
+ lineRef.current.material.needsUpdate = true;
898
+ }
899
+ },
900
+ strokeColor: (strokeColor) => {
901
+ if (lineRef.current?.material.color) {
902
+ if ((0, import_utils5.instanceOfRawRGB)(strokeColor)) {
903
+ lineRef.current.material.color.setRGB(
904
+ strokeColor.r,
905
+ strokeColor.g,
906
+ strokeColor.b
907
+ );
908
+ lineRef.current.material.needsUpdate = true;
909
+ } else if ((0, import_utils5.instanceOfRawHSL)(strokeColor)) {
910
+ lineRef.current.material.color.setHSL(
911
+ strokeColor.h,
912
+ strokeColor.s,
913
+ strokeColor.l
914
+ );
915
+ lineRef.current.material.needsUpdate = true;
916
+ }
917
+ }
918
+ },
919
+ strokeWidth: (strokeWidth) => {
920
+ if (lineRef.current?.material && rectangleRef.current) {
921
+ if ((0, import_utils5.instanceOfRawNumber)(strokeWidth)) {
922
+ strokeWidthRef.current = strokeWidth;
923
+ const offset = strokeWidth * strokeOffsetRef.current / 2 + strokeOffsetRef.current * -1;
924
+ lineRef.current.scale.set(
925
+ rectangleRef.current.scale.x + offset,
926
+ rectangleRef.current.scale.y + offset,
927
+ 1
928
+ );
929
+ lineRef.current.material.linewidth = strokeWidth;
930
+ lineRef.current.material.needsUpdate = true;
931
+ }
932
+ }
933
+ },
934
+ strokeOffset: (strokeOffset) => {
935
+ if (lineRef.current?.material && rectangleRef.current) {
936
+ if ((0, import_utils5.instanceOfRawNumber)(strokeOffset)) {
937
+ strokeOffsetRef.current = strokeOffset;
938
+ const offset = strokeOffset * strokeWidthRef.current / 2 + strokeOffset * -1;
939
+ lineRef.current.scale.set(
940
+ rectangleRef.current.scale.x + offset,
941
+ rectangleRef.current.scale.y + offset,
942
+ 1
943
+ );
944
+ }
945
+ }
946
+ }
947
+ });
948
+ const setReference = useVizijStore(
949
+ (0, import_shallow5.useShallow)((state) => state.setReference)
950
+ );
951
+ const points = (0, import_react7.useMemo)(() => {
952
+ return [
953
+ [-0.5, 0.5, 0],
954
+ [0.5, 0.5, 0],
955
+ [0.5, -0.5, 0],
956
+ [-0.5, -0.5, 0],
957
+ [-0.5, 0.5, 0]
958
+ ];
959
+ }, []);
960
+ (0, import_react7.useEffect)(() => {
961
+ if (rectangleRef.current && refIsNull)
962
+ setReference(rectangle.id, namespace, rectangleRef);
963
+ }, [rectangle.id, namespace, rectangleRef, setReference, refIsNull]);
964
+ const handlePointerOver = (0, import_react7.useCallback)(
965
+ (event) => {
966
+ event.stopPropagation();
967
+ setHoveredElement({ id, namespace, type: "rectangle" });
968
+ },
969
+ [id, namespace, setHoveredElement]
970
+ );
971
+ const handlePointerOut = (0, import_react7.useCallback)(
972
+ (event) => {
973
+ event.stopPropagation();
974
+ setHoveredElement(null);
975
+ },
976
+ [setHoveredElement]
977
+ );
978
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
979
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
980
+ import_drei2.Plane,
981
+ {
982
+ ref: rectangleRef,
983
+ userData,
984
+ args: [1, 1],
985
+ onPointerOver: handlePointerOver,
986
+ onPointerOut: handlePointerOut,
987
+ onClick: (e) => {
988
+ onElementClick(
989
+ { id, type: "rectangle", namespace },
990
+ [...chain, id],
991
+ e
992
+ );
993
+ },
994
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("meshStandardMaterial", { attach: "material", ref: materialRef })
995
+ }
996
+ ),
997
+ showLine2(rectangle) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
998
+ import_drei2.Line,
999
+ {
1000
+ ref: lineRef,
1001
+ points,
1002
+ onPointerOver: handlePointerOver,
1003
+ onPointerOut: handlePointerOut
1004
+ }
1005
+ )
1006
+ ] });
1007
+ }
1008
+ var RenderedRectangle = (0, import_react7.memo)(InnerRenderedRectangle);
1009
+ var showLine2 = (rectangle) => {
1010
+ if ("strokeOpacity" in rectangle.features) {
1011
+ return true;
1012
+ } else if ("strokeColor" in rectangle.features) {
1013
+ return true;
1014
+ } else if ("strokeWidth" in rectangle.features) {
1015
+ return true;
1016
+ } else if ("strokeOffset" in rectangle.features) {
1017
+ return true;
1018
+ }
1019
+ return false;
1020
+ };
1021
+
1022
+ // src/renderables/shape.tsx
1023
+ var import_react8 = require("react");
1024
+ var THREE2 = __toESM(require("three"));
1025
+ var import_shallow6 = require("zustand/react/shallow");
1026
+ var import_utils6 = require("@vizij/utils");
1027
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1028
+ THREE2.Object3D.DEFAULT_UP.set(0, 0, 1);
1029
+ function InnerRenderedShape({
1030
+ id,
1031
+ namespace,
1032
+ chain
1033
+ }) {
1034
+ const refGroup = (0, import_react8.useRef)();
1035
+ const ref = (0, import_react8.useRef)();
1036
+ const shape = useVizijStore((0, import_shallow6.useShallow)((state) => state.world[id]));
1037
+ const refs = useVizijStore(
1038
+ (0, import_shallow6.useShallow)((state) => state.world[id].refs)
1039
+ );
1040
+ const refIsNull = !refs[namespace]?.current;
1041
+ const animatables = useVizijStore((0, import_shallow6.useShallow)((state) => state.animatables));
1042
+ const animatableValues = (0, import_react8.useMemo)(() => {
1043
+ const av = {};
1044
+ Object.values(shape.features).forEach((feat) => {
1045
+ if (feat.animated) {
1046
+ const animatable = animatables[feat.value];
1047
+ av[animatable.id] = animatable;
1048
+ }
1049
+ });
1050
+ return av;
1051
+ }, [shape.features, animatables]);
1052
+ const geometry = (0, import_react8.useMemo)(() => shape.geometry.clone(), [shape.geometry]);
1053
+ const selectionData = (0, import_react8.useMemo)(
1054
+ () => ({ id, namespace, type: "shape" }),
1055
+ [id, namespace]
1056
+ );
1057
+ const userData = (0, import_react8.useMemo)(
1058
+ () => ({
1059
+ gltfExtensions: {
1060
+ RobotData: createStoredRenderable(shape, animatableValues)
1061
+ },
1062
+ selection: selectionData
1063
+ }),
1064
+ [shape, animatableValues, selectionData]
1065
+ );
1066
+ const material = (0, import_react8.useRef)();
1067
+ const morphTargetSettings = (0, import_react8.useMemo)(() => {
1068
+ if (shape.morphTargets) {
1069
+ const dictionary = shape.morphTargets.reduce(
1070
+ (acc, target, i) => ({ ...acc, [target]: i }),
1071
+ {}
1072
+ );
1073
+ const initialInfluences = shape.morphTargets.map(() => 0);
1074
+ const morphFeatureHandlers = {};
1075
+ shape.morphTargets.forEach((target, i) => {
1076
+ morphFeatureHandlers[target] = (value) => {
1077
+ if (ref.current?.morphTargetInfluences && (0, import_utils6.instanceOfRawNumber)(value)) {
1078
+ ref.current.morphTargetInfluences[i] = value;
1079
+ }
1080
+ };
1081
+ });
1082
+ return [dictionary, initialInfluences, morphFeatureHandlers];
1083
+ } else {
1084
+ return [void 0, void 0, {}];
1085
+ }
1086
+ }, [shape.morphTargets]);
1087
+ useFeatures(
1088
+ namespace,
1089
+ shape.features,
1090
+ {
1091
+ translation: (pos) => {
1092
+ if (ref.current?.position && (0, import_utils6.instanceOfRawVector3)(pos)) {
1093
+ ref.current.position.set(
1094
+ pos.x,
1095
+ pos.y,
1096
+ pos.z
1097
+ );
1098
+ }
1099
+ if (refGroup.current?.position && (0, import_utils6.instanceOfRawVector3)(pos)) {
1100
+ refGroup.current.position.set(
1101
+ pos.x,
1102
+ pos.y,
1103
+ pos.z
1104
+ );
1105
+ }
1106
+ },
1107
+ rotation: (rot) => {
1108
+ if (ref.current?.rotation && (0, import_utils6.instanceOfRawEuler)(rot)) {
1109
+ ref.current.rotation.set(rot.x, rot.y, rot.z, "ZYX");
1110
+ }
1111
+ if (refGroup.current?.rotation && (0, import_utils6.instanceOfRawEuler)(rot)) {
1112
+ refGroup.current.rotation.set(rot.x, rot.y, rot.z, "ZYX");
1113
+ }
1114
+ },
1115
+ scale: (scale) => {
1116
+ if (ref.current?.scale && (0, import_utils6.instanceOfRawVector3)(scale)) {
1117
+ ref.current.scale.set(scale.x, scale.y, scale.z);
1118
+ } else if (ref.current && (0, import_utils6.instanceOfRawNumber)(scale)) {
1119
+ ref.current.scale.set(scale, scale, scale);
1120
+ } else if (ref.current) {
1121
+ ref.current.scale.set(1, 1, 1);
1122
+ }
1123
+ },
1124
+ opacity: (op) => {
1125
+ if (material.current?.opacity !== void 0 && (0, import_utils6.instanceOfRawNumber)(op)) {
1126
+ material.current.opacity = op;
1127
+ if (op < 1) {
1128
+ material.current.transparent = true;
1129
+ } else {
1130
+ material.current.transparent = false;
1131
+ }
1132
+ material.current.needsUpdate = true;
1133
+ }
1134
+ },
1135
+ color: (color) => {
1136
+ if ((material.current || void 0)?.color && (0, import_utils6.instanceOfRawRGB)(color)) {
1137
+ material.current.color.setRGB(
1138
+ color.r,
1139
+ color.g,
1140
+ color.b
1141
+ );
1142
+ if ((material.current || void 0)?.color) {
1143
+ material.current.needsUpdate = true;
1144
+ }
1145
+ } else if (material.current && (0, import_utils6.instanceOfRawHSL)(color)) {
1146
+ material.current.color.setHSL(
1147
+ color.h,
1148
+ color.s,
1149
+ color.l
1150
+ );
1151
+ }
1152
+ },
1153
+ ...morphTargetSettings[2]
1154
+ },
1155
+ shape
1156
+ );
1157
+ const setReference = useVizijStore((0, import_shallow6.useShallow)((state) => state.setReference));
1158
+ const onElementClick = useVizijStore(
1159
+ (0, import_shallow6.useShallow)((state) => state.onElementClick)
1160
+ );
1161
+ const setHoveredElement = useVizijStore(
1162
+ (0, import_shallow6.useShallow)((state) => state.setHoveredElement)
1163
+ );
1164
+ (0, import_react8.useEffect)(() => {
1165
+ if (ref.current && refIsNull) setReference(shape.id, namespace, ref);
1166
+ }, [shape.id, namespace, ref, setReference, refIsNull]);
1167
+ const handlePointerOver = (0, import_react8.useCallback)(
1168
+ (event) => {
1169
+ event.stopPropagation();
1170
+ setHoveredElement({ id, namespace, type: "shape" });
1171
+ },
1172
+ [id, namespace, setHoveredElement]
1173
+ );
1174
+ const handlePointerOut = (0, import_react8.useCallback)(
1175
+ (event) => {
1176
+ event.stopPropagation();
1177
+ setHoveredElement(null);
1178
+ },
1179
+ [setHoveredElement]
1180
+ );
1181
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1182
+ "mesh",
1183
+ {
1184
+ ref,
1185
+ userData,
1186
+ castShadow: true,
1187
+ receiveShadow: true,
1188
+ up: [0, 0, 1],
1189
+ geometry,
1190
+ morphTargetDictionary: morphTargetSettings[0],
1191
+ morphTargetInfluences: morphTargetSettings[1],
1192
+ onPointerOver: handlePointerOver,
1193
+ onPointerOut: handlePointerOut,
1194
+ onClick: (e) => {
1195
+ console.log("Clicked element", shape);
1196
+ onElementClick({ id, type: "shape", namespace }, [...chain, id], e);
1197
+ },
1198
+ children: [
1199
+ shape.material === "basic" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1200
+ "meshBasicMaterial",
1201
+ {
1202
+ attach: "material",
1203
+ ref: material,
1204
+ side: THREE2.DoubleSide
1205
+ }
1206
+ ),
1207
+ shape.material === "lambert" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1208
+ "meshLambertMaterial",
1209
+ {
1210
+ attach: "material",
1211
+ ref: material,
1212
+ side: THREE2.DoubleSide
1213
+ }
1214
+ ),
1215
+ shape.material === "phong" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1216
+ "meshPhongMaterial",
1217
+ {
1218
+ attach: "material",
1219
+ ref: material,
1220
+ side: THREE2.DoubleSide
1221
+ }
1222
+ ),
1223
+ shape.material === "standard" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1224
+ "meshStandardMaterial",
1225
+ {
1226
+ attach: "material",
1227
+ ref: material,
1228
+ side: THREE2.DoubleSide
1229
+ }
1230
+ ),
1231
+ shape.material === "normal" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1232
+ "meshNormalMaterial",
1233
+ {
1234
+ attach: "material",
1235
+ ref: material,
1236
+ side: THREE2.DoubleSide
1237
+ }
1238
+ ),
1239
+ shape.children?.map((child) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1240
+ Renderable,
1241
+ {
1242
+ id: child,
1243
+ namespace,
1244
+ chain: [...chain, id]
1245
+ },
1246
+ child
1247
+ ))
1248
+ ]
1249
+ }
1250
+ );
1251
+ }
1252
+ var RenderedShape = (0, import_react8.memo)(InnerRenderedShape);
1253
+
1254
+ // src/renderables/renderable.tsx
1255
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1256
+ function InnerRenderable({
1257
+ id,
1258
+ namespace,
1259
+ chain
1260
+ }) {
1261
+ const type = useVizijStore((0, import_shallow7.useShallow)((state) => state.world[id].type));
1262
+ const refs = useVizijStore((0, import_shallow7.useShallow)((state) => state.world[id].refs));
1263
+ const resolvedNamespaces = (0, import_react9.useMemo)(() => {
1264
+ let namespaces = [namespace];
1265
+ if (namespace in refs) {
1266
+ namespaces = [namespace];
1267
+ } else {
1268
+ namespaces = Object.keys(refs);
1269
+ }
1270
+ return namespaces;
1271
+ }, [namespace, refs]);
1272
+ if (resolvedNamespaces.length === 0) {
1273
+ return null;
1274
+ }
1275
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: resolvedNamespaces.map((ns) => {
1276
+ switch (type) {
1277
+ case "group":
1278
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1279
+ RenderedGroup,
1280
+ {
1281
+ id,
1282
+ namespace: ns,
1283
+ chain
1284
+ },
1285
+ `${ns}.${id}`
1286
+ );
1287
+ case "ellipse":
1288
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1289
+ RenderedEllipse,
1290
+ {
1291
+ id,
1292
+ namespace: ns,
1293
+ chain
1294
+ },
1295
+ `${ns}.${id}`
1296
+ );
1297
+ case "rectangle":
1298
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1299
+ RenderedRectangle,
1300
+ {
1301
+ id,
1302
+ namespace: ns,
1303
+ chain
1304
+ },
1305
+ `${ns}.${id}`
1306
+ );
1307
+ case "shape":
1308
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1309
+ RenderedShape,
1310
+ {
1311
+ id,
1312
+ namespace: ns,
1313
+ chain
1314
+ },
1315
+ `${ns}.${id}`
1316
+ );
1317
+ default:
1318
+ return null;
1319
+ }
1320
+ }) });
1321
+ }
1322
+ var Renderable = (0, import_react9.memo)(InnerRenderable);
1323
+
1324
+ // src/store.ts
1325
+ var import_zustand2 = require("zustand");
1326
+ var import_middleware = require("zustand/middleware");
1327
+ var import_immer = require("immer");
1328
+ var THREE3 = __toESM(require("three"));
1329
+ var import_utils7 = require("@vizij/utils");
1330
+
1331
+ // src/actions/create-new-element.ts
1332
+ var import_react10 = require("react");
1333
+ var import_lodash3 = require("lodash");
1334
+
1335
+ // src/functions/create-world-element.ts
1336
+ function createDefaultGroup(partialBody) {
1337
+ const translation = partialBody.features?.translation || { animated: false, value: { x: 0, y: 0 } };
1338
+ const rotation = partialBody.features?.rotation || { animated: false, value: { x: 0, y: 0, z: 0 } };
1339
+ const scale = partialBody.features?.scale || { animated: false, value: { x: 1, y: 1, z: 1 } };
1340
+ return {
1341
+ id: partialBody.id || crypto.randomUUID(),
1342
+ name: partialBody.name || "new-body",
1343
+ type: partialBody.type || "group",
1344
+ tags: partialBody.tags || [],
1345
+ refs: partialBody.refs || {},
1346
+ features: { translation, rotation, scale },
1347
+ root: partialBody.root ?? false,
1348
+ children: partialBody.children || []
1349
+ };
1350
+ }
1351
+
1352
+ // src/actions/create-new-element.ts
1353
+ function createNewElement(state, type, root = false) {
1354
+ if (type === "group") {
1355
+ const buildSelection = (id) => ({
1356
+ id,
1357
+ namespace: "world",
1358
+ type: "group"
1359
+ });
1360
+ if (Object.entries(state.world).length === 0) {
1361
+ const name = `New-Root`;
1362
+ const refs = { default: (0, import_react10.createRef)() };
1363
+ const newElement = createDefaultGroup({
1364
+ name,
1365
+ root: true,
1366
+ refs
1367
+ });
1368
+ state.world[newElement.id] = newElement;
1369
+ state.elementSelection = [buildSelection(newElement.id)];
1370
+ } else {
1371
+ const worldRootEntry = Object.values(state.world).find(
1372
+ (entry) => entry.type === "group" && entry.root
1373
+ );
1374
+ if (!worldRootEntry) {
1375
+ return;
1376
+ }
1377
+ const name = `New-Body`;
1378
+ const refs = (0, import_lodash3.mapValues)(
1379
+ worldRootEntry.refs,
1380
+ () => (0, import_react10.createRef)()
1381
+ );
1382
+ const newChild = createDefaultGroup({ name, root, refs });
1383
+ worldRootEntry.children.push(newChild.id);
1384
+ state.world[newChild.id] = newChild;
1385
+ state.elementSelection = [buildSelection(newChild.id)];
1386
+ }
1387
+ }
1388
+ }
1389
+
1390
+ // src/actions/remove-children.ts
1391
+ function removeFromTree(state, nodesToRemove) {
1392
+ Object.entries(state.world).forEach(([, element]) => {
1393
+ if (element.type === "group") {
1394
+ element.children = element.children.filter(
1395
+ (c) => !nodesToRemove.includes(c)
1396
+ );
1397
+ state.world[element.id] = element;
1398
+ }
1399
+ });
1400
+ }
1401
+
1402
+ // src/functions/create-animatable.ts
1403
+ function createAnimatable(value) {
1404
+ if (!value.type) {
1405
+ return null;
1406
+ }
1407
+ if (!value.name) {
1408
+ value.name = "New Animatable";
1409
+ }
1410
+ if (value.type === "euler") {
1411
+ const newAnimatable = {
1412
+ id: value.id ?? crypto.randomUUID(),
1413
+ name: `${value.name} Rotation`,
1414
+ type: value.type,
1415
+ default: value.default ?? { x: 0, y: 0, z: 0 },
1416
+ constraints: value.constraints ?? {
1417
+ min: [0, 0, 0],
1418
+ max: [1, 1, 1],
1419
+ velocity: 1
1420
+ },
1421
+ pub: value.pub ?? {
1422
+ output: `${value.name}-rotation`,
1423
+ public: true
1424
+ }
1425
+ };
1426
+ return newAnimatable;
1427
+ } else if (value.type === "vector3") {
1428
+ const newAnimatable = {
1429
+ id: value.id ?? crypto.randomUUID(),
1430
+ name: `${value.name} Vector3`,
1431
+ type: value.type,
1432
+ default: value.default ?? { x: 0, y: 0, z: 0 },
1433
+ constraints: value.constraints ?? {
1434
+ min: [0, 0, 0],
1435
+ max: [1, 1, 1],
1436
+ velocity: 1
1437
+ },
1438
+ pub: value.pub ?? {
1439
+ output: `${value.name}-translation`,
1440
+ public: true
1441
+ }
1442
+ };
1443
+ return newAnimatable;
1444
+ } else if (value.type === "string") {
1445
+ const newAnimatable = {
1446
+ id: value.id ?? crypto.randomUUID(),
1447
+ name: value.name,
1448
+ type: value.type,
1449
+ default: value.default ?? "Hello World",
1450
+ constraints: value.constraints ?? { length: 25 },
1451
+ pub: value.pub ?? {
1452
+ output: `${value.name}-string`,
1453
+ public: true
1454
+ }
1455
+ };
1456
+ return newAnimatable;
1457
+ } else if (value.type === "number") {
1458
+ const newAnimatable = {
1459
+ id: value.id ?? crypto.randomUUID(),
1460
+ name: value.name,
1461
+ type: value.type,
1462
+ default: value.default ?? 0,
1463
+ constraints: value.constraints ?? { min: 0, max: 255, velocity: 1 },
1464
+ pub: value.pub ?? {
1465
+ output: `${value.name}-number`,
1466
+ public: true
1467
+ }
1468
+ };
1469
+ return newAnimatable;
1470
+ } else if (value.type === "boolean") {
1471
+ const newAnimatable = {
1472
+ id: value.id ?? crypto.randomUUID(),
1473
+ name: value.name,
1474
+ type: value.type,
1475
+ default: value.default ?? false,
1476
+ constraints: value.constraints ?? { frequency: 1 },
1477
+ pub: value.pub ?? {
1478
+ output: `${value.name}-boolean`,
1479
+ public: true
1480
+ }
1481
+ };
1482
+ return newAnimatable;
1483
+ } else if (value.type === "rgb") {
1484
+ const newAnimatable = {
1485
+ id: value.id ?? crypto.randomUUID(),
1486
+ name: value.name,
1487
+ type: value.type,
1488
+ default: value.default ?? { r: 0, g: 0, b: 0 },
1489
+ constraints: value.constraints ?? {
1490
+ min: [0, 0, 0],
1491
+ max: [1, 1, 1],
1492
+ velocity: 10
1493
+ },
1494
+ pub: value.pub ?? {
1495
+ output: `${value.name}-color`,
1496
+ public: true
1497
+ }
1498
+ };
1499
+ return newAnimatable;
1500
+ } else if (value.type === "hsl") {
1501
+ const newAnimatable = {
1502
+ id: value.id ?? crypto.randomUUID(),
1503
+ name: value.name,
1504
+ type: value.type,
1505
+ default: value.default ?? { h: 0, s: 0, l: 0 },
1506
+ constraints: value.constraints ?? {
1507
+ min: [0, 0, 0],
1508
+ max: [360, 100, 100],
1509
+ velocity: 10
1510
+ },
1511
+ pub: value.pub ?? {
1512
+ output: `${value.name}-color`,
1513
+ public: true
1514
+ }
1515
+ };
1516
+ return newAnimatable;
1517
+ }
1518
+ return null;
1519
+ }
1520
+ createAnimatable({ type: "euler", name: "Rotation" });
1521
+
1522
+ // src/store.ts
1523
+ THREE3.Object3D.DEFAULT_UP.set(0, 0, 1);
1524
+ (0, import_immer.enableMapSet)();
1525
+ var VizijSlice = (set, get) => ({
1526
+ // worldRef: createRef<THREE.Group>(),
1527
+ world: {},
1528
+ animatables: {},
1529
+ values: /* @__PURE__ */ new Map(),
1530
+ renderHit: false,
1531
+ preferences: {
1532
+ damping: false
1533
+ },
1534
+ elementSelection: [],
1535
+ hoveredElement: null,
1536
+ slotConfig: {},
1537
+ clearSelection: () => {
1538
+ set({ elementSelection: [] });
1539
+ },
1540
+ updateElementSelection: (selection, _chain) => {
1541
+ set(
1542
+ (0, import_immer.produce)((state) => {
1543
+ state.elementSelection = [selection];
1544
+ })
1545
+ );
1546
+ },
1547
+ setHoveredElement: (selection) => {
1548
+ set({ hoveredElement: selection });
1549
+ },
1550
+ onElementClick: (selection, _chain, event) => {
1551
+ event.stopPropagation();
1552
+ const makeKey = (sel) => `${sel.namespace}__${sel.type}__${sel.id}`;
1553
+ const stack = [];
1554
+ const seen = /* @__PURE__ */ new Set();
1555
+ const push = (sel) => {
1556
+ if (!sel) return;
1557
+ if (!sel.id || !sel.namespace || !sel.type) return;
1558
+ const key = makeKey(sel);
1559
+ if (seen.has(key)) return;
1560
+ seen.add(key);
1561
+ stack.push(sel);
1562
+ };
1563
+ const intersections = event.intersections ?? [];
1564
+ intersections.forEach((hit) => {
1565
+ const hitSelection = hit.object?.userData?.selection;
1566
+ push(hitSelection);
1567
+ });
1568
+ if (stack.length === 0) {
1569
+ push(selection);
1570
+ }
1571
+ const stackKeys = new Set(stack.map(makeKey));
1572
+ const primary = stack[0];
1573
+ const primaryKey = makeKey(primary);
1574
+ set(
1575
+ (0, import_immer.produce)((state) => {
1576
+ if (event.metaKey) {
1577
+ const existing = state.elementSelection ?? [];
1578
+ const alreadySelected = existing.some(
1579
+ (item) => makeKey(item) === primaryKey
1580
+ );
1581
+ const existingWithoutStack = existing.filter(
1582
+ (item) => !stackKeys.has(makeKey(item))
1583
+ );
1584
+ if (alreadySelected) {
1585
+ state.elementSelection = existingWithoutStack;
1586
+ } else {
1587
+ state.elementSelection = [...stack, ...existingWithoutStack];
1588
+ }
1589
+ } else {
1590
+ state.elementSelection = stack;
1591
+ }
1592
+ })
1593
+ );
1594
+ },
1595
+ getExportableBodies: (filterIds) => {
1596
+ const worldData = get().world;
1597
+ if (!filterIds) {
1598
+ const bodies = Object.values(worldData).filter((entry) => entry.type === "group" && entry.rootBounds).map((entry) => {
1599
+ const firstNs = Object.keys(entry.refs)[0];
1600
+ const refGroup = entry.refs[firstNs].current;
1601
+ return refGroup;
1602
+ });
1603
+ return bodies;
1604
+ } else {
1605
+ const bodies = Object.values(worldData).filter(
1606
+ (entry) => entry.type === "group" && entry.rootBounds && filterIds.includes(entry.id)
1607
+ ).map((entry) => {
1608
+ const firstNs = Object.keys(entry.refs)[0];
1609
+ const refGroup = entry.refs[firstNs].current;
1610
+ return refGroup;
1611
+ });
1612
+ return bodies;
1613
+ }
1614
+ },
1615
+ setGeometry: (id, geometry) => {
1616
+ set(
1617
+ (0, import_immer.produce)((state) => {
1618
+ state.world[id].geometry = geometry;
1619
+ })
1620
+ );
1621
+ },
1622
+ setValue: (id, namespace, value) => {
1623
+ set(
1624
+ (0, import_immer.produce)((state) => {
1625
+ const lookupId = (0, import_utils7.getLookup)(namespace, id);
1626
+ if (typeof value === "function") {
1627
+ const current = state.values.get(lookupId);
1628
+ if (current !== void 0) {
1629
+ if (value(current !== void 0)) {
1630
+ state.values.set(lookupId, value(current));
1631
+ }
1632
+ } else {
1633
+ const animatableLookup = state.animatables[id];
1634
+ const updatedValue = value(
1635
+ animatableLookup !== void 0 ? animatableLookup.default : void 0
1636
+ );
1637
+ if (updatedValue !== void 0) {
1638
+ state.values.set(lookupId, updatedValue);
1639
+ }
1640
+ }
1641
+ } else {
1642
+ state.values.set(lookupId, value);
1643
+ }
1644
+ })
1645
+ );
1646
+ },
1647
+ setWorldElementName: (id, value) => {
1648
+ set(
1649
+ (0, import_immer.produce)((state) => {
1650
+ state.world[id].name = value;
1651
+ })
1652
+ );
1653
+ },
1654
+ setParent: (id, parent) => {
1655
+ set(
1656
+ (0, import_immer.produce)((state) => {
1657
+ state.world[id].parent = parent;
1658
+ })
1659
+ );
1660
+ },
1661
+ setChild: (id, child) => {
1662
+ set(
1663
+ (0, import_immer.produce)((state) => {
1664
+ removeFromTree(state, [child]);
1665
+ state.world[id].child = child;
1666
+ })
1667
+ );
1668
+ },
1669
+ setChildren: (id, children) => {
1670
+ set(
1671
+ (0, import_immer.produce)((state) => {
1672
+ removeFromTree(state, children);
1673
+ state.world[id].children = children;
1674
+ })
1675
+ );
1676
+ },
1677
+ createGroup: (root) => {
1678
+ set(
1679
+ (0, import_immer.produce)((state) => {
1680
+ createNewElement(state, "group", root);
1681
+ })
1682
+ );
1683
+ },
1684
+ setOrigin: (id, origin) => {
1685
+ const { translation, rotation } = origin;
1686
+ set(
1687
+ (0, import_immer.produce)((state) => {
1688
+ if (!state.world[id].origin) {
1689
+ } else {
1690
+ if (rotation) state.world[id].origin.rotation = rotation;
1691
+ if (translation) state.world[id].origin.translation = translation;
1692
+ }
1693
+ })
1694
+ );
1695
+ },
1696
+ setAxis: (id, axis) => {
1697
+ set(
1698
+ (0, import_immer.produce)((state) => {
1699
+ state.world[id].axis = axis;
1700
+ })
1701
+ );
1702
+ },
1703
+ setTags: (id, tags) => {
1704
+ set(
1705
+ (0, import_immer.produce)((state) => {
1706
+ state.world[id].tags = tags;
1707
+ })
1708
+ );
1709
+ },
1710
+ setMaterial: (id, material) => {
1711
+ set(
1712
+ (0, import_immer.produce)((state) => {
1713
+ state.world[id].material = material;
1714
+ })
1715
+ );
1716
+ },
1717
+ setStaticFeature: (id, feature, value) => {
1718
+ set(
1719
+ (0, import_immer.produce)((state) => {
1720
+ if (!state.world[id].features) {
1721
+ }
1722
+ const entry = state.world[id];
1723
+ switch (entry.type) {
1724
+ case "group":
1725
+ entry.features[feature].value = value;
1726
+ state.world[id] = entry;
1727
+ break;
1728
+ default:
1729
+ break;
1730
+ }
1731
+ })
1732
+ );
1733
+ },
1734
+ createAnimatable: (elementId, featureName, value) => {
1735
+ set(
1736
+ (0, import_immer.produce)((state) => {
1737
+ console.log("Creating animatable", elementId, featureName, value);
1738
+ const animatable = createAnimatable(value);
1739
+ if (!animatable) {
1740
+ return;
1741
+ }
1742
+ console.log("Created animatable", animatable);
1743
+ state.world[elementId].features[featureName] = {
1744
+ animated: true,
1745
+ value: animatable.id
1746
+ };
1747
+ state.animatables[animatable.id] = animatable;
1748
+ })
1749
+ );
1750
+ },
1751
+ createStatic: (elementId, featureName, value) => {
1752
+ set(
1753
+ (0, import_immer.produce)((state) => {
1754
+ state.world[elementId].features[featureName] = {
1755
+ animated: false,
1756
+ value
1757
+ };
1758
+ })
1759
+ );
1760
+ },
1761
+ setAnimatableValue: (id, value) => {
1762
+ set(
1763
+ (0, import_immer.produce)((state) => {
1764
+ console.log("Setting animatable value", id, value);
1765
+ state.animatables[id] = value;
1766
+ })
1767
+ );
1768
+ },
1769
+ setSlot: (parentId, parentNamespace, childId, childNamespace) => {
1770
+ set(
1771
+ (0, import_immer.produce)((state) => {
1772
+ const parentLookupId = (0, import_utils7.getLookup)(parentNamespace, parentId);
1773
+ const childLookupId = (0, import_utils7.getLookup)(childNamespace, childId);
1774
+ state.slotConfig[parentLookupId] = childLookupId;
1775
+ })
1776
+ );
1777
+ },
1778
+ setSlots: (slots, replace) => {
1779
+ set(
1780
+ (0, import_immer.produce)((state) => {
1781
+ if (replace) {
1782
+ state.slotConfig = slots;
1783
+ } else {
1784
+ state.slotConfig = { ...state.slotConfig, ...slots };
1785
+ }
1786
+ })
1787
+ );
1788
+ },
1789
+ clearSlot: (parentId, parentNamespace) => {
1790
+ set(
1791
+ (0, import_immer.produce)((state) => {
1792
+ const parentLookupId = (0, import_utils7.getLookup)(parentNamespace, parentId);
1793
+ delete state.slotConfig[parentLookupId];
1794
+ })
1795
+ );
1796
+ },
1797
+ setVizij: (scene, animatables) => {
1798
+ set({
1799
+ world: scene,
1800
+ animatables
1801
+ });
1802
+ },
1803
+ addWorldElements(world, animatables, replace) {
1804
+ if (replace) {
1805
+ set({ world, animatables });
1806
+ } else {
1807
+ set((state) => ({
1808
+ world: { ...state.world, ...world },
1809
+ animatables: { ...state.animatables, ...animatables }
1810
+ }));
1811
+ }
1812
+ },
1813
+ setPreferences: (preferences) => {
1814
+ set((state) => ({
1815
+ preferences: { ...state.preferences, ...preferences }
1816
+ }));
1817
+ },
1818
+ setReference: (id, namespace, ref) => {
1819
+ set(
1820
+ (0, import_immer.produce)((state) => {
1821
+ state.world[id].refs[namespace].current = ref.current;
1822
+ if (ref.current?.children && state.world[id].refs[namespace].current) {
1823
+ state.world[id].refs[namespace].current.children = ref.current.children;
1824
+ }
1825
+ })
1826
+ );
1827
+ }
1828
+ });
1829
+ var useDefaultVizijStore = (0, import_zustand2.create)()(
1830
+ (0, import_middleware.subscribeWithSelector)((set, get) => ({
1831
+ ...VizijSlice(set, get)
1832
+ }))
1833
+ );
1834
+ var createVizijStore = (initial) => (0, import_zustand2.create)()(
1835
+ (0, import_middleware.subscribeWithSelector)((set, get) => ({
1836
+ ...VizijSlice(set, get),
1837
+ ...initial ?? {}
1838
+ }))
1839
+ );
1840
+
1841
+ // src/vizij.tsx
1842
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1843
+ import_three.Object3D.DEFAULT_UP.set(0, 0, 1);
1844
+ function Vizij({
1845
+ style,
1846
+ className,
1847
+ rootId,
1848
+ namespace = "default",
1849
+ showSafeArea = false,
1850
+ onPointerMissed
1851
+ }) {
1852
+ const ctx = (0, import_react11.useContext)(VizijContext);
1853
+ if (ctx) {
1854
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1855
+ import_fiber.Canvas,
1856
+ {
1857
+ shadows: false,
1858
+ style,
1859
+ className,
1860
+ onPointerMissed,
1861
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1862
+ MemoizedInnerVizij,
1863
+ {
1864
+ rootId,
1865
+ namespace,
1866
+ showSafeArea
1867
+ }
1868
+ )
1869
+ }
1870
+ );
1871
+ } else {
1872
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(VizijContext.Provider, { value: useDefaultVizijStore, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1873
+ import_fiber.Canvas,
1874
+ {
1875
+ style,
1876
+ className,
1877
+ onPointerMissed,
1878
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1879
+ MemoizedInnerVizij,
1880
+ {
1881
+ rootId,
1882
+ namespace,
1883
+ showSafeArea
1884
+ }
1885
+ )
1886
+ }
1887
+ ) });
1888
+ }
1889
+ }
1890
+ function InnerVizij({
1891
+ rootId,
1892
+ namespace = "default",
1893
+ container,
1894
+ showSafeArea
1895
+ }) {
1896
+ const sceneParentSizing = container ? {
1897
+ width: container.width * container.resolution,
1898
+ height: container.height * container.resolution
1899
+ } : void 0;
1900
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1901
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ambientLight", { intensity: Math.PI / 2 }),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1903
+ import_drei3.OrthographicCamera,
1904
+ {
1905
+ makeDefault: true,
1906
+ position: [0, 0, 100],
1907
+ near: 0.1,
1908
+ far: 101
1909
+ }
1910
+ ),
1911
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react11.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1912
+ World,
1913
+ {
1914
+ rootId,
1915
+ namespace,
1916
+ parentSizing: sceneParentSizing
1917
+ }
1918
+ ) }),
1919
+ showSafeArea && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SafeAreaRenderer, { rootId })
1920
+ ] });
1921
+ }
1922
+ var MemoizedInnerVizij = (0, import_react11.memo)(InnerVizij);
1923
+ function InnerWorld({
1924
+ rootId,
1925
+ namespace = "default",
1926
+ parentSizing
1927
+ }) {
1928
+ const [present, rootBounds] = useVizijStore(
1929
+ (0, import_shallow8.useShallow)((state) => {
1930
+ const group = state.world[rootId];
1931
+ const bounds = group?.rootBounds ?? defaultRootBounds;
1932
+ return [group !== void 0, bounds];
1933
+ })
1934
+ );
1935
+ const { camera, size } = (0, import_fiber.useThree)((state) => ({
1936
+ camera: state.camera,
1937
+ size: state.size
1938
+ }));
1939
+ (0, import_react11.useEffect)(() => {
1940
+ const width = rootBounds.size.x;
1941
+ const height = rootBounds.size.y;
1942
+ if (camera && parentSizing === void 0 && camera.isOrthographicCamera) {
1943
+ const zoom = Math.min(size.width / width, size.height / height);
1944
+ const center = rootBounds.center;
1945
+ if (camera.zoom !== zoom) {
1946
+ camera.zoom = zoom;
1947
+ camera.updateProjectionMatrix();
1948
+ }
1949
+ if (camera.position.x !== center.x || camera.position.y !== center.y) {
1950
+ camera.position.x = center.x;
1951
+ camera.position.y = center.y;
1952
+ camera.updateProjectionMatrix();
1953
+ }
1954
+ } else if (camera && parentSizing !== void 0 && camera.isOrthographicCamera) {
1955
+ const zoom = Math.min(
1956
+ parentSizing.width / width,
1957
+ parentSizing.height / height
1958
+ );
1959
+ const center = rootBounds.center;
1960
+ camera.left = -0.5 * parentSizing.width / zoom + center.x;
1961
+ camera.right = 0.5 * parentSizing.width / zoom + center.x;
1962
+ camera.top = 0.5 * parentSizing.height / zoom + center.y;
1963
+ camera.bottom = -0.5 * parentSizing.height / zoom + center.y;
1964
+ camera.updateProjectionMatrix();
1965
+ }
1966
+ }, [rootBounds, camera, parentSizing, size]);
1967
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_error_boundary.ErrorBoundary, { fallback: null, children: [
1968
+ present && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Renderable, { id: rootId, namespace, chain: [] }),
1969
+ !present && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1970
+ import_drei3.Text,
1971
+ {
1972
+ position: [0, 0, 0],
1973
+ color: "white",
1974
+ anchorX: "center",
1975
+ anchorY: "middle",
1976
+ fontSize: 0.7,
1977
+ children: "No Output"
1978
+ }
1979
+ )
1980
+ ] });
1981
+ }
1982
+ var World = (0, import_react11.memo)(InnerWorld);
1983
+ function SafeAreaRenderer({ rootId }) {
1984
+ const rootBounds = useVizijStore((state) => {
1985
+ const group = state.world[rootId];
1986
+ return group?.rootBounds ?? defaultRootBounds;
1987
+ });
1988
+ const left = rootBounds.center.x - rootBounds.size.x / 2;
1989
+ const right = rootBounds.center.x + rootBounds.size.x / 2;
1990
+ const top = rootBounds.center.y + rootBounds.size.y / 2;
1991
+ const bottom = rootBounds.center.y - rootBounds.size.y / 2;
1992
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1993
+ import_drei3.Line,
1994
+ {
1995
+ points: [
1996
+ [left, top, 99],
1997
+ [right, top, 99],
1998
+ [right, bottom, 99],
1999
+ [left, bottom, 99],
2000
+ [left, top, 99]
2001
+ ],
2002
+ color: "red",
2003
+ lineWidth: 2
2004
+ }
2005
+ );
2006
+ }
2007
+ var defaultRootBounds = {
2008
+ center: { x: 0, y: 0 },
2009
+ size: { x: 5, y: 4 }
2010
+ };
2011
+
2012
+ // src/types/shape.ts
2013
+ var ShapeMaterial = /* @__PURE__ */ ((ShapeMaterial2) => {
2014
+ ShapeMaterial2["Standard"] = "standard";
2015
+ ShapeMaterial2["Phong"] = "phong";
2016
+ ShapeMaterial2["Basic"] = "basic";
2017
+ ShapeMaterial2["Lambert"] = "lambert";
2018
+ ShapeMaterial2["Normal"] = "normal";
2019
+ return ShapeMaterial2;
2020
+ })(ShapeMaterial || {});
2021
+
2022
+ // src/hooks/use-vizij-store-subscription.ts
2023
+ var import_react12 = require("react");
2024
+ function useVizijStoreSubscription(selector, listener) {
2025
+ const store = (0, import_react12.useContext)(VizijContext);
2026
+ if (!store) throw new Error("Missing VizijProvider in the tree");
2027
+ (0, import_react12.useEffect)(() => {
2028
+ const initialValue = selector(store.getState());
2029
+ listener(initialValue);
2030
+ return store.subscribe(selector, listener);
2031
+ }, [store, selector, listener]);
2032
+ }
2033
+
2034
+ // src/hooks/use-vizij-store-setter.ts
2035
+ var import_react13 = require("react");
2036
+ function useVizijStoreSetter() {
2037
+ const store = (0, import_react13.useContext)(VizijContext);
2038
+ if (!store) throw new Error("Missing VizijProvider in the tree");
2039
+ return store.setState;
2040
+ }
2041
+
2042
+ // src/hooks/use-vizij-store-getter.ts
2043
+ var import_react14 = require("react");
2044
+ function useVizijStoreGetter() {
2045
+ const store = (0, import_react14.useContext)(VizijContext);
2046
+ if (!store) throw new Error("Missing VizijProvider in the tree");
2047
+ return store.getState;
2048
+ }
2049
+
2050
+ // src/functions/load-gltf.ts
2051
+ var THREE5 = __toESM(require("three"));
2052
+ var import_three_stdlib = require("three-stdlib");
2053
+
2054
+ // src/functions/gltf-loading/traverse-three.ts
2055
+ var import_react16 = require("react");
2056
+ var THREE4 = __toESM(require("three"));
2057
+
2058
+ // src/functions/gltf-loading/map-features.ts
2059
+ function mapFeatures(features) {
2060
+ const animatableValues = {};
2061
+ const mappedFeatures = {};
2062
+ Object.keys(features).forEach((f) => {
2063
+ const feature = features[f];
2064
+ if (feature.animated) {
2065
+ const animatedValue = feature.value;
2066
+ mappedFeatures[f] = {
2067
+ animated: true,
2068
+ value: animatedValue.id,
2069
+ ...feature.label ? { label: feature.label } : {}
2070
+ };
2071
+ animatableValues[animatedValue.id] = animatedValue;
2072
+ } else {
2073
+ const { animated, value, label } = feature;
2074
+ mappedFeatures[f] = label ? { animated, value, label } : { animated, value };
2075
+ }
2076
+ });
2077
+ return [mappedFeatures, animatableValues];
2078
+ }
2079
+
2080
+ // src/functions/gltf-loading/import-scene.ts
2081
+ var import_three4 = require("three");
2082
+
2083
+ // src/functions/gltf-loading/import-group.ts
2084
+ var import_three3 = require("three");
2085
+
2086
+ // src/functions/util.ts
2087
+ var import_react15 = require("react");
2088
+ function namespaceArrayToRefs(namespaces) {
2089
+ return namespaces.reduce((acc, ns) => ({ ...acc, [ns]: (0, import_react15.createRef)() }), {});
2090
+ }
2091
+
2092
+ // src/functions/gltf-loading/import-mesh.ts
2093
+ var import_three2 = require("three");
2094
+
2095
+ // src/functions/gltf-loading/import-geometry.ts
2096
+ function sanitizeMorphKey(name, fallbackIndex, used) {
2097
+ const baseName = name && name.trim().length > 0 ? name.trim() : `morph_${fallbackIndex + 1}`;
2098
+ const slug = baseName.toLowerCase().replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "");
2099
+ const safeBase = slug.length > 0 ? slug : `morph_${fallbackIndex + 1}`;
2100
+ let candidate = safeBase;
2101
+ let counter = 1;
2102
+ while (used.has(candidate)) {
2103
+ candidate = `${safeBase}_${counter++}`;
2104
+ }
2105
+ used.add(candidate);
2106
+ return candidate;
2107
+ }
2108
+ function importGeometry(geometry, mesh) {
2109
+ const features = {};
2110
+ const animatableValues = {};
2111
+ const morphIds = [];
2112
+ const morphTargets = mesh.morphTargetDictionary;
2113
+ if (!morphTargets) {
2114
+ return [features, animatableValues, void 0];
2115
+ } else {
2116
+ const usedKeys = /* @__PURE__ */ new Set();
2117
+ Object.entries(mesh.morphTargetDictionary ?? {}).forEach(
2118
+ ([name, index]) => {
2119
+ const morphId = crypto.randomUUID();
2120
+ const featureKey = sanitizeMorphKey(name, index, usedKeys);
2121
+ morphIds.push(featureKey);
2122
+ features[featureKey] = {
2123
+ animated: true,
2124
+ value: morphId
2125
+ };
2126
+ const displayName = name && name.trim().length > 0 ? name.trim() : featureKey;
2127
+ const animatableMorphValue = {
2128
+ id: morphId,
2129
+ name: `${mesh.name ?? "Shape"} ${displayName}`,
2130
+ type: "number",
2131
+ default: mesh.morphTargetInfluences?.[index] ?? 0,
2132
+ constraints: {
2133
+ min: 0,
2134
+ max: 1
2135
+ },
2136
+ pub: {
2137
+ public: true,
2138
+ output: displayName
2139
+ }
2140
+ };
2141
+ animatableValues[morphId] = animatableMorphValue;
2142
+ }
2143
+ );
2144
+ return [features, animatableValues, morphIds];
2145
+ }
2146
+ }
2147
+
2148
+ // src/functions/gltf-loading/import-mesh.ts
2149
+ import_three2.Object3D.DEFAULT_UP.set(0, 0, 1);
2150
+ function importMesh(mesh, namespaces, colorLookup) {
2151
+ let world = {};
2152
+ let animatables = {};
2153
+ let newColorLookup = {};
2154
+ const translationAnimatable = {
2155
+ id: crypto.randomUUID(),
2156
+ name: `${mesh.name ?? "Mesh"} translation`,
2157
+ type: "vector3",
2158
+ default: { x: mesh.position.x, y: mesh.position.y, z: mesh.position.z },
2159
+ constraints: {},
2160
+ pub: {
2161
+ public: true,
2162
+ output: `${mesh.name ?? "Mesh"} translation`,
2163
+ units: "m"
2164
+ }
2165
+ };
2166
+ animatables = {
2167
+ ...animatables,
2168
+ [translationAnimatable.id]: translationAnimatable
2169
+ };
2170
+ const rotationAnimatable = {
2171
+ id: crypto.randomUUID(),
2172
+ name: `${mesh.name ?? "Mesh"} rotation`,
2173
+ type: "euler",
2174
+ default: { x: mesh.rotation.x, y: mesh.rotation.y, z: mesh.rotation.z },
2175
+ constraints: {},
2176
+ pub: {
2177
+ public: true,
2178
+ output: `${mesh.name ?? "Mesh"} rotation`,
2179
+ units: "rad"
2180
+ }
2181
+ };
2182
+ animatables = { ...animatables, [rotationAnimatable.id]: rotationAnimatable };
2183
+ const scaleAnimatable = {
2184
+ id: crypto.randomUUID(),
2185
+ name: `${mesh.name ?? "Mesh"} scale`,
2186
+ type: "vector3",
2187
+ default: { x: mesh.scale.x, y: mesh.scale.y, z: mesh.scale.z },
2188
+ constraints: {},
2189
+ pub: {
2190
+ public: true,
2191
+ output: `${mesh.name ?? "Mesh"} scale`
2192
+ }
2193
+ };
2194
+ animatables = { ...animatables, [scaleAnimatable.id]: scaleAnimatable };
2195
+ const color = mesh.material.color;
2196
+ let useEmissive = false;
2197
+ if (color.r === 0 && color.g === 0 && color.b === 0 && mesh.material.emissive) {
2198
+ color.copy(mesh.material.emissive);
2199
+ useEmissive = true;
2200
+ }
2201
+ const colorName = mesh.material.name;
2202
+ const colorAnimatable = {
2203
+ id: crypto.randomUUID(),
2204
+ name: mesh.material.name ?? `${mesh.name ?? "Mesh"} color`,
2205
+ type: "rgb",
2206
+ default: { r: color.r, g: color.g, b: color.b },
2207
+ constraints: {
2208
+ min: [0, 0, 0],
2209
+ max: [1, 1, 1]
2210
+ },
2211
+ pub: {
2212
+ public: true,
2213
+ output: mesh.material.name ? `${mesh.material.name} color` : `${mesh.name ?? "Mesh"} color`
2214
+ }
2215
+ };
2216
+ const opacityAnimatable = {
2217
+ id: crypto.randomUUID(),
2218
+ name: mesh.material.name ? `${mesh.material.name} opacity` : `${mesh.name ?? "Mesh"} opacity`,
2219
+ type: "number",
2220
+ default: mesh.material.opacity,
2221
+ constraints: {
2222
+ min: 0,
2223
+ max: 1
2224
+ },
2225
+ pub: {
2226
+ public: true,
2227
+ output: mesh.material.name ? `${mesh.material.name} opacity` : `${mesh.name ?? "Mesh"} opacity`
2228
+ }
2229
+ };
2230
+ let colorId = colorAnimatable.id;
2231
+ let opacityId = opacityAnimatable.id;
2232
+ if (colorName && colorLookup[colorName]) {
2233
+ colorId = colorLookup[colorName][0];
2234
+ opacityId = colorLookup[colorName][1];
2235
+ useEmissive = colorLookup[colorName][2];
2236
+ } else {
2237
+ animatables = { ...animatables, [colorAnimatable.id]: colorAnimatable };
2238
+ animatables = { ...animatables, [opacityAnimatable.id]: opacityAnimatable };
2239
+ if (colorName) {
2240
+ newColorLookup[colorName] = [
2241
+ colorAnimatable.id,
2242
+ opacityAnimatable.id,
2243
+ useEmissive
2244
+ ];
2245
+ }
2246
+ }
2247
+ const [geometryFeatures, geometryAnimatables, morphTargets] = importGeometry(
2248
+ mesh.geometry,
2249
+ mesh
2250
+ );
2251
+ animatables = { ...animatables, ...geometryAnimatables };
2252
+ const children = [];
2253
+ mesh.children.forEach((child) => {
2254
+ if (child.isMesh) {
2255
+ const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child, namespaces, {
2256
+ ...colorLookup,
2257
+ ...newColorLookup
2258
+ });
2259
+ newColorLookup = { ...newColorLookup, ...newMeshColors };
2260
+ world = { ...world, ...newWorldItems };
2261
+ animatables = { ...animatables, ...newAnimatables };
2262
+ children.push(childId);
2263
+ }
2264
+ });
2265
+ const newShape = {
2266
+ id: mesh.uuid,
2267
+ name: mesh.name,
2268
+ geometry: mesh.geometry,
2269
+ material: getShapeMaterial(mesh, useEmissive),
2270
+ type: "shape",
2271
+ tags: [],
2272
+ morphTargets,
2273
+ features: {
2274
+ translation: { animated: true, value: translationAnimatable.id },
2275
+ rotation: { animated: true, value: rotationAnimatable.id },
2276
+ scale: { animated: true, value: scaleAnimatable.id },
2277
+ color: { animated: true, value: colorId },
2278
+ opacity: { animated: true, value: opacityId },
2279
+ ...geometryFeatures
2280
+ },
2281
+ children: children.length > 0 ? children : void 0,
2282
+ refs: namespaceArrayToRefs(namespaces)
2283
+ };
2284
+ world = { ...world, [newShape.id]: newShape };
2285
+ return [world, animatables, newShape.id, newColorLookup];
2286
+ }
2287
+ function getShapeMaterial(mesh, useEmissive) {
2288
+ const material = mesh.material;
2289
+ if (useEmissive) {
2290
+ return "basic" /* Basic */;
2291
+ }
2292
+ if (material.isMeshStandardMaterial) {
2293
+ return "standard" /* Standard */;
2294
+ } else if (material.isMeshPhongMaterial) {
2295
+ return "phong" /* Phong */;
2296
+ } else if (material.isMeshBasicMaterial) {
2297
+ return "basic" /* Basic */;
2298
+ } else if (material.isMeshNormalMaterial) {
2299
+ return "normal" /* Normal */;
2300
+ } else if (material.isMeshLambertMaterial) {
2301
+ return "lambert" /* Lambert */;
2302
+ } else {
2303
+ return "standard" /* Standard */;
2304
+ }
2305
+ }
2306
+
2307
+ // src/functions/gltf-loading/import-group.ts
2308
+ import_three3.Object3D.DEFAULT_UP.set(0, 0, 1);
2309
+ function importGroup(group, namespaces, colorLookup, rootBounds) {
2310
+ let world = {};
2311
+ let animatables = {};
2312
+ let newColorLookup = {};
2313
+ const children = [];
2314
+ const translationAnimatable = {
2315
+ id: crypto.randomUUID(),
2316
+ name: `${group.name ?? "Group"} translation`,
2317
+ type: "vector3",
2318
+ default: { x: group.position.x, y: group.position.y, z: group.position.z },
2319
+ constraints: {},
2320
+ pub: {
2321
+ public: true,
2322
+ output: `${group.name ?? "Group"} translation`,
2323
+ units: "m"
2324
+ }
2325
+ };
2326
+ animatables = {
2327
+ ...animatables,
2328
+ [translationAnimatable.id]: translationAnimatable
2329
+ };
2330
+ const rotationAnimatable = {
2331
+ id: crypto.randomUUID(),
2332
+ name: `${group.name ?? "Group"} rotation`,
2333
+ type: "euler",
2334
+ default: { x: group.rotation.x, y: group.rotation.y, z: group.rotation.z },
2335
+ constraints: {},
2336
+ pub: {
2337
+ public: true,
2338
+ output: `${group.name ?? "Group"} rotation`,
2339
+ units: "rad"
2340
+ }
2341
+ };
2342
+ animatables = { ...animatables, [rotationAnimatable.id]: rotationAnimatable };
2343
+ const scaleAnimatable = {
2344
+ id: crypto.randomUUID(),
2345
+ name: `${group.name ?? "Group"} scale`,
2346
+ type: "vector3",
2347
+ default: { x: group.scale.x, y: group.scale.y, z: group.scale.z },
2348
+ constraints: {},
2349
+ pub: {
2350
+ public: true,
2351
+ output: `${group.name ?? "Group"} scale`
2352
+ }
2353
+ };
2354
+ animatables = { ...animatables, [scaleAnimatable.id]: scaleAnimatable };
2355
+ group.children.forEach((child) => {
2356
+ if (child.isMesh) {
2357
+ const [newWorldItems, newAnimatables, childId, newMeshColors] = importMesh(child, namespaces, {
2358
+ ...colorLookup,
2359
+ ...newColorLookup
2360
+ });
2361
+ newColorLookup = { ...newColorLookup, ...newMeshColors };
2362
+ world = { ...world, ...newWorldItems };
2363
+ animatables = { ...animatables, ...newAnimatables };
2364
+ children.push(childId);
2365
+ } else if (child.isGroup || child.isObject3D && child.children.length !== 0) {
2366
+ const [newWorldItems, newAnimatables, childId, newMeshColors] = importGroup(child, namespaces, {
2367
+ ...colorLookup,
2368
+ ...newColorLookup
2369
+ });
2370
+ newColorLookup = { ...newColorLookup, ...newMeshColors };
2371
+ world = { ...world, ...newWorldItems };
2372
+ animatables = { ...animatables, ...newAnimatables };
2373
+ children.push(childId);
2374
+ }
2375
+ });
2376
+ const newGroup = {
2377
+ id: group.uuid,
2378
+ name: group.name,
2379
+ type: "group",
2380
+ tags: [],
2381
+ features: {
2382
+ translation: { animated: true, value: translationAnimatable.id },
2383
+ rotation: { animated: true, value: rotationAnimatable.id },
2384
+ scale: { animated: true, value: scaleAnimatable.id }
2385
+ },
2386
+ root: Boolean(rootBounds),
2387
+ rootBounds,
2388
+ children,
2389
+ refs: namespaceArrayToRefs(namespaces)
2390
+ };
2391
+ world = { ...world, [newGroup.id]: newGroup };
2392
+ return [world, animatables, newGroup.id, newColorLookup];
2393
+ }
2394
+
2395
+ // src/functions/gltf-loading/import-scene.ts
2396
+ import_three4.Object3D.DEFAULT_UP.set(0, 0, 1);
2397
+ function importScene(scene, namespaces, rootBounds) {
2398
+ let world = {};
2399
+ let animatables = {};
2400
+ const [newWorldItems, newAnimatables] = importGroup(
2401
+ scene,
2402
+ namespaces,
2403
+ {},
2404
+ rootBounds
2405
+ );
2406
+ world = { ...world, ...newWorldItems };
2407
+ animatables = { ...animatables, ...newAnimatables };
2408
+ return [world, animatables];
2409
+ }
2410
+
2411
+ // src/functions/gltf-loading/traverse-three.ts
2412
+ THREE4.Object3D.DEFAULT_UP.set(0, 0, 1);
2413
+ function traverseThree(group, namespaces, aggressiveImport = false, rootBounds) {
2414
+ const worldData = {};
2415
+ const animatableData = {};
2416
+ let hasRobotData = false;
2417
+ group.traverse((child) => {
2418
+ if (child.userData?.gltfExtensions?.RobotData) {
2419
+ hasRobotData = true;
2420
+ }
2421
+ });
2422
+ const useRobotData = !aggressiveImport || hasRobotData;
2423
+ if (useRobotData) {
2424
+ group.traverse((child) => {
2425
+ if (child.userData?.gltfExtensions?.RobotData) {
2426
+ const data = child.userData.gltfExtensions.RobotData;
2427
+ let loadedData;
2428
+ let mappedFeatures;
2429
+ let animatableValues;
2430
+ switch (data.type) {
2431
+ case "group":
2432
+ loadedData = {
2433
+ ...data,
2434
+ refs: namespaces.reduce(
2435
+ (acc, ns) => ({ ...acc, [ns]: (0, import_react16.createRef)() }),
2436
+ {}
2437
+ )
2438
+ };
2439
+ [mappedFeatures, animatableValues] = mapFeatures(data.features);
2440
+ isGroupFeatures(mappedFeatures);
2441
+ loadedData.features = mappedFeatures;
2442
+ Object.assign(animatableData, animatableValues);
2443
+ worldData[loadedData.id] = loadedData;
2444
+ break;
2445
+ case "shape":
2446
+ loadedData = {
2447
+ ...data,
2448
+ geometry: child.geometry,
2449
+ refs: namespaces.reduce(
2450
+ (acc, ns) => ({ ...acc, [ns]: (0, import_react16.createRef)() }),
2451
+ {}
2452
+ )
2453
+ };
2454
+ [mappedFeatures, animatableValues] = mapFeatures(data.features);
2455
+ isShapeFeatures(mappedFeatures);
2456
+ loadedData.features = mappedFeatures;
2457
+ Object.assign(animatableData, animatableValues);
2458
+ worldData[loadedData.id] = loadedData;
2459
+ break;
2460
+ case "ellipse":
2461
+ loadedData = {
2462
+ ...data,
2463
+ refs: namespaces.reduce(
2464
+ (acc, ns) => ({ ...acc, [ns]: (0, import_react16.createRef)() }),
2465
+ {}
2466
+ )
2467
+ };
2468
+ [mappedFeatures, animatableValues] = mapFeatures(data.features);
2469
+ isEllipseFeatures(mappedFeatures);
2470
+ loadedData.features = mappedFeatures;
2471
+ Object.assign(animatableData, animatableValues);
2472
+ worldData[loadedData.id] = loadedData;
2473
+ break;
2474
+ case "rectangle":
2475
+ loadedData = {
2476
+ ...data,
2477
+ refs: namespaces.reduce(
2478
+ (acc, ns) => ({ ...acc, [ns]: (0, import_react16.createRef)() }),
2479
+ {}
2480
+ )
2481
+ };
2482
+ [mappedFeatures, animatableValues] = mapFeatures(data.features);
2483
+ isRectangleFeatures(mappedFeatures);
2484
+ loadedData.features = mappedFeatures;
2485
+ Object.assign(animatableData, animatableValues);
2486
+ worldData[loadedData.id] = loadedData;
2487
+ break;
2488
+ default:
2489
+ throw new Error(`Unhandled type`);
2490
+ }
2491
+ }
2492
+ });
2493
+ } else {
2494
+ const derivedRootBounds = rootBounds ?? deriveRootBounds(group);
2495
+ if (!derivedRootBounds) {
2496
+ throw new Error("Root bounds are expected if using an aggressive import");
2497
+ }
2498
+ const [newWorldData, newAnimatableData] = importScene(
2499
+ group,
2500
+ namespaces,
2501
+ derivedRootBounds
2502
+ );
2503
+ Object.assign(worldData, newWorldData);
2504
+ Object.assign(animatableData, newAnimatableData);
2505
+ }
2506
+ return [worldData, animatableData];
2507
+ }
2508
+ function isGroupFeatures(value) {
2509
+ if (!value || typeof value !== "object") {
2510
+ throw new Error("Expected object");
2511
+ }
2512
+ if (!["translation", "rotation"].every((key) => key in value)) {
2513
+ throw new Error("Expected translation and rotation keys in features");
2514
+ }
2515
+ }
2516
+ function isShapeFeatures(value) {
2517
+ if (!value || typeof value !== "object") {
2518
+ throw new Error("Expected object");
2519
+ }
2520
+ if (!["translation", "rotation"].every((key) => key in value)) {
2521
+ throw new Error("Expected translation and rotation keys in features");
2522
+ }
2523
+ }
2524
+ function isEllipseFeatures(value) {
2525
+ if (!value || typeof value !== "object") {
2526
+ throw new Error("Expected object");
2527
+ }
2528
+ if (!["translation", "rotation", "height", "width"].every((key) => key in value)) {
2529
+ throw new Error(
2530
+ "Expected translation, rotation, width, and height keys in features"
2531
+ );
2532
+ }
2533
+ }
2534
+ function isRectangleFeatures(value) {
2535
+ if (!value || typeof value !== "object") {
2536
+ throw new Error("Expected object");
2537
+ }
2538
+ if (!["translation", "rotation", "height", "width"].every((key) => key in value)) {
2539
+ throw new Error(
2540
+ "Expected translation, rotation, width, and height keys in features"
2541
+ );
2542
+ }
2543
+ }
2544
+ function deriveRootBounds(group) {
2545
+ const boundingBox = new THREE4.Box3().setFromObject(group);
2546
+ if (boundingBox.isEmpty()) {
2547
+ return null;
2548
+ }
2549
+ const { min, max } = boundingBox;
2550
+ if (!Number.isFinite(min.x) || !Number.isFinite(min.y) || !Number.isFinite(max.x) || !Number.isFinite(max.y)) {
2551
+ return null;
2552
+ }
2553
+ const width = max.x - min.x;
2554
+ const height = max.y - min.y;
2555
+ if (!Number.isFinite(width) || !Number.isFinite(height)) {
2556
+ return null;
2557
+ }
2558
+ const safeWidth = Math.max(Math.abs(width), 1e-3);
2559
+ const safeHeight = Math.max(Math.abs(height), 1e-3);
2560
+ return {
2561
+ center: {
2562
+ x: (min.x + max.x) / 2,
2563
+ y: (min.y + max.y) / 2
2564
+ },
2565
+ size: {
2566
+ x: safeWidth,
2567
+ y: safeHeight
2568
+ }
2569
+ };
2570
+ }
2571
+
2572
+ // src/functions/load-gltf.ts
2573
+ THREE5.Object3D.DEFAULT_UP.set(0, 0, 1);
2574
+ var EmptyModelError = class extends Error {
2575
+ constructor(message) {
2576
+ super(message);
2577
+ this.name = "EmptyModelError";
2578
+ }
2579
+ };
2580
+ async function loadGLTF(url, namespaces, aggressiveImport = false, rootBounds) {
2581
+ const modelLoader = new import_three_stdlib.GLTFLoader();
2582
+ modelLoader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
2583
+ const modelData = await modelLoader.loadAsync(url);
2584
+ const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
2585
+ return traverseThree(
2586
+ modelData.scene,
2587
+ actualizedNamespaces,
2588
+ aggressiveImport,
2589
+ rootBounds
2590
+ );
2591
+ }
2592
+ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, rootBounds) {
2593
+ const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
2594
+ if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
2595
+ const objectUrl = URL.createObjectURL(blob);
2596
+ try {
2597
+ return await loadGLTF(
2598
+ objectUrl,
2599
+ actualizedNamespaces,
2600
+ aggressiveImport,
2601
+ rootBounds
2602
+ );
2603
+ } finally {
2604
+ URL.revokeObjectURL(objectUrl);
2605
+ }
2606
+ }
2607
+ const arrayBuffer = typeof blob.arrayBuffer === "function" ? await blob.arrayBuffer() : await new Response(blob).arrayBuffer();
2608
+ return new Promise((resolve, reject) => {
2609
+ const loader = new import_three_stdlib.GLTFLoader();
2610
+ loader.setDRACOLoader(new import_three_stdlib.DRACOLoader());
2611
+ loader.parse(
2612
+ arrayBuffer,
2613
+ "",
2614
+ (gltf) => {
2615
+ try {
2616
+ resolve(
2617
+ traverseThree(
2618
+ gltf.scene,
2619
+ actualizedNamespaces,
2620
+ aggressiveImport,
2621
+ rootBounds
2622
+ )
2623
+ );
2624
+ } catch (error) {
2625
+ if (error instanceof Error) {
2626
+ reject(error);
2627
+ } else {
2628
+ reject(new Error(String(error)));
2629
+ }
2630
+ }
2631
+ },
2632
+ (error) => {
2633
+ reject(new Error(`Error loading GLTF: ${error.message}`));
2634
+ }
2635
+ );
2636
+ });
2637
+ }
2638
+
2639
+ // src/functions/load-gltf-blob.ts
2640
+ var import_three_stdlib2 = require("three-stdlib");
2641
+ var loadGltfFromBlob = (blob, namespaces) => {
2642
+ return new Promise((resolve, reject) => {
2643
+ const loader = new import_three_stdlib2.GLTFLoader();
2644
+ loader.setDRACOLoader(new import_three_stdlib2.DRACOLoader());
2645
+ const reader = new FileReader();
2646
+ reader.onload = () => {
2647
+ const arrayBuffer = reader.result;
2648
+ loader.parse(
2649
+ arrayBuffer,
2650
+ "",
2651
+ // Base path for resolving external resources
2652
+ (gltf) => {
2653
+ const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
2654
+ resolve(traverseThree(gltf.scene, actualizedNamespaces));
2655
+ },
2656
+ (error) => {
2657
+ reject(new Error(`Error loading GLTF: ${error.message}`));
2658
+ }
2659
+ );
2660
+ };
2661
+ reader.onerror = () => {
2662
+ reject(new Error("Failed to read Blob as ArrayBuffer."));
2663
+ };
2664
+ reader.readAsArrayBuffer(blob);
2665
+ });
2666
+ };
2667
+
2668
+ // src/functions/export.ts
2669
+ var import_three_stdlib3 = require("three-stdlib");
2670
+ var THREE6 = __toESM(require("three"));
2671
+ THREE6.Object3D.DEFAULT_UP.set(0, 0, 1);
2672
+ function exportScene(data, fileName = "scene.glb") {
2673
+ const exporter = new import_three_stdlib3.GLTFExporter();
2674
+ exporter.parse(
2675
+ data,
2676
+ (gltf) => {
2677
+ if (!(gltf instanceof ArrayBuffer)) {
2678
+ throw new Error("Failed to export scene!");
2679
+ }
2680
+ const link = document.createElement("a");
2681
+ link.href = URL.createObjectURL(
2682
+ new Blob([gltf], {
2683
+ type: "application/octet-stream"
2684
+ })
2685
+ );
2686
+ const trimmed = fileName.trim();
2687
+ const safeFileName = trimmed.length > 0 ? trimmed : "scene.glb";
2688
+ const downloadName = safeFileName.toLowerCase().endsWith(".glb") ? safeFileName : `${safeFileName}.glb`;
2689
+ link.download = downloadName;
2690
+ link.click();
2691
+ URL.revokeObjectURL(link.href);
2692
+ },
2693
+ () => {
2694
+ },
2695
+ {
2696
+ trs: true,
2697
+ onlyVisible: false,
2698
+ binary: true,
2699
+ includeCustomExtensions: true
2700
+ }
2701
+ );
2702
+ }
2703
+ // Annotate the CommonJS export names for ESM import in node:
2704
+ 0 && (module.exports = {
2705
+ Controller,
2706
+ EmptyModelError,
2707
+ InnerVizij,
2708
+ ShapeMaterial,
2709
+ Vizij,
2710
+ VizijContext,
2711
+ VizijSlice,
2712
+ createVizijStore,
2713
+ exportScene,
2714
+ loadGLTF,
2715
+ loadGLTFFromBlob,
2716
+ loadGltfFromBlob,
2717
+ useDefaultVizijStore,
2718
+ useFeatures,
2719
+ useVizijStore,
2720
+ useVizijStoreGetter,
2721
+ useVizijStoreSetter,
2722
+ useVizijStoreSubscription
2723
+ });