@fonsecabarreto/genesis-gl-react 0.1.3 → 0.1.32

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.
@@ -0,0 +1,269 @@
1
+ // src/hooks/useGenesisGL.ts
2
+ import { useRef, useEffect, useState } from "react";
3
+ import {
4
+ WebGLCore as WebGLCoreImpl,
5
+ Scene as SceneImpl,
6
+ Renderer as RendererImpl,
7
+ Viewport as ViewportImpl
8
+ } from "@fonsecabarreto/genesis-gl-core/Core";
9
+ import { loadOBJWithMTL } from "@fonsecabarreto/genesis-gl-core/Core/utils/parse-obj";
10
+ var nullLoadOBJ = () => Promise.reject(new Error("GenesisGL not initialized"));
11
+ function useGenesisGL(options) {
12
+ const [context, setContext] = useState({
13
+ renderer: null,
14
+ scene: null,
15
+ viewport: null,
16
+ webglCore: null,
17
+ loadOBJ: nullLoadOBJ
18
+ });
19
+ const contextRef = useRef(context);
20
+ useEffect(() => {
21
+ const {
22
+ canvasRef,
23
+ onReady,
24
+ onError,
25
+ width,
26
+ height,
27
+ initialYaw,
28
+ initialPitch,
29
+ initialZoom
30
+ } = options;
31
+ if (!canvasRef.current) return;
32
+ try {
33
+ const canvas = canvasRef.current;
34
+ const vpWidth = width ?? window.innerWidth;
35
+ const vpHeight = height ?? window.innerHeight;
36
+ const webglCore = new WebGLCoreImpl(canvas);
37
+ const viewport = new ViewportImpl(canvas, vpWidth, vpHeight, webglCore, {
38
+ pointerLock: false
39
+ });
40
+ const renderer = new RendererImpl(webglCore, viewport);
41
+ const scene = SceneImpl.withDefaultLights(webglCore);
42
+ viewport.camera.target = [0, 0, 0];
43
+ viewport.camera.position = [4, 2, 8];
44
+ if (initialYaw !== void 0) viewport.camera.yaw = initialYaw;
45
+ if (initialPitch !== void 0) viewport.camera.pitch = initialPitch;
46
+ if (initialZoom !== void 0) viewport.camera.setZoom(initialZoom);
47
+ viewport.camera.invalidate();
48
+ const loadOBJ = (objUrl, opts = {}) => loadOBJWithMTL(
49
+ webglCore,
50
+ objUrl,
51
+ opts.mtlUrl ?? null,
52
+ opts.translation,
53
+ opts.scale
54
+ );
55
+ const ctx = {
56
+ renderer,
57
+ scene,
58
+ viewport,
59
+ webglCore,
60
+ loadOBJ
61
+ };
62
+ contextRef.current = ctx;
63
+ setContext(ctx);
64
+ if (onReady) onReady(ctx);
65
+ } catch (error) {
66
+ const err = error instanceof Error ? error : new Error(String(error));
67
+ console.error("Failed to initialize GenesisGL:", err);
68
+ if (onError) onError(err);
69
+ }
70
+ return () => {
71
+ const { scene, viewport, webglCore } = contextRef.current;
72
+ if (scene && webglCore) scene.dispose(webglCore);
73
+ if (viewport) viewport.dispose();
74
+ if (webglCore) webglCore.dispose();
75
+ };
76
+ }, []);
77
+ return context;
78
+ }
79
+
80
+ // src/hooks/useRenderer.ts
81
+ import { useRef as useRef2, useEffect as useEffect2 } from "react";
82
+ function useRenderer(options) {
83
+ const { renderer, onFrame, enabled = true } = options;
84
+ const animationIdRef = useRef2(null);
85
+ useEffect2(() => {
86
+ if (!renderer || !enabled) return;
87
+ const animate = (time) => {
88
+ if (onFrame) onFrame(time);
89
+ animationIdRef.current = requestAnimationFrame(animate);
90
+ };
91
+ animationIdRef.current = requestAnimationFrame(animate);
92
+ return () => {
93
+ if (animationIdRef.current !== null) {
94
+ cancelAnimationFrame(animationIdRef.current);
95
+ }
96
+ };
97
+ }, [renderer, onFrame, enabled]);
98
+ }
99
+
100
+ // src/hooks/useWorldToScreen.ts
101
+ import { useState as useState2, useCallback } from "react";
102
+ function mat4TransformVec4(m, x, y, z, w) {
103
+ return {
104
+ x: m[0] * x + m[4] * y + m[8] * z + m[12] * w,
105
+ y: m[1] * x + m[5] * y + m[9] * z + m[13] * w,
106
+ z: m[2] * x + m[6] * y + m[10] * z + m[14] * w,
107
+ w: m[3] * x + m[7] * y + m[11] * z + m[15] * w
108
+ };
109
+ }
110
+ function useWorldToScreen(context) {
111
+ const [, forceUpdate] = useState2(0);
112
+ const project = useCallback(
113
+ (worldX, worldY, worldZ) => {
114
+ if (!context?.viewport) return { x: 0, y: 0, visible: false };
115
+ const { viewport } = context;
116
+ const camera = viewport.camera;
117
+ const canvas = viewport.getCanvas();
118
+ const view = camera.getViewMatrix();
119
+ const proj = camera.getProjectionMatrix();
120
+ const v = mat4TransformVec4(view, worldX, worldY, worldZ, 1);
121
+ const c = mat4TransformVec4(proj, v.x, v.y, v.z, v.w);
122
+ if (Math.abs(c.w) < 1e-6) return { x: 0, y: 0, visible: false };
123
+ const ndcX = c.x / c.w;
124
+ const ndcY = c.y / c.w;
125
+ const ndcZ = c.z / c.w;
126
+ const visible = ndcZ > -1 && ndcZ < 1 && Math.abs(ndcX) < 1.2 && Math.abs(ndcY) < 1.2;
127
+ return {
128
+ x: (ndcX + 1) * 0.5 * canvas.clientWidth,
129
+ y: (1 - ndcY) * 0.5 * canvas.clientHeight,
130
+ visible
131
+ };
132
+ },
133
+ [context]
134
+ );
135
+ const tick = useCallback(() => forceUpdate((n) => n + 1), []);
136
+ return { project, tick };
137
+ }
138
+
139
+ // src/hooks/useCameraControls.ts
140
+ import { useCallback as useCallback2, useState as useState3 } from "react";
141
+ var DEFAULT_YAW = 0;
142
+ var DEFAULT_PITCH = 0;
143
+ var DEFAULT_ZOOM = 1;
144
+ function useCameraControls(ctx) {
145
+ const [camera, setCameraState] = useState3({
146
+ yaw: DEFAULT_YAW,
147
+ pitch: DEFAULT_PITCH,
148
+ zoom: DEFAULT_ZOOM
149
+ });
150
+ const sync = useCallback2((c) => {
151
+ setCameraState({ yaw: c.yaw, pitch: c.pitch, zoom: c.zoom });
152
+ }, []);
153
+ const rotate = useCallback2(
154
+ (deltaYaw, deltaPitch) => {
155
+ const c = ctx?.viewport?.camera;
156
+ if (!c) return;
157
+ c.rotate(deltaYaw, deltaPitch);
158
+ sync(c);
159
+ },
160
+ [ctx, sync]
161
+ );
162
+ const zoomBy = useCallback2(
163
+ (delta) => {
164
+ const c = ctx?.viewport?.camera;
165
+ if (!c) return;
166
+ c.zoomBy(delta);
167
+ sync(c);
168
+ },
169
+ [ctx, sync]
170
+ );
171
+ const setZoom = useCallback2(
172
+ (zoom) => {
173
+ const c = ctx?.viewport?.camera;
174
+ if (!c) return;
175
+ c.setZoom(zoom);
176
+ sync(c);
177
+ },
178
+ [ctx, sync]
179
+ );
180
+ const setYaw = useCallback2(
181
+ (yaw) => {
182
+ const c = ctx?.viewport?.camera;
183
+ if (!c) return;
184
+ c.yaw = yaw;
185
+ c.invalidate();
186
+ sync(c);
187
+ },
188
+ [ctx, sync]
189
+ );
190
+ const setPitch = useCallback2(
191
+ (pitch) => {
192
+ const c = ctx?.viewport?.camera;
193
+ if (!c) return;
194
+ c.pitch = pitch;
195
+ c.invalidate();
196
+ sync(c);
197
+ },
198
+ [ctx, sync]
199
+ );
200
+ const reset = useCallback2(() => {
201
+ const c = ctx?.viewport?.camera;
202
+ if (!c) return;
203
+ c.yaw = DEFAULT_YAW;
204
+ c.pitch = DEFAULT_PITCH;
205
+ c.invalidate();
206
+ c.setZoom(DEFAULT_ZOOM);
207
+ sync(c);
208
+ }, [ctx, sync]);
209
+ return { camera, rotate, setYaw, setPitch, zoomBy, setZoom, reset };
210
+ }
211
+
212
+ // src/hooks/useCameraMouseDrag.ts
213
+ import { useEffect as useEffect3, useRef as useRef3 } from "react";
214
+ import { MouseDragControl } from "@fonsecabarreto/genesis-gl-core/Core";
215
+ var SENSITIVITY = 8e-3;
216
+ function useCameraMouseDrag(ctx, canvasRef) {
217
+ const { rotate } = useCameraControls(ctx);
218
+ const rotateRef = useRef3(rotate);
219
+ rotateRef.current = rotate;
220
+ useEffect3(() => {
221
+ const el = canvasRef.current;
222
+ if (!el || !ctx) return;
223
+ const drag = new MouseDragControl(el);
224
+ const onDrag = (dx, dy, button) => {
225
+ if (button !== 2) return;
226
+ rotateRef.current(-dx * SENSITIVITY, dy * SENSITIVITY);
227
+ };
228
+ drag.onChange(onDrag);
229
+ drag.enable();
230
+ const onMouseDown = (e) => {
231
+ if (e.button !== 2) return;
232
+ el.style.cursor = "grabbing";
233
+ };
234
+ const onMouseUp = (e) => {
235
+ if (e.button !== 2) return;
236
+ el.style.cursor = "grab";
237
+ };
238
+ const onMouseEnter = () => {
239
+ el.style.cursor = "grab";
240
+ };
241
+ const onMouseLeave = () => {
242
+ el.style.cursor = "";
243
+ };
244
+ const onContextMenu = (e) => e.preventDefault();
245
+ el.addEventListener("mousedown", onMouseDown);
246
+ el.addEventListener("mouseenter", onMouseEnter);
247
+ el.addEventListener("mouseleave", onMouseLeave);
248
+ window.addEventListener("mouseup", onMouseUp);
249
+ el.addEventListener("contextmenu", onContextMenu);
250
+ return () => {
251
+ drag.disable();
252
+ el.removeEventListener("mousedown", onMouseDown);
253
+ el.removeEventListener("mouseenter", onMouseEnter);
254
+ el.removeEventListener("mouseleave", onMouseLeave);
255
+ window.removeEventListener("mouseup", onMouseUp);
256
+ el.removeEventListener("contextmenu", onContextMenu);
257
+ el.style.cursor = "";
258
+ };
259
+ }, [ctx]);
260
+ }
261
+
262
+ export {
263
+ useGenesisGL,
264
+ useRenderer,
265
+ useWorldToScreen,
266
+ useCameraControls,
267
+ useCameraMouseDrag
268
+ };
269
+ //# sourceMappingURL=chunk-MAGVIIUT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useGenesisGL.ts","../src/hooks/useRenderer.ts","../src/hooks/useWorldToScreen.ts","../src/hooks/useCameraControls.ts","../src/hooks/useCameraMouseDrag.ts"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport {\n WebGLCore,\n WebGLCore as WebGLCoreImpl,\n Scene,\n Scene as SceneImpl,\n Renderer,\n Renderer as RendererImpl,\n Viewport,\n Viewport as ViewportImpl,\n type Model,\n} from '@fonsecabarreto/genesis-gl-core/Core';\nimport { loadOBJWithMTL } from '@fonsecabarreto/genesis-gl-core/Core/utils/parse-obj';\nexport interface LoadOBJOptions {\n mtlUrl?: string | null;\n translation?: [number, number, number];\n scale?: [number, number, number];\n}\n\nexport interface GenesisGLContext {\n renderer: Renderer | null;\n scene: Scene | null;\n viewport: Viewport | null;\n webglCore: WebGLCore | null;\n loadOBJ: (objUrl: string, options?: LoadOBJOptions) => Promise<Model>;\n}\n\nexport interface UseGenesisGLOptions {\n canvasRef: React.RefObject<HTMLCanvasElement>;\n width?: number;\n height?: number;\n initialYaw?: number;\n initialPitch?: number;\n initialZoom?: number;\n onReady?: (context: GenesisGLContext) => void;\n onError?: (error: Error) => void;\n}\n\nconst nullLoadOBJ = (): Promise<never> =>\n Promise.reject(new Error('GenesisGL not initialized'));\n\nexport function useGenesisGL(options: UseGenesisGLOptions): GenesisGLContext {\n const [context, setContext] = useState<GenesisGLContext>({\n renderer: null,\n scene: null,\n viewport: null,\n webglCore: null,\n loadOBJ: nullLoadOBJ,\n });\n\n const contextRef = useRef<GenesisGLContext>(context);\n\n useEffect(() => {\n const {\n canvasRef,\n onReady,\n onError,\n width,\n height,\n initialYaw,\n initialPitch,\n initialZoom,\n } = options;\n if (!canvasRef.current) return;\n\n try {\n const canvas = canvasRef.current;\n const vpWidth = width ?? window.innerWidth;\n const vpHeight = height ?? window.innerHeight;\n\n const webglCore = new WebGLCoreImpl(canvas);\n const viewport = new ViewportImpl(canvas, vpWidth, vpHeight, webglCore, {\n pointerLock: false,\n });\n const renderer = new RendererImpl(webglCore, viewport);\n const scene = SceneImpl.withDefaultLights(webglCore);\n\n viewport.camera.target = [0, 0, 0];\n viewport.camera.position = [4, 2, 8];\n if (initialYaw !== undefined) viewport.camera.yaw = initialYaw;\n if (initialPitch !== undefined) viewport.camera.pitch = initialPitch;\n if (initialZoom !== undefined) viewport.camera.setZoom(initialZoom);\n viewport.camera.invalidate();\n\n const loadOBJ = (objUrl: string, opts: LoadOBJOptions = {}) =>\n loadOBJWithMTL(\n webglCore,\n objUrl,\n opts.mtlUrl ?? null,\n opts.translation,\n opts.scale,\n );\n\n const ctx: GenesisGLContext = {\n renderer,\n scene,\n viewport,\n webglCore,\n loadOBJ,\n };\n contextRef.current = ctx;\n setContext(ctx);\n\n if (onReady) onReady(ctx);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n console.error('Failed to initialize GenesisGL:', err);\n if (onError) onError(err);\n }\n\n return () => {\n const { scene, viewport, webglCore } = contextRef.current;\n if (scene && webglCore) scene.dispose(webglCore);\n if (viewport) viewport.dispose();\n if (webglCore) webglCore.dispose();\n };\n }, []);\n\n return context;\n}\n","import { useRef, useEffect } from 'react';\nimport type { Renderer } from '@fonsecabarreto/genesis-gl-core/Core';\n\nexport interface UseRendererOptions {\n renderer: Renderer | null;\n onFrame?: (time: number) => void;\n enabled?: boolean;\n}\n\n/**\n * Hook to manage the render loop with requestAnimationFrame.\n * Handles starting/stopping animation and cleanup.\n */\nexport function useRenderer(options: UseRendererOptions): void {\n const { renderer, onFrame, enabled = true } = options;\n const animationIdRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (!renderer || !enabled) return;\n\n const animate = (time: number) => {\n if (onFrame) onFrame(time);\n animationIdRef.current = requestAnimationFrame(animate);\n };\n\n animationIdRef.current = requestAnimationFrame(animate);\n\n return () => {\n if (animationIdRef.current !== null) {\n cancelAnimationFrame(animationIdRef.current);\n }\n };\n }, [renderer, onFrame, enabled]);\n}\n","import { useState, useCallback } from 'react';\nimport type { GenesisGLContext } from './useGenesisGL';\n\nexport interface ScreenPoint {\n x: number;\n y: number;\n visible: boolean;\n}\n\nfunction mat4TransformVec4(m: Float32Array, x: number, y: number, z: number, w: number) {\n return {\n x: m[0] * x + m[4] * y + m[8] * z + m[12] * w,\n y: m[1] * x + m[5] * y + m[9] * z + m[13] * w,\n z: m[2] * x + m[6] * y + m[10] * z + m[14] * w,\n w: m[3] * x + m[7] * y + m[11] * z + m[15] * w,\n };\n}\n\nexport function useWorldToScreen(context: GenesisGLContext | null) {\n const [, forceUpdate] = useState(0);\n\n const project = useCallback(\n (worldX: number, worldY: number, worldZ: number): ScreenPoint => {\n if (!context?.viewport) return { x: 0, y: 0, visible: false };\n\n const { viewport } = context;\n const camera = viewport.camera;\n const canvas = viewport.getCanvas();\n\n const view = camera.getViewMatrix() as unknown as Float32Array;\n const proj = camera.getProjectionMatrix() as unknown as Float32Array;\n\n // view * worldPos\n const v = mat4TransformVec4(view, worldX, worldY, worldZ, 1);\n // proj * (view * worldPos)\n const c = mat4TransformVec4(proj, v.x, v.y, v.z, v.w);\n\n if (Math.abs(c.w) < 1e-6) return { x: 0, y: 0, visible: false };\n\n const ndcX = c.x / c.w;\n const ndcY = c.y / c.w;\n const ndcZ = c.z / c.w;\n\n const visible = ndcZ > -1 && ndcZ < 1 && Math.abs(ndcX) < 1.2 && Math.abs(ndcY) < 1.2;\n\n return {\n x: ((ndcX + 1) * 0.5) * canvas.clientWidth,\n y: ((1 - ndcY) * 0.5) * canvas.clientHeight,\n visible,\n };\n },\n [context],\n );\n\n // expose a tick function callers can plug into onFrame to re-render\n const tick = useCallback(() => forceUpdate((n) => n + 1), []);\n\n return { project, tick };\n}\n","import { useCallback, useState } from 'react';\nimport type { GenesisGLContext } from './useGenesisGL';\n\nexport interface CameraState {\n yaw: number;\n pitch: number;\n zoom: number;\n}\n\nexport interface UseCameraControlsResult {\n camera: CameraState;\n rotate: (deltaYaw: number, deltaPitch: number) => void;\n setYaw: (yaw: number) => void;\n setPitch: (pitch: number) => void;\n zoomBy: (delta: number) => void;\n setZoom: (zoom: number) => void;\n reset: () => void;\n}\n\nconst DEFAULT_YAW = 0;\nconst DEFAULT_PITCH = 0;\nconst DEFAULT_ZOOM = 1;\n\nexport function useCameraControls(\n ctx: GenesisGLContext | null,\n): UseCameraControlsResult {\n const [camera, setCameraState] = useState<CameraState>({\n yaw: DEFAULT_YAW,\n pitch: DEFAULT_PITCH,\n zoom: DEFAULT_ZOOM,\n });\n\n const sync = useCallback((c: { yaw: number; pitch: number; zoom: number }) => {\n setCameraState({ yaw: c.yaw, pitch: c.pitch, zoom: c.zoom });\n }, []);\n\n const rotate = useCallback(\n (deltaYaw: number, deltaPitch: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.rotate(deltaYaw, deltaPitch);\n sync(c);\n },\n [ctx, sync],\n );\n\n const zoomBy = useCallback(\n (delta: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.zoomBy(delta);\n sync(c);\n },\n [ctx, sync],\n );\n\n const setZoom = useCallback(\n (zoom: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.setZoom(zoom);\n sync(c);\n },\n [ctx, sync],\n );\n\n const setYaw = useCallback(\n (yaw: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.yaw = yaw;\n c.invalidate();\n sync(c);\n },\n [ctx, sync],\n );\n\n const setPitch = useCallback(\n (pitch: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.pitch = pitch;\n c.invalidate();\n sync(c);\n },\n [ctx, sync],\n );\n\n const reset = useCallback(() => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.yaw = DEFAULT_YAW;\n c.pitch = DEFAULT_PITCH;\n c.invalidate();\n c.setZoom(DEFAULT_ZOOM);\n sync(c);\n }, [ctx, sync]);\n\n return { camera, rotate, setYaw, setPitch, zoomBy, setZoom, reset };\n}\n","import { useEffect, useRef } from 'react';\nimport { MouseDragControl } from '@fonsecabarreto/genesis-gl-core/Core';\nimport { useCameraControls } from './useCameraControls';\nimport type { GenesisGLContext } from './useGenesisGL';\n\nconst SENSITIVITY = 0.008;\n\nexport function useCameraMouseDrag(\n ctx: GenesisGLContext | null,\n canvasRef: React.RefObject<HTMLElement | null>,\n) {\n const { rotate } = useCameraControls(ctx);\n const rotateRef = useRef(rotate);\n rotateRef.current = rotate;\n\n useEffect(() => {\n const el = canvasRef.current;\n if (!el || !ctx) return;\n\n const drag = new MouseDragControl(el);\n\n const onDrag = (dx: number, dy: number, button: number) => {\n if (button !== 2) return;\n rotateRef.current(-dx * SENSITIVITY, dy * SENSITIVITY);\n };\n\n drag.onChange(onDrag);\n drag.enable();\n\n const onMouseDown = (e: MouseEvent) => {\n if (e.button !== 2) return;\n el.style.cursor = 'grabbing';\n };\n\n const onMouseUp = (e: MouseEvent) => {\n if (e.button !== 2) return;\n el.style.cursor = 'grab';\n };\n\n const onMouseEnter = () => {\n el.style.cursor = 'grab';\n };\n\n const onMouseLeave = () => {\n el.style.cursor = '';\n };\n\n const onContextMenu = (e: Event) => e.preventDefault();\n\n el.addEventListener('mousedown', onMouseDown);\n el.addEventListener('mouseenter', onMouseEnter);\n el.addEventListener('mouseleave', onMouseLeave);\n window.addEventListener('mouseup', onMouseUp);\n el.addEventListener('contextmenu', onContextMenu);\n\n return () => {\n drag.disable();\n el.removeEventListener('mousedown', onMouseDown);\n el.removeEventListener('mouseenter', onMouseEnter);\n el.removeEventListener('mouseleave', onMouseLeave);\n window.removeEventListener('mouseup', onMouseUp);\n el.removeEventListener('contextmenu', onContextMenu);\n el.style.cursor = '';\n };\n }, [ctx]);\n}\n"],"mappings":"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","names":["useRef","useEffect","useState","useCallback","useState","useEffect","useRef","useRef","useEffect"]}
@@ -0,0 +1,267 @@
1
+ // src/hooks/useGenesisGL.ts
2
+ import { useRef, useEffect, useState } from "react";
3
+ import { WebGLCore as WebGLCoreImpl } from "@fonsecabarreto/genesis-gl-core/Core/classes/WebGLCore";
4
+ import { Viewport as ViewportImpl } from "@fonsecabarreto/genesis-gl-core/Core/classes/Viewport";
5
+ import { Renderer as RendererImpl } from "@fonsecabarreto/genesis-gl-core/Core/classes/Renderer";
6
+ import { Scene as SceneImpl } from "@fonsecabarreto/genesis-gl-core/Core/classes/Scene";
7
+ import { loadOBJWithMTL } from "@fonsecabarreto/genesis-gl-core/Core/utils/parse-obj";
8
+ var nullLoadOBJ = () => Promise.reject(new Error("GenesisGL not initialized"));
9
+ function useGenesisGL(options) {
10
+ const [context, setContext] = useState({
11
+ renderer: null,
12
+ scene: null,
13
+ viewport: null,
14
+ webglCore: null,
15
+ loadOBJ: nullLoadOBJ
16
+ });
17
+ const contextRef = useRef(context);
18
+ useEffect(() => {
19
+ const {
20
+ canvasRef,
21
+ onReady,
22
+ onError,
23
+ width,
24
+ height,
25
+ initialYaw,
26
+ initialPitch,
27
+ initialZoom
28
+ } = options;
29
+ if (!canvasRef.current) return;
30
+ try {
31
+ const canvas = canvasRef.current;
32
+ const vpWidth = width ?? window.innerWidth;
33
+ const vpHeight = height ?? window.innerHeight;
34
+ const webglCore = new WebGLCoreImpl(canvas);
35
+ const viewport = new ViewportImpl(canvas, vpWidth, vpHeight, webglCore, {
36
+ pointerLock: false
37
+ });
38
+ const renderer = new RendererImpl(webglCore, viewport);
39
+ const scene = SceneImpl.withDefaultLights(webglCore);
40
+ viewport.camera.target = [0, 0, 0];
41
+ viewport.camera.position = [4, 2, 8];
42
+ if (initialYaw !== void 0) viewport.camera.yaw = initialYaw;
43
+ if (initialPitch !== void 0) viewport.camera.pitch = initialPitch;
44
+ if (initialZoom !== void 0) viewport.camera.setZoom(initialZoom);
45
+ viewport.camera.invalidate();
46
+ const loadOBJ = (objUrl, opts = {}) => loadOBJWithMTL(
47
+ webglCore,
48
+ objUrl,
49
+ opts.mtlUrl ?? null,
50
+ opts.translation,
51
+ opts.scale
52
+ );
53
+ const ctx = {
54
+ renderer,
55
+ scene,
56
+ viewport,
57
+ webglCore,
58
+ loadOBJ
59
+ };
60
+ contextRef.current = ctx;
61
+ setContext(ctx);
62
+ if (onReady) onReady(ctx);
63
+ } catch (error) {
64
+ const err = error instanceof Error ? error : new Error(String(error));
65
+ console.error("Failed to initialize GenesisGL:", err);
66
+ if (onError) onError(err);
67
+ }
68
+ return () => {
69
+ const { scene, viewport, webglCore } = contextRef.current;
70
+ if (scene && webglCore) scene.dispose(webglCore);
71
+ if (viewport) viewport.dispose();
72
+ if (webglCore) webglCore.dispose();
73
+ };
74
+ }, []);
75
+ return context;
76
+ }
77
+
78
+ // src/hooks/useRenderer.ts
79
+ import { useRef as useRef2, useEffect as useEffect2 } from "react";
80
+ function useRenderer(options) {
81
+ const { renderer, onFrame, enabled = true } = options;
82
+ const animationIdRef = useRef2(null);
83
+ useEffect2(() => {
84
+ if (!renderer || !enabled) return;
85
+ const animate = (time) => {
86
+ if (onFrame) onFrame(time);
87
+ animationIdRef.current = requestAnimationFrame(animate);
88
+ };
89
+ animationIdRef.current = requestAnimationFrame(animate);
90
+ return () => {
91
+ if (animationIdRef.current !== null) {
92
+ cancelAnimationFrame(animationIdRef.current);
93
+ }
94
+ };
95
+ }, [renderer, onFrame, enabled]);
96
+ }
97
+
98
+ // src/hooks/useWorldToScreen.ts
99
+ import { useState as useState2, useCallback } from "react";
100
+ function mat4TransformVec4(m, x, y, z, w) {
101
+ return {
102
+ x: m[0] * x + m[4] * y + m[8] * z + m[12] * w,
103
+ y: m[1] * x + m[5] * y + m[9] * z + m[13] * w,
104
+ z: m[2] * x + m[6] * y + m[10] * z + m[14] * w,
105
+ w: m[3] * x + m[7] * y + m[11] * z + m[15] * w
106
+ };
107
+ }
108
+ function useWorldToScreen(context) {
109
+ const [, forceUpdate] = useState2(0);
110
+ const project = useCallback(
111
+ (worldX, worldY, worldZ) => {
112
+ if (!context?.viewport) return { x: 0, y: 0, visible: false };
113
+ const { viewport } = context;
114
+ const camera = viewport.camera;
115
+ const canvas = viewport.getCanvas();
116
+ const view = camera.getViewMatrix();
117
+ const proj = camera.getProjectionMatrix();
118
+ const v = mat4TransformVec4(view, worldX, worldY, worldZ, 1);
119
+ const c = mat4TransformVec4(proj, v.x, v.y, v.z, v.w);
120
+ if (Math.abs(c.w) < 1e-6) return { x: 0, y: 0, visible: false };
121
+ const ndcX = c.x / c.w;
122
+ const ndcY = c.y / c.w;
123
+ const ndcZ = c.z / c.w;
124
+ const visible = ndcZ > -1 && ndcZ < 1 && Math.abs(ndcX) < 1.2 && Math.abs(ndcY) < 1.2;
125
+ return {
126
+ x: (ndcX + 1) * 0.5 * canvas.clientWidth,
127
+ y: (1 - ndcY) * 0.5 * canvas.clientHeight,
128
+ visible
129
+ };
130
+ },
131
+ [context]
132
+ );
133
+ const tick = useCallback(() => forceUpdate((n) => n + 1), []);
134
+ return { project, tick };
135
+ }
136
+
137
+ // src/hooks/useCameraControls.ts
138
+ import { useCallback as useCallback2, useState as useState3 } from "react";
139
+ var DEFAULT_YAW = 0;
140
+ var DEFAULT_PITCH = 0;
141
+ var DEFAULT_ZOOM = 1;
142
+ function useCameraControls(ctx) {
143
+ const [camera, setCameraState] = useState3({
144
+ yaw: DEFAULT_YAW,
145
+ pitch: DEFAULT_PITCH,
146
+ zoom: DEFAULT_ZOOM
147
+ });
148
+ const sync = useCallback2((c) => {
149
+ setCameraState({ yaw: c.yaw, pitch: c.pitch, zoom: c.zoom });
150
+ }, []);
151
+ const rotate = useCallback2(
152
+ (deltaYaw, deltaPitch) => {
153
+ const c = ctx?.viewport?.camera;
154
+ if (!c) return;
155
+ c.rotate(deltaYaw, deltaPitch);
156
+ sync(c);
157
+ },
158
+ [ctx, sync]
159
+ );
160
+ const zoomBy = useCallback2(
161
+ (delta) => {
162
+ const c = ctx?.viewport?.camera;
163
+ if (!c) return;
164
+ c.zoomBy(delta);
165
+ sync(c);
166
+ },
167
+ [ctx, sync]
168
+ );
169
+ const setZoom = useCallback2(
170
+ (zoom) => {
171
+ const c = ctx?.viewport?.camera;
172
+ if (!c) return;
173
+ c.setZoom(zoom);
174
+ sync(c);
175
+ },
176
+ [ctx, sync]
177
+ );
178
+ const setYaw = useCallback2(
179
+ (yaw) => {
180
+ const c = ctx?.viewport?.camera;
181
+ if (!c) return;
182
+ c.yaw = yaw;
183
+ c.invalidate();
184
+ sync(c);
185
+ },
186
+ [ctx, sync]
187
+ );
188
+ const setPitch = useCallback2(
189
+ (pitch) => {
190
+ const c = ctx?.viewport?.camera;
191
+ if (!c) return;
192
+ c.pitch = pitch;
193
+ c.invalidate();
194
+ sync(c);
195
+ },
196
+ [ctx, sync]
197
+ );
198
+ const reset = useCallback2(() => {
199
+ const c = ctx?.viewport?.camera;
200
+ if (!c) return;
201
+ c.yaw = DEFAULT_YAW;
202
+ c.pitch = DEFAULT_PITCH;
203
+ c.invalidate();
204
+ c.setZoom(DEFAULT_ZOOM);
205
+ sync(c);
206
+ }, [ctx, sync]);
207
+ return { camera, rotate, setYaw, setPitch, zoomBy, setZoom, reset };
208
+ }
209
+
210
+ // src/hooks/useCameraMouseDrag.ts
211
+ import { useEffect as useEffect3, useRef as useRef3 } from "react";
212
+ import { MouseDragControl } from "@fonsecabarreto/genesis-gl-core/Core";
213
+ var SENSITIVITY = 8e-3;
214
+ function useCameraMouseDrag(ctx, canvasRef) {
215
+ const { rotate } = useCameraControls(ctx);
216
+ const rotateRef = useRef3(rotate);
217
+ rotateRef.current = rotate;
218
+ useEffect3(() => {
219
+ const el = canvasRef.current;
220
+ if (!el || !ctx) return;
221
+ const drag = new MouseDragControl(el);
222
+ const onDrag = (dx, dy, button) => {
223
+ if (button !== 2) return;
224
+ rotateRef.current(-dx * SENSITIVITY, dy * SENSITIVITY);
225
+ };
226
+ drag.onChange(onDrag);
227
+ drag.enable();
228
+ const onMouseDown = (e) => {
229
+ if (e.button !== 2) return;
230
+ el.style.cursor = "grabbing";
231
+ };
232
+ const onMouseUp = (e) => {
233
+ if (e.button !== 2) return;
234
+ el.style.cursor = "grab";
235
+ };
236
+ const onMouseEnter = () => {
237
+ el.style.cursor = "grab";
238
+ };
239
+ const onMouseLeave = () => {
240
+ el.style.cursor = "";
241
+ };
242
+ const onContextMenu = (e) => e.preventDefault();
243
+ el.addEventListener("mousedown", onMouseDown);
244
+ el.addEventListener("mouseenter", onMouseEnter);
245
+ el.addEventListener("mouseleave", onMouseLeave);
246
+ window.addEventListener("mouseup", onMouseUp);
247
+ el.addEventListener("contextmenu", onContextMenu);
248
+ return () => {
249
+ drag.disable();
250
+ el.removeEventListener("mousedown", onMouseDown);
251
+ el.removeEventListener("mouseenter", onMouseEnter);
252
+ el.removeEventListener("mouseleave", onMouseLeave);
253
+ window.removeEventListener("mouseup", onMouseUp);
254
+ el.removeEventListener("contextmenu", onContextMenu);
255
+ el.style.cursor = "";
256
+ };
257
+ }, [ctx]);
258
+ }
259
+
260
+ export {
261
+ useGenesisGL,
262
+ useRenderer,
263
+ useWorldToScreen,
264
+ useCameraControls,
265
+ useCameraMouseDrag
266
+ };
267
+ //# sourceMappingURL=chunk-MINHVZ2M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useGenesisGL.ts","../src/hooks/useRenderer.ts","../src/hooks/useWorldToScreen.ts","../src/hooks/useCameraControls.ts","../src/hooks/useCameraMouseDrag.ts"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport type {\n WebGLCore,\n Scene,\n Renderer,\n Viewport,\n Model,\n} from '@fonsecabarreto/genesis-gl-core/Core';\nimport { WebGLCore as WebGLCoreImpl } from '@fonsecabarreto/genesis-gl-core/Core/classes/WebGLCore';\nimport { Viewport as ViewportImpl } from '@fonsecabarreto/genesis-gl-core/Core/classes/Viewport';\nimport { Renderer as RendererImpl } from '@fonsecabarreto/genesis-gl-core/Core/classes/Renderer';\nimport { Scene as SceneImpl } from '@fonsecabarreto/genesis-gl-core/Core/classes/Scene';\nimport { loadOBJWithMTL } from '@fonsecabarreto/genesis-gl-core/Core/utils/parse-obj';\nexport interface LoadOBJOptions {\n mtlUrl?: string | null;\n translation?: [number, number, number];\n scale?: [number, number, number];\n}\n\nexport interface GenesisGLContext {\n renderer: Renderer | null;\n scene: Scene | null;\n viewport: Viewport | null;\n webglCore: WebGLCore | null;\n loadOBJ: (objUrl: string, options?: LoadOBJOptions) => Promise<Model>;\n}\n\nexport interface UseGenesisGLOptions {\n canvasRef: React.RefObject<HTMLCanvasElement>;\n width?: number;\n height?: number;\n initialYaw?: number;\n initialPitch?: number;\n initialZoom?: number;\n onReady?: (context: GenesisGLContext) => void;\n onError?: (error: Error) => void;\n}\n\nconst nullLoadOBJ = (): Promise<never> =>\n Promise.reject(new Error('GenesisGL not initialized'));\n\nexport function useGenesisGL(options: UseGenesisGLOptions): GenesisGLContext {\n const [context, setContext] = useState<GenesisGLContext>({\n renderer: null,\n scene: null,\n viewport: null,\n webglCore: null,\n loadOBJ: nullLoadOBJ,\n });\n\n const contextRef = useRef<GenesisGLContext>(context);\n\n useEffect(() => {\n const {\n canvasRef,\n onReady,\n onError,\n width,\n height,\n initialYaw,\n initialPitch,\n initialZoom,\n } = options;\n if (!canvasRef.current) return;\n\n try {\n const canvas = canvasRef.current;\n const vpWidth = width ?? window.innerWidth;\n const vpHeight = height ?? window.innerHeight;\n\n const webglCore = new WebGLCoreImpl(canvas);\n const viewport = new ViewportImpl(canvas, vpWidth, vpHeight, webglCore, {\n pointerLock: false,\n });\n const renderer = new RendererImpl(webglCore, viewport);\n const scene = SceneImpl.withDefaultLights(webglCore);\n\n viewport.camera.target = [0, 0, 0];\n viewport.camera.position = [4, 2, 8];\n if (initialYaw !== undefined) viewport.camera.yaw = initialYaw;\n if (initialPitch !== undefined) viewport.camera.pitch = initialPitch;\n if (initialZoom !== undefined) viewport.camera.setZoom(initialZoom);\n viewport.camera.invalidate();\n\n const loadOBJ = (objUrl: string, opts: LoadOBJOptions = {}) =>\n loadOBJWithMTL(\n webglCore,\n objUrl,\n opts.mtlUrl ?? null,\n opts.translation,\n opts.scale,\n );\n\n const ctx: GenesisGLContext = {\n renderer,\n scene,\n viewport,\n webglCore,\n loadOBJ,\n };\n contextRef.current = ctx;\n setContext(ctx);\n\n if (onReady) onReady(ctx);\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n console.error('Failed to initialize GenesisGL:', err);\n if (onError) onError(err);\n }\n\n return () => {\n const { scene, viewport, webglCore } = contextRef.current;\n if (scene && webglCore) scene.dispose(webglCore);\n if (viewport) viewport.dispose();\n if (webglCore) webglCore.dispose();\n };\n }, []);\n\n return context;\n}\n","import { useRef, useEffect } from 'react';\nimport type { Renderer } from '../../../GenesisGL/src/Core/classes/Renderer';\n\nexport interface UseRendererOptions {\n renderer: Renderer | null;\n onFrame?: (time: number) => void;\n enabled?: boolean;\n}\n\n/**\n * Hook to manage the render loop with requestAnimationFrame.\n * Handles starting/stopping animation and cleanup.\n */\nexport function useRenderer(options: UseRendererOptions): void {\n const { renderer, onFrame, enabled = true } = options;\n const animationIdRef = useRef<number | null>(null);\n\n useEffect(() => {\n if (!renderer || !enabled) return;\n\n const animate = (time: number) => {\n if (onFrame) onFrame(time);\n animationIdRef.current = requestAnimationFrame(animate);\n };\n\n animationIdRef.current = requestAnimationFrame(animate);\n\n return () => {\n if (animationIdRef.current !== null) {\n cancelAnimationFrame(animationIdRef.current);\n }\n };\n }, [renderer, onFrame, enabled]);\n}\n","import { useState, useCallback } from 'react';\nimport type { GenesisGLContext } from './useGenesisGL';\n\nexport interface ScreenPoint {\n x: number;\n y: number;\n visible: boolean;\n}\n\nfunction mat4TransformVec4(m: Float32Array, x: number, y: number, z: number, w: number) {\n return {\n x: m[0] * x + m[4] * y + m[8] * z + m[12] * w,\n y: m[1] * x + m[5] * y + m[9] * z + m[13] * w,\n z: m[2] * x + m[6] * y + m[10] * z + m[14] * w,\n w: m[3] * x + m[7] * y + m[11] * z + m[15] * w,\n };\n}\n\nexport function useWorldToScreen(context: GenesisGLContext | null) {\n const [, forceUpdate] = useState(0);\n\n const project = useCallback(\n (worldX: number, worldY: number, worldZ: number): ScreenPoint => {\n if (!context?.viewport) return { x: 0, y: 0, visible: false };\n\n const { viewport } = context;\n const camera = viewport.camera;\n const canvas = viewport.getCanvas();\n\n const view = camera.getViewMatrix() as unknown as Float32Array;\n const proj = camera.getProjectionMatrix() as unknown as Float32Array;\n\n // view * worldPos\n const v = mat4TransformVec4(view, worldX, worldY, worldZ, 1);\n // proj * (view * worldPos)\n const c = mat4TransformVec4(proj, v.x, v.y, v.z, v.w);\n\n if (Math.abs(c.w) < 1e-6) return { x: 0, y: 0, visible: false };\n\n const ndcX = c.x / c.w;\n const ndcY = c.y / c.w;\n const ndcZ = c.z / c.w;\n\n const visible = ndcZ > -1 && ndcZ < 1 && Math.abs(ndcX) < 1.2 && Math.abs(ndcY) < 1.2;\n\n return {\n x: ((ndcX + 1) * 0.5) * canvas.clientWidth,\n y: ((1 - ndcY) * 0.5) * canvas.clientHeight,\n visible,\n };\n },\n [context],\n );\n\n // expose a tick function callers can plug into onFrame to re-render\n const tick = useCallback(() => forceUpdate((n) => n + 1), []);\n\n return { project, tick };\n}\n","import { useCallback, useState } from 'react';\nimport type { GenesisGLContext } from './useGenesisGL';\n\nexport interface CameraState {\n yaw: number;\n pitch: number;\n zoom: number;\n}\n\nexport interface UseCameraControlsResult {\n camera: CameraState;\n rotate: (deltaYaw: number, deltaPitch: number) => void;\n setYaw: (yaw: number) => void;\n setPitch: (pitch: number) => void;\n zoomBy: (delta: number) => void;\n setZoom: (zoom: number) => void;\n reset: () => void;\n}\n\nconst DEFAULT_YAW = 0;\nconst DEFAULT_PITCH = 0;\nconst DEFAULT_ZOOM = 1;\n\nexport function useCameraControls(\n ctx: GenesisGLContext | null,\n): UseCameraControlsResult {\n const [camera, setCameraState] = useState<CameraState>({\n yaw: DEFAULT_YAW,\n pitch: DEFAULT_PITCH,\n zoom: DEFAULT_ZOOM,\n });\n\n const sync = useCallback((c: { yaw: number; pitch: number; zoom: number }) => {\n setCameraState({ yaw: c.yaw, pitch: c.pitch, zoom: c.zoom });\n }, []);\n\n const rotate = useCallback(\n (deltaYaw: number, deltaPitch: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.rotate(deltaYaw, deltaPitch);\n sync(c);\n },\n [ctx, sync],\n );\n\n const zoomBy = useCallback(\n (delta: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.zoomBy(delta);\n sync(c);\n },\n [ctx, sync],\n );\n\n const setZoom = useCallback(\n (zoom: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.setZoom(zoom);\n sync(c);\n },\n [ctx, sync],\n );\n\n const setYaw = useCallback(\n (yaw: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.yaw = yaw;\n c.invalidate();\n sync(c);\n },\n [ctx, sync],\n );\n\n const setPitch = useCallback(\n (pitch: number) => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.pitch = pitch;\n c.invalidate();\n sync(c);\n },\n [ctx, sync],\n );\n\n const reset = useCallback(() => {\n const c = ctx?.viewport?.camera;\n if (!c) return;\n c.yaw = DEFAULT_YAW;\n c.pitch = DEFAULT_PITCH;\n c.invalidate();\n c.setZoom(DEFAULT_ZOOM);\n sync(c);\n }, [ctx, sync]);\n\n return { camera, rotate, setYaw, setPitch, zoomBy, setZoom, reset };\n}\n","import { useEffect, useRef } from 'react';\nimport { MouseDragControl } from '@fonsecabarreto/genesis-gl-core/Core';\nimport { useCameraControls } from './useCameraControls';\nimport type { GenesisGLContext } from './useGenesisGL';\n\nconst SENSITIVITY = 0.008;\n\nexport function useCameraMouseDrag(\n ctx: GenesisGLContext | null,\n canvasRef: React.RefObject<HTMLElement | null>,\n) {\n const { rotate } = useCameraControls(ctx);\n const rotateRef = useRef(rotate);\n rotateRef.current = rotate;\n\n useEffect(() => {\n const el = canvasRef.current;\n if (!el || !ctx) return;\n\n const drag = new MouseDragControl(el);\n\n const onDrag = (dx: number, dy: number, button: number) => {\n if (button !== 2) return;\n rotateRef.current(-dx * SENSITIVITY, dy * SENSITIVITY);\n };\n\n drag.onChange(onDrag);\n drag.enable();\n\n const onMouseDown = (e: MouseEvent) => {\n if (e.button !== 2) return;\n el.style.cursor = 'grabbing';\n };\n\n const onMouseUp = (e: MouseEvent) => {\n if (e.button !== 2) return;\n el.style.cursor = 'grab';\n };\n\n const onMouseEnter = () => {\n el.style.cursor = 'grab';\n };\n\n const onMouseLeave = () => {\n el.style.cursor = '';\n };\n\n const onContextMenu = (e: Event) => e.preventDefault();\n\n el.addEventListener('mousedown', onMouseDown);\n el.addEventListener('mouseenter', onMouseEnter);\n el.addEventListener('mouseleave', onMouseLeave);\n window.addEventListener('mouseup', onMouseUp);\n el.addEventListener('contextmenu', onContextMenu);\n\n return () => {\n drag.disable();\n el.removeEventListener('mousedown', onMouseDown);\n el.removeEventListener('mouseenter', onMouseEnter);\n el.removeEventListener('mouseleave', onMouseLeave);\n window.removeEventListener('mouseup', onMouseUp);\n el.removeEventListener('contextmenu', onContextMenu);\n el.style.cursor = '';\n };\n }, [ctx]);\n}\n"],"mappings":"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","names":["useRef","useEffect","useState","useCallback","useState","useEffect","useRef","useRef","useEffect"]}