@fonsecabarreto/genesis-gl-react 0.1.33 → 0.1.34
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/chunk-5SN3UL2T.js +825 -0
- package/dist/chunk-5SN3UL2T.js.map +1 -0
- package/dist/chunk-7AGC27WM.js +221 -0
- package/dist/chunk-7AGC27WM.js.map +1 -0
- package/dist/chunk-YFZKO7RD.js +153 -0
- package/dist/chunk-YFZKO7RD.js.map +1 -0
- package/dist/components/index.js +2 -2
- package/dist/hooks/index.js +2 -2
- package/dist/index.js +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/GenesisGLCanvas.tsx","../src/components/ViewportGizmo.tsx","../src/components/OrbitArrows.tsx","../src/components/RotationControls.tsx","../src/components/FaceLabel.tsx"],"sourcesContent":["import React, { useRef, useCallback, useEffect } from 'react';\nimport { useGenesisGL } from '../hooks/useGenesisGL';\nimport type { GenesisGLContext } from '../hooks/useGenesisGL';\nimport { useRenderer } from '../hooks/useRenderer';\nimport { useCameraControls } from '../hooks/useCameraControls';\n\nexport interface GenesisGLCanvasProps {\n onReady?: (context: GenesisGLContext) => void;\n onFrame?: (time: number) => void;\n width?: number;\n height?: number;\n initialYaw?: number;\n initialPitch?: number;\n initialZoom?: number;\n /** RGBA clear color, e.g. [0.05, 0.05, 0.05, 1] */\n background?: [number, number, number, number];\n style?: React.CSSProperties;\n className?: string;\n}\n\nfunction ResetButton({ onClick }: { onClick: () => void }) {\n return (\n <button\n onClick={onClick}\n title=\"Reset camera\"\n style={{\n position: 'absolute',\n top: 12,\n left: 12,\n width: 32,\n height: 32,\n borderRadius: 8,\n border: '1px solid rgba(255,255,255,0.1)',\n background: 'rgba(8,8,14,0.6)',\n backdropFilter: 'blur(8px)',\n color: 'rgba(255,255,255,0.6)',\n fontSize: 15,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n lineHeight: 1,\n padding: 0,\n transition: 'background 0.15s, color 0.15s',\n zIndex: 10,\n }}\n onMouseEnter={(e) => {\n (e.currentTarget as HTMLButtonElement).style.background =\n 'rgba(255,255,255,0.12)';\n (e.currentTarget as HTMLButtonElement).style.color = '#fff';\n }}\n onMouseLeave={(e) => {\n (e.currentTarget as HTMLButtonElement).style.background =\n 'rgba(8,8,14,0.6)';\n (e.currentTarget as HTMLButtonElement).style.color =\n 'rgba(255,255,255,0.6)';\n }}\n >\n ⊘\n </button>\n );\n}\n\nfunction CanvasInner({\n setRef,\n style,\n className,\n onDoubleClick,\n}: {\n setRef: (el: HTMLCanvasElement | null) => void;\n style?: React.CSSProperties;\n className?: string;\n onDoubleClick: () => void;\n}) {\n return (\n <canvas\n ref={setRef}\n onDoubleClick={onDoubleClick}\n style={{ display: 'block', width: '100%', height: '100%', ...style }}\n className={className}\n />\n );\n}\n\n// Inner component that has access to context for camera controls\nfunction GenesisGLCanvasInner({\n context,\n setRef,\n initialYaw,\n initialPitch,\n initialZoom,\n background,\n style,\n className,\n onFrame,\n}: {\n context: GenesisGLContext;\n setRef: (el: HTMLCanvasElement | null) => void;\n initialYaw?: number;\n initialPitch?: number;\n initialZoom?: number;\n background?: [number, number, number, number];\n style?: React.CSSProperties;\n className?: string;\n onFrame?: (time: number) => void;\n}) {\n const { reset, setYaw, setPitch, setZoom } = useCameraControls(context);\n const contextRef = useRef(context);\n contextRef.current = context;\n const onFrameRef = useRef(onFrame);\n onFrameRef.current = onFrame;\n\n const stableOnFrame = useCallback((time: number) => {\n const { renderer, scene } = contextRef.current;\n if (renderer && scene) {\n renderer.render(scene);\n onFrameRef.current?.(time);\n }\n }, []);\n\n useEffect(() => {\n if (context.renderer && background) {\n context.renderer.clearColor = background;\n }\n }, [context.renderer, background]);\n\n useRenderer({ renderer: context.renderer, onFrame: stableOnFrame });\n\n const handleReset = useCallback(() => {\n if (initialYaw !== undefined) setYaw(initialYaw);\n else reset();\n if (initialPitch !== undefined) setPitch(initialPitch);\n if (initialZoom !== undefined) setZoom(initialZoom);\n }, [reset, setYaw, setPitch, setZoom, initialYaw, initialPitch, initialZoom]);\n\n return (\n <>\n <ResetButton onClick={handleReset} />\n <CanvasInner\n setRef={setRef}\n style={style}\n className={className}\n onDoubleClick={handleReset}\n />\n </>\n );\n}\n\nexport const GenesisGLCanvas = React.forwardRef<\n HTMLCanvasElement,\n GenesisGLCanvasProps\n>(\n (\n {\n onReady,\n onFrame,\n width,\n height,\n initialYaw,\n initialPitch,\n initialZoom,\n background,\n style,\n className,\n },\n ref,\n ) => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n\n const setRef = useCallback(\n (el: HTMLCanvasElement | null) => {\n (\n canvasRef as React.MutableRefObject<HTMLCanvasElement | null>\n ).current = el;\n if (typeof ref === 'function') ref(el);\n else if (ref) ref.current = el;\n },\n [ref],\n );\n\n const genesisContext = useGenesisGL({\n canvasRef,\n width,\n height,\n initialYaw,\n initialPitch,\n initialZoom,\n onReady,\n });\n\n if (!genesisContext.renderer) {\n // Canvas not ready yet — render the raw canvas so the ref attaches\n return (\n <canvas\n ref={setRef}\n style={{ display: 'block', width: '100%', height: '100%', ...style }}\n className={className}\n />\n );\n }\n\n return (\n <GenesisGLCanvasInner\n context={genesisContext}\n setRef={setRef}\n initialYaw={initialYaw}\n initialPitch={initialPitch}\n initialZoom={initialZoom}\n background={background}\n style={style}\n className={className}\n onFrame={onFrame}\n />\n );\n },\n);\n\nGenesisGLCanvas.displayName = 'GenesisGLCanvas';\n","import React, { useRef, useEffect, useCallback } from 'react';\nimport { useCameraControls } from '../hooks/useCameraControls';\nimport type { GenesisGLContext } from '../hooks/useGenesisGL';\n\nexport interface ViewportGizmoProps {\n context: GenesisGLContext | null;\n /** Size of the gizmo widget in px. Default 96 */\n size?: number;\n /** Corner to anchor in. Default 'top-right' */\n position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n style?: React.CSSProperties;\n}\n\n// Each axis face: label, unit direction [x,y,z], color\nconst FACES = [\n { label: '+X', dir: [1, 0, 0] as [number, number, number], color: '#ff5370' },\n { label: '-X', dir: [-1, 0, 0] as [number, number, number], color: '#ff5370', dim: true },\n { label: '+Y', dir: [0, 1, 0] as [number, number, number], color: '#c3e88d' },\n { label: '-Y', dir: [0, -1, 0] as [number, number, number], color: '#c3e88d', dim: true },\n { label: '+Z', dir: [0, 0, 1] as [number, number, number], color: '#82aaff' },\n { label: '-Z', dir: [0, 0, -1] as [number, number, number], color: '#82aaff', dim: true },\n];\n\nconst SNAP_PITCH: Record<string, number> = {\n '+Y': Math.PI / 2 - 0.01,\n '-Y': -(Math.PI / 2 - 0.01),\n};\n\n/** Project a unit-sphere point through the camera's current yaw/pitch to a 2D gizmo position. */\nfunction project(\n dir: [number, number, number],\n yaw: number,\n pitch: number,\n radius: number,\n): { x: number; y: number; z: number } {\n // Rotate dir by the inverse camera orbit (yaw around Y, pitch around X)\n const [dx, dy, dz] = dir;\n\n // Apply inverse yaw (rotate around Y)\n const cosY = Math.cos(-yaw);\n const sinY = Math.sin(-yaw);\n const rx = dx * cosY + dz * sinY;\n const ry = dy;\n const rz = -dx * sinY + dz * cosY;\n\n // Apply inverse pitch (rotate around X)\n const cosP = Math.cos(-pitch);\n const sinP = Math.sin(-pitch);\n const fx = rx;\n const fy = ry * cosP - rz * sinP;\n const fz = ry * sinP + rz * cosP;\n\n return { x: fx * radius, y: -fy * radius, z: fz };\n}\n\nconst DRAG_SENSITIVITY = 0.008;\n\nexport function ViewportGizmo({\n context,\n size = 96,\n position = 'top-right',\n style,\n}: ViewportGizmoProps) {\n const { camera, setYaw, setPitch, rotate } = useCameraControls(context);\n const dragging = useRef(false);\n const lastPos = useRef({ x: 0, y: 0 });\n const containerRef = useRef<HTMLDivElement>(null);\n\n const onMouseDown = useCallback((e: React.MouseEvent) => {\n if (e.button !== 0) return;\n dragging.current = true;\n lastPos.current = { x: e.clientX, y: e.clientY };\n e.stopPropagation();\n e.preventDefault();\n }, []);\n\n useEffect(() => {\n const onMove = (e: MouseEvent) => {\n if (!dragging.current) return;\n const dx = e.clientX - lastPos.current.x;\n const dy = e.clientY - lastPos.current.y;\n lastPos.current = { x: e.clientX, y: e.clientY };\n rotate(-dx * DRAG_SENSITIVITY, -dy * DRAG_SENSITIVITY);\n };\n const onUp = () => { dragging.current = false; };\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n return () => {\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n };\n }, [rotate]);\n\n const snapTo = useCallback((face: typeof FACES[0]) => {\n const [dx, , dz] = face.dir;\n const targetYaw = Math.atan2(dx, dz);\n const targetPitch = SNAP_PITCH[face.label] ?? 0;\n setYaw(targetYaw);\n setPitch(targetPitch);\n }, [setYaw, setPitch]);\n\n const half = size / 2;\n const dotRadius = size * 0.14;\n const orbitRadius = half * 0.62;\n\n // Project all faces and sort back-to-front\n const projected = FACES.map((face) => ({\n ...face,\n ...project(face.dir, camera.yaw, camera.pitch, orbitRadius),\n })).sort((a, b) => a.z - b.z);\n\n const posStyle: React.CSSProperties =\n position === 'top-right' ? { top: 12, right: 12 } :\n position === 'top-left' ? { top: 12, left: 12 } :\n position === 'bottom-right' ? { bottom: 12, right: 12 } :\n { bottom: 12, left: 12 };\n\n return (\n <div\n ref={containerRef}\n onMouseDown={onMouseDown}\n style={{\n position: 'absolute',\n width: size,\n height: size,\n borderRadius: '50%',\n background: 'rgba(8,8,14,0.55)',\n border: '1px solid rgba(255,255,255,0.07)',\n backdropFilter: 'blur(8px)',\n cursor: dragging.current ? 'grabbing' : 'grab',\n userSelect: 'none',\n ...posStyle,\n ...style,\n }}\n >\n <svg\n width={size}\n height={size}\n viewBox={`${-half} ${-half} ${size} ${size}`}\n style={{ overflow: 'visible', display: 'block' }}\n >\n {/* Axis lines — draw behind dots */}\n {(['x', 'y', 'z'] as const).map((axis) => {\n const pos = projected.find((f) => f.label === `+${axis.toUpperCase()}`);\n const neg = projected.find((f) => f.label === `-${axis.toUpperCase()}`);\n if (!pos || !neg) return null;\n return (\n <line\n key={axis}\n x1={neg.x} y1={neg.y}\n x2={pos.x} y2={pos.y}\n stroke={pos.color}\n strokeWidth={1.5}\n strokeOpacity={0.35}\n />\n );\n })}\n\n {/* Dots — sorted back to front */}\n {projected.map((face) => {\n const isFront = face.z >= 0;\n const opacity = isFront ? 1 : 0.28;\n const r = isFront ? dotRadius : dotRadius * 0.75;\n return (\n <g\n key={face.label}\n style={{ cursor: 'pointer' }}\n onClick={(e) => { e.stopPropagation(); snapTo(face); }}\n >\n <circle\n cx={face.x} cy={face.y} r={r}\n fill={face.color}\n fillOpacity={opacity * (face.dim ? 0.6 : 1)}\n stroke={face.color}\n strokeWidth={isFront ? 1.5 : 0.5}\n strokeOpacity={opacity * 0.6}\n />\n {isFront && (\n <text\n x={face.x} y={face.y}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n fontSize={r * 0.75}\n fontWeight={700}\n fontFamily=\"system-ui, monospace\"\n fill=\"#fff\"\n fillOpacity={0.9}\n style={{ pointerEvents: 'none' }}\n >\n {face.label}\n </text>\n )}\n </g>\n );\n })}\n </svg>\n </div>\n );\n}\n","import React, { useCallback, useEffect, useRef } from 'react';\nimport { useCameraControls } from '../hooks/useCameraControls';\nimport { useWorldToScreen } from '../hooks/useWorldToScreen';\nimport type { GenesisGLContext } from '../hooks/useGenesisGL';\n\nexport interface OrbitArrowsProps {\n context: GenesisGLContext | null;\n /** World-space centre the rings are drawn around. Default [0,0,0] */\n center?: [number, number, number];\n /** Radius of the orbit rings in world units. Default 1.2 */\n radius?: number;\n /** How many points to sample per arc. Default 48 */\n segments?: number;\n style?: React.CSSProperties;\n}\n\nconst DRAG_SENSITIVITY = 0.008;\nconst ARC_GAP = 0.18; // fraction of full circle to leave as gap (for the arrow head end)\n\n/** Sample `n` points on a circle in a given plane, skipping the gap at the tip end. */\nfunction sampleArc(\n cx: number,\n cy: number,\n cz: number,\n radius: number,\n segments: number,\n plane: 'xz' | 'yz' | 'xy',\n angleOffset = 0,\n): [number, number, number][] {\n const pts: [number, number, number][] = [];\n const total = Math.PI * 2 * (1 - ARC_GAP);\n for (let i = 0; i <= segments; i++) {\n const t = angleOffset + (i / segments) * total;\n const cos = Math.cos(t);\n const sin = Math.sin(t);\n if (plane === 'xz') pts.push([cx + cos * radius, cy, cz + sin * radius]);\n else if (plane === 'yz') pts.push([cx, cy + cos * radius, cz + sin * radius]);\n else pts.push([cx + cos * radius, cy + sin * radius, cz]);\n }\n return pts;\n}\n\n/** Build an SVG arrowhead polygon string at the tip of the arc. */\nfunction arrowHead(\n tip: { x: number; y: number },\n prev: { x: number; y: number },\n size: number,\n): string {\n const dx = tip.x - prev.x;\n const dy = tip.y - prev.y;\n const len = Math.sqrt(dx * dx + dy * dy) || 1;\n const ux = dx / len;\n const uy = dy / len;\n const px = -uy;\n const py = ux;\n const base = { x: tip.x - ux * size, y: tip.y - uy * size };\n return [\n `${tip.x},${tip.y}`,\n `${base.x + px * size * 0.45},${base.y + py * size * 0.45}`,\n `${base.x - px * size * 0.45},${base.y - py * size * 0.45}`,\n ].join(' ');\n}\n\ninterface ArcConfig {\n plane: 'xz' | 'yz' | 'xy';\n color: string;\n /** Which camera delta to apply on drag: [yaw multiplier, pitch multiplier] */\n dragAxis: [number, number];\n angleOffset?: number;\n}\n\nconst ARCS: ArcConfig[] = [\n { plane: 'xz', color: '#c3e88d', dragAxis: [-1, 0], angleOffset: Math.PI * 0.6 },\n { plane: 'yz', color: '#82aaff', dragAxis: [0, -1], angleOffset: Math.PI * 0.1 },\n];\n\nexport function OrbitArrows({\n context,\n center = [0, 0, 0],\n radius = 1.2,\n segments = 48,\n style,\n}: OrbitArrowsProps) {\n const { rotate } = useCameraControls(context);\n const { project } = useWorldToScreen(context);\n\n // Per-arc drag state\n const dragging = useRef<{ arcIndex: number; lastX: number; lastY: number } | null>(null);\n const rotateRef = useRef(rotate);\n rotateRef.current = rotate;\n\n useEffect(() => {\n const onMove = (e: MouseEvent) => {\n if (!dragging.current) return;\n const dx = e.clientX - dragging.current.lastX;\n const dy = e.clientY - dragging.current.lastY;\n dragging.current.lastX = e.clientX;\n dragging.current.lastY = e.clientY;\n const arc = ARCS[dragging.current.arcIndex];\n rotateRef.current(\n dx * DRAG_SENSITIVITY * arc.dragAxis[0],\n dy * DRAG_SENSITIVITY * arc.dragAxis[1],\n );\n };\n const onUp = () => { dragging.current = null; };\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n return () => {\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n };\n }, []);\n\n const onArcMouseDown = useCallback((arcIndex: number, e: React.MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n dragging.current = { arcIndex, lastX: e.clientX, lastY: e.clientY };\n }, []);\n\n if (!context?.viewport) return null;\n\n const canvas = context.viewport.getCanvas();\n const W = canvas.clientWidth;\n const H = canvas.clientHeight;\n\n const [cx, cy, cz] = center;\n\n return (\n <svg\n style={{\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n overflow: 'visible',\n ...style,\n }}\n viewBox={`0 0 ${W} ${H}`}\n >\n {ARCS.map((arc, i) => {\n const worldPts = sampleArc(cx, cy, cz, radius, segments, arc.plane, arc.angleOffset);\n const screenPts = worldPts.map((p) => project(p[0], p[1], p[2]));\n\n // Skip arc if any segment is not visible\n if (screenPts.some((p) => !p.visible)) return null;\n\n const polyline = screenPts.map((p) => `${p.x},${p.y}`).join(' ');\n const tip = screenPts[screenPts.length - 1];\n const prev = screenPts[screenPts.length - 4];\n const arrowSize = 10;\n const arrowPoly = arrowHead(tip, prev, arrowSize);\n\n return (\n <g key={i} style={{ pointerEvents: 'auto', cursor: 'grab' }}>\n {/* Wider invisible stroke for easier grab */}\n <polyline\n points={polyline}\n fill=\"none\"\n stroke=\"transparent\"\n strokeWidth={14}\n onMouseDown={(e) => onArcMouseDown(i, e)}\n style={{ cursor: 'grab' }}\n />\n {/* Visible arc */}\n <polyline\n points={polyline}\n fill=\"none\"\n stroke={arc.color}\n strokeWidth={2.5}\n strokeOpacity={0.75}\n strokeLinecap=\"round\"\n style={{ pointerEvents: 'none' }}\n />\n {/* Arrow head */}\n <polygon\n points={arrowPoly}\n fill={arc.color}\n fillOpacity={0.9}\n style={{ pointerEvents: 'none' }}\n />\n </g>\n );\n })}\n </svg>\n );\n}\n","import React, { useState } from 'react';\nimport { useCameraControls } from '../hooks/useCameraControls';\nimport type { GenesisGLContext } from '../hooks/useGenesisGL';\n\nconst STEP = 0.05;\n\nfunction IconBtn({\n children,\n title,\n onClick,\n color,\n}: {\n children: React.ReactNode;\n title?: string;\n onClick: () => void;\n color: string;\n}) {\n const [active, setActive] = useState(false);\n const [hover, setHover] = useState(false);\n\n return (\n <button\n title={title}\n onClick={onClick}\n onMouseEnter={() => setHover(true)}\n onMouseLeave={() => { setHover(false); setActive(false); }}\n onMouseDown={() => setActive(true)}\n onMouseUp={() => setActive(false)}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '22px',\n height: '22px',\n border: `1px solid ${hover ? color + '88' : color + '33'}`,\n borderRadius: '5px',\n background: active ? color + '30' : hover ? color + '18' : color + '0c',\n color: hover ? color : color + 'aa',\n cursor: 'pointer',\n fontSize: '11px',\n fontWeight: 700,\n lineHeight: 1,\n padding: 0,\n transition: 'all 0.12s',\n transform: active ? 'scale(0.88)' : 'scale(1)',\n flexShrink: 0,\n }}\n >\n {children}\n </button>\n );\n}\n\nfunction AxisPill({\n label,\n color,\n value,\n onDec,\n onInc,\n onReset,\n}: {\n label: string;\n color: string;\n value: number;\n onDec: () => void;\n onInc: () => void;\n onReset: () => void;\n}) {\n const deg = ((value * 180) / Math.PI).toFixed(1);\n const normalized = ((value % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);\n const pct = (normalized / (Math.PI * 2)) * 100;\n\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '5px',\n background: color + '0a',\n border: `1px solid ${color}22`,\n borderRadius: '8px',\n padding: '5px 7px',\n flex: 1,\n minWidth: 0,\n }}\n >\n <div style={{ position: 'relative', width: '18px', height: '18px', flexShrink: 0 }}>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\">\n <circle cx=\"9\" cy=\"9\" r=\"7\" fill=\"none\" stroke={color + '22'} strokeWidth=\"2\" />\n <circle\n cx=\"9\" cy=\"9\" r=\"7\"\n fill=\"none\"\n stroke={color}\n strokeWidth=\"2\"\n strokeDasharray={`${(pct / 100) * 44} 44`}\n strokeLinecap=\"round\"\n transform=\"rotate(-90 9 9)\"\n style={{ transition: 'stroke-dasharray 0.1s ease' }}\n />\n </svg>\n <span\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '7px',\n fontWeight: 800,\n color,\n letterSpacing: '-0.02em',\n }}\n >\n {label}\n </span>\n </div>\n\n <span\n style={{\n fontSize: '10px',\n color: color + 'cc',\n fontVariantNumeric: 'tabular-nums',\n width: '36px',\n textAlign: 'right',\n flexShrink: 0,\n }}\n >\n {deg}°\n </span>\n\n <div style={{ display: 'flex', gap: '3px', marginLeft: '2px' }}>\n <IconBtn color={color} title={`−${label}`} onClick={onDec}>−</IconBtn>\n <IconBtn color={color} title={`+${label}`} onClick={onInc}>+</IconBtn>\n <IconBtn color={color + '88'} title=\"Reset\" onClick={onReset}>↺</IconBtn>\n </div>\n </div>\n );\n}\n\nexport interface RotationControlsProps {\n context: GenesisGLContext | null;\n style?: React.CSSProperties;\n}\n\nexport function RotationControls({ context, style }: RotationControlsProps) {\n const { camera, rotate, setYaw, setPitch, reset } = useCameraControls(context);\n\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '6px',\n background: 'rgba(8,8,12,0.78)',\n border: '1px solid rgba(255,255,255,0.07)',\n borderRadius: '12px',\n padding: '6px 8px',\n backdropFilter: 'blur(16px)',\n boxShadow: '0 4px 24px rgba(0,0,0,0.5)',\n fontFamily: '\"Inter\", system-ui, monospace',\n ...style,\n }}\n >\n <div\n title={context ? 'Camera ready' : 'Waiting for context…'}\n style={{\n width: '6px',\n height: '6px',\n borderRadius: '50%',\n background: context ? '#c3e88d' : '#555',\n boxShadow: context ? '0 0 6px #c3e88daa' : 'none',\n flexShrink: 0,\n transition: 'all 0.3s',\n }}\n />\n\n <AxisPill\n label=\"Yaw\"\n color=\"#ff5370\"\n value={camera.yaw}\n onDec={() => rotate(-STEP, 0)}\n onInc={() => rotate(STEP, 0)}\n onReset={() => setYaw(0)}\n />\n\n <AxisPill\n label=\"Pitch\"\n color=\"#82aaff\"\n value={camera.pitch}\n onDec={() => rotate(0, -STEP)}\n onInc={() => rotate(0, STEP)}\n onReset={() => setPitch(0)}\n />\n\n <IconBtn color=\"#ffffff\" title=\"Reset all\" onClick={reset}>⊘</IconBtn>\n </div>\n );\n}\n","import React from 'react';\nimport type { Model } from '@fonsecabarreto/genesis-gl-core/Core';\nimport type { GenesisGLContext } from '../hooks/useGenesisGL';\nimport { useWorldToScreen } from '../hooks/useWorldToScreen';\n\nexport interface FaceSkinProps {\n context: GenesisGLContext | null;\n model: Model | null;\n corners: [\n [number, number, number],\n [number, number, number],\n [number, number, number],\n [number, number, number],\n ];\n /** Width of the virtual surface div warped onto the face (px) */\n surfaceWidth?: number;\n /** Height of the virtual surface div warped onto the face (px) */\n surfaceHeight?: number;\n children?: React.ReactNode;\n style?: React.CSSProperties;\n className?: string;\n}\n\nfunction transformLocalToWorld(\n m: Float32Array,\n x: number,\n y: number,\n z: number,\n) {\n return {\n x: m[0] * x + m[4] * y + m[8] * z + m[12],\n y: m[1] * x + m[5] * y + m[9] * z + m[13],\n z: m[2] * x + m[6] * y + m[10] * z + m[14],\n };\n}\n\nfunction cross(\n ax: number,\n ay: number,\n az: number,\n bx: number,\n by: number,\n bz: number,\n) {\n return {\n x: ay * bz - az * by,\n y: az * bx - ax * bz,\n z: ax * by - ay * bx,\n };\n}\n\n/**\n * Solve for the homography matrix H (8 unknowns, h22=1) that maps\n * a w×h rectangle to four destination points using Gaussian elimination.\n * Returns [h00,h01,h02,h10,h11,h12,h20,h21] or null on failure.\n */\nfunction solveHomography(\n w: number,\n h: number,\n p: { x: number; y: number }[],\n): number[] | null {\n const [p0, p1, p2, p3] = p;\n const sx = [0, w, w, 0];\n const sy = [0, 0, h, h];\n const dx = [p0.x, p1.x, p2.x, p3.x];\n const dy = [p0.y, p1.y, p2.y, p3.y];\n\n // Build augmented 8×9 matrix\n const M: number[][] = [];\n for (let i = 0; i < 4; i++) {\n M.push([sx[i], sy[i], 1, 0, 0, 0, -dx[i] * sx[i], -dx[i] * sy[i], dx[i]]);\n M.push([0, 0, 0, sx[i], sy[i], 1, -dy[i] * sx[i], -dy[i] * sy[i], dy[i]]);\n }\n\n const n = 8;\n for (let col = 0; col < n; col++) {\n let maxRow = col;\n for (let row = col + 1; row < n; row++) {\n if (Math.abs(M[row][col]) > Math.abs(M[maxRow][col])) maxRow = row;\n }\n [M[col], M[maxRow]] = [M[maxRow], M[col]];\n if (Math.abs(M[col][col]) < 1e-10) return null;\n const pivot = M[col][col];\n for (let k = col; k <= n; k++) M[col][k] /= pivot;\n for (let row = 0; row < n; row++) {\n if (row === col) continue;\n const f = M[row][col];\n for (let k = col; k <= n; k++) M[row][k] -= f * M[col][k];\n }\n }\n\n return M.map((row) => row[n]);\n}\n\n/**\n * Build the CSS matrix3d string that perspectively maps a w×h div\n * (origin top-left) onto four screen-space points [p0,p1,p2,p3]\n * corresponding to the div corners (0,0),(w,0),(w,h),(0,h).\n */\nfunction buildMatrix3d(\n w: number,\n h: number,\n p: { x: number; y: number }[],\n): string {\n const hv = solveHomography(w, h, p);\n if (!hv) return 'none';\n const [h00, h01, h02, h10, h11, h12, h20, h21] = hv;\n // CSS matrix3d is column-major 4×4\n return (\n `matrix3d(` +\n `${h00},${h10},0,${h20},` +\n `${h01},${h11},0,${h21},` +\n `0,0,1,0,` +\n `${h02},${h12},0,1)`\n );\n}\n\nexport function FaceSkin({\n context,\n model,\n corners,\n children,\n style,\n className,\n surfaceWidth = 300,\n surfaceHeight = 200,\n}: FaceSkinProps) {\n const { project } = useWorldToScreen(context);\n\n if (!model || !context) return null;\n\n const mm = model.getModelMatrix() as unknown as Float32Array;\n\n const worldPts = corners.map(([lx, ly, lz]) =>\n transformLocalToWorld(mm, lx, ly, lz),\n );\n\n const e1x = worldPts[1].x - worldPts[0].x;\n const e1y = worldPts[1].y - worldPts[0].y;\n const e1z = worldPts[1].z - worldPts[0].z;\n const e2x = worldPts[3].x - worldPts[0].x;\n const e2y = worldPts[3].y - worldPts[0].y;\n const e2z = worldPts[3].z - worldPts[0].z;\n const normal = cross(e1x, e1y, e1z, e2x, e2y, e2z);\n\n const camera = context.viewport!.camera;\n const radius = Math.sqrt(\n (camera.position[0] - camera.target[0]) ** 2 +\n (camera.position[1] - camera.target[1]) ** 2 +\n (camera.position[2] - camera.target[2]) ** 2,\n );\n const eyeX =\n camera.target[0] + radius * Math.cos(camera.pitch) * Math.sin(camera.yaw);\n const eyeY = camera.target[1] + radius * Math.sin(camera.pitch);\n const eyeZ =\n camera.target[2] + radius * Math.cos(camera.pitch) * Math.cos(camera.yaw);\n\n const toCamera = {\n x: eyeX - worldPts[0].x,\n y: eyeY - worldPts[0].y,\n z: eyeZ - worldPts[0].z,\n };\n const dot =\n normal.x * toCamera.x + normal.y * toCamera.y + normal.z * toCamera.z;\n\n if (dot <= 0) return null;\n\n const screenPts = worldPts.map((w) => project(w.x, w.y, w.z));\n if (screenPts.some((pt) => !pt.visible)) return null;\n\n const [s0, s1, s2, s3] = screenPts;\n\n const signedArea =\n (s1.x - s0.x) * (s2.y - s0.y) - (s2.x - s0.x) * (s1.y - s0.y);\n const remapped =\n signedArea > 0\n ? [s2, s3, s0, s1]\n : [s3, s2, s1, s0];\n const matrix = buildMatrix3d(surfaceWidth, surfaceHeight, remapped);\n\n return (\n <div\n style={{\n position: 'absolute',\n inset: 0,\n pointerEvents: 'none',\n overflow: 'hidden',\n }}\n >\n <div\n className={className}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: surfaceWidth,\n height: surfaceHeight,\n transformOrigin: '0 0',\n transform: matrix,\n overflow: 'hidden',\n pointerEvents: 'auto',\n ...style,\n }}\n >\n {children}\n </div>\n </div>\n );\n}\n\nexport { FaceSkin as FaceLabel };\nexport type { FaceSkinProps as FaceLabelProps };\n"],"mappings":"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","names":["useRef","useEffect","useCallback","jsx","jsxs","useRef","useCallback","useEffect","useCallback","useEffect","useRef","jsx","jsxs","DRAG_SENSITIVITY","project","useRef","useEffect","useCallback","jsx","jsxs","jsx","project"]}
|
|
@@ -0,0 +1,221 @@
|
|
|
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 [canvas, setCanvas] = useState(null);
|
|
20
|
+
const contextRef = useRef(context);
|
|
21
|
+
const { canvasRef } = options;
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
setCanvas(canvasRef.current);
|
|
24
|
+
});
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const {
|
|
27
|
+
onReady,
|
|
28
|
+
onError,
|
|
29
|
+
width,
|
|
30
|
+
height,
|
|
31
|
+
initialYaw,
|
|
32
|
+
initialPitch,
|
|
33
|
+
initialZoom
|
|
34
|
+
} = options;
|
|
35
|
+
if (!canvas) return;
|
|
36
|
+
try {
|
|
37
|
+
const vpWidth = width ?? window.innerWidth;
|
|
38
|
+
const vpHeight = height ?? window.innerHeight;
|
|
39
|
+
const webglCore = new WebGLCoreImpl(canvas);
|
|
40
|
+
const viewport = new ViewportImpl(canvas, vpWidth, vpHeight, webglCore, {
|
|
41
|
+
pointerLock: false
|
|
42
|
+
});
|
|
43
|
+
const renderer = new RendererImpl(webglCore, viewport);
|
|
44
|
+
const scene = SceneImpl.withDefaultLights(webglCore);
|
|
45
|
+
viewport.camera.target = [0, 0, 0];
|
|
46
|
+
viewport.camera.position = [4, 2, 8];
|
|
47
|
+
if (initialYaw !== void 0) viewport.camera.yaw = initialYaw;
|
|
48
|
+
if (initialPitch !== void 0) viewport.camera.pitch = initialPitch;
|
|
49
|
+
if (initialZoom !== void 0) viewport.camera.setZoom(initialZoom);
|
|
50
|
+
viewport.camera.invalidate();
|
|
51
|
+
const loadOBJ = (objUrl, opts = {}) => loadOBJWithMTL(
|
|
52
|
+
webglCore,
|
|
53
|
+
objUrl,
|
|
54
|
+
opts.mtlUrl ?? null,
|
|
55
|
+
opts.translation,
|
|
56
|
+
opts.scale
|
|
57
|
+
);
|
|
58
|
+
const ctx = {
|
|
59
|
+
renderer,
|
|
60
|
+
scene,
|
|
61
|
+
viewport,
|
|
62
|
+
webglCore,
|
|
63
|
+
loadOBJ
|
|
64
|
+
};
|
|
65
|
+
contextRef.current = ctx;
|
|
66
|
+
setContext(ctx);
|
|
67
|
+
if (onReady) onReady(ctx);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
70
|
+
console.error("Failed to initialize GenesisGL:", err);
|
|
71
|
+
if (onError) onError(err);
|
|
72
|
+
}
|
|
73
|
+
return () => {
|
|
74
|
+
const { scene, viewport, webglCore } = contextRef.current;
|
|
75
|
+
if (scene && webglCore) scene.dispose(webglCore);
|
|
76
|
+
if (viewport) viewport.dispose();
|
|
77
|
+
if (webglCore) webglCore.dispose();
|
|
78
|
+
};
|
|
79
|
+
}, [canvas]);
|
|
80
|
+
return context;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/hooks/useRenderer.ts
|
|
84
|
+
import { useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
85
|
+
function useRenderer(options) {
|
|
86
|
+
const { renderer, onFrame, enabled = true } = options;
|
|
87
|
+
const animationIdRef = useRef2(null);
|
|
88
|
+
useEffect2(() => {
|
|
89
|
+
if (!renderer || !enabled) return;
|
|
90
|
+
const animate = (time) => {
|
|
91
|
+
if (onFrame) onFrame(time);
|
|
92
|
+
animationIdRef.current = requestAnimationFrame(animate);
|
|
93
|
+
};
|
|
94
|
+
animationIdRef.current = requestAnimationFrame(animate);
|
|
95
|
+
return () => {
|
|
96
|
+
if (animationIdRef.current !== null) {
|
|
97
|
+
cancelAnimationFrame(animationIdRef.current);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}, [renderer, onFrame, enabled]);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/hooks/useWorldToScreen.ts
|
|
104
|
+
import { useState as useState2, useCallback } from "react";
|
|
105
|
+
function mat4TransformVec4(m, x, y, z, w) {
|
|
106
|
+
return {
|
|
107
|
+
x: m[0] * x + m[4] * y + m[8] * z + m[12] * w,
|
|
108
|
+
y: m[1] * x + m[5] * y + m[9] * z + m[13] * w,
|
|
109
|
+
z: m[2] * x + m[6] * y + m[10] * z + m[14] * w,
|
|
110
|
+
w: m[3] * x + m[7] * y + m[11] * z + m[15] * w
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function useWorldToScreen(context) {
|
|
114
|
+
const [, forceUpdate] = useState2(0);
|
|
115
|
+
const project = useCallback(
|
|
116
|
+
(worldX, worldY, worldZ) => {
|
|
117
|
+
if (!context?.viewport) return { x: 0, y: 0, visible: false };
|
|
118
|
+
const { viewport } = context;
|
|
119
|
+
const camera = viewport.camera;
|
|
120
|
+
const canvas = viewport.getCanvas();
|
|
121
|
+
const view = camera.getViewMatrix();
|
|
122
|
+
const proj = camera.getProjectionMatrix();
|
|
123
|
+
const v = mat4TransformVec4(view, worldX, worldY, worldZ, 1);
|
|
124
|
+
const c = mat4TransformVec4(proj, v.x, v.y, v.z, v.w);
|
|
125
|
+
if (Math.abs(c.w) < 1e-6) return { x: 0, y: 0, visible: false };
|
|
126
|
+
const ndcX = c.x / c.w;
|
|
127
|
+
const ndcY = c.y / c.w;
|
|
128
|
+
const ndcZ = c.z / c.w;
|
|
129
|
+
const visible = ndcZ > -1 && ndcZ < 1 && Math.abs(ndcX) < 1.2 && Math.abs(ndcY) < 1.2;
|
|
130
|
+
return {
|
|
131
|
+
x: (ndcX + 1) * 0.5 * canvas.clientWidth,
|
|
132
|
+
y: (1 - ndcY) * 0.5 * canvas.clientHeight,
|
|
133
|
+
visible
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
[context]
|
|
137
|
+
);
|
|
138
|
+
const tick = useCallback(() => forceUpdate((n) => n + 1), []);
|
|
139
|
+
return { project, tick };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/hooks/useCameraControls.ts
|
|
143
|
+
import { useCallback as useCallback2, useState as useState3 } from "react";
|
|
144
|
+
var DEFAULT_YAW = 0;
|
|
145
|
+
var DEFAULT_PITCH = 0;
|
|
146
|
+
var DEFAULT_ZOOM = 1;
|
|
147
|
+
function useCameraControls(ctx) {
|
|
148
|
+
const [camera, setCameraState] = useState3({
|
|
149
|
+
yaw: DEFAULT_YAW,
|
|
150
|
+
pitch: DEFAULT_PITCH,
|
|
151
|
+
zoom: DEFAULT_ZOOM
|
|
152
|
+
});
|
|
153
|
+
const sync = useCallback2((c) => {
|
|
154
|
+
setCameraState({ yaw: c.yaw, pitch: c.pitch, zoom: c.zoom });
|
|
155
|
+
}, []);
|
|
156
|
+
const rotate = useCallback2(
|
|
157
|
+
(deltaYaw, deltaPitch) => {
|
|
158
|
+
const c = ctx?.viewport?.camera;
|
|
159
|
+
if (!c) return;
|
|
160
|
+
c.rotate(deltaYaw, deltaPitch);
|
|
161
|
+
sync(c);
|
|
162
|
+
},
|
|
163
|
+
[ctx, sync]
|
|
164
|
+
);
|
|
165
|
+
const zoomBy = useCallback2(
|
|
166
|
+
(delta) => {
|
|
167
|
+
const c = ctx?.viewport?.camera;
|
|
168
|
+
if (!c) return;
|
|
169
|
+
c.zoomBy(delta);
|
|
170
|
+
sync(c);
|
|
171
|
+
},
|
|
172
|
+
[ctx, sync]
|
|
173
|
+
);
|
|
174
|
+
const setZoom = useCallback2(
|
|
175
|
+
(zoom) => {
|
|
176
|
+
const c = ctx?.viewport?.camera;
|
|
177
|
+
if (!c) return;
|
|
178
|
+
c.setZoom(zoom);
|
|
179
|
+
sync(c);
|
|
180
|
+
},
|
|
181
|
+
[ctx, sync]
|
|
182
|
+
);
|
|
183
|
+
const setYaw = useCallback2(
|
|
184
|
+
(yaw) => {
|
|
185
|
+
const c = ctx?.viewport?.camera;
|
|
186
|
+
if (!c) return;
|
|
187
|
+
c.yaw = yaw;
|
|
188
|
+
c.invalidate();
|
|
189
|
+
sync(c);
|
|
190
|
+
},
|
|
191
|
+
[ctx, sync]
|
|
192
|
+
);
|
|
193
|
+
const setPitch = useCallback2(
|
|
194
|
+
(pitch) => {
|
|
195
|
+
const c = ctx?.viewport?.camera;
|
|
196
|
+
if (!c) return;
|
|
197
|
+
c.pitch = pitch;
|
|
198
|
+
c.invalidate();
|
|
199
|
+
sync(c);
|
|
200
|
+
},
|
|
201
|
+
[ctx, sync]
|
|
202
|
+
);
|
|
203
|
+
const reset = useCallback2(() => {
|
|
204
|
+
const c = ctx?.viewport?.camera;
|
|
205
|
+
if (!c) return;
|
|
206
|
+
c.yaw = DEFAULT_YAW;
|
|
207
|
+
c.pitch = DEFAULT_PITCH;
|
|
208
|
+
c.invalidate();
|
|
209
|
+
c.setZoom(DEFAULT_ZOOM);
|
|
210
|
+
sync(c);
|
|
211
|
+
}, [ctx, sync]);
|
|
212
|
+
return { camera, rotate, setYaw, setPitch, zoomBy, setZoom, reset };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export {
|
|
216
|
+
useGenesisGL,
|
|
217
|
+
useRenderer,
|
|
218
|
+
useWorldToScreen,
|
|
219
|
+
useCameraControls
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=chunk-7AGC27WM.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"],"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 // Track the canvas element so the effect re-runs if it remounts\n const [canvas, setCanvas] = useState<HTMLCanvasElement | null>(null);\n\n const contextRef = useRef<GenesisGLContext>(context);\n\n // Wrap the canvasRef so we detect when the actual DOM element changes\n const { canvasRef } = options;\n useEffect(() => {\n setCanvas(canvasRef.current);\n });\n\n useEffect(() => {\n const {\n onReady,\n onError,\n width,\n height,\n initialYaw,\n initialPitch,\n initialZoom,\n } = options;\n if (!canvas) return;\n\n try {\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 }, [canvas]);\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"],"mappings":"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","names":["useRef","useEffect","useState","useCallback","useState"]}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCameraControls
|
|
3
|
+
} from "./chunk-7AGC27WM.js";
|
|
4
|
+
|
|
5
|
+
// src/hooks/useModel.ts
|
|
6
|
+
import { useEffect, useRef, useState } from "react";
|
|
7
|
+
function useModel(context, options) {
|
|
8
|
+
const [result, setResult] = useState({
|
|
9
|
+
model: null,
|
|
10
|
+
loading: false,
|
|
11
|
+
error: null
|
|
12
|
+
});
|
|
13
|
+
const optionsRef = useRef(options);
|
|
14
|
+
optionsRef.current = options;
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (!context?.scene || !context?.loadOBJ || !context?.webglCore) return;
|
|
17
|
+
const { scene, loadOBJ, webglCore } = context;
|
|
18
|
+
const { name, objUrl, postLoad, ...loadOpts } = optionsRef.current;
|
|
19
|
+
let cancelled = false;
|
|
20
|
+
setResult({ model: null, loading: true, error: null });
|
|
21
|
+
loadOBJ(objUrl, loadOpts).then(async (model) => {
|
|
22
|
+
if (cancelled) return;
|
|
23
|
+
if (postLoad) await postLoad(model, webglCore);
|
|
24
|
+
scene.add(name, model);
|
|
25
|
+
setResult({ model, loading: false, error: null });
|
|
26
|
+
}).catch((err) => {
|
|
27
|
+
if (cancelled) return;
|
|
28
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
29
|
+
setResult({ model: null, loading: false, error });
|
|
30
|
+
});
|
|
31
|
+
return () => {
|
|
32
|
+
cancelled = true;
|
|
33
|
+
};
|
|
34
|
+
}, [context?.scene, context?.loadOBJ, context?.webglCore]);
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/hooks/useModelRotation.ts
|
|
39
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
40
|
+
function useModelRotation(model) {
|
|
41
|
+
const [rotation, setRotationState] = useState2([0, 0, 0]);
|
|
42
|
+
const modelRef = useRef2(model);
|
|
43
|
+
modelRef.current = model;
|
|
44
|
+
useEffect2(() => {
|
|
45
|
+
if (model) setRotationState([...model.rotation]);
|
|
46
|
+
}, [model]);
|
|
47
|
+
const setRotation = useCallback((x, y, z) => {
|
|
48
|
+
const m = modelRef.current;
|
|
49
|
+
if (!m) return;
|
|
50
|
+
m.setRotation(x, y, z);
|
|
51
|
+
setRotationState([x, y, z]);
|
|
52
|
+
}, []);
|
|
53
|
+
const rotate = useCallback((dx, dy, dz) => {
|
|
54
|
+
const m = modelRef.current;
|
|
55
|
+
if (!m) return;
|
|
56
|
+
const [cx, cy, cz] = m.rotation;
|
|
57
|
+
const nx = cx + dx;
|
|
58
|
+
const ny = cy + dy;
|
|
59
|
+
const nz = cz + dz;
|
|
60
|
+
m.setRotation(nx, ny, nz);
|
|
61
|
+
setRotationState([nx, ny, nz]);
|
|
62
|
+
}, []);
|
|
63
|
+
return { rotation, setRotation, rotate };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/hooks/useCameraMouseDrag.ts
|
|
67
|
+
import { useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
68
|
+
import { MouseDragControl } from "@fonsecabarreto/genesis-gl-core/Core";
|
|
69
|
+
var SENSITIVITY = 8e-3;
|
|
70
|
+
function useCameraMouseDrag(ctx, canvasRef) {
|
|
71
|
+
const { rotate } = useCameraControls(ctx);
|
|
72
|
+
const rotateRef = useRef3(rotate);
|
|
73
|
+
rotateRef.current = rotate;
|
|
74
|
+
useEffect3(() => {
|
|
75
|
+
const el = canvasRef.current;
|
|
76
|
+
if (!el || !ctx) return;
|
|
77
|
+
const drag = new MouseDragControl(el);
|
|
78
|
+
const onDrag = (dx, dy, button) => {
|
|
79
|
+
if (button !== 2) return;
|
|
80
|
+
rotateRef.current(-dx * SENSITIVITY, dy * SENSITIVITY);
|
|
81
|
+
};
|
|
82
|
+
drag.onChange(onDrag);
|
|
83
|
+
drag.enable();
|
|
84
|
+
const onMouseDown = (e) => {
|
|
85
|
+
if (e.button !== 2) return;
|
|
86
|
+
el.style.cursor = "grabbing";
|
|
87
|
+
};
|
|
88
|
+
const onMouseUp = (e) => {
|
|
89
|
+
if (e.button !== 2) return;
|
|
90
|
+
el.style.cursor = "grab";
|
|
91
|
+
};
|
|
92
|
+
const onMouseEnter = () => {
|
|
93
|
+
el.style.cursor = "grab";
|
|
94
|
+
};
|
|
95
|
+
const onMouseLeave = () => {
|
|
96
|
+
el.style.cursor = "";
|
|
97
|
+
};
|
|
98
|
+
const onContextMenu = (e) => e.preventDefault();
|
|
99
|
+
el.addEventListener("mousedown", onMouseDown);
|
|
100
|
+
el.addEventListener("mouseenter", onMouseEnter);
|
|
101
|
+
el.addEventListener("mouseleave", onMouseLeave);
|
|
102
|
+
window.addEventListener("mouseup", onMouseUp);
|
|
103
|
+
el.addEventListener("contextmenu", onContextMenu);
|
|
104
|
+
return () => {
|
|
105
|
+
drag.disable();
|
|
106
|
+
el.removeEventListener("mousedown", onMouseDown);
|
|
107
|
+
el.removeEventListener("mouseenter", onMouseEnter);
|
|
108
|
+
el.removeEventListener("mouseleave", onMouseLeave);
|
|
109
|
+
window.removeEventListener("mouseup", onMouseUp);
|
|
110
|
+
el.removeEventListener("contextmenu", onContextMenu);
|
|
111
|
+
el.style.cursor = "";
|
|
112
|
+
};
|
|
113
|
+
}, [ctx]);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/hooks/useGroundShadow.ts
|
|
117
|
+
import { useEffect as useEffect4 } from "react";
|
|
118
|
+
import {
|
|
119
|
+
Model,
|
|
120
|
+
createGroundShadow
|
|
121
|
+
} from "@fonsecabarreto/genesis-gl-core/Core";
|
|
122
|
+
var SHADOW_ID = "__ground_shadow__";
|
|
123
|
+
function useGroundShadow(context, options = {}) {
|
|
124
|
+
const { y, radius, opacity, color } = options;
|
|
125
|
+
useEffect4(() => {
|
|
126
|
+
if (!context?.scene || !context?.webglCore) return;
|
|
127
|
+
const { scene, webglCore } = context;
|
|
128
|
+
const mesh = createGroundShadow(webglCore, { y, radius, opacity, color });
|
|
129
|
+
mesh.isCollidable = false;
|
|
130
|
+
const model = new Model([mesh]);
|
|
131
|
+
scene.add(SHADOW_ID, model);
|
|
132
|
+
return () => {
|
|
133
|
+
scene.remove(SHADOW_ID);
|
|
134
|
+
};
|
|
135
|
+
}, [
|
|
136
|
+
context?.scene,
|
|
137
|
+
context?.webglCore,
|
|
138
|
+
y,
|
|
139
|
+
radius,
|
|
140
|
+
opacity,
|
|
141
|
+
color?.[0],
|
|
142
|
+
color?.[1],
|
|
143
|
+
color?.[2]
|
|
144
|
+
]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export {
|
|
148
|
+
useModel,
|
|
149
|
+
useModelRotation,
|
|
150
|
+
useCameraMouseDrag,
|
|
151
|
+
useGroundShadow
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=chunk-YFZKO7RD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useModel.ts","../src/hooks/useModelRotation.ts","../src/hooks/useCameraMouseDrag.ts","../src/hooks/useGroundShadow.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport type { Model, WebGLCore } from '@fonsecabarreto/genesis-gl-core/Core';\nimport type { GenesisGLContext, LoadOBJOptions } from './useGenesisGL';\n\nexport interface UseModelOptions extends LoadOBJOptions {\n name: string;\n objUrl: string;\n postLoad?: (model: Model, webglCore: WebGLCore) => Promise<void> | void;\n}\n\nexport interface UseModelResult {\n model: Model | null;\n loading: boolean;\n error: Error | null;\n}\n\nexport function useModel(\n context: GenesisGLContext | null,\n options: UseModelOptions,\n): UseModelResult {\n const [result, setResult] = useState<UseModelResult>({\n model: null,\n loading: false,\n error: null,\n });\n\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n useEffect(() => {\n if (!context?.scene || !context?.loadOBJ || !context?.webglCore) return;\n\n const { scene, loadOBJ, webglCore } = context;\n const { name, objUrl, postLoad, ...loadOpts } = optionsRef.current;\n let cancelled = false;\n\n setResult({ model: null, loading: true, error: null });\n\n loadOBJ(objUrl, loadOpts)\n .then(async (model) => {\n if (cancelled) return;\n if (postLoad) await postLoad(model, webglCore);\n scene.add(name, model);\n setResult({ model, loading: false, error: null });\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n const error = err instanceof Error ? err : new Error(String(err));\n setResult({ model: null, loading: false, error });\n });\n\n return () => {\n cancelled = true;\n };\n }, [context?.scene, context?.loadOBJ, context?.webglCore]);\n\n return result;\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport type { Model } from '@fonsecabarreto/genesis-gl-core/Core';\n\ntype Rotation = [number, number, number];\n\nexport interface UseModelRotationResult {\n rotation: Rotation;\n setRotation: (x: number, y: number, z: number) => void;\n rotate: (dx: number, dy: number, dz: number) => void;\n}\n\nexport function useModelRotation(model: Model | null): UseModelRotationResult {\n const [rotation, setRotationState] = useState<Rotation>([0, 0, 0]);\n const modelRef = useRef(model);\n modelRef.current = model;\n\n useEffect(() => {\n if (model) setRotationState([...model.rotation]);\n }, [model]);\n\n const setRotation = useCallback((x: number, y: number, z: number) => {\n const m = modelRef.current;\n if (!m) return;\n m.setRotation(x, y, z);\n setRotationState([x, y, z]);\n }, []);\n\n const rotate = useCallback((dx: number, dy: number, dz: number) => {\n const m = modelRef.current;\n if (!m) return;\n const [cx, cy, cz] = m.rotation;\n const nx = cx + dx;\n const ny = cy + dy;\n const nz = cz + dz;\n m.setRotation(nx, ny, nz);\n setRotationState([nx, ny, nz]);\n }, []);\n\n return { rotation, setRotation, rotate };\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","import { useEffect } from 'react';\nimport {\n Model,\n createGroundShadow,\n type GroundShadowOptions,\n} from '@fonsecabarreto/genesis-gl-core/Core';\nimport type { GenesisGLContext } from './useGenesisGL';\n\nconst SHADOW_ID = '__ground_shadow__';\n\nexport function useGroundShadow(\n context: GenesisGLContext | null,\n options: GroundShadowOptions = {},\n) {\n const { y, radius, opacity, color } = options;\n\n useEffect(() => {\n if (!context?.scene || !context?.webglCore) return;\n const { scene, webglCore } = context;\n\n const mesh = createGroundShadow(webglCore, { y, radius, opacity, color });\n mesh.isCollidable = false;\n const model = new Model([mesh]);\n scene.add(SHADOW_ID, model);\n\n return () => {\n scene.remove(SHADOW_ID);\n };\n }, [\n context?.scene,\n context?.webglCore,\n y,\n radius,\n opacity,\n color?.[0],\n color?.[1],\n color?.[2],\n ]);\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","useEffect","useRef","useRef","useEffect","useEffect"]}
|
package/dist/components/index.js
CHANGED
package/dist/hooks/index.js
CHANGED
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
useGroundShadow,
|
|
4
4
|
useModel,
|
|
5
5
|
useModelRotation
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-YFZKO7RD.js";
|
|
7
7
|
import {
|
|
8
8
|
useCameraControls,
|
|
9
9
|
useGenesisGL,
|
|
10
10
|
useRenderer,
|
|
11
11
|
useWorldToScreen
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-7AGC27WM.js";
|
|
13
13
|
export {
|
|
14
14
|
useCameraControls,
|
|
15
15
|
useCameraMouseDrag,
|
package/dist/index.js
CHANGED
|
@@ -4,19 +4,19 @@ import {
|
|
|
4
4
|
OrbitArrows,
|
|
5
5
|
RotationControls,
|
|
6
6
|
ViewportGizmo
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5SN3UL2T.js";
|
|
8
8
|
import {
|
|
9
9
|
useCameraMouseDrag,
|
|
10
10
|
useGroundShadow,
|
|
11
11
|
useModel,
|
|
12
12
|
useModelRotation
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-YFZKO7RD.js";
|
|
14
14
|
import {
|
|
15
15
|
useCameraControls,
|
|
16
16
|
useGenesisGL,
|
|
17
17
|
useRenderer,
|
|
18
18
|
useWorldToScreen
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-7AGC27WM.js";
|
|
20
20
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
import { loadOBJWithMTL } from "@fonsecabarreto/genesis-gl-core/Core/utils/parse-obj";
|