@glyphcss/react 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,766 @@
1
+ // src/index.ts
2
+ import {
3
+ CAMERA_BACKFACE_CULL_EPS,
4
+ VOXEL_CAMERA_CULL_AXIS_EPS,
5
+ VOXEL_CAMERA_CULL_NORMAL_LIMIT,
6
+ normalizePolygons,
7
+ mergePolygons,
8
+ coverPlanarPolygons,
9
+ optimizeMeshPolygons,
10
+ cullInteriorPolygons,
11
+ cameraCullNormalGroups,
12
+ cameraCullNormalGroupsFromPolygons,
13
+ cameraCullNormalKey,
14
+ cameraCullVisibleSignature,
15
+ cameraFacingDepth,
16
+ isAxisAlignedSurfaceNormal,
17
+ isVoxelCameraCullableNormalGroups,
18
+ normalFacesCamera,
19
+ polygonCssSurfaceNormal,
20
+ polygonFacesCamera,
21
+ parseObj,
22
+ parseMtl,
23
+ parseGltf,
24
+ bakeSolidTextureSamples,
25
+ bakeSolidTextureSampledPolygons,
26
+ loadMesh,
27
+ createIsometricCamera,
28
+ parseVox,
29
+ polygonFaces,
30
+ computeShapeLighting,
31
+ parseColor,
32
+ parsePureColor,
33
+ parseHexColor,
34
+ parseRgbColor,
35
+ formatColor,
36
+ clampChannel,
37
+ shadeColor,
38
+ rotateVec3,
39
+ inverseRotateVec3,
40
+ axesHelperPolygons,
41
+ arrowPolygons,
42
+ ringPolygons,
43
+ octahedronPolygons,
44
+ buildSceneContext,
45
+ computeSceneBbox,
46
+ BASE_TILE,
47
+ DEFAULT_CAMERA_STATE,
48
+ DEFAULT_PROJECTION,
49
+ normalizeInvertMultiplier,
50
+ createGlyphcssAnimationMixer as createGlyphcssAnimationMixer2,
51
+ LoopOnce,
52
+ LoopRepeat,
53
+ LoopPingPong
54
+ } from "@glyphcss/core";
55
+
56
+ // src/glyphcss/scene/GlyphcssScene.tsx
57
+ import { memo, useCallback, useEffect, useMemo, useRef } from "react";
58
+ import { createGlyphcssScene, injectGlyphcssBaseStyles } from "glyphcss";
59
+
60
+ // src/glyphcss/scene/context.ts
61
+ import { createContext, useContext } from "react";
62
+ var GlyphcssSceneContext = createContext(null);
63
+ function useGlyphcssSceneContext() {
64
+ const ctx = useContext(GlyphcssSceneContext);
65
+ if (!ctx) {
66
+ throw new Error("glyphcss: GlyphcssMesh must be used inside a GlyphcssScene.");
67
+ }
68
+ return ctx;
69
+ }
70
+ var GlyphcssMeshContext = createContext(null);
71
+
72
+ // src/glyphcss/scene/GlyphcssScene.tsx
73
+ import { jsx } from "react/jsx-runtime";
74
+ function GlyphcssSceneInner({
75
+ mode,
76
+ glyphPalette,
77
+ useColors,
78
+ cols,
79
+ rows,
80
+ cellAspect,
81
+ directionalLight,
82
+ ambientLight,
83
+ className,
84
+ style,
85
+ children
86
+ }) {
87
+ const hostRef = useRef(null);
88
+ const sceneRef = useRef(null);
89
+ const initialOpts = useMemo(() => ({
90
+ mode,
91
+ glyphPalette,
92
+ useColors,
93
+ cols,
94
+ rows,
95
+ cellAspect,
96
+ directionalLight,
97
+ ambientLight
98
+ }), []);
99
+ const hostCallbackRef = useCallback((el) => {
100
+ if (el && !sceneRef.current) {
101
+ hostRef.current = el;
102
+ injectGlyphcssBaseStyles(el.ownerDocument ?? void 0);
103
+ sceneRef.current = createGlyphcssScene(el, initialOpts);
104
+ } else if (!el && sceneRef.current) {
105
+ sceneRef.current.destroy();
106
+ sceneRef.current = null;
107
+ hostRef.current = null;
108
+ }
109
+ }, [initialOpts]);
110
+ useEffect(() => {
111
+ const scene = sceneRef.current;
112
+ if (!scene) return;
113
+ const partial = {};
114
+ if (mode !== void 0) partial.mode = mode;
115
+ if (glyphPalette !== void 0) partial.glyphPalette = glyphPalette;
116
+ if (useColors !== void 0) partial.useColors = useColors;
117
+ if (cols !== void 0) partial.cols = cols;
118
+ if (rows !== void 0) partial.rows = rows;
119
+ if (cellAspect !== void 0) partial.cellAspect = cellAspect;
120
+ if (directionalLight !== void 0) partial.directionalLight = directionalLight;
121
+ if (ambientLight !== void 0) partial.ambientLight = ambientLight;
122
+ if (Object.keys(partial).length > 0) {
123
+ scene.setOptions(partial);
124
+ }
125
+ }, [mode, glyphPalette, useColors, cols, rows, cellAspect, directionalLight, ambientLight]);
126
+ const ctxValue = useMemo(() => ({ sceneRef }), [sceneRef]);
127
+ const computedClassName = `glyphcss-host${className ? ` ${className}` : ""}`;
128
+ return /* @__PURE__ */ jsx(GlyphcssSceneContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsx("div", { ref: hostCallbackRef, className: computedClassName, style, children }) });
129
+ }
130
+ var GlyphcssScene = memo(GlyphcssSceneInner);
131
+
132
+ // src/glyphcss/scene/GlyphcssMesh.tsx
133
+ import { memo as memo2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
134
+
135
+ // src/glyphcss/scene/events.ts
136
+ var MESH_REGISTRY = /* @__PURE__ */ new WeakMap();
137
+ function registerMeshElement(el, handle) {
138
+ MESH_REGISTRY.set(el, handle);
139
+ }
140
+ function unregisterMeshElement(el) {
141
+ MESH_REGISTRY.delete(el);
142
+ }
143
+ function findGlyphcssMeshHandle(el) {
144
+ let cur = el;
145
+ while (cur) {
146
+ if (cur instanceof HTMLElement) {
147
+ const h = MESH_REGISTRY.get(cur);
148
+ if (h) return h;
149
+ }
150
+ cur = cur.parentElement;
151
+ }
152
+ return null;
153
+ }
154
+
155
+ // src/glyphcss/scene/GlyphcssMesh.tsx
156
+ import { jsx as jsx2 } from "react/jsx-runtime";
157
+ function GlyphcssMeshInner({
158
+ id,
159
+ triangles: trianglesProp,
160
+ position,
161
+ scale,
162
+ rotation,
163
+ className,
164
+ style,
165
+ children
166
+ }) {
167
+ const { sceneRef } = useGlyphcssSceneContext();
168
+ const meshRef = useRef2(null);
169
+ const wrapperRef = useRef2(null);
170
+ const triangles = useMemo2(() => trianglesProp ?? [], [trianglesProp]);
171
+ const transform = useMemo2(() => ({
172
+ position,
173
+ scale,
174
+ rotation
175
+ }), [position, scale, rotation]);
176
+ useEffect2(() => {
177
+ const scene = sceneRef.current;
178
+ if (!scene) return;
179
+ const handle = scene.add(triangles, transform);
180
+ meshRef.current = handle;
181
+ return () => {
182
+ handle.dispose();
183
+ meshRef.current = null;
184
+ };
185
+ }, [sceneRef, triangles]);
186
+ useEffect2(() => {
187
+ const mesh = meshRef.current;
188
+ if (!mesh) return;
189
+ mesh.setTransform(transform);
190
+ sceneRef.current?.rerender();
191
+ }, [sceneRef, transform]);
192
+ useEffect2(() => {
193
+ const el = wrapperRef.current;
194
+ const handle = meshRef.current;
195
+ if (!el || !handle) return;
196
+ registerMeshElement(el, handle);
197
+ return () => unregisterMeshElement(el);
198
+ });
199
+ const computedClassName = `glyphcss-mesh${className ? ` ${className}` : ""}`;
200
+ return /* @__PURE__ */ jsx2(
201
+ "div",
202
+ {
203
+ ref: wrapperRef,
204
+ "data-glyphcss-mesh-id": id,
205
+ className: computedClassName,
206
+ style,
207
+ children
208
+ }
209
+ );
210
+ }
211
+ var GlyphcssMesh = memo2(GlyphcssMeshInner);
212
+
213
+ // src/glyphcss/scene/GlyphcssHotspot.tsx
214
+ import { memo as memo3, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef3 } from "react";
215
+ import { jsx as jsx3 } from "react/jsx-runtime";
216
+ function GlyphcssHotspotInner({
217
+ id,
218
+ at,
219
+ size,
220
+ onClick,
221
+ className,
222
+ children
223
+ }) {
224
+ const { sceneRef } = useGlyphcssSceneContext();
225
+ const hotspotRef = useRef3(null);
226
+ const onClickRef = useRef3(onClick);
227
+ onClickRef.current = onClick;
228
+ const atKey = useMemo3(() => at.join(","), [at]);
229
+ const sizeKey = size ? size.join(",") : "";
230
+ useEffect3(() => {
231
+ const scene = sceneRef.current;
232
+ if (!scene) return;
233
+ const handle = scene.addHotspot(
234
+ { id, at, size },
235
+ () => {
236
+ }
237
+ );
238
+ hotspotRef.current = handle;
239
+ return () => {
240
+ handle.remove();
241
+ hotspotRef.current = null;
242
+ };
243
+ }, [sceneRef, id, atKey, sizeKey]);
244
+ if (!children && !onClick && !className) return null;
245
+ return /* @__PURE__ */ jsx3(
246
+ "div",
247
+ {
248
+ "data-glyphcss-hotspot-id": id,
249
+ className,
250
+ style: { display: "contents" },
251
+ onClick,
252
+ children
253
+ }
254
+ );
255
+ }
256
+ var GlyphcssHotspot = memo3(GlyphcssHotspotInner);
257
+
258
+ // src/glyphcss/scene/useGlyphcssMesh.ts
259
+ import { useEffect as useEffect4, useRef as useRef4, useState } from "react";
260
+ function useGlyphcssMesh(triangles, options) {
261
+ const { sceneRef } = useGlyphcssSceneContext();
262
+ const meshRef = useRef4(null);
263
+ const [loading] = useState(false);
264
+ useEffect4(() => {
265
+ const scene = sceneRef.current;
266
+ if (!scene) return;
267
+ const handle = scene.add(triangles, options?.transform);
268
+ meshRef.current = handle;
269
+ return () => {
270
+ handle.dispose();
271
+ meshRef.current = null;
272
+ };
273
+ }, [sceneRef, triangles]);
274
+ useEffect4(() => {
275
+ const mesh = meshRef.current;
276
+ if (!mesh) return;
277
+ if (options?.transform) {
278
+ mesh.setTransform(options.transform);
279
+ sceneRef.current?.rerender();
280
+ }
281
+ }, [sceneRef, options?.transform]);
282
+ return { meshRef, loading };
283
+ }
284
+
285
+ // src/glyphcss/camera/GlyphcssPerspectiveCamera.tsx
286
+ import { memo as memo4, useEffect as useEffect5, useMemo as useMemo4, useRef as useRef5 } from "react";
287
+ import { createGlyphcssPerspectiveCamera } from "glyphcss";
288
+
289
+ // src/glyphcss/camera/context.ts
290
+ import { createContext as createContext2, useContext as useContext2 } from "react";
291
+ var GlyphcssCameraContext = createContext2(null);
292
+ function useGlyphcssCamera() {
293
+ const ctx = useContext2(GlyphcssCameraContext);
294
+ if (!ctx) {
295
+ throw new Error("glyphcss: camera hook must be used inside a GlyphcssCamera.");
296
+ }
297
+ return ctx;
298
+ }
299
+
300
+ // src/glyphcss/camera/GlyphcssPerspectiveCamera.tsx
301
+ import { jsx as jsx4 } from "react/jsx-runtime";
302
+ function GlyphcssPerspectiveCameraInner({
303
+ rotX,
304
+ rotY,
305
+ distance,
306
+ scale,
307
+ stretch,
308
+ center,
309
+ children
310
+ }) {
311
+ const { sceneRef } = useGlyphcssSceneContext();
312
+ const cameraRef = useRef5(null);
313
+ if (!cameraRef.current) {
314
+ const opts = {};
315
+ if (rotX !== void 0) opts.rotX = rotX;
316
+ if (rotY !== void 0) opts.rotY = rotY;
317
+ if (distance !== void 0) opts.distance = distance;
318
+ if (scale !== void 0) opts.scale = scale;
319
+ if (stretch !== void 0) opts.stretch = stretch;
320
+ if (center !== void 0) opts.center = center;
321
+ cameraRef.current = createGlyphcssPerspectiveCamera(opts);
322
+ }
323
+ useEffect5(() => {
324
+ const scene = sceneRef.current;
325
+ if (!scene || !cameraRef.current) return;
326
+ scene.setOptions({ camera: cameraRef.current });
327
+ scene.rerender();
328
+ }, [sceneRef]);
329
+ useEffect5(() => {
330
+ const camera = cameraRef.current;
331
+ if (!camera) return;
332
+ let dirty = false;
333
+ if (rotX !== void 0 && camera.rotX !== rotX) {
334
+ camera.rotX = rotX;
335
+ dirty = true;
336
+ }
337
+ if (rotY !== void 0 && camera.rotY !== rotY) {
338
+ camera.rotY = rotY;
339
+ dirty = true;
340
+ }
341
+ if (distance !== void 0 && camera.distance !== distance) {
342
+ camera.distance = distance;
343
+ dirty = true;
344
+ }
345
+ if (scale !== void 0 && camera.scale !== scale) {
346
+ camera.scale = scale;
347
+ dirty = true;
348
+ }
349
+ if (stretch !== void 0 && camera.stretch !== stretch) {
350
+ camera.stretch = stretch;
351
+ dirty = true;
352
+ }
353
+ if (dirty) {
354
+ sceneRef.current?.rerender();
355
+ }
356
+ });
357
+ const rerender = () => sceneRef.current?.rerender();
358
+ const ctxValue = useMemo4(() => ({ cameraRef, rerender }), [cameraRef]);
359
+ return /* @__PURE__ */ jsx4(GlyphcssCameraContext.Provider, { value: ctxValue, children });
360
+ }
361
+ var GlyphcssPerspectiveCamera = memo4(GlyphcssPerspectiveCameraInner);
362
+
363
+ // src/glyphcss/camera/GlyphcssOrthographicCamera.tsx
364
+ import { memo as memo5, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef6 } from "react";
365
+ import { createGlyphcssOrthographicCamera } from "glyphcss";
366
+ import { jsx as jsx5 } from "react/jsx-runtime";
367
+ function GlyphcssOrthographicCameraInner({
368
+ rotX,
369
+ rotY,
370
+ zoom,
371
+ center,
372
+ children
373
+ }) {
374
+ const { sceneRef } = useGlyphcssSceneContext();
375
+ const cameraRef = useRef6(null);
376
+ if (!cameraRef.current) {
377
+ const opts = {};
378
+ if (rotX !== void 0) opts.rotX = rotX;
379
+ if (rotY !== void 0) opts.rotY = rotY;
380
+ if (zoom !== void 0) opts.zoom = zoom;
381
+ if (center !== void 0) opts.center = center;
382
+ cameraRef.current = createGlyphcssOrthographicCamera(opts);
383
+ }
384
+ useEffect6(() => {
385
+ const scene = sceneRef.current;
386
+ if (!scene || !cameraRef.current) return;
387
+ scene.setOptions({ camera: cameraRef.current });
388
+ scene.rerender();
389
+ }, [sceneRef]);
390
+ useEffect6(() => {
391
+ const camera = cameraRef.current;
392
+ if (!camera) return;
393
+ let dirty = false;
394
+ if (rotX !== void 0 && camera.rotX !== rotX) {
395
+ camera.rotX = rotX;
396
+ dirty = true;
397
+ }
398
+ if (rotY !== void 0 && camera.rotY !== rotY) {
399
+ camera.rotY = rotY;
400
+ dirty = true;
401
+ }
402
+ if (zoom !== void 0 && camera.scale !== zoom) {
403
+ camera.scale = zoom;
404
+ dirty = true;
405
+ }
406
+ if (dirty) sceneRef.current?.rerender();
407
+ });
408
+ const rerender = () => sceneRef.current?.rerender();
409
+ const ctxValue = useMemo5(() => ({ cameraRef, rerender }), [cameraRef]);
410
+ return /* @__PURE__ */ jsx5(GlyphcssCameraContext.Provider, { value: ctxValue, children });
411
+ }
412
+ var GlyphcssOrthographicCamera = memo5(GlyphcssOrthographicCameraInner);
413
+
414
+ // src/glyphcss/camera/useGlyphcssCamera.ts
415
+ import { useCallback as useCallback2, useEffect as useEffect7, useRef as useRef7 } from "react";
416
+ import { createGlyphcssPerspectiveCamera as createGlyphcssPerspectiveCamera2 } from "glyphcss";
417
+
418
+ // src/glyphcss/controls/GlyphcssOrbitControls.tsx
419
+ import { useEffect as useEffect8, useRef as useRef8 } from "react";
420
+ import { createGlyphcssOrbitControls } from "glyphcss";
421
+ function GlyphcssOrbitControls({
422
+ drag = true,
423
+ wheel = true,
424
+ invert = false,
425
+ animate = false
426
+ }) {
427
+ const { sceneRef } = useGlyphcssSceneContext();
428
+ const controlsRef = useRef8(null);
429
+ const propsRef = useRef8({ drag, wheel, invert, animate });
430
+ propsRef.current = { drag, wheel, invert, animate };
431
+ useEffect8(() => {
432
+ const scene = sceneRef.current;
433
+ if (!scene) return;
434
+ const opts = {
435
+ drag: propsRef.current.drag,
436
+ wheel: propsRef.current.wheel,
437
+ invert: propsRef.current.invert,
438
+ animate: propsRef.current.animate === false ? false : propsRef.current.animate
439
+ };
440
+ const controls = createGlyphcssOrbitControls(scene, opts);
441
+ controlsRef.current = controls;
442
+ return () => {
443
+ controls.destroy();
444
+ controlsRef.current = null;
445
+ };
446
+ }, [sceneRef]);
447
+ useEffect8(() => {
448
+ const controls = controlsRef.current;
449
+ if (!controls) return;
450
+ controls.update({ drag, wheel, invert, animate: animate === false ? false : animate });
451
+ });
452
+ return null;
453
+ }
454
+
455
+ // src/glyphcss/controls/GlyphcssMapControls.tsx
456
+ import { useEffect as useEffect9, useRef as useRef9 } from "react";
457
+ import { createGlyphcssMapControls } from "glyphcss";
458
+ function GlyphcssMapControls({
459
+ drag = true,
460
+ wheel = true,
461
+ invert = false,
462
+ animate = false
463
+ }) {
464
+ const { sceneRef } = useGlyphcssSceneContext();
465
+ const controlsRef = useRef9(null);
466
+ const propsRef = useRef9({ drag, wheel, invert, animate });
467
+ propsRef.current = { drag, wheel, invert, animate };
468
+ useEffect9(() => {
469
+ const scene = sceneRef.current;
470
+ if (!scene) return;
471
+ const opts = {
472
+ drag: propsRef.current.drag,
473
+ wheel: propsRef.current.wheel,
474
+ invert: propsRef.current.invert,
475
+ animate: propsRef.current.animate === false ? false : propsRef.current.animate
476
+ };
477
+ const controls = createGlyphcssMapControls(scene, opts);
478
+ controlsRef.current = controls;
479
+ return () => {
480
+ controls.destroy();
481
+ controlsRef.current = null;
482
+ };
483
+ }, [sceneRef]);
484
+ useEffect9(() => {
485
+ const controls = controlsRef.current;
486
+ if (!controls) return;
487
+ controls.update({ drag, wheel, invert, animate: animate === false ? false : animate });
488
+ });
489
+ return null;
490
+ }
491
+
492
+ // src/glyphcss/controls/GlyphcssFirstPersonControls.tsx
493
+ import { useEffect as useEffect10, useRef as useRef10 } from "react";
494
+ import { createGlyphcssFirstPersonControls } from "glyphcss";
495
+ function GlyphcssFirstPersonControls({
496
+ drag = true,
497
+ keyboard = true,
498
+ moveSpeed = 0.05,
499
+ lookSpeed = 4e-3,
500
+ invert = false
501
+ }) {
502
+ const { sceneRef } = useGlyphcssSceneContext();
503
+ const controlsRef = useRef10(null);
504
+ const propsRef = useRef10({ drag, keyboard, moveSpeed, lookSpeed, invert });
505
+ propsRef.current = { drag, keyboard, moveSpeed, lookSpeed, invert };
506
+ useEffect10(() => {
507
+ const scene = sceneRef.current;
508
+ if (!scene) return;
509
+ const opts = {
510
+ drag: propsRef.current.drag,
511
+ keyboard: propsRef.current.keyboard,
512
+ moveSpeed: propsRef.current.moveSpeed,
513
+ lookSpeed: propsRef.current.lookSpeed,
514
+ invert: propsRef.current.invert
515
+ };
516
+ const controls = createGlyphcssFirstPersonControls(scene, opts);
517
+ controlsRef.current = controls;
518
+ return () => {
519
+ controls.destroy();
520
+ controlsRef.current = null;
521
+ };
522
+ }, [sceneRef]);
523
+ useEffect10(() => {
524
+ const controls = controlsRef.current;
525
+ if (!controls) return;
526
+ controls.update({ drag, keyboard, moveSpeed, lookSpeed, invert });
527
+ });
528
+ return null;
529
+ }
530
+
531
+ // src/glyphcss/helpers/GlyphcssAxesHelper.tsx
532
+ import { memo as memo6, useEffect as useEffect11, useMemo as useMemo7, useRef as useRef11 } from "react";
533
+ function axisTriangles(size) {
534
+ const s = size;
535
+ const t = s * 0.05;
536
+ const triangles = [];
537
+ function addBar(a, b, color) {
538
+ const v0 = [a[0] - t, a[1] - t, a[2]];
539
+ const v1 = [b[0] - t, b[1] - t, b[2]];
540
+ const v2 = [b[0] + t, b[1] + t, b[2]];
541
+ const v3 = [a[0] + t, a[1] + t, a[2]];
542
+ triangles.push({ vertices: [v0, v1, v2], color });
543
+ triangles.push({ vertices: [v0, v2, v3], color });
544
+ }
545
+ addBar([0, 0, 0], [s, 0, 0], "#ff0000");
546
+ addBar([0, 0, 0], [0, s, 0], "#00ff00");
547
+ addBar([0, 0, 0], [0, 0, s], "#0000ff");
548
+ return triangles;
549
+ }
550
+ function GlyphcssAxesHelperInner({ size = 1 }) {
551
+ const { sceneRef } = useGlyphcssSceneContext();
552
+ const meshRef = useRef11(null);
553
+ const triangles = useMemo7(() => axisTriangles(size), [size]);
554
+ useEffect11(() => {
555
+ const scene = sceneRef.current;
556
+ if (!scene) return;
557
+ const handle = scene.add(triangles);
558
+ meshRef.current = handle;
559
+ return () => {
560
+ handle.dispose();
561
+ meshRef.current = null;
562
+ };
563
+ }, [sceneRef, triangles]);
564
+ return null;
565
+ }
566
+ var GlyphcssAxesHelper = memo6(GlyphcssAxesHelperInner);
567
+
568
+ // src/glyphcss/helpers/GlyphcssDirectionalLightHelper.tsx
569
+ import { memo as memo7, useEffect as useEffect12, useMemo as useMemo8, useRef as useRef12 } from "react";
570
+ function lightMarkerTriangles(position, color, size) {
571
+ const [px, py, pz] = position;
572
+ const s = size;
573
+ const top = [px, py, pz + s];
574
+ const bot = [px, py, pz - s];
575
+ const right = [px + s, py, pz];
576
+ const left = [px - s, py, pz];
577
+ const front = [px, py + s, pz];
578
+ const back = [px, py - s, pz];
579
+ return [
580
+ { vertices: [top, right, front], color },
581
+ { vertices: [top, front, left], color },
582
+ { vertices: [top, left, back], color },
583
+ { vertices: [top, back, right], color },
584
+ { vertices: [bot, front, right], color },
585
+ { vertices: [bot, left, front], color },
586
+ { vertices: [bot, back, left], color },
587
+ { vertices: [bot, right, back], color }
588
+ ];
589
+ }
590
+ function GlyphcssDirectionalLightHelperInner({
591
+ position = [1, 1, 1],
592
+ color = "#ffff00",
593
+ size = 0.1
594
+ }) {
595
+ const { sceneRef } = useGlyphcssSceneContext();
596
+ const meshRef = useRef12(null);
597
+ const triangles = useMemo8(
598
+ () => lightMarkerTriangles(position, color, size),
599
+ [position, color, size]
600
+ );
601
+ useEffect12(() => {
602
+ const scene = sceneRef.current;
603
+ if (!scene) return;
604
+ const handle = scene.add(triangles);
605
+ meshRef.current = handle;
606
+ return () => {
607
+ handle.dispose();
608
+ meshRef.current = null;
609
+ };
610
+ }, [sceneRef, triangles]);
611
+ return null;
612
+ }
613
+ var GlyphcssDirectionalLightHelper = memo7(GlyphcssDirectionalLightHelperInner);
614
+
615
+ // src/glyphcss/styles/index.ts
616
+ import { injectGlyphcssBaseStyles as injectGlyphcssBaseStyles2 } from "glyphcss";
617
+
618
+ // src/animation/useGlyphcssAnimation.ts
619
+ import { useEffect as useEffect13, useRef as useRef13, useMemo as useMemo9 } from "react";
620
+ import { createGlyphcssAnimationMixer } from "@glyphcss/core";
621
+ function resolveRoot(rootArg) {
622
+ if (!rootArg) return null;
623
+ if ("current" in rootArg) return rootArg.current;
624
+ return rootArg;
625
+ }
626
+ function useGlyphcssAnimation(clips, controller, root) {
627
+ const internalRef = useRef13(null);
628
+ const mixerRef = useRef13(null);
629
+ useEffect13(() => {
630
+ if (!clips || clips.length === 0 || !controller) {
631
+ mixerRef.current = null;
632
+ return;
633
+ }
634
+ const resolvedRoot = resolveRoot(root) ?? internalRef.current;
635
+ if (!resolvedRoot) {
636
+ mixerRef.current = null;
637
+ return;
638
+ }
639
+ mixerRef.current = createGlyphcssAnimationMixer(resolvedRoot, controller);
640
+ return () => {
641
+ mixerRef.current?.stopAllAction();
642
+ mixerRef.current?.uncacheRoot();
643
+ mixerRef.current = null;
644
+ };
645
+ }, [clips, controller]);
646
+ useEffect13(() => {
647
+ if (!clips || clips.length === 0 || !controller) return;
648
+ let rafId;
649
+ let lastTime = null;
650
+ function tick(now) {
651
+ if (lastTime === null) {
652
+ lastTime = now;
653
+ rafId = requestAnimationFrame(tick);
654
+ return;
655
+ }
656
+ const dt = (now - lastTime) / 1e3;
657
+ lastTime = now;
658
+ mixerRef.current?.update(dt);
659
+ rafId = requestAnimationFrame(tick);
660
+ }
661
+ rafId = requestAnimationFrame(tick);
662
+ return () => {
663
+ cancelAnimationFrame(rafId);
664
+ lastTime = null;
665
+ };
666
+ }, [clips, controller]);
667
+ const resolvedClips = clips ?? [];
668
+ const resolvedNames = resolvedClips.map((c) => c.name);
669
+ const actions = useMemo9(() => {
670
+ const target = {};
671
+ for (const clip of resolvedClips) {
672
+ Object.defineProperty(target, clip.name, {
673
+ enumerable: true,
674
+ get() {
675
+ const m = mixerRef.current;
676
+ if (!m) return null;
677
+ try {
678
+ return m.clipAction(clip.name);
679
+ } catch {
680
+ return null;
681
+ }
682
+ }
683
+ });
684
+ }
685
+ return target;
686
+ }, [resolvedClips]);
687
+ return {
688
+ ref: internalRef,
689
+ mixer: mixerRef.current,
690
+ clips: resolvedClips,
691
+ names: resolvedNames,
692
+ actions
693
+ };
694
+ }
695
+ export {
696
+ BASE_TILE,
697
+ CAMERA_BACKFACE_CULL_EPS,
698
+ DEFAULT_CAMERA_STATE,
699
+ DEFAULT_PROJECTION,
700
+ GlyphcssAxesHelper,
701
+ GlyphcssPerspectiveCamera as GlyphcssCamera,
702
+ GlyphcssCameraContext,
703
+ GlyphcssDirectionalLightHelper,
704
+ GlyphcssFirstPersonControls,
705
+ GlyphcssHotspot,
706
+ GlyphcssMapControls,
707
+ GlyphcssMesh,
708
+ GlyphcssOrbitControls,
709
+ GlyphcssOrthographicCamera,
710
+ GlyphcssPerspectiveCamera,
711
+ GlyphcssScene,
712
+ GlyphcssSceneContext,
713
+ LoopOnce,
714
+ LoopPingPong,
715
+ LoopRepeat,
716
+ VOXEL_CAMERA_CULL_AXIS_EPS,
717
+ VOXEL_CAMERA_CULL_NORMAL_LIMIT,
718
+ arrowPolygons,
719
+ axesHelperPolygons,
720
+ bakeSolidTextureSampledPolygons,
721
+ bakeSolidTextureSamples,
722
+ buildSceneContext,
723
+ cameraCullNormalGroups,
724
+ cameraCullNormalGroupsFromPolygons,
725
+ cameraCullNormalKey,
726
+ cameraCullVisibleSignature,
727
+ cameraFacingDepth,
728
+ clampChannel,
729
+ computeSceneBbox,
730
+ computeShapeLighting,
731
+ coverPlanarPolygons,
732
+ createGlyphcssAnimationMixer2 as createGlyphcssAnimationMixer,
733
+ createIsometricCamera,
734
+ cullInteriorPolygons,
735
+ findGlyphcssMeshHandle,
736
+ formatColor,
737
+ injectGlyphcssBaseStyles2 as injectGlyphcssBaseStyles,
738
+ inverseRotateVec3,
739
+ isAxisAlignedSurfaceNormal,
740
+ isVoxelCameraCullableNormalGroups,
741
+ loadMesh,
742
+ mergePolygons,
743
+ normalFacesCamera,
744
+ normalizeInvertMultiplier,
745
+ normalizePolygons,
746
+ octahedronPolygons,
747
+ optimizeMeshPolygons,
748
+ parseColor,
749
+ parseGltf,
750
+ parseHexColor,
751
+ parseMtl,
752
+ parseObj,
753
+ parsePureColor,
754
+ parseRgbColor,
755
+ parseVox,
756
+ polygonCssSurfaceNormal,
757
+ polygonFaces,
758
+ polygonFacesCamera,
759
+ ringPolygons,
760
+ rotateVec3,
761
+ shadeColor,
762
+ useGlyphcssAnimation,
763
+ useGlyphcssCamera,
764
+ useGlyphcssMesh,
765
+ useGlyphcssSceneContext
766
+ };