@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/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/index.cjs +808 -0
- package/dist/index.d.cts +189 -0
- package/dist/index.d.ts +189 -0
- package/dist/index.js +766 -0
- package/package.json +66 -0
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
|
+
};
|