@fonsecabarreto/genesis-gl-react 0.1.32 → 0.1.33
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-7RTMMLA7.js +579 -0
- package/dist/chunk-7RTMMLA7.js.map +1 -0
- package/dist/chunk-A2C6CGTL.js +823 -0
- package/dist/chunk-A2C6CGTL.js.map +1 -0
- package/dist/chunk-HR2GWVYU.js +153 -0
- package/dist/chunk-HR2GWVYU.js.map +1 -0
- package/dist/chunk-TJHSBQII.js +218 -0
- package/dist/chunk-TJHSBQII.js.map +1 -0
- package/dist/components/index.d.ts +25 -1
- package/dist/components/index.js +8 -4
- package/dist/hooks/index.d.ts +4 -2
- package/dist/hooks/index.js +5 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- 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 // Remap corners so the div renders right-side-up from the isometric view:\n // div (0,0)→screenPts[3], (w,0)→[2], (w,h)→[1], (0,h)→[0]\n const remapped = [screenPts[3], screenPts[2], screenPts[1], screenPts[0]];\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,153 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useCameraControls
|
|
3
|
+
} from "./chunk-TJHSBQII.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-HR2GWVYU.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"]}
|
|
@@ -0,0 +1,218 @@
|
|
|
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
|
+
export {
|
|
213
|
+
useGenesisGL,
|
|
214
|
+
useRenderer,
|
|
215
|
+
useWorldToScreen,
|
|
216
|
+
useCameraControls
|
|
217
|
+
};
|
|
218
|
+
//# sourceMappingURL=chunk-TJHSBQII.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\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"],"mappings":"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","names":["useRef","useEffect","useState","useCallback","useState"]}
|
|
@@ -11,11 +11,35 @@ interface GenesisGLCanvasProps {
|
|
|
11
11
|
initialYaw?: number;
|
|
12
12
|
initialPitch?: number;
|
|
13
13
|
initialZoom?: number;
|
|
14
|
+
/** RGBA clear color, e.g. [0.05, 0.05, 0.05, 1] */
|
|
15
|
+
background?: [number, number, number, number];
|
|
14
16
|
style?: React.CSSProperties;
|
|
15
17
|
className?: string;
|
|
16
18
|
}
|
|
17
19
|
declare const GenesisGLCanvas: React.ForwardRefExoticComponent<GenesisGLCanvasProps & React.RefAttributes<HTMLCanvasElement>>;
|
|
18
20
|
|
|
21
|
+
interface ViewportGizmoProps {
|
|
22
|
+
context: GenesisGLContext | null;
|
|
23
|
+
/** Size of the gizmo widget in px. Default 96 */
|
|
24
|
+
size?: number;
|
|
25
|
+
/** Corner to anchor in. Default 'top-right' */
|
|
26
|
+
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
27
|
+
style?: React.CSSProperties;
|
|
28
|
+
}
|
|
29
|
+
declare function ViewportGizmo({ context, size, position, style, }: ViewportGizmoProps): react_jsx_runtime.JSX.Element;
|
|
30
|
+
|
|
31
|
+
interface OrbitArrowsProps {
|
|
32
|
+
context: GenesisGLContext | null;
|
|
33
|
+
/** World-space centre the rings are drawn around. Default [0,0,0] */
|
|
34
|
+
center?: [number, number, number];
|
|
35
|
+
/** Radius of the orbit rings in world units. Default 1.2 */
|
|
36
|
+
radius?: number;
|
|
37
|
+
/** How many points to sample per arc. Default 48 */
|
|
38
|
+
segments?: number;
|
|
39
|
+
style?: React.CSSProperties;
|
|
40
|
+
}
|
|
41
|
+
declare function OrbitArrows({ context, center, radius, segments, style, }: OrbitArrowsProps): react_jsx_runtime.JSX.Element | null;
|
|
42
|
+
|
|
19
43
|
interface RotationControlsProps {
|
|
20
44
|
context: GenesisGLContext | null;
|
|
21
45
|
style?: React.CSSProperties;
|
|
@@ -57,4 +81,4 @@ interface FaceSkinProps {
|
|
|
57
81
|
}
|
|
58
82
|
declare function FaceSkin({ context, model, corners, children, style, className, surfaceWidth, surfaceHeight, }: FaceSkinProps): react_jsx_runtime.JSX.Element | null;
|
|
59
83
|
|
|
60
|
-
export { FaceSkin as FaceLabel, type FaceSkinProps as FaceLabelProps, FaceSkin, type FaceSkinProps, GenesisGLCanvas, type GenesisGLCanvasProps, RotationControls, type RotationControlsProps };
|
|
84
|
+
export { FaceSkin as FaceLabel, type FaceSkinProps as FaceLabelProps, FaceSkin, type FaceSkinProps, GenesisGLCanvas, type GenesisGLCanvasProps, OrbitArrows, type OrbitArrowsProps, RotationControls, type RotationControlsProps, ViewportGizmo, type ViewportGizmoProps };
|
package/dist/components/index.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FaceSkin,
|
|
3
3
|
GenesisGLCanvas,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
OrbitArrows,
|
|
5
|
+
RotationControls,
|
|
6
|
+
ViewportGizmo
|
|
7
|
+
} from "../chunk-A2C6CGTL.js";
|
|
8
|
+
import "../chunk-TJHSBQII.js";
|
|
7
9
|
export {
|
|
8
10
|
FaceSkin as FaceLabel,
|
|
9
11
|
FaceSkin,
|
|
10
12
|
GenesisGLCanvas,
|
|
11
|
-
|
|
13
|
+
OrbitArrows,
|
|
14
|
+
RotationControls,
|
|
15
|
+
ViewportGizmo
|
|
12
16
|
};
|
|
13
17
|
//# sourceMappingURL=index.js.map
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { L as LoadOBJOptions, G as GenesisGLContext } from '../useGenesisGL-VdB4J3Hl.js';
|
|
2
2
|
export { U as UseGenesisGLOptions, u as useGenesisGL } from '../useGenesisGL-VdB4J3Hl.js';
|
|
3
|
-
import { Renderer, Model, WebGLCore } from '@fonsecabarreto/genesis-gl-core/Core';
|
|
3
|
+
import { Renderer, Model, WebGLCore, GroundShadowOptions } from '@fonsecabarreto/genesis-gl-core/Core';
|
|
4
4
|
|
|
5
5
|
interface UseRendererOptions {
|
|
6
6
|
renderer: Renderer | null;
|
|
@@ -61,4 +61,6 @@ declare function useCameraControls(ctx: GenesisGLContext | null): UseCameraContr
|
|
|
61
61
|
|
|
62
62
|
declare function useCameraMouseDrag(ctx: GenesisGLContext | null, canvasRef: React.RefObject<HTMLElement | null>): void;
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
declare function useGroundShadow(context: GenesisGLContext | null, options?: GroundShadowOptions): void;
|
|
65
|
+
|
|
66
|
+
export { type CameraState, GenesisGLContext, LoadOBJOptions, type ScreenPoint, type UseCameraControlsResult, type UseModelOptions, type UseModelResult, type UseModelRotationResult, type UseRendererOptions, useCameraControls, useCameraMouseDrag, useGroundShadow, useModel, useModelRotation, useRenderer, useWorldToScreen };
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
|
+
useCameraMouseDrag,
|
|
3
|
+
useGroundShadow,
|
|
2
4
|
useModel,
|
|
3
5
|
useModelRotation
|
|
4
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-HR2GWVYU.js";
|
|
5
7
|
import {
|
|
6
8
|
useCameraControls,
|
|
7
|
-
useCameraMouseDrag,
|
|
8
9
|
useGenesisGL,
|
|
9
10
|
useRenderer,
|
|
10
11
|
useWorldToScreen
|
|
11
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-TJHSBQII.js";
|
|
12
13
|
export {
|
|
13
14
|
useCameraControls,
|
|
14
15
|
useCameraMouseDrag,
|
|
15
16
|
useGenesisGL,
|
|
17
|
+
useGroundShadow,
|
|
16
18
|
useModel,
|
|
17
19
|
useModelRotation,
|
|
18
20
|
useRenderer,
|