Favivon - Correção

This commit is contained in:
2026-05-30 19:59:39 -03:00
parent 76ddaa815d
commit d7dfd221f0
32859 changed files with 5459654 additions and 404 deletions
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("@react-three/fiber");function n(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var r=n(e);exports.CycleRaycast=function({onChanged:e,portal:n,preventDefault:o=!0,scroll:l=!0,keyCode:u=9}){const c=r.useRef(0),d=t.useThree((e=>e.setEvents)),i=t.useThree((e=>e.get)),a=t.useThree((e=>e.gl));return r.useEffect((()=>{var t;let r,s=[];const v=i().events.filter,f=null!==(t=null==n?void 0:n.current)&&void 0!==t?t:a.domElement.parentNode,h=()=>f&&e&&e(s,Math.round(c.current)%s.length);d({filter:(e,t)=>{let n=[...e];n.length===s.length&&s.every((e=>n.map((e=>e.object.uuid)).includes(e.object.uuid)))||(c.current=0,s=n,h()),v&&(n=v(n,t));for(let e=0;e<Math.round(c.current)%n.length;e++){const e=n.shift();n=[...n,e]}return n}});const m=e=>{var t,n;c.current=e(c.current),null==(t=i().events.handlers)||t.onPointerCancel(void 0),null==(n=i().events.handlers)||n.onPointerMove(r),h()},p=e=>{(e.keyCode||e.which)===u&&(o&&e.preventDefault(),s.length>1&&m((e=>e+1)))},g=e=>{o&&e.preventDefault();let t=0;e||(e=window.event),e.wheelDelta?t=e.wheelDelta/120:e.detail&&(t=-e.detail/3),s.length>1&&m((e=>Math.abs(e-t)))},b=e=>r=e;return document.addEventListener("pointermove",b,{passive:!0}),l&&document.addEventListener("wheel",g),void 0!==u&&document.addEventListener("keydown",p),()=>{d({filter:v}),void 0!==u&&document.removeEventListener("keydown",p),l&&document.removeEventListener("wheel",g),document.removeEventListener("pointermove",b)}}),[a,i,d,o,l,u]),null};
+10
View File
@@ -0,0 +1,10 @@
import * as React from 'react';
import * as THREE from 'three';
export type CycleRaycastProps = {
onChanged?: (hits: THREE.Intersection[], cycle: number) => null;
preventDefault?: boolean;
scroll?: boolean;
keyCode?: number;
portal?: React.RefObject<HTMLElement>;
};
export declare function CycleRaycast({ onChanged, portal, preventDefault, scroll, keyCode, }: CycleRaycastProps): null;
+93
View File
@@ -0,0 +1,93 @@
import * as React from 'react';
import { useThree } from '@react-three/fiber';
function CycleRaycast({
onChanged,
portal,
preventDefault = true,
scroll = true,
keyCode = 9
}) {
const cycle = React.useRef(0);
const setEvents = useThree(state => state.setEvents);
const get = useThree(state => state.get);
const gl = useThree(state => state.gl);
React.useEffect(() => {
var _portal$current;
let hits = [];
let lastEvent = undefined;
const prev = get().events.filter;
const target = (_portal$current = portal == null ? void 0 : portal.current) !== null && _portal$current !== void 0 ? _portal$current : gl.domElement.parentNode;
// Render custom status
const renderStatus = () => target && onChanged && onChanged(hits, Math.round(cycle.current) % hits.length);
// Overwrite the raycasters custom filter (this only exists in r3f)
setEvents({
filter: (intersections, state) => {
// Reset cycle when the intersections change
let clone = [...intersections];
if (clone.length !== hits.length || !hits.every(hit => clone.map(e => e.object.uuid).includes(hit.object.uuid))) {
cycle.current = 0;
hits = clone;
renderStatus();
}
// Run custom filter if there is one
if (prev) clone = prev(clone, state);
// Cycle through the actual raycast intersects
for (let i = 0; i < Math.round(cycle.current) % clone.length; i++) {
const first = clone.shift();
clone = [...clone, first];
}
return clone;
}
});
// Cycle, refresh events and render status
const refresh = fn => {
var _get$events$handlers, _get$events$handlers2;
cycle.current = fn(cycle.current);
// Cancel hovered elements and fake a pointer-move
(_get$events$handlers = get().events.handlers) == null || _get$events$handlers.onPointerCancel(undefined);
(_get$events$handlers2 = get().events.handlers) == null || _get$events$handlers2.onPointerMove(lastEvent);
renderStatus();
};
// Key events
const tabEvent = event => {
if ((event.keyCode || event.which) === keyCode) {
if (preventDefault) event.preventDefault();
if (hits.length > 1) refresh(current => current + 1);
}
};
// Wheel events
const wheelEvent = event => {
if (preventDefault) event.preventDefault();
let delta = 0;
if (!event) event = window.event;
if (event.wheelDelta) delta = event.wheelDelta / 120;else if (event.detail) delta = -event.detail / 3;
if (hits.length > 1) refresh(current => Math.abs(current - delta));
};
// Catch last move event and position custom status
const moveEvent = event => lastEvent = event;
document.addEventListener('pointermove', moveEvent, {
passive: true
});
if (scroll) document.addEventListener('wheel', wheelEvent);
if (keyCode !== undefined) document.addEventListener('keydown', tabEvent);
return () => {
// Clean up
setEvents({
filter: prev
});
if (keyCode !== undefined) document.removeEventListener('keydown', tabEvent);
if (scroll) document.removeEventListener('wheel', wheelEvent);
document.removeEventListener('pointermove', moveEvent);
};
}, [gl, get, setEvents, preventDefault, scroll, keyCode]);
return null;
}
export { CycleRaycast };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("react"),t=require("three"),n=require("@react-three/fiber"),a=require("@use-gesture/react");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function i(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}var c=o(e),u=i(r),s=i(t);const l=new s.Vector3,m=new s.Vector2,f=new s.Vector3,d=new s.Vector3,x=new s.Vector3,p=new s.Plane,y=u.forwardRef((({autoTransform:e=!0,matrix:r,axisLock:t,dragLimits:o,onHover:i,onDragStart:y,onDrag:g,onDragEnd:h,children:b,dragConfig:v,...w},D)=>{const M=n.useThree((e=>e.controls)),{camera:j,size:z,raycaster:P,invalidate:O}=n.useThree(),V=u.useRef(null),q=a.useGesture({onHover:({hovering:e})=>i&&i(null!=e&&e),onDragStart:({event:e})=>{M&&(M.enabled=!1);const{point:r}=e;V.current.matrix.decompose(l,new s.Quaternion,new s.Vector3),f.copy(r),d.copy(f).sub(l),y&&y(l),O()},onDrag:({xy:[r,n],intentional:a})=>{if(!a)return;const i=(r-z.left)/z.width*2-1,c=-(n-z.top)/z.height*2+1;if(m.set(i,c),P.setFromCamera(m,j),t)switch(t){case"x":x.set(1,0,0);break;case"y":x.set(0,1,0);break;case"z":x.set(0,0,1)}else j.getWorldDirection(x).negate();p.setFromNormalAndCoplanarPoint(x,f),P.ray.intersectPlane(p,f);const u=V.current.matrix.clone(),l=V.current.matrixWorld.clone(),y=new s.Vector3(f.x-d.x,f.y-d.y,f.z-d.z);if(o&&(y.x=o[0]?Math.max(Math.min(y.x,o[0][1]),o[0][0]):y.x,y.y=o[1]?Math.max(Math.min(y.y,o[1][1]),o[1][0]):y.y,y.z=o[2]?Math.max(Math.min(y.z,o[2][1]),o[2][0]):y.z),e){V.current.matrix.setPosition(y);const e=V.current.matrix.clone().multiply(u.invert()),r=V.current.matrix.clone().multiply(l.invert());g&&g(V.current.matrix,e,V.current.matrixWorld,r)}else{const e=(new s.Matrix4).copy(V.current.matrix);e.setPosition(y);const r=e.clone().multiply(u.invert()),t=e.clone().multiply(l.invert());g&&g(e,r,V.current.matrixWorld,t)}O()},onDragEnd:()=>{M&&(M.enabled=!0),h&&h(),O()}},{drag:{filterTaps:!0,threshold:1,..."object"==typeof v?v:{}}});return u.useImperativeHandle(D,(()=>V.current),[]),u.useLayoutEffect((()=>{r&&(V.current.matrix=r)}),[r]),u.createElement("group",c.default({ref:V},q(),{matrix:r,matrixAutoUpdate:!1},w),b)}));exports.DragControls=y;
+17
View File
@@ -0,0 +1,17 @@
import * as React from 'react';
import * as THREE from 'three';
import { DragConfig } from '@use-gesture/react';
import { ForwardRefComponent } from '../helpers/ts-utils';
export type DragControlsProps = {
autoTransform?: boolean;
matrix?: THREE.Matrix4;
axisLock?: 'x' | 'y' | 'z';
dragLimits?: [[number, number] | undefined, [number, number] | undefined, [number, number] | undefined];
onHover?: (hovering: boolean) => void;
onDragStart?: (origin: THREE.Vector3) => void;
onDrag?: (localMatrix: THREE.Matrix4, deltaLocalMatrix: THREE.Matrix4, worldMatrix: THREE.Matrix4, deltaWorldMatrix: THREE.Matrix4) => void;
onDragEnd?: () => void;
children: React.ReactNode;
dragConfig?: DragConfig;
};
export declare const DragControls: ForwardRefComponent<DragControlsProps, THREE.Group>;
+127
View File
@@ -0,0 +1,127 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as React from 'react';
import * as THREE from 'three';
import { useThree } from '@react-three/fiber';
import { useGesture } from '@use-gesture/react';
const initialModelPosition = /* @__PURE__ */new THREE.Vector3();
const mousePosition2D = /* @__PURE__ */new THREE.Vector2();
const mousePosition3D = /* @__PURE__ */new THREE.Vector3();
const dragOffset = /* @__PURE__ */new THREE.Vector3();
const dragPlaneNormal = /* @__PURE__ */new THREE.Vector3();
const dragPlane = /* @__PURE__ */new THREE.Plane();
const DragControls = /*#__PURE__*/React.forwardRef(({
autoTransform = true,
matrix,
axisLock,
dragLimits,
onHover,
onDragStart,
onDrag,
onDragEnd,
children,
dragConfig,
...props
}, fRef) => {
const defaultControls = useThree(state => state.controls);
const {
camera,
size,
raycaster,
invalidate
} = useThree();
const ref = React.useRef(null);
const bind = useGesture({
onHover: ({
hovering
}) => onHover && onHover(hovering !== null && hovering !== void 0 ? hovering : false),
onDragStart: ({
event
}) => {
if (defaultControls) defaultControls.enabled = false;
const {
point
} = event;
ref.current.matrix.decompose(initialModelPosition, new THREE.Quaternion(), new THREE.Vector3());
mousePosition3D.copy(point);
dragOffset.copy(mousePosition3D).sub(initialModelPosition);
onDragStart && onDragStart(initialModelPosition);
invalidate();
},
onDrag: ({
xy: [dragX, dragY],
intentional
}) => {
if (!intentional) return;
const normalizedMouseX = (dragX - size.left) / size.width * 2 - 1;
const normalizedMouseY = -((dragY - size.top) / size.height) * 2 + 1;
mousePosition2D.set(normalizedMouseX, normalizedMouseY);
raycaster.setFromCamera(mousePosition2D, camera);
if (!axisLock) {
camera.getWorldDirection(dragPlaneNormal).negate();
} else {
switch (axisLock) {
case 'x':
dragPlaneNormal.set(1, 0, 0);
break;
case 'y':
dragPlaneNormal.set(0, 1, 0);
break;
case 'z':
dragPlaneNormal.set(0, 0, 1);
break;
}
}
dragPlane.setFromNormalAndCoplanarPoint(dragPlaneNormal, mousePosition3D);
raycaster.ray.intersectPlane(dragPlane, mousePosition3D);
const previousLocalMatrix = ref.current.matrix.clone();
const previousWorldMatrix = ref.current.matrixWorld.clone();
const intendedNewPosition = new THREE.Vector3(mousePosition3D.x - dragOffset.x, mousePosition3D.y - dragOffset.y, mousePosition3D.z - dragOffset.z);
if (dragLimits) {
intendedNewPosition.x = dragLimits[0] ? Math.max(Math.min(intendedNewPosition.x, dragLimits[0][1]), dragLimits[0][0]) : intendedNewPosition.x;
intendedNewPosition.y = dragLimits[1] ? Math.max(Math.min(intendedNewPosition.y, dragLimits[1][1]), dragLimits[1][0]) : intendedNewPosition.y;
intendedNewPosition.z = dragLimits[2] ? Math.max(Math.min(intendedNewPosition.z, dragLimits[2][1]), dragLimits[2][0]) : intendedNewPosition.z;
}
if (autoTransform) {
ref.current.matrix.setPosition(intendedNewPosition);
const deltaLocalMatrix = ref.current.matrix.clone().multiply(previousLocalMatrix.invert());
const deltaWorldMatrix = ref.current.matrix.clone().multiply(previousWorldMatrix.invert());
onDrag && onDrag(ref.current.matrix, deltaLocalMatrix, ref.current.matrixWorld, deltaWorldMatrix);
} else {
const tempMatrix = new THREE.Matrix4().copy(ref.current.matrix);
tempMatrix.setPosition(intendedNewPosition);
const deltaLocalMatrix = tempMatrix.clone().multiply(previousLocalMatrix.invert());
const deltaWorldMatrix = tempMatrix.clone().multiply(previousWorldMatrix.invert());
onDrag && onDrag(tempMatrix, deltaLocalMatrix, ref.current.matrixWorld, deltaWorldMatrix);
}
invalidate();
},
onDragEnd: () => {
if (defaultControls) defaultControls.enabled = true;
onDragEnd && onDragEnd();
invalidate();
}
}, {
drag: {
filterTaps: true,
threshold: 1,
...(typeof dragConfig === 'object' ? dragConfig : {})
}
});
React.useImperativeHandle(fRef, () => ref.current, []);
React.useLayoutEffect(() => {
if (!matrix) return;
// If the matrix is a real matrix4 it means that the user wants to control the gizmo
// In that case it should just be set, as a bare prop update would merely copy it
ref.current.matrix = matrix;
}, [matrix]);
return /*#__PURE__*/React.createElement("group", _extends({
ref: ref
}, bind(), {
matrix: matrix,
matrixAutoUpdate: false
}, props), children);
});
export { DragControls };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("three"),t=require("react"),o=require("@react-three/fiber"),n=require("maath"),c=require("../core/VideoTexture.cjs.js"),a=require("./WebcamVideoTexture.cjs.js"),u=require("./Facemesh.cjs.js"),s=require("./FaceLandmarker.cjs.js");function i(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function l(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var o=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,o.get?o:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}require("suspend-react"),require("hls.js"),require("../core/Line.cjs.js"),require("three-stdlib");var f=i(e),d=l(r),p=l(t);function m(e,r){return e.clone().add(r).multiplyScalar(.5)}function b(e,r,t){const o=e.localToWorld(r);return t.worldToLocal(o)}const h=t.createContext({}),y=t.forwardRef((({camera:e,videoTexture:r={start:!0},manualDetect:i=!1,faceLandmarkerResult:l,manualUpdate:y=!1,makeDefault:j,smoothTime:v=.25,offset:T=!0,offsetScalar:V=80,eyes:w=!1,eyesAsOrigin:g=!0,depth:q=.15,debug:x=!1,facemesh:O},k)=>{var S,R;const E=o.useThree((e=>e.scene)),D=o.useThree((e=>e.camera)),F=o.useThree((e=>e.set)),C=o.useThree((e=>e.get)),L=e||D,M=t.useRef(null),[A]=t.useState((()=>new d.Object3D)),[P]=t.useState((()=>new d.Vector3)),[W]=t.useState((()=>new d.Vector3)),[_]=t.useState((()=>new d.Vector3)),[z]=t.useState((()=>new d.Vector3)),B=t.useCallback((()=>{A.parent=L.parent;const e=M.current;if(e){const{outerRef:r,eyeRightRef:t,eyeLeftRef:o}=e;if(t.current&&o.current){const{irisDirRef:e}=t.current,{irisDirRef:n}=o.current;e.current&&n.current&&r.current&&(P.copy(b(e.current,new d.Vector3(0,0,0),r.current)),W.copy(b(n.current,new d.Vector3(0,0,0),r.current)),A.position.copy(b(r.current,m(P,W),L.parent||E)),_.copy(b(e.current,new d.Vector3(0,0,1),r.current)),z.copy(b(n.current,new d.Vector3(0,0,1),r.current)),A.lookAt(r.current.localToWorld(m(_,z))))}else r.current&&(A.position.copy(b(r.current,new d.Vector3(0,0,0),L.parent||E)),A.lookAt(r.current.localToWorld(new d.Vector3(0,0,1))))}return A}),[L,W,z,P,_,E,A]),[I]=t.useState((()=>new d.Object3D)),H=t.useCallback((function(e,r){if(L){var t;if(null!==(t=r)&&void 0!==t||(r=B()),v>0){const t=1e-9;n.easing.damp3(I.position,r.position,v,e,void 0,void 0,t),n.easing.dampE(I.rotation,r.rotation,v,e,void 0,void 0,t)}else I.position.copy(r.position),I.rotation.copy(r.rotation);L.position.copy(I.position),L.rotation.copy(I.rotation)}}),[L,B,v,I.position,I.rotation]);o.useFrame(((e,r)=>{y||H(r)}));const N=t.useRef(null),[U,G]=t.useState(),J=s.useFaceLandmarker(),K=t.useCallback(((e,r)=>{const t=N.current;if(!t)return;const o=t.source.data,n=null==J?void 0:J.detectForVideo(o,e);G(n)}),[J]),Q=t.useMemo((()=>Object.assign(Object.create(d.EventDispatcher.prototype),{computeTarget:B,update:H,facemeshApiRef:M})),[B,H]);t.useImperativeHandle(k,(()=>Q),[Q]),t.useEffect((()=>{if(j){const e=C().controls;return F({controls:Q}),()=>F({controls:e})}}),[j,Q,C,F]);const X=null!=l?l:U,Y=null==X?void 0:X.faceLandmarks[0],Z=null==X||null==(S=X.facialTransformationMatrixes)?void 0:S[0],$=null==X||null==(R=X.faceBlendshapes)?void 0:R[0],ee={onVideoFrame:K,...r};return p.createElement(h.Provider,{value:Q},!i&&p.createElement(t.Suspense,{fallback:null},"src"in ee?p.createElement(c.VideoTexture,f.default({ref:N},ee)):p.createElement(a.WebcamVideoTexture,f.default({ref:N},ee))),p.createElement(u.Facemesh,f.default({ref:M,children:p.createElement("meshNormalMaterial",{side:d.DoubleSide})},O,{points:Y,depth:q,facialTransformationMatrix:Z,faceBlendshapes:$,eyes:w,eyesAsOrigin:g,offset:T,offsetScalar:V,debug:x,"rotation-z":Math.PI,visible:x})))}));exports.FaceControls=y,exports.useFaceControls=()=>t.useContext(h);
+29
View File
@@ -0,0 +1,29 @@
import * as THREE from 'three';
import * as React from 'react';
import { RefObject } from 'react';
import type { FaceLandmarkerResult } from '@mediapipe/tasks-vision';
import { VideoTextureProps } from '../core/VideoTexture';
import { FacemeshApi, FacemeshProps } from './Facemesh';
export type FaceControlsProps = {
camera?: THREE.Camera;
videoTexture?: VideoTextureProps;
manualDetect?: boolean;
faceLandmarkerResult?: FaceLandmarkerResult;
manualUpdate?: boolean;
makeDefault?: boolean;
smoothTime?: number;
offset?: boolean;
offsetScalar?: number;
eyes?: boolean;
eyesAsOrigin?: boolean;
depth?: number;
debug?: boolean;
facemesh?: FacemeshProps;
};
export type FaceControlsApi = THREE.EventDispatcher & {
computeTarget: () => THREE.Object3D;
update: (delta: number, target?: THREE.Object3D) => void;
facemeshApiRef: RefObject<FacemeshApi>;
};
export declare const FaceControls: React.ForwardRefExoticComponent<FaceControlsProps & React.RefAttributes<FaceControlsApi>>;
export declare const useFaceControls: () => FaceControlsApi;
+236
View File
@@ -0,0 +1,236 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as THREE from 'three';
import * as React from 'react';
import { forwardRef, useRef, useState, useCallback, useMemo, useImperativeHandle, useEffect, Suspense, useContext, createContext } from 'react';
import { useThree, useFrame } from '@react-three/fiber';
import { easing } from 'maath';
import { VideoTexture } from '../core/VideoTexture.js';
import { WebcamVideoTexture } from './WebcamVideoTexture.js';
import { Facemesh } from './Facemesh.js';
import { useFaceLandmarker } from './FaceLandmarker.js';
function mean(v1, v2) {
return v1.clone().add(v2).multiplyScalar(0.5);
}
function localToLocal(objSrc, v, objDst) {
// see: https://discourse.threejs.org/t/object3d-localtolocal/51564
const v_world = objSrc.localToWorld(v);
return objDst.worldToLocal(v_world);
}
//
//
//
const FaceControlsContext = /* @__PURE__ */createContext({});
/**
* The camera follows your face.
*
* Pre-requisite: wrap into a `FaceLandmarker` provider:
*
* ```jsx
* <FaceLandmarker>...</FaceLandmarker>
* ```
*/
const FaceControls = /* @__PURE__ */forwardRef(({
camera,
videoTexture = {
start: true
},
manualDetect = false,
faceLandmarkerResult,
manualUpdate = false,
makeDefault,
smoothTime = 0.25,
offset = true,
offsetScalar = 80,
eyes = false,
eyesAsOrigin = true,
depth = 0.15,
debug = false,
facemesh
}, fref) => {
var _result$facialTransfo, _result$faceBlendshap;
const scene = useThree(state => state.scene);
const defaultCamera = useThree(state => state.camera);
const set = useThree(state => state.set);
const get = useThree(state => state.get);
const explCamera = camera || defaultCamera;
const facemeshApiRef = useRef(null);
//
// computeTarget()
//
// Compute `target` position and rotation for the camera (according to <Facemesh>)
//
// 1. 👀 either following the 2 eyes
// 2. 👤 or just the head mesh
//
const [target] = useState(() => new THREE.Object3D());
const [irisRightDirPos] = useState(() => new THREE.Vector3());
const [irisLeftDirPos] = useState(() => new THREE.Vector3());
const [irisRightLookAt] = useState(() => new THREE.Vector3());
const [irisLeftLookAt] = useState(() => new THREE.Vector3());
const computeTarget = useCallback(() => {
// same parent as the camera
target.parent = explCamera.parent;
const facemeshApi = facemeshApiRef.current;
if (facemeshApi) {
const {
outerRef,
eyeRightRef,
eyeLeftRef
} = facemeshApi;
if (eyeRightRef.current && eyeLeftRef.current) {
// 1. 👀
const {
irisDirRef: irisRightDirRef
} = eyeRightRef.current;
const {
irisDirRef: irisLeftDirRef
} = eyeLeftRef.current;
if (irisRightDirRef.current && irisLeftDirRef.current && outerRef.current) {
//
// position: mean of irisRightDirPos,irisLeftDirPos
//
irisRightDirPos.copy(localToLocal(irisRightDirRef.current, new THREE.Vector3(0, 0, 0), outerRef.current));
irisLeftDirPos.copy(localToLocal(irisLeftDirRef.current, new THREE.Vector3(0, 0, 0), outerRef.current));
target.position.copy(localToLocal(outerRef.current, mean(irisRightDirPos, irisLeftDirPos), explCamera.parent || scene));
//
// lookAt: mean of irisRightLookAt,irisLeftLookAt
//
irisRightLookAt.copy(localToLocal(irisRightDirRef.current, new THREE.Vector3(0, 0, 1), outerRef.current));
irisLeftLookAt.copy(localToLocal(irisLeftDirRef.current, new THREE.Vector3(0, 0, 1), outerRef.current));
target.lookAt(outerRef.current.localToWorld(mean(irisRightLookAt, irisLeftLookAt)));
}
} else {
// 2. 👤
if (outerRef.current) {
target.position.copy(localToLocal(outerRef.current, new THREE.Vector3(0, 0, 0), explCamera.parent || scene));
target.lookAt(outerRef.current.localToWorld(new THREE.Vector3(0, 0, 1)));
}
}
}
return target;
}, [explCamera, irisLeftDirPos, irisLeftLookAt, irisRightDirPos, irisRightLookAt, scene, target]);
//
// update()
//
// Updating the camera `current` position and rotation, following `target`
//
const [current] = useState(() => new THREE.Object3D());
const update = useCallback(function (delta, target) {
if (explCamera) {
var _target;
(_target = target) !== null && _target !== void 0 ? _target : target = computeTarget();
if (smoothTime > 0) {
// damping current
const eps = 1e-9;
easing.damp3(current.position, target.position, smoothTime, delta, undefined, undefined, eps);
easing.dampE(current.rotation, target.rotation, smoothTime, delta, undefined, undefined, eps);
} else {
// instant
current.position.copy(target.position);
current.rotation.copy(target.rotation);
}
explCamera.position.copy(current.position);
explCamera.rotation.copy(current.rotation);
}
}, [explCamera, computeTarget, smoothTime, current.position, current.rotation]);
useFrame((_, delta) => {
if (manualUpdate) return;
update(delta);
});
//
// onVideoFrame (only used if !manualDetect)
//
const videoTextureRef = useRef(null);
const [_faceLandmarkerResult, setFaceLandmarkerResult] = useState();
const faceLandmarker = useFaceLandmarker();
const onVideoFrame = useCallback((now, metadata) => {
const texture = videoTextureRef.current;
if (!texture) return;
const videoFrame = texture.source.data;
const result = faceLandmarker == null ? void 0 : faceLandmarker.detectForVideo(videoFrame, now);
setFaceLandmarkerResult(result);
}, [faceLandmarker]);
//
// Ref API
//
const api = useMemo(() => Object.assign(Object.create(THREE.EventDispatcher.prototype), {
computeTarget,
update,
facemeshApiRef
}), [computeTarget, update]);
useImperativeHandle(fref, () => api, [api]);
//
// makeDefault (`controls` global state)
//
useEffect(() => {
if (makeDefault) {
const old = get().controls;
set({
controls: api
});
return () => set({
controls: old
});
}
}, [makeDefault, api, get, set]);
//
//
//
const result = faceLandmarkerResult !== null && faceLandmarkerResult !== void 0 ? faceLandmarkerResult : _faceLandmarkerResult;
const points = result == null ? void 0 : result.faceLandmarks[0];
const facialTransformationMatrix = result == null || (_result$facialTransfo = result.facialTransformationMatrixes) == null ? void 0 : _result$facialTransfo[0];
const faceBlendshapes = result == null || (_result$faceBlendshap = result.faceBlendshapes) == null ? void 0 : _result$faceBlendshap[0];
const videoTextureProps = {
onVideoFrame,
...videoTexture
};
return /*#__PURE__*/React.createElement(FaceControlsContext.Provider, {
value: api
}, !manualDetect && /*#__PURE__*/React.createElement(Suspense, {
fallback: null
}, 'src' in videoTextureProps ? /*#__PURE__*/React.createElement(VideoTexture, _extends({
ref: videoTextureRef
}, videoTextureProps)) : /*#__PURE__*/React.createElement(WebcamVideoTexture, _extends({
ref: videoTextureRef
}, videoTextureProps))), /*#__PURE__*/React.createElement(Facemesh, _extends({
ref: facemeshApiRef,
children: /*#__PURE__*/React.createElement("meshNormalMaterial", {
side: THREE.DoubleSide
})
}, facemesh, {
points: points,
depth: depth,
facialTransformationMatrix: facialTransformationMatrix,
faceBlendshapes: faceBlendshapes,
eyes: eyes,
eyesAsOrigin: eyesAsOrigin,
offset: offset,
offsetScalar: offsetScalar,
debug: debug,
"rotation-z": Math.PI,
visible: debug
})));
});
const useFaceControls = () => useContext(FaceControlsContext);
export { FaceControls, useFaceControls };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("suspend-react");function r(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var a=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,a.get?a:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var a=r(e);const s=e.createContext({}),n={basePath:"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.17/wasm",options:{baseOptions:{modelAssetPath:"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task",delegate:"GPU"},runningMode:"VIDEO",outputFaceBlendshapes:!0,outputFacialTransformationMatrixes:!0}},o=e.forwardRef((({basePath:o=n.basePath,options:i=n.options,children:c},u)=>{const l=JSON.stringify(i),d=t.suspend((async()=>{const{FilesetResolver:e,FaceLandmarker:t}=await Promise.resolve().then((function(){return r(require("@mediapipe/tasks-vision"))})),a=await e.forVisionTasks(o);return t.createFromOptions(a,i)}),[o,l]);return e.useEffect((()=>()=>{null==d||d.close(),t.clear([o,l])}),[d,o,l]),e.useImperativeHandle(u,(()=>d),[d]),a.createElement(s.Provider,{value:d},c)}));exports.FaceLandmarker=o,exports.FaceLandmarkerDefaults=n,exports.useFaceLandmarker=function(){return e.useContext(s)};
+14
View File
@@ -0,0 +1,14 @@
import * as React from 'react';
import { ReactNode } from 'react';
import type { FaceLandmarker as FaceLandmarkerImpl, FaceLandmarkerOptions } from '@mediapipe/tasks-vision';
export type FaceLandmarkerProps = {
basePath?: string;
options?: FaceLandmarkerOptions;
children?: ReactNode;
};
export declare const FaceLandmarkerDefaults: {
basePath: string;
options: FaceLandmarkerOptions;
};
export declare const FaceLandmarker: React.ForwardRefExoticComponent<FaceLandmarkerProps & React.RefAttributes<FaceLandmarkerImpl>>;
export declare function useFaceLandmarker(): FaceLandmarkerImpl | undefined;
+49
View File
@@ -0,0 +1,49 @@
import * as React from 'react';
import { forwardRef, useEffect, useImperativeHandle, useContext, createContext } from 'react';
import { suspend, clear } from 'suspend-react';
/* eslint react-hooks/exhaustive-deps: 1 */
const FaceLandmarkerContext = /* @__PURE__ */createContext({});
const FaceLandmarkerDefaults = {
basePath: 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.17/wasm',
options: {
baseOptions: {
modelAssetPath: 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task',
delegate: 'GPU'
},
runningMode: 'VIDEO',
outputFaceBlendshapes: true,
outputFacialTransformationMatrixes: true
}
};
const FaceLandmarker = /*#__PURE__*/forwardRef(({
basePath = FaceLandmarkerDefaults.basePath,
options = FaceLandmarkerDefaults.options,
children
}, fref) => {
const opts = JSON.stringify(options);
const faceLandmarker = suspend(async () => {
const {
FilesetResolver,
FaceLandmarker
} = await import('@mediapipe/tasks-vision');
const vision = await FilesetResolver.forVisionTasks(basePath);
return FaceLandmarker.createFromOptions(vision, options);
}, [basePath, opts]);
useEffect(() => {
return () => {
faceLandmarker == null || faceLandmarker.close();
clear([basePath, opts]);
};
}, [faceLandmarker, basePath, opts]);
useImperativeHandle(fref, () => faceLandmarker, [faceLandmarker]); // expose faceLandmarker through ref
return /*#__PURE__*/React.createElement(FaceLandmarkerContext.Provider, {
value: faceLandmarker
}, children);
});
function useFaceLandmarker() {
return useContext(FaceLandmarkerContext);
}
export { FaceLandmarker, FaceLandmarkerDefaults, useFaceLandmarker };
File diff suppressed because one or more lines are too long
+118
View File
@@ -0,0 +1,118 @@
import * as React from 'react';
import * as THREE from 'three';
import { ThreeElements } from '@react-three/fiber';
export type MediaPipeFaceMesh = typeof FacemeshDatas.SAMPLE_FACE;
export type MediaPipePoints = typeof FacemeshDatas.SAMPLE_FACE.keypoints | (typeof FacemeshDatas.SAMPLE_FACELANDMARKER_RESULT.faceLandmarks)[0];
export type FacemeshProps = {
points?: MediaPipePoints;
face?: MediaPipeFaceMesh;
width?: number;
height?: number;
depth?: number;
verticalTri?: [number, number, number];
origin?: number | THREE.Vector3;
facialTransformationMatrix?: (typeof FacemeshDatas.SAMPLE_FACELANDMARKER_RESULT.facialTransformationMatrixes)[0];
offset?: boolean;
offsetScalar?: number;
faceBlendshapes?: (typeof FacemeshDatas.SAMPLE_FACELANDMARKER_RESULT.faceBlendshapes)[0];
eyes?: boolean;
eyesAsOrigin?: boolean;
debug?: boolean;
} & Omit<ThreeElements['group'], 'ref'>;
export type FacemeshApi = {
meshRef: React.RefObject<THREE.Mesh>;
outerRef: React.RefObject<THREE.Group>;
eyeRightRef: React.RefObject<FacemeshEyeApi>;
eyeLeftRef: React.RefObject<FacemeshEyeApi>;
};
export declare const Facemesh: React.ForwardRefExoticComponent<{
points?: MediaPipePoints;
face?: MediaPipeFaceMesh;
width?: number;
height?: number;
depth?: number;
verticalTri?: [number, number, number];
origin?: number | THREE.Vector3;
facialTransformationMatrix?: (typeof FacemeshDatas.SAMPLE_FACELANDMARKER_RESULT.facialTransformationMatrixes)[0];
offset?: boolean;
offsetScalar?: number;
faceBlendshapes?: (typeof FacemeshDatas.SAMPLE_FACELANDMARKER_RESULT.faceBlendshapes)[0];
eyes?: boolean;
eyesAsOrigin?: boolean;
debug?: boolean;
} & Omit<import("@react-three/fiber/dist/declarations/src/core/utils").Mutable<import("@react-three/fiber/dist/declarations/src/core/utils").Overwrite<Partial<import("@react-three/fiber/dist/declarations/src/core/utils").Overwrite<THREE.Group<THREE.Object3DEventMap>, import("@react-three/fiber").MathProps<THREE.Group<THREE.Object3DEventMap>> & import("@react-three/fiber").ReactProps<THREE.Group<THREE.Object3DEventMap>> & Partial<import("@react-three/fiber").EventHandlers>>>, Omit<import("@react-three/fiber").InstanceProps<THREE.Group<THREE.Object3DEventMap>, typeof THREE.Group>, "object">>>, "ref"> & React.RefAttributes<FacemeshApi>>;
export type FacemeshEyeProps = {
side: 'left' | 'right';
debug?: boolean;
};
export type FacemeshEyeApi = {
eyeMeshRef: React.RefObject<THREE.Group>;
irisDirRef: React.RefObject<THREE.Group>;
_computeSphere: (faceGeometry: THREE.BufferGeometry) => THREE.Sphere;
_update: (faceGeometry: THREE.BufferGeometry, faceBlendshapes: FacemeshProps['faceBlendshapes'], sphere?: THREE.Sphere) => void;
};
export declare const FacemeshEyeDefaults: {
contourLandmarks: {
right: number[];
left: number[];
};
blendshapes: {
right: number[];
left: number[];
};
color: {
right: string;
left: string;
};
fov: {
horizontal: number;
vertical: number;
};
};
export declare const FacemeshEye: React.ForwardRefExoticComponent<FacemeshEyeProps & React.RefAttributes<FacemeshEyeApi>>;
export declare const FacemeshDatas: {
TRIANGULATION: number[];
SAMPLE_FACE: {
keypoints: ({
x: number;
y: number;
z: number;
name: string;
} | {
x: number;
y: number;
z: number;
name?: undefined;
})[];
box: {
xMin: number;
yMin: number;
xMax: number;
yMax: number;
width: number;
height: number;
};
};
SAMPLE_FACELANDMARKER_RESULT: {
faceLandmarks: {
x: number;
y: number;
z: number;
}[][];
faceBlendshapes: {
categories: {
index: number;
score: number;
categoryName: string;
displayName: string;
}[];
headIndex: number;
headName: string;
}[];
facialTransformationMatrixes: {
rows: number;
columns: number;
data: number[];
}[];
};
};
+4538
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+34
View File
@@ -0,0 +1,34 @@
import * as React from 'react';
import { Object3D, Camera } from 'three';
import { Assign } from 'utility-types';
import { ThreeElements } from '@react-three/fiber';
import { ForwardRefComponent } from '../helpers/ts-utils';
declare function defaultCalculatePosition(el: Object3D, camera: Camera, size: {
width: number;
height: number;
}): number[];
export type CalculatePosition = typeof defaultCalculatePosition;
type PointerEventsProperties = 'auto' | 'none' | 'visiblePainted' | 'visibleFill' | 'visibleStroke' | 'visible' | 'painted' | 'fill' | 'stroke' | 'all' | 'inherit';
export interface HtmlProps extends Omit<Assign<React.HTMLAttributes<HTMLDivElement>, ThreeElements['group']>, 'ref'> {
prepend?: boolean;
center?: boolean;
fullscreen?: boolean;
eps?: number;
portal?: React.RefObject<HTMLElement>;
distanceFactor?: number;
sprite?: boolean;
transform?: boolean;
zIndexRange?: Array<number>;
calculatePosition?: CalculatePosition;
as?: string;
wrapperClass?: string;
pointerEvents?: PointerEventsProperties;
occlude?: React.RefObject<Object3D>[] | boolean | 'raycast' | 'blending';
onOcclude?: (hidden: boolean) => void;
material?: React.ReactNode;
geometry?: React.ReactNode;
castShadow?: boolean;
receiveShadow?: boolean;
}
export declare const Html: ForwardRefComponent<HtmlProps, HTMLDivElement>;
export {};
+375
View File
@@ -0,0 +1,375 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import { Vector3, DoubleSide, OrthographicCamera, PerspectiveCamera, Vector2 } from 'three';
import { useThree, useFrame } from '@react-three/fiber';
const v1 = /* @__PURE__ */new Vector3();
const v2 = /* @__PURE__ */new Vector3();
const v3 = /* @__PURE__ */new Vector3();
const v4 = /* @__PURE__ */new Vector2();
function defaultCalculatePosition(el, camera, size) {
const objectPos = v1.setFromMatrixPosition(el.matrixWorld);
objectPos.project(camera);
const widthHalf = size.width / 2;
const heightHalf = size.height / 2;
return [objectPos.x * widthHalf + widthHalf, -(objectPos.y * heightHalf) + heightHalf];
}
function isObjectBehindCamera(el, camera) {
const objectPos = v1.setFromMatrixPosition(el.matrixWorld);
const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld);
const deltaCamObj = objectPos.sub(cameraPos);
const camDir = camera.getWorldDirection(v3);
return deltaCamObj.angleTo(camDir) > Math.PI / 2;
}
function isObjectVisible(el, camera, raycaster, occlude) {
const elPos = v1.setFromMatrixPosition(el.matrixWorld);
const screenPos = elPos.clone();
screenPos.project(camera);
v4.set(screenPos.x, screenPos.y);
raycaster.setFromCamera(v4, camera);
const intersects = raycaster.intersectObjects(occlude, true);
if (intersects.length) {
const intersectionDistance = intersects[0].distance;
const pointDistance = elPos.distanceTo(raycaster.ray.origin);
return pointDistance < intersectionDistance;
}
return true;
}
function objectScale(el, camera) {
if (camera instanceof OrthographicCamera) {
return camera.zoom;
} else if (camera instanceof PerspectiveCamera) {
const objectPos = v1.setFromMatrixPosition(el.matrixWorld);
const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld);
const vFOV = camera.fov * Math.PI / 180;
const dist = objectPos.distanceTo(cameraPos);
const scaleFOV = 2 * Math.tan(vFOV / 2) * dist;
return 1 / scaleFOV;
} else {
return 1;
}
}
function objectZIndex(el, camera, zIndexRange) {
if (camera instanceof PerspectiveCamera || camera instanceof OrthographicCamera) {
const objectPos = v1.setFromMatrixPosition(el.matrixWorld);
const cameraPos = v2.setFromMatrixPosition(camera.matrixWorld);
const dist = objectPos.distanceTo(cameraPos);
const A = (zIndexRange[1] - zIndexRange[0]) / (camera.far - camera.near);
const B = zIndexRange[1] - A * camera.far;
return Math.round(A * dist + B);
}
return undefined;
}
const epsilon = value => Math.abs(value) < 1e-10 ? 0 : value;
function getCSSMatrix(matrix, multipliers, prepend = '') {
let matrix3d = 'matrix3d(';
for (let i = 0; i !== 16; i++) {
matrix3d += epsilon(multipliers[i] * matrix.elements[i]) + (i !== 15 ? ',' : ')');
}
return prepend + matrix3d;
}
const getCameraCSSMatrix = (multipliers => {
return matrix => getCSSMatrix(matrix, multipliers);
})([1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1]);
const getObjectCSSMatrix = (scaleMultipliers => {
return (matrix, factor) => getCSSMatrix(matrix, scaleMultipliers(factor), 'translate(-50%,-50%)');
})(f => [1 / f, 1 / f, 1 / f, 1, -1 / f, -1 / f, -1 / f, -1, 1 / f, 1 / f, 1 / f, 1, 1, 1, 1, 1]);
function isRefObject(ref) {
return ref && typeof ref === 'object' && 'current' in ref;
}
const Html = /* @__PURE__ */React.forwardRef(({
children,
eps = 0.001,
style,
className,
prepend,
center,
fullscreen,
portal,
distanceFactor,
sprite = false,
transform = false,
occlude,
onOcclude,
castShadow,
receiveShadow,
material,
geometry,
zIndexRange = [16777271, 0],
calculatePosition = defaultCalculatePosition,
as = 'div',
wrapperClass,
pointerEvents = 'auto',
...props
}, ref) => {
const {
gl,
camera,
scene,
size,
raycaster,
events,
viewport
} = useThree();
const [el] = React.useState(() => document.createElement(as));
const root = React.useRef(null);
const group = React.useRef(null);
const oldZoom = React.useRef(0);
const oldPosition = React.useRef([0, 0]);
const transformOuterRef = React.useRef(null);
const transformInnerRef = React.useRef(null);
// Append to the connected element, which makes HTML work with views
const target = (portal == null ? void 0 : portal.current) || events.connected || gl.domElement.parentNode;
const occlusionMeshRef = React.useRef(null);
const isMeshSizeSet = React.useRef(false);
const isRayCastOcclusion = React.useMemo(() => {
return occlude && occlude !== 'blending' || Array.isArray(occlude) && occlude.length && isRefObject(occlude[0]);
}, [occlude]);
React.useLayoutEffect(() => {
const el = gl.domElement;
if (occlude && occlude === 'blending') {
el.style.zIndex = `${Math.floor(zIndexRange[0] / 2)}`;
el.style.position = 'absolute';
el.style.pointerEvents = 'none';
} else {
el.style.zIndex = null;
el.style.position = null;
el.style.pointerEvents = null;
}
}, [occlude]);
React.useLayoutEffect(() => {
if (group.current) {
const currentRoot = root.current = ReactDOM.createRoot(el);
scene.updateMatrixWorld();
if (transform) {
el.style.cssText = `position:absolute;top:0;left:0;pointer-events:none;overflow:hidden;`;
} else {
const vec = calculatePosition(group.current, camera, size);
el.style.cssText = `position:absolute;top:0;left:0;transform:translate3d(${vec[0]}px,${vec[1]}px,0);transform-origin:0 0;`;
}
if (target) {
if (prepend) target.prepend(el);else target.appendChild(el);
}
return () => {
if (target) target.removeChild(el);
currentRoot.unmount();
};
}
}, [target, transform]);
React.useLayoutEffect(() => {
if (wrapperClass) el.className = wrapperClass;
}, [wrapperClass]);
const styles = React.useMemo(() => {
if (transform) {
return {
position: 'absolute',
top: 0,
left: 0,
width: size.width,
height: size.height,
transformStyle: 'preserve-3d',
pointerEvents: 'none'
};
} else {
return {
position: 'absolute',
transform: center ? 'translate3d(-50%,-50%,0)' : 'none',
...(fullscreen && {
top: -size.height / 2,
left: -size.width / 2,
width: size.width,
height: size.height
}),
...style
};
}
}, [style, center, fullscreen, size, transform]);
const transformInnerStyles = React.useMemo(() => ({
position: 'absolute',
pointerEvents
}), [pointerEvents]);
React.useLayoutEffect(() => {
isMeshSizeSet.current = false;
if (transform) {
var _root$current;
(_root$current = root.current) == null || _root$current.render(/*#__PURE__*/React.createElement("div", {
ref: transformOuterRef,
style: styles
}, /*#__PURE__*/React.createElement("div", {
ref: transformInnerRef,
style: transformInnerStyles
}, /*#__PURE__*/React.createElement("div", {
ref: ref,
className: className,
style: style,
children: children
}))));
} else {
var _root$current2;
(_root$current2 = root.current) == null || _root$current2.render(/*#__PURE__*/React.createElement("div", {
ref: ref,
style: styles,
className: className,
children: children
}));
}
});
const visible = React.useRef(true);
useFrame(gl => {
if (group.current) {
camera.updateMatrixWorld();
group.current.updateWorldMatrix(true, false);
const vec = transform ? oldPosition.current : calculatePosition(group.current, camera, size);
if (transform || Math.abs(oldZoom.current - camera.zoom) > eps || Math.abs(oldPosition.current[0] - vec[0]) > eps || Math.abs(oldPosition.current[1] - vec[1]) > eps) {
const isBehindCamera = isObjectBehindCamera(group.current, camera);
let raytraceTarget = false;
if (isRayCastOcclusion) {
if (Array.isArray(occlude)) {
raytraceTarget = occlude.map(item => item.current);
} else if (occlude !== 'blending') {
raytraceTarget = [scene];
}
}
const previouslyVisible = visible.current;
if (raytraceTarget) {
const isvisible = isObjectVisible(group.current, camera, raycaster, raytraceTarget);
visible.current = isvisible && !isBehindCamera;
} else {
visible.current = !isBehindCamera;
}
if (previouslyVisible !== visible.current) {
if (onOcclude) onOcclude(!visible.current);else el.style.display = visible.current ? 'block' : 'none';
}
const halfRange = Math.floor(zIndexRange[0] / 2);
const zRange = occlude ? isRayCastOcclusion //
? [zIndexRange[0], halfRange] : [halfRange - 1, 0] : zIndexRange;
el.style.zIndex = `${objectZIndex(group.current, camera, zRange)}`;
if (transform) {
const [widthHalf, heightHalf] = [size.width / 2, size.height / 2];
const fov = camera.projectionMatrix.elements[5] * heightHalf;
const {
isOrthographicCamera,
top,
left,
bottom,
right
} = camera;
const cameraMatrix = getCameraCSSMatrix(camera.matrixWorldInverse);
const cameraTransform = isOrthographicCamera ? `scale(${fov})translate(${epsilon(-(right + left) / 2)}px,${epsilon((top + bottom) / 2)}px)` : `translateZ(${fov}px)`;
let matrix = group.current.matrixWorld;
if (sprite) {
matrix = camera.matrixWorldInverse.clone().transpose().copyPosition(matrix).scale(group.current.scale);
matrix.elements[3] = matrix.elements[7] = matrix.elements[11] = 0;
matrix.elements[15] = 1;
}
el.style.width = size.width + 'px';
el.style.height = size.height + 'px';
el.style.perspective = isOrthographicCamera ? '' : `${fov}px`;
if (transformOuterRef.current && transformInnerRef.current) {
transformOuterRef.current.style.transform = `${cameraTransform}${cameraMatrix}translate(${widthHalf}px,${heightHalf}px)`;
transformInnerRef.current.style.transform = getObjectCSSMatrix(matrix, 1 / ((distanceFactor || 10) / 400));
}
} else {
const scale = distanceFactor === undefined ? 1 : objectScale(group.current, camera) * distanceFactor;
el.style.transform = `translate3d(${vec[0]}px,${vec[1]}px,0) scale(${scale})`;
}
oldPosition.current = vec;
oldZoom.current = camera.zoom;
}
}
if (!isRayCastOcclusion && occlusionMeshRef.current && !isMeshSizeSet.current) {
if (transform) {
if (transformOuterRef.current) {
const el = transformOuterRef.current.children[0];
if (el != null && el.clientWidth && el != null && el.clientHeight) {
const {
isOrthographicCamera
} = camera;
if (isOrthographicCamera || geometry) {
if (props.scale) {
if (!Array.isArray(props.scale)) {
occlusionMeshRef.current.scale.setScalar(1 / props.scale);
} else if (props.scale instanceof Vector3) {
occlusionMeshRef.current.scale.copy(props.scale.clone().divideScalar(1));
} else {
occlusionMeshRef.current.scale.set(1 / props.scale[0], 1 / props.scale[1], 1 / props.scale[2]);
}
}
} else {
const ratio = (distanceFactor || 10) / 400;
const w = el.clientWidth * ratio;
const h = el.clientHeight * ratio;
occlusionMeshRef.current.scale.set(w, h, 1);
}
isMeshSizeSet.current = true;
}
}
} else {
const ele = el.children[0];
if (ele != null && ele.clientWidth && ele != null && ele.clientHeight) {
const ratio = 1 / viewport.factor;
const w = ele.clientWidth * ratio;
const h = ele.clientHeight * ratio;
occlusionMeshRef.current.scale.set(w, h, 1);
isMeshSizeSet.current = true;
}
occlusionMeshRef.current.lookAt(gl.camera.position);
}
}
});
const shaders = React.useMemo(() => ({
vertexShader: !transform ? /* glsl */`
/*
This shader is from the THREE's SpriteMaterial.
We need to turn the backing plane into a Sprite
(make it always face the camera) if "transfrom"
is false.
*/
#include <common>
void main() {
vec2 center = vec2(0., 1.);
float rotation = 0.0;
// This is somewhat arbitrary, but it seems to work well
// Need to figure out how to derive this dynamically if it even matters
float size = 0.03;
vec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );
vec2 scale;
scale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );
scale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );
bool isPerspective = isPerspectiveMatrix( projectionMatrix );
if ( isPerspective ) scale *= - mvPosition.z;
vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale * size;
vec2 rotatedPosition;
rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;
rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;
mvPosition.xy += rotatedPosition;
gl_Position = projectionMatrix * mvPosition;
}
` : undefined,
fragmentShader: /* glsl */`
void main() {
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
}
`
}), [transform]);
return /*#__PURE__*/React.createElement("group", _extends({}, props, {
ref: group
}), occlude && !isRayCastOcclusion && /*#__PURE__*/React.createElement("mesh", {
castShadow: castShadow,
receiveShadow: receiveShadow,
ref: occlusionMeshRef
}, geometry || /*#__PURE__*/React.createElement("planeGeometry", null), material || /*#__PURE__*/React.createElement("shaderMaterial", {
side: DoubleSide,
vertexShader: shaders.vertexShader,
fragmentShader: shaders.fragmentShader
})));
});
export { Html };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("zustand"),r=require("zustand/middleware");function n(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var s=n(e);const o=s.createContext(null);exports.KeyboardControls=function({map:e,children:n,onChange:u,domElement:c}){const a=e.map((e=>e.name+e.keys)).join("-"),d=s.useMemo((()=>t.create(r.subscribeWithSelector((()=>e.reduce(((e,t)=>({...e,[t.name]:!1})),{}))))),[a]),i=s.useMemo((()=>[d.subscribe,d.getState,d]),[a]),p=d.setState;return s.useEffect((()=>{const t=e.map((({name:e,keys:t,up:r})=>({keys:t,up:r,fn:t=>{p({[e]:t}),u&&u(e,t,i[1]())}}))).reduce(((e,{keys:t,fn:r,up:n=!0})=>(t.forEach((t=>e[t]={fn:r,pressed:!1,up:n})),e)),{}),r=({key:e,code:r})=>{const n=t[e]||t[r];if(!n)return;const{fn:s,pressed:o,up:u}=n;n.pressed=!0,!u&&o||s(!0)},n=({key:e,code:r})=>{const n=t[e]||t[r];if(!n)return;const{fn:s,up:o}=n;n.pressed=!1,o&&s(!1)},s=c||window;return s.addEventListener("keydown",r,{passive:!0}),s.addEventListener("keyup",n,{passive:!0}),()=>{s.removeEventListener("keydown",r),s.removeEventListener("keyup",n)}}),[c,a]),s.createElement(o.Provider,{value:i,children:n})},exports.useKeyboardControls=function(e){const[t,r,n]=s.useContext(o);return e?n(e):[t,r]};
+37
View File
@@ -0,0 +1,37 @@
import * as React from 'react';
import { StoreApi } from 'zustand';
type State = object;
type StateSelector<T extends State, U> = (state: T) => U;
type EqualityChecker<T> = (state: T, newState: T) => boolean;
type StateListener<T> = (state: T, previousState: T) => void;
type StoreApiWithSubscribeWithSelector<T extends State> = Omit<StoreApi<T>, 'subscribe'> & {
subscribe: {
(listener: StateListener<T>): () => void;
<StateSlice>(selector: StateSelector<T, StateSlice>, listener: StateListener<StateSlice>, options?: {
equalityFn?: EqualityChecker<StateSlice>;
fireImmediately?: boolean;
}): () => void;
};
};
type KeyboardControlsState<T extends string = string> = {
[K in T]: boolean;
};
export type KeyboardControlsEntry<T extends string = string> = {
name: T;
keys: string[];
up?: boolean;
};
export type KeyboardControlsProps = {
map: KeyboardControlsEntry[];
children: React.ReactNode;
onChange?: (name: string, pressed: boolean, state: KeyboardControlsState) => void;
domElement?: HTMLElement;
};
export declare function KeyboardControls({ map, children, onChange, domElement }: KeyboardControlsProps): React.JSX.Element;
type Selector<T extends string = string> = (state: KeyboardControlsState<T>) => boolean;
export declare function useKeyboardControls<T extends string = string>(): [
StoreApiWithSubscribeWithSelector<KeyboardControlsState<T>>['subscribe'],
StoreApiWithSubscribeWithSelector<KeyboardControlsState<T>>['getState']
];
export declare function useKeyboardControls<T extends string = string>(sel: Selector<T>): ReturnType<Selector<T>>;
export {};
+104
View File
@@ -0,0 +1,104 @@
import * as React from 'react';
import { create } from 'zustand';
import { subscribeWithSelector } from 'zustand/middleware';
// These are removed in Zustand v4
// unknown
// Zustand v3 marked deprecations in 3.x, but there's no visible upgrade path
const context = /* @__PURE__ */React.createContext(null);
function KeyboardControls({
map,
children,
onChange,
domElement
}) {
const key = map.map(item => item.name + item.keys).join('-');
const useControls = React.useMemo(() => {
return create(subscribeWithSelector(() => map.reduce((prev, cur) => ({
...prev,
[cur.name]: false
}), {})));
}, [key]);
const api = React.useMemo(() => [useControls.subscribe, useControls.getState, useControls], [key]);
const set = useControls.setState;
React.useEffect(() => {
const config = map.map(({
name,
keys,
up
}) => ({
keys,
up,
fn: value => {
// Set zustand state
set({
[name]: value
});
// Inform callback
if (onChange) onChange(name, value, api[1]());
}
}));
const keyMap = config.reduce((out, {
keys,
fn,
up = true
}) => {
keys.forEach(key => out[key] = {
fn,
pressed: false,
up
});
return out;
}, {});
const downHandler = ({
key,
code
}) => {
const obj = keyMap[key] || keyMap[code];
if (!obj) return;
const {
fn,
pressed,
up
} = obj;
obj.pressed = true;
if (up || !pressed) fn(true);
};
const upHandler = ({
key,
code
}) => {
const obj = keyMap[key] || keyMap[code];
if (!obj) return;
const {
fn,
up
} = obj;
obj.pressed = false;
if (up) fn(false);
};
const source = domElement || window;
source.addEventListener('keydown', downHandler, {
passive: true
});
source.addEventListener('keyup', upHandler, {
passive: true
});
return () => {
source.removeEventListener('keydown', downHandler);
source.removeEventListener('keyup', upHandler);
};
}, [domElement, key]);
return /*#__PURE__*/React.createElement(context.Provider, {
value: api,
children: children
});
}
function useKeyboardControls(sel) {
const [sub, get, store] = React.useContext(context);
if (sel) return store(sel);else return [sub, get];
}
export { KeyboardControls, useKeyboardControls };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("../core/Progress.cjs.js");function r(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}require("three"),require("zustand");var n=r(e);const a=e=>`Loading ${e.toFixed(2)}%`;const i={container:{position:"absolute",top:0,left:0,width:"100%",height:"100%",background:"#171717",display:"flex",alignItems:"center",justifyContent:"center",transition:"opacity 300ms ease",zIndex:1e3},inner:{width:100,height:3,background:"#272727",textAlign:"center"},bar:{height:3,width:"100%",background:"white",transition:"transform 200ms",transformOrigin:"left center"},data:{display:"inline-block",position:"relative",fontVariantNumeric:"tabular-nums",marginTop:"0.8em",color:"#f0f0f0",fontSize:"0.6em",fontFamily:'-apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", "Helvetica Neue", Helvetica, Arial, Roboto, Ubuntu, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"',whiteSpace:"nowrap"}};exports.Loader=function({containerStyles:e,innerStyles:r,barStyles:o,dataStyles:c,dataInterpolation:s=a,initialState:l=e=>e}){const{active:u,progress:f}=t.useProgress(),m=n.useRef(0),d=n.useRef(0),p=n.useRef(null),[y,b]=n.useState(l(u));n.useEffect((()=>{let e;return u!==y&&(e=setTimeout((()=>b(u)),300)),()=>clearTimeout(e)}),[y,u]);const g=n.useCallback((()=>{p.current&&(m.current+=(f-m.current)/2,(m.current>.95*f||100===f)&&(m.current=f),p.current.innerText=s(m.current),m.current<f&&(d.current=requestAnimationFrame(g)))}),[s,f]);return n.useEffect((()=>(g(),()=>cancelAnimationFrame(d.current))),[g]),y?n.createElement("div",{style:{...i.container,opacity:u?1:0,...e}},n.createElement("div",null,n.createElement("div",{style:{...i.inner,...r}},n.createElement("div",{style:{...i.bar,transform:`scaleX(${f/100})`,...o}}),n.createElement("span",{ref:p,style:{...i.data,...c}})))):null};
+12
View File
@@ -0,0 +1,12 @@
import * as React from 'react';
import { CSSProperties } from 'react';
interface LoaderOptions {
containerStyles: CSSProperties;
innerStyles: CSSProperties;
barStyles: CSSProperties;
dataStyles: CSSProperties;
dataInterpolation: (p: number) => string;
initialState: (active: boolean) => boolean;
}
export declare function Loader({ containerStyles, innerStyles, barStyles, dataStyles, dataInterpolation, initialState, }: Partial<LoaderOptions>): React.JSX.Element | null;
export {};
+101
View File
@@ -0,0 +1,101 @@
import * as React from 'react';
import { useProgress } from '../core/Progress.js';
const defaultDataInterpolation = p => `Loading ${p.toFixed(2)}%`;
function Loader({
containerStyles,
innerStyles,
barStyles,
dataStyles,
dataInterpolation = defaultDataInterpolation,
initialState = active => active
}) {
const {
active,
progress
} = useProgress();
const progressRef = React.useRef(0);
const rafRef = React.useRef(0);
const progressSpanRef = React.useRef(null);
const [shown, setShown] = React.useState(initialState(active));
React.useEffect(() => {
let t;
if (active !== shown) t = setTimeout(() => setShown(active), 300);
return () => clearTimeout(t);
}, [shown, active]);
const updateProgress = React.useCallback(() => {
if (!progressSpanRef.current) return;
progressRef.current += (progress - progressRef.current) / 2;
if (progressRef.current > 0.95 * progress || progress === 100) progressRef.current = progress;
progressSpanRef.current.innerText = dataInterpolation(progressRef.current);
if (progressRef.current < progress) rafRef.current = requestAnimationFrame(updateProgress);
}, [dataInterpolation, progress]);
React.useEffect(() => {
updateProgress();
return () => cancelAnimationFrame(rafRef.current);
}, [updateProgress]);
return shown ? /*#__PURE__*/React.createElement("div", {
style: {
...styles.container,
opacity: active ? 1 : 0,
...containerStyles
}
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
style: {
...styles.inner,
...innerStyles
}
}, /*#__PURE__*/React.createElement("div", {
style: {
...styles.bar,
transform: `scaleX(${progress / 100})`,
...barStyles
}
}), /*#__PURE__*/React.createElement("span", {
ref: progressSpanRef,
style: {
...styles.data,
...dataStyles
}
})))) : null;
}
const styles = {
container: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
background: '#171717',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'opacity 300ms ease',
zIndex: 1000
},
inner: {
width: 100,
height: 3,
background: '#272727',
textAlign: 'center'
},
bar: {
height: 3,
width: '100%',
background: 'white',
transition: 'transform 200ms',
transformOrigin: 'left center'
},
data: {
display: 'inline-block',
position: 'relative',
fontVariantNumeric: 'tabular-nums',
marginTop: '0.8em',
color: '#f0f0f0',
fontSize: '0.6em',
fontFamily: `-apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", "Helvetica Neue", Helvetica, Arial, Roboto, Ubuntu, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`,
whiteSpace: 'nowrap'
}
};
export { Loader };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),t=require("react"),r=require("three"),a=require("@react-three/fiber"),o=require("@use-gesture/react"),n=require("maath");function u(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function s(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var a=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,a.get?a:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var l=u(e),i=s(t);exports.PresentationControls=function({enabled:e=!0,snap:t,global:u,domElement:s,cursor:c=!0,children:d,speed:m=1,rotation:f=[0,0,0],zoom:p=1,polar:g=[0,Math.PI/2],azimuth:h=[-1/0,1/0],damping:b=.25}){const y=a.useThree((e=>e.events)),M=a.useThree((e=>e.gl)),v=s||y.connected||M.domElement,{size:E}=a.useThree(),j=i.useMemo((()=>[f[0]+g[0],f[0]+g[1]]),[f[0],g[0],g[1]]),O=i.useMemo((()=>[f[1]+h[0],f[1]+h[1]]),[f[1],h[0],h[1]]),P=i.useMemo((()=>[r.MathUtils.clamp(f[0],...j),r.MathUtils.clamp(f[1],...O),f[2]]),[f[0],f[1],f[2],j,O]);i.useEffect((()=>{if(u&&c&&e)return v.style.cursor="grab",M.domElement.style.cursor="",()=>{v.style.cursor="default",M.domElement.style.cursor="default"}}),[u,c,v,e]);const[q]=i.useState({scale:1,rotation:P,damping:b}),z=i.useRef(null);a.useFrame(((e,t)=>{n.easing.damp3(z.current.scale,q.scale,q.damping,t),n.easing.dampE(z.current.rotation,q.rotation,q.damping,t)}));const U=o.useGesture({onHover:({last:t})=>{c&&!u&&e&&(v.style.cursor=t?"auto":"grab")},onDrag:({down:a,delta:[o,n],memo:[u,s]=q.rotation||P})=>e?(c&&(v.style.cursor=a?"grabbing":"grab"),o=r.MathUtils.clamp(s+o/E.width*Math.PI*m,...O),n=r.MathUtils.clamp(u+n/E.height*Math.PI*m,...j),q.scale=a&&n>j[1]/2?p:1,q.rotation=t&&!a?P:[n,o,0],q.damping=t&&!a&&"boolean"!=typeof t?t:b,[n,o]):[n,o]},{target:u?v:void 0});return i.createElement("group",l.default({ref:z},null==U?void 0:U()),d)};
+16
View File
@@ -0,0 +1,16 @@
import * as React from 'react';
export type PresentationControlProps = {
snap?: Boolean | number;
global?: boolean;
cursor?: boolean;
speed?: number;
zoom?: number;
rotation?: [number, number, number];
polar?: [number, number];
azimuth?: [number, number];
damping?: number;
enabled?: boolean;
children?: React.ReactNode;
domElement?: HTMLElement;
};
export declare function PresentationControls({ enabled, snap, global, domElement, cursor, children, speed, rotation, zoom, polar, azimuth, damping, }: PresentationControlProps): React.JSX.Element;
+79
View File
@@ -0,0 +1,79 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as React from 'react';
import { MathUtils } from 'three';
import { useThree, useFrame } from '@react-three/fiber';
import { useGesture } from '@use-gesture/react';
import { easing } from 'maath';
function PresentationControls({
enabled = true,
snap,
global,
domElement,
cursor = true,
children,
speed = 1,
rotation = [0, 0, 0],
zoom = 1,
polar = [0, Math.PI / 2],
azimuth = [-Infinity, Infinity],
damping = 0.25
}) {
const events = useThree(state => state.events);
const gl = useThree(state => state.gl);
const explDomElement = domElement || events.connected || gl.domElement;
const {
size
} = useThree();
const rPolar = React.useMemo(() => [rotation[0] + polar[0], rotation[0] + polar[1]], [rotation[0], polar[0], polar[1]]);
const rAzimuth = React.useMemo(() => [rotation[1] + azimuth[0], rotation[1] + azimuth[1]], [rotation[1], azimuth[0], azimuth[1]]);
const rInitial = React.useMemo(() => [MathUtils.clamp(rotation[0], ...rPolar), MathUtils.clamp(rotation[1], ...rAzimuth), rotation[2]], [rotation[0], rotation[1], rotation[2], rPolar, rAzimuth]);
React.useEffect(() => {
if (global && cursor && enabled) {
explDomElement.style.cursor = 'grab';
gl.domElement.style.cursor = '';
return () => {
explDomElement.style.cursor = 'default';
gl.domElement.style.cursor = 'default';
};
}
}, [global, cursor, explDomElement, enabled]);
const [animation] = React.useState({
scale: 1,
rotation: rInitial,
damping
});
const ref = React.useRef(null);
useFrame((state, delta) => {
easing.damp3(ref.current.scale, animation.scale, animation.damping, delta);
easing.dampE(ref.current.rotation, animation.rotation, animation.damping, delta);
});
const bind = useGesture({
onHover: ({
last
}) => {
if (cursor && !global && enabled) explDomElement.style.cursor = last ? 'auto' : 'grab';
},
onDrag: ({
down,
delta: [x, y],
memo: [oldY, oldX] = animation.rotation || rInitial
}) => {
if (!enabled) return [y, x];
if (cursor) explDomElement.style.cursor = down ? 'grabbing' : 'grab';
x = MathUtils.clamp(oldX + x / size.width * Math.PI * speed, ...rAzimuth);
y = MathUtils.clamp(oldY + y / size.height * Math.PI * speed, ...rPolar);
animation.scale = down && y > rPolar[1] / 2 ? zoom : 1;
animation.rotation = snap && !down ? rInitial : [y, x, 0];
animation.damping = snap && !down && typeof snap !== 'boolean' ? snap : damping;
return [y, x];
}
}, {
target: global ? explDomElement : undefined
});
return /*#__PURE__*/React.createElement("group", _extends({
ref: ref
}, bind == null ? void 0 : bind()), children);
}
export { PresentationControls };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("react"),t=require("suspend-react"),u=require("../core/VideoTexture.cjs.js");function c(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function i(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var u=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,u.get?u:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}require("three"),require("@react-three/fiber"),require("hls.js");var n=c(e),o=i(r);const a=r.forwardRef((({options:e={video:!0},...c},i)=>{const a=t.suspend((()=>navigator.mediaDevices.getDisplayMedia(e)),[]);return r.useEffect((()=>()=>{null==a||a.getTracks().forEach((e=>e.stop())),t.clear([])}),[a]),o.createElement(u.VideoTexture,n.default({ref:i},c,{src:a}))}));exports.ScreenVideoTexture=a;
+17
View File
@@ -0,0 +1,17 @@
import * as React from 'react';
import * as THREE from 'three';
import { VideoTextureProps } from '../core/VideoTexture';
export type ScreenVideoTextureProps = Omit<VideoTextureProps, 'src'> & {
options?: DisplayMediaStreamOptions;
};
export declare const ScreenVideoTexture: React.ForwardRefExoticComponent<Omit<{
children?: (texture: THREE.VideoTexture) => React.ReactNode;
src: string | MediaProvider | null;
} & {
unsuspend?: keyof HTMLVideoElementEventMap;
start?: boolean;
hls?: Parameters<(userConfig?: Partial<import("hls.js").HlsConfig> | undefined) => Promise<import("hls.js").default | null>>[0];
onVideoFrame?: VideoFrameRequestCallback;
} & Partial<Omit<HTMLVideoElement, "children" | "src" | "srcObject">>, "src"> & {
options?: DisplayMediaStreamOptions;
} & React.RefAttributes<THREE.VideoTexture>>;
+30
View File
@@ -0,0 +1,30 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as React from 'react';
import { forwardRef, useEffect } from 'react';
import { suspend, clear } from 'suspend-react';
import { VideoTexture } from '../core/VideoTexture.js';
/**
* Create a video texture from [`getDisplayMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia)
*/
const ScreenVideoTexture = /* @__PURE__ */forwardRef(({
options = {
video: true
},
...props
}, fref) => {
const mediaStream = suspend(() => navigator.mediaDevices.getDisplayMedia(options), []);
useEffect(() => {
return () => {
mediaStream == null || mediaStream.getTracks().forEach(track => track.stop());
clear([]);
};
}, [mediaStream]);
return /*#__PURE__*/React.createElement(VideoTexture, _extends({
ref: fref
}, props, {
src: mediaStream
}));
});
export { ScreenVideoTexture };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),t=require("react"),r=require("react-dom/client"),n=require("@react-three/fiber"),o=require("maath");function s(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function l(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var i=s(e),c=l(t),a=l(r);const f=c.createContext(null);function u(){return c.useContext(f)}const d=c.forwardRef((({children:e},t)=>{const r=c.useRef(null);c.useImperativeHandle(t,(()=>r.current),[]);const o=u(),{width:s,height:l}=n.useThree((e=>e.viewport));return n.useFrame((()=>{r.current.position.x=o.horizontal?-s*(o.pages-1)*o.offset:0,r.current.position.y=o.horizontal?0:l*(o.pages-1)*o.offset})),c.createElement("group",{ref:r},e)})),p=c.forwardRef((({children:e,style:t,...r},o)=>{const s=u(),l=c.useRef(null);c.useImperativeHandle(o,(()=>l.current),[]);const{width:d,height:p}=n.useThree((e=>e.size)),h=c.useContext(n.context),m=c.useMemo((()=>a.createRoot(s.fixed)),[s.fixed]);return n.useFrame((()=>{s.delta>s.eps&&(l.current.style.transform=`translate3d(${s.horizontal?-d*(s.pages-1)*s.offset:0}px,${s.horizontal?0:p*(s.pages-1)*-s.offset}px,0)`)})),m.render(c.createElement("div",i.default({ref:l,style:{...t,position:"absolute",top:0,left:0,willChange:"transform"}},r),c.createElement(f.Provider,{value:s},c.createElement(n.context.Provider,{value:h},e)))),null})),h=c.forwardRef((({html:e,...t},r)=>{const n=e?p:d;return c.createElement(n,i.default({ref:r},t))}));exports.Scroll=h,exports.ScrollControls=function({eps:e=1e-5,enabled:t=!0,infinite:r,horizontal:s,pages:l=1,distance:i=1,damping:a=.25,maxSpeed:u=1/0,prepend:d=!1,style:p={},children:h}){const{get:m,setEvents:v,gl:g,size:y,invalidate:x,events:w}=n.useThree(),[E]=c.useState((()=>document.createElement("div"))),[b]=c.useState((()=>document.createElement("div"))),[z]=c.useState((()=>document.createElement("div"))),C=g.domElement.parentNode,L=c.useRef(0),R=c.useMemo((()=>{const t={el:E,eps:e,fill:b,fixed:z,horizontal:s,damping:a,offset:0,delta:0,scroll:L,pages:l,range(e,t,r=0){const n=e-r,o=n+t+2*r;return this.offset<n?0:this.offset>o?1:(this.offset-n)/(o-n)},curve(e,t,r=0){return Math.sin(this.range(e,t,r)*Math.PI)},visible(e,t,r=0){const n=e-r,o=n+t+2*r;return this.offset>=n&&this.offset<=o}};return t}),[e,a,s,l]);c.useEffect((()=>{E.style.position="absolute",E.style.width="100%",E.style.height="100%",E.style[s?"overflowX":"overflowY"]="auto",E.style[s?"overflowY":"overflowX"]="hidden",E.style.top="0px",E.style.left="0px";for(const e in p)E.style[e]=p[e];z.style.position="sticky",z.style.top="0px",z.style.left="0px",z.style.width="100%",z.style.height="100%",z.style.overflow="hidden",E.appendChild(z),b.style.height=s?"100%":l*i*100+"%",b.style.width=s?l*i*100+"%":"100%",b.style.pointerEvents="none",E.appendChild(b),d?C.prepend(E):C.appendChild(E),E[s?"scrollLeft":"scrollTop"]=1;const e=w.connected||g.domElement;requestAnimationFrame((()=>null==w.connect?void 0:w.connect(E)));const t=m().events.compute;return v({compute(e,t){const{left:r,top:n}=C.getBoundingClientRect(),o=e.clientX-r,s=e.clientY-n;t.pointer.set(o/t.size.width*2-1,-s/t.size.height*2+1),t.raycaster.setFromCamera(t.pointer,t.camera)}}),()=>{C.removeChild(E),v({compute:t}),null==w.connect||w.connect(e)}}),[l,i,s,E,b,z,C]),c.useEffect((()=>{if(w.connected===E){const e=y[s?"width":"height"],n=E[s?"scrollWidth":"scrollHeight"],o=n-e;let l=0,i=!0,c=!0;const a=()=>{if(t&&!c&&(x(),l=E[s?"scrollLeft":"scrollTop"],L.current=l/o,r)){if(!i)if(l>=o){const e=1-R.offset;E[s?"scrollLeft":"scrollTop"]=1,L.current=R.offset=-e,i=!0}else if(l<=0){const e=1+R.offset;E[s?"scrollLeft":"scrollTop"]=n,L.current=R.offset=e,i=!0}i&&setTimeout((()=>i=!1),40)}};E.addEventListener("scroll",a,{passive:!0}),requestAnimationFrame((()=>c=!1));const f=e=>E.scrollLeft+=e.deltaY/2;return s&&E.addEventListener("wheel",f,{passive:!0}),()=>{E.removeEventListener("scroll",a),s&&E.removeEventListener("wheel",f)}}}),[E,w,y,r,R,x,s,t]);let T=0;return n.useFrame(((t,r)=>{T=R.offset,o.easing.damp(R,"offset",L.current,a,r,u,void 0,e),o.easing.damp(R,"delta",Math.abs(T-R.offset),a,r,u,void 0,e),R.delta>e&&x()})),c.createElement(f.Provider,{value:R},h)},exports.useScroll=u;
+45
View File
@@ -0,0 +1,45 @@
import * as THREE from 'three';
import * as React from 'react';
import { ForwardRefComponent } from '../helpers/ts-utils';
export type ScrollControlsProps = {
eps?: number;
horizontal?: boolean;
infinite?: boolean;
pages?: number;
distance?: number;
damping?: number;
maxSpeed?: number;
prepend?: boolean;
enabled?: boolean;
style?: React.CSSProperties;
children: React.ReactNode;
};
export type ScrollControlsState = {
el: HTMLDivElement;
eps: number;
fill: HTMLDivElement;
fixed: HTMLDivElement;
horizontal: boolean | undefined;
damping: number;
offset: number;
delta: number;
pages: number;
range(from: number, distance: number, margin?: number): number;
curve(from: number, distance: number, margin?: number): number;
visible(from: number, distance: number, margin?: number): boolean;
};
export declare function useScroll(): ScrollControlsState;
export declare function ScrollControls({ eps, enabled, infinite, horizontal, pages, distance, damping, maxSpeed, prepend, style, children, }: ScrollControlsProps): React.JSX.Element;
interface ScrollPropsWithFalseHtml {
children?: React.ReactNode;
html?: false;
style?: never;
}
interface ScrollPropsWithTrueHtml {
children?: React.ReactNode;
html: true;
style?: React.CSSProperties;
}
export type ScrollProps = ScrollPropsWithFalseHtml | ScrollPropsWithTrueHtml;
export declare const Scroll: ForwardRefComponent<ScrollProps, THREE.Group & HTMLDivElement>;
export {};
+237
View File
@@ -0,0 +1,237 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import { useThree, useFrame, context as context$1 } from '@react-three/fiber';
import { easing } from 'maath';
const context = /* @__PURE__ */React.createContext(null);
function useScroll() {
return React.useContext(context);
}
function ScrollControls({
eps = 0.00001,
enabled = true,
infinite,
horizontal,
pages = 1,
distance = 1,
damping = 0.25,
maxSpeed = Infinity,
prepend = false,
style = {},
children
}) {
const {
get,
setEvents,
gl,
size,
invalidate,
events
} = useThree();
const [el] = React.useState(() => document.createElement('div'));
const [fill] = React.useState(() => document.createElement('div'));
const [fixed] = React.useState(() => document.createElement('div'));
const target = gl.domElement.parentNode;
const scroll = React.useRef(0);
const state = React.useMemo(() => {
const state = {
el,
eps,
fill,
fixed,
horizontal,
damping,
offset: 0,
delta: 0,
scroll,
pages,
// 0-1 for a range between from -> from + distance
range(from, distance, margin = 0) {
const start = from - margin;
const end = start + distance + margin * 2;
return this.offset < start ? 0 : this.offset > end ? 1 : (this.offset - start) / (end - start);
},
// 0-1-0 for a range between from -> from + distance
curve(from, distance, margin = 0) {
return Math.sin(this.range(from, distance, margin) * Math.PI);
},
// true/false for a range between from -> from + distance
visible(from, distance, margin = 0) {
const start = from - margin;
const end = start + distance + margin * 2;
return this.offset >= start && this.offset <= end;
}
};
return state;
}, [eps, damping, horizontal, pages]);
React.useEffect(() => {
el.style.position = 'absolute';
el.style.width = '100%';
el.style.height = '100%';
el.style[horizontal ? 'overflowX' : 'overflowY'] = 'auto';
el.style[horizontal ? 'overflowY' : 'overflowX'] = 'hidden';
el.style.top = '0px';
el.style.left = '0px';
for (const key in style) {
el.style[key] = style[key];
}
fixed.style.position = 'sticky';
fixed.style.top = '0px';
fixed.style.left = '0px';
fixed.style.width = '100%';
fixed.style.height = '100%';
fixed.style.overflow = 'hidden';
el.appendChild(fixed);
fill.style.height = horizontal ? '100%' : `${pages * distance * 100}%`;
fill.style.width = horizontal ? `${pages * distance * 100}%` : '100%';
fill.style.pointerEvents = 'none';
el.appendChild(fill);
if (prepend) target.prepend(el);else target.appendChild(el);
// Init scroll one pixel in to allow upward/leftward scroll
el[horizontal ? 'scrollLeft' : 'scrollTop'] = 1;
const oldTarget = events.connected || gl.domElement;
requestAnimationFrame(() => events.connect == null ? void 0 : events.connect(el));
const oldCompute = get().events.compute;
setEvents({
compute(event, state) {
// we are using boundingClientRect because we could not rely on target.offsetTop as canvas could be positioned anywhere in dom
const {
left,
top
} = target.getBoundingClientRect();
const offsetX = event.clientX - left;
const offsetY = event.clientY - top;
state.pointer.set(offsetX / state.size.width * 2 - 1, -(offsetY / state.size.height) * 2 + 1);
state.raycaster.setFromCamera(state.pointer, state.camera);
}
});
return () => {
target.removeChild(el);
setEvents({
compute: oldCompute
});
events.connect == null || events.connect(oldTarget);
};
}, [pages, distance, horizontal, el, fill, fixed, target]);
React.useEffect(() => {
if (events.connected === el) {
const containerLength = size[horizontal ? 'width' : 'height'];
const scrollLength = el[horizontal ? 'scrollWidth' : 'scrollHeight'];
const scrollThreshold = scrollLength - containerLength;
let current = 0;
let disableScroll = true;
let firstRun = true;
const onScroll = () => {
// Prevent first scroll because it is indirectly caused by the one pixel offset
if (!enabled || firstRun) return;
invalidate();
current = el[horizontal ? 'scrollLeft' : 'scrollTop'];
scroll.current = current / scrollThreshold;
if (infinite) {
if (!disableScroll) {
if (current >= scrollThreshold) {
const damp = 1 - state.offset;
el[horizontal ? 'scrollLeft' : 'scrollTop'] = 1;
scroll.current = state.offset = -damp;
disableScroll = true;
} else if (current <= 0) {
const damp = 1 + state.offset;
el[horizontal ? 'scrollLeft' : 'scrollTop'] = scrollLength;
scroll.current = state.offset = damp;
disableScroll = true;
}
}
if (disableScroll) setTimeout(() => disableScroll = false, 40);
}
};
el.addEventListener('scroll', onScroll, {
passive: true
});
requestAnimationFrame(() => firstRun = false);
const onWheel = e => el.scrollLeft += e.deltaY / 2;
if (horizontal) el.addEventListener('wheel', onWheel, {
passive: true
});
return () => {
el.removeEventListener('scroll', onScroll);
if (horizontal) el.removeEventListener('wheel', onWheel);
};
}
}, [el, events, size, infinite, state, invalidate, horizontal, enabled]);
let last = 0;
useFrame((_, delta) => {
last = state.offset;
easing.damp(state, 'offset', scroll.current, damping, delta, maxSpeed, undefined, eps);
easing.damp(state, 'delta', Math.abs(last - state.offset), damping, delta, maxSpeed, undefined, eps);
if (state.delta > eps) invalidate();
});
return /*#__PURE__*/React.createElement(context.Provider, {
value: state
}, children);
}
const ScrollCanvas = /* @__PURE__ */React.forwardRef(({
children
}, ref) => {
const group = React.useRef(null);
React.useImperativeHandle(ref, () => group.current, []);
const state = useScroll();
const {
width,
height
} = useThree(state => state.viewport);
useFrame(() => {
group.current.position.x = state.horizontal ? -width * (state.pages - 1) * state.offset : 0;
group.current.position.y = state.horizontal ? 0 : height * (state.pages - 1) * state.offset;
});
return /*#__PURE__*/React.createElement("group", {
ref: group
}, children);
});
const ScrollHtml = /*#__PURE__*/React.forwardRef(({
children,
style,
...props
}, ref) => {
const state = useScroll();
const group = React.useRef(null);
React.useImperativeHandle(ref, () => group.current, []);
const {
width,
height
} = useThree(state => state.size);
const fiberState = React.useContext(context$1);
const root = React.useMemo(() => ReactDOM.createRoot(state.fixed), [state.fixed]);
useFrame(() => {
if (state.delta > state.eps) {
group.current.style.transform = `translate3d(${state.horizontal ? -width * (state.pages - 1) * state.offset : 0}px,${state.horizontal ? 0 : height * (state.pages - 1) * -state.offset}px,0)`;
}
});
root.render(/*#__PURE__*/React.createElement("div", _extends({
ref: group,
style: {
...style,
position: 'absolute',
top: 0,
left: 0,
willChange: 'transform'
}
}, props), /*#__PURE__*/React.createElement(context.Provider, {
value: state
}, /*#__PURE__*/React.createElement(context$1.Provider, {
value: fiberState
}, children))));
return null;
});
const Scroll = /* @__PURE__ */React.forwardRef(({
html,
...props
}, ref) => {
const El = html ? ScrollHtml : ScrollCanvas;
return /*#__PURE__*/React.createElement(El, _extends({
ref: ref
}, props));
});
export { Scroll, ScrollControls, useScroll };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),t=require("react"),n=require("three"),r=require("three-stdlib"),o=require("@react-three/fiber"),i=require("zustand/shallow");function l(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function s(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var c=l(e),u=s(t),a=s(n);const d=u.createContext([]);exports.Select=function({box:e,multiple:t,children:n,onChange:l,onChangePointerUp:s,border:f="1px solid #55aaff",backgroundColor:p="rgba(75, 160, 255, 0.1)",filter:h=e=>e,...v}){const[b,y]=u.useState(!1),{setEvents:m,camera:x,raycaster:E,gl:g,controls:w,size:j,get:C}=o.useThree(),[P,O]=u.useState(!1),[M,k]=u.useReducer(((e,{object:t,shift:n})=>void 0===t?[]:Array.isArray(t)?t:n?e.includes(t)?e.filter((e=>e!==t)):[t,...e]:e[0]===t?[]:[t]),[]);u.useEffect((()=>{b?null==l||l(M):null==s||s(M)}),[M,b]);const q=u.useCallback((e=>{e.stopPropagation(),k({object:h([e.object])[0],shift:t&&e.shiftKey})}),[]),L=u.useCallback((e=>!P&&k({})),[P]),S=u.useRef(null);return u.useEffect((()=>{if(!e||!t)return;const n=new r.SelectionBox(x,S.current),o=document.createElement("div");o.style.pointerEvents="none",o.style.border=f,o.style.backgroundColor=p,o.style.position="fixed";const l=new a.Vector2,s=new a.Vector2,c=new a.Vector2,u=C().events.enabled,d=null==w?void 0:w.enabled;let v=!1;function b(e,t){const{offsetX:n,offsetY:r}=e,{width:o,height:i}=j;t.set(n/o*2-1,-r/i*2+1)}function E(e){e.shiftKey&&(!function(e){var t;w&&(w.enabled=!1),m({enabled:!1}),y(v=!0),null==(t=g.domElement.parentElement)||t.appendChild(o),o.style.left=`${e.clientX}px`,o.style.top=`${e.clientY}px`,o.style.width="0px",o.style.height="0px",l.x=e.clientX,l.y=e.clientY}(e),b(e,n.startPoint))}let P=[];function O(e){if(v){!function(e){c.x=Math.max(l.x,e.clientX),c.y=Math.max(l.y,e.clientY),s.x=Math.min(l.x,e.clientX),s.y=Math.min(l.y,e.clientY),o.style.left=`${s.x}px`,o.style.top=`${s.y}px`,o.style.width=c.x-s.x+"px",o.style.height=c.y-s.y+"px"}(e),b(e,n.endPoint);const t=n.select().sort((e=>e.uuid)).filter((e=>e.isMesh));i.shallow(t,P)||(P=t,k({object:h(t)}))}}function M(e){var t;v&&v&&(w&&(w.enabled=d),m({enabled:u}),y(v=!1),null==(t=o.parentElement)||t.removeChild(o))}return document.addEventListener("pointerdown",E,{passive:!0}),document.addEventListener("pointermove",O,{passive:!0,capture:!0}),document.addEventListener("pointerup",M,{passive:!0}),()=>{document.removeEventListener("pointerdown",E),document.removeEventListener("pointermove",O,!0),document.removeEventListener("pointerup",M)}}),[j.width,j.height,E,x,w,g]),u.createElement("group",c.default({ref:S,onClick:q,onPointerOver:()=>O(!0),onPointerOut:()=>O(!1),onPointerMissed:L},v),u.createElement(d.Provider,{value:M},n))},exports.useSelect=function(){return u.useContext(d)};
+14
View File
@@ -0,0 +1,14 @@
import * as React from 'react';
import * as THREE from 'three';
import { ThreeElements } from '@react-three/fiber';
export type SelectProps = Omit<ThreeElements['group'], 'ref'> & {
multiple?: boolean;
box?: boolean;
border?: string;
backgroundColor?: string;
onChange?: (selected: THREE.Object3D[]) => void;
onChangePointerUp?: (selected: THREE.Object3D[]) => void;
filter?: (selected: THREE.Object3D[]) => THREE.Object3D[];
};
export declare function Select({ box, multiple, children, onChange, onChangePointerUp, border, backgroundColor, filter: customFilter, ...props }: SelectProps): React.JSX.Element;
export declare function useSelect(): THREE.Object3D[];
+171
View File
@@ -0,0 +1,171 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as React from 'react';
import * as THREE from 'three';
import { SelectionBox } from 'three-stdlib';
import { useThree } from '@react-three/fiber';
import { shallow } from 'zustand/shallow';
const context = /* @__PURE__ */React.createContext([]);
function Select({
box,
multiple,
children,
onChange,
onChangePointerUp,
border = '1px solid #55aaff',
backgroundColor = 'rgba(75, 160, 255, 0.1)',
filter: customFilter = item => item,
...props
}) {
const [downed, down] = React.useState(false);
const {
setEvents,
camera,
raycaster,
gl,
controls,
size,
get
} = useThree();
const [hovered, hover] = React.useState(false);
const [active, dispatch] = React.useReducer(
// @ts-expect-error
(state, {
object,
shift
}) => {
if (object === undefined) return [];else if (Array.isArray(object)) return object;else if (!shift) return state[0] === object ? [] : [object];
// @ts-expect-error
else if (state.includes(object)) return state.filter(o => o !== object);else return [object, ...state];
}, []);
React.useEffect(() => {
if (downed) onChange == null || onChange(active);else onChangePointerUp == null || onChangePointerUp(active);
}, [active, downed]);
const onClick = React.useCallback(e => {
e.stopPropagation();
dispatch({
object: customFilter([e.object])[0],
shift: multiple && e.shiftKey
});
}, []);
const onPointerMissed = React.useCallback(e => !hovered && dispatch({}), [hovered]);
const ref = React.useRef(null);
React.useEffect(() => {
if (!box || !multiple) return;
const selBox = new SelectionBox(camera, ref.current);
const element = document.createElement('div');
element.style.pointerEvents = 'none';
element.style.border = border;
element.style.backgroundColor = backgroundColor;
element.style.position = 'fixed';
const startPoint = new THREE.Vector2();
const pointTopLeft = new THREE.Vector2();
const pointBottomRight = new THREE.Vector2();
const oldRaycasterEnabled = get().events.enabled;
const oldControlsEnabled = controls == null ? void 0 : controls.enabled;
let isDown = false;
function prepareRay(event, vec) {
const {
offsetX,
offsetY
} = event;
const {
width,
height
} = size;
vec.set(offsetX / width * 2 - 1, -(offsetY / height) * 2 + 1);
}
function onSelectStart(event) {
var _gl$domElement$parent;
if (controls) controls.enabled = false;
setEvents({
enabled: false
});
down(isDown = true);
(_gl$domElement$parent = gl.domElement.parentElement) == null || _gl$domElement$parent.appendChild(element);
element.style.left = `${event.clientX}px`;
element.style.top = `${event.clientY}px`;
element.style.width = '0px';
element.style.height = '0px';
startPoint.x = event.clientX;
startPoint.y = event.clientY;
}
function onSelectMove(event) {
pointBottomRight.x = Math.max(startPoint.x, event.clientX);
pointBottomRight.y = Math.max(startPoint.y, event.clientY);
pointTopLeft.x = Math.min(startPoint.x, event.clientX);
pointTopLeft.y = Math.min(startPoint.y, event.clientY);
element.style.left = `${pointTopLeft.x}px`;
element.style.top = `${pointTopLeft.y}px`;
element.style.width = `${pointBottomRight.x - pointTopLeft.x}px`;
element.style.height = `${pointBottomRight.y - pointTopLeft.y}px`;
}
function onSelectOver() {
if (isDown) {
var _element$parentElemen;
if (controls) controls.enabled = oldControlsEnabled;
setEvents({
enabled: oldRaycasterEnabled
});
down(isDown = false);
(_element$parentElemen = element.parentElement) == null || _element$parentElemen.removeChild(element);
}
}
function pointerDown(event) {
if (event.shiftKey) {
onSelectStart(event);
prepareRay(event, selBox.startPoint);
}
}
let previous = [];
function pointerMove(event) {
if (isDown) {
onSelectMove(event);
prepareRay(event, selBox.endPoint);
const allSelected = selBox.select().sort(o => o.uuid).filter(o => o.isMesh);
if (!shallow(allSelected, previous)) {
previous = allSelected;
dispatch({
object: customFilter(allSelected)
});
}
}
}
function pointerUp(event) {
if (isDown) onSelectOver();
}
document.addEventListener('pointerdown', pointerDown, {
passive: true
});
document.addEventListener('pointermove', pointerMove, {
passive: true,
capture: true
});
document.addEventListener('pointerup', pointerUp, {
passive: true
});
return () => {
document.removeEventListener('pointerdown', pointerDown);
document.removeEventListener('pointermove', pointerMove, true);
document.removeEventListener('pointerup', pointerUp);
};
}, [size.width, size.height, raycaster, camera, controls, gl]);
return /*#__PURE__*/React.createElement("group", _extends({
ref: ref,
onClick: onClick,
onPointerOver: () => hover(true),
onPointerOut: () => hover(false),
onPointerMissed: onPointerMissed
}, props), /*#__PURE__*/React.createElement(context.Provider, {
value: active
}, children));
}
// The return type is explicitly declared here because otherwise TypeScript will emit `THREE.Object3D<THREE.Event>[]`.
// The meaning of the generic parameter for `Object3D` was changed in r156, so it should not be included so that it
// works with all versions of @types/three.
function useSelect() {
return React.useContext(context);
}
export { Select, useSelect };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),t=require("react"),r=require("three"),n=require("@react-three/fiber"),c=require("tunnel-rat");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function i(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var l=a(e),o=i(t),u=i(r),s=a(c);const f=new u.Color,d=s.default();function m(e,t){const{right:r,top:n,left:c,bottom:a,width:i,height:l}=t,o=t.bottom<0||n>e.height||r<0||t.left>e.width,u=e.top+e.height-a;return{position:{width:i,height:l,left:c-e.left,top:n,bottom:u,right:r},isOffscreen:o}}function g(e,{left:t,bottom:r,width:n,height:c}){let a;const i=n/c;var l;return(l=e.camera)&&l.isOrthographicCamera?e.camera.manual?e.camera.updateProjectionMatrix():e.camera.left===n/-2&&e.camera.right===n/2&&e.camera.top===c/2&&e.camera.bottom===c/-2||(Object.assign(e.camera,{left:n/-2,right:n/2,top:c/2,bottom:c/-2}),e.camera.updateProjectionMatrix()):e.camera.aspect!==i&&(e.camera.aspect=i,e.camera.updateProjectionMatrix()),a=e.gl.autoClear,e.gl.autoClear=!1,e.gl.setViewport(t,r,n,c),e.gl.setScissor(t,r,n,c),e.gl.setScissorTest(!0),a}function h(e,t){e.gl.setScissorTest(!1),e.gl.autoClear=t}function p(e){e.gl.getClearColor(f),e.gl.setClearColor(f,e.gl.getClearAlpha()),e.gl.clear(!0,!0)}function v({visible:e=!0,canvasSize:t,scene:r,index:c,children:a,frames:i,rect:l,track:u}){const s=n.useThree(),[f,d]=o.useState(!1);let v=0;return n.useFrame((n=>{var c;(i===1/0||v<=i)&&(u&&(l.current=null==(c=u.current)?void 0:c.getBoundingClientRect()),v++);if(l.current){const{position:c,isOffscreen:i}=m(t,l.current);if(f!==i&&d(i),e&&!f&&l.current){const e=g(n,c);n.gl.render(a?n.scene:r,n.camera),h(n,e)}}}),c),o.useLayoutEffect((()=>{const r=l.current;if(r&&(!e||!f)){const{position:e}=m(t,r),n=g(s,e);p(s),h(s,n)}}),[e,f]),o.useEffect((()=>{if(!u)return;const e=l.current,r=s.get().events.connected;return s.setEvents({connected:u.current}),()=>{if(e){const{position:r}=m(t,e),n=g(s,r);p(s),h(s,n)}s.setEvents({connected:r})}}),[u]),o.createElement(o.Fragment,null,a,o.createElement("group",{onPointerOver:()=>null}))}const b=o.forwardRef((({track:e,visible:t=!0,index:r=1,id:c,style:a,className:i,frames:s=1/0,children:f,...d},m)=>{var g,h,p,b;const E=o.useRef(null),{size:w,scene:C}=n.useThree(),[x]=o.useState((()=>new u.Scene)),[O,y]=o.useReducer((()=>!0),!1),j=o.useCallback(((t,r)=>{if(E.current&&e&&e.current&&t.target===e.current){const{width:e,height:n,left:c,top:a}=E.current,i=t.clientX-c,l=t.clientY-a;r.pointer.set(i/e*2-1,-l/n*2+1),r.raycaster.setFromCamera(r.pointer,r.camera)}}),[E,e]);return o.useEffect((()=>{var t;e&&(E.current=null==(t=e.current)?void 0:t.getBoundingClientRect()),y()}),[e]),o.createElement("group",l.default({ref:m},d),O&&n.createPortal(o.createElement(v,{visible:t,canvasSize:w,frames:s,scene:C,track:e,rect:E,index:r},f),x,{events:{compute:j,priority:r},size:{width:null==(g=E.current)?void 0:g.width,height:null==(h=E.current)?void 0:h.height,top:null==(p=E.current)?void 0:p.top,left:null==(b=E.current)?void 0:b.left}}))})),E=o.forwardRef((({as:e="div",id:t,visible:r,className:n,style:c,index:a=1,track:i,frames:u=1/0,children:s,...f},m)=>{const g=o.useId(),h=o.useRef(null);return o.useImperativeHandle(m,(()=>h.current)),o.createElement(o.Fragment,null,o.createElement(e,l.default({ref:h,id:t,className:n,style:c},f)),o.createElement(d.In,null,o.createElement(b,{visible:r,key:g,track:h,frames:u,index:a},s)))})),w=(()=>{const e=o.forwardRef(((e,t)=>o.useContext(n.context)?o.createElement(b,l.default({ref:t},e)):o.createElement(E,l.default({ref:t},e))));return e.Port=()=>o.createElement(d.Out,null),e})();exports.View=w;
+34
View File
@@ -0,0 +1,34 @@
import * as React from 'react';
import * as THREE from 'three';
type CanvasSize = {
top: number;
left: number;
height: number;
width: number;
};
export type ContainerProps = {
visible: boolean;
scene: THREE.Scene;
index: number;
children?: React.ReactNode;
frames: number;
rect: React.RefObject<DOMRect>;
track?: React.RefObject<HTMLElement>;
canvasSize: CanvasSize;
};
export type ViewProps = {
as?: string;
id?: string;
className?: string;
style?: React.CSSProperties;
visible?: boolean;
index?: number;
frames?: number;
children?: React.ReactNode;
track?: React.RefObject<HTMLElement>;
};
export type ViewportProps = {
Port: () => React.JSX.Element;
} & React.ForwardRefExoticComponent<ViewProps & React.RefAttributes<HTMLElement | THREE.Group>>;
export declare const View: ViewportProps;
export {};
+259
View File
@@ -0,0 +1,259 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as React from 'react';
import * as THREE from 'three';
import { context, useThree, createPortal, useFrame } from '@react-three/fiber';
import tunnel from 'tunnel-rat';
const isOrthographicCamera = def => def && def.isOrthographicCamera;
const col = /* @__PURE__ */new THREE.Color();
const tracked = /* @__PURE__ */tunnel();
function computeContainerPosition(canvasSize, trackRect) {
const {
right,
top,
left: trackLeft,
bottom: trackBottom,
width,
height
} = trackRect;
const isOffscreen = trackRect.bottom < 0 || top > canvasSize.height || right < 0 || trackRect.left > canvasSize.width;
const canvasBottom = canvasSize.top + canvasSize.height;
const bottom = canvasBottom - trackBottom;
const left = trackLeft - canvasSize.left;
return {
position: {
width,
height,
left,
top,
bottom,
right
},
isOffscreen
};
}
function prepareSkissor(state, {
left,
bottom,
width,
height
}) {
let autoClear;
const aspect = width / height;
if (isOrthographicCamera(state.camera)) {
if (!state.camera.manual) {
if (state.camera.left !== width / -2 || state.camera.right !== width / 2 || state.camera.top !== height / 2 || state.camera.bottom !== height / -2) {
Object.assign(state.camera, {
left: width / -2,
right: width / 2,
top: height / 2,
bottom: height / -2
});
state.camera.updateProjectionMatrix();
}
} else {
state.camera.updateProjectionMatrix();
}
} else if (state.camera.aspect !== aspect) {
state.camera.aspect = aspect;
state.camera.updateProjectionMatrix();
}
autoClear = state.gl.autoClear;
state.gl.autoClear = false;
state.gl.setViewport(left, bottom, width, height);
state.gl.setScissor(left, bottom, width, height);
state.gl.setScissorTest(true);
return autoClear;
}
function finishSkissor(state, autoClear) {
// Restore the default state
state.gl.setScissorTest(false);
state.gl.autoClear = autoClear;
}
function clear(state) {
state.gl.getClearColor(col);
state.gl.setClearColor(col, state.gl.getClearAlpha());
state.gl.clear(true, true);
}
function Container({
visible = true,
canvasSize,
scene,
index,
children,
frames,
rect,
track
}) {
const rootState = useThree();
const [isOffscreen, setOffscreen] = React.useState(false);
let frameCount = 0;
useFrame(state => {
if (frames === Infinity || frameCount <= frames) {
var _track$current;
if (track) rect.current = (_track$current = track.current) == null ? void 0 : _track$current.getBoundingClientRect();
frameCount++;
}
if (rect.current) {
const {
position,
isOffscreen: _isOffscreen
} = computeContainerPosition(canvasSize, rect.current);
if (isOffscreen !== _isOffscreen) setOffscreen(_isOffscreen);
if (visible && !isOffscreen && rect.current) {
const autoClear = prepareSkissor(state, position);
// When children are present render the portalled scene, otherwise the default scene
state.gl.render(children ? state.scene : scene, state.camera);
finishSkissor(state, autoClear);
}
}
}, index);
React.useLayoutEffect(() => {
const curRect = rect.current;
if (curRect && (!visible || !isOffscreen)) {
// If the view is not visible clear it once, but stop rendering afterwards!
const {
position
} = computeContainerPosition(canvasSize, curRect);
const autoClear = prepareSkissor(rootState, position);
clear(rootState);
finishSkissor(rootState, autoClear);
}
}, [visible, isOffscreen]);
React.useEffect(() => {
if (!track) return;
const curRect = rect.current;
// Connect the event layer to the tracking element
const old = rootState.get().events.connected;
rootState.setEvents({
connected: track.current
});
return () => {
if (curRect) {
const {
position
} = computeContainerPosition(canvasSize, curRect);
const autoClear = prepareSkissor(rootState, position);
clear(rootState);
finishSkissor(rootState, autoClear);
}
rootState.setEvents({
connected: old
});
};
}, [track]);
return /*#__PURE__*/React.createElement(React.Fragment, null, children, /*#__PURE__*/React.createElement("group", {
onPointerOver: () => null
}));
}
const CanvasView = /* @__PURE__ */React.forwardRef(({
track,
visible = true,
index = 1,
id,
style,
className,
frames = Infinity,
children,
...props
}, fref) => {
var _rect$current, _rect$current2, _rect$current3, _rect$current4;
const rect = React.useRef(null);
const {
size,
scene
} = useThree();
const [virtualScene] = React.useState(() => new THREE.Scene());
const [ready, toggle] = React.useReducer(() => true, false);
const compute = React.useCallback((event, state) => {
if (rect.current && track && track.current && event.target === track.current) {
const {
width,
height,
left,
top
} = rect.current;
const x = event.clientX - left;
const y = event.clientY - top;
state.pointer.set(x / width * 2 - 1, -(y / height) * 2 + 1);
state.raycaster.setFromCamera(state.pointer, state.camera);
}
}, [rect, track]);
React.useEffect(() => {
var _track$current2;
// We need the tracking elements bounds beforehand in order to inject it into the portal
if (track) rect.current = (_track$current2 = track.current) == null ? void 0 : _track$current2.getBoundingClientRect();
// And now we can proceed
toggle();
}, [track]);
return /*#__PURE__*/React.createElement("group", _extends({
ref: fref
}, props), ready && createPortal(/*#__PURE__*/React.createElement(Container, {
visible: visible,
canvasSize: size,
frames: frames,
scene: scene,
track: track,
rect: rect,
index: index
}, children), virtualScene, {
events: {
compute,
priority: index
},
size: {
width: (_rect$current = rect.current) == null ? void 0 : _rect$current.width,
height: (_rect$current2 = rect.current) == null ? void 0 : _rect$current2.height,
// @ts-ignore
top: (_rect$current3 = rect.current) == null ? void 0 : _rect$current3.top,
// @ts-ignore
left: (_rect$current4 = rect.current) == null ? void 0 : _rect$current4.left
}
}));
});
const HtmlView = /* @__PURE__ */React.forwardRef(({
as: El = 'div',
id,
visible,
className,
style,
index = 1,
track,
frames = Infinity,
children,
...props
}, fref) => {
const uuid = React.useId();
const ref = React.useRef(null);
React.useImperativeHandle(fref, () => ref.current);
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(El, _extends({
ref: ref,
id: id,
className: className,
style: style
}, props)), /*#__PURE__*/React.createElement(tracked.In, null, /*#__PURE__*/React.createElement(CanvasView, {
visible: visible,
key: uuid,
track: ref,
frames: frames,
index: index
}, children)));
});
const View = /* @__PURE__ */(() => {
const _View = /*#__PURE__*/React.forwardRef((props, fref) => {
// If we're inside a canvas we should be able to access the context store
const store = React.useContext(context);
// If that's not the case we render a tunnel
if (!store) return /*#__PURE__*/React.createElement(HtmlView, _extends({
ref: fref
}, props));
// Otherwise a plain canvas-view
else return /*#__PURE__*/React.createElement(CanvasView, _extends({
ref: fref
}, props));
});
_View.Port = () => /*#__PURE__*/React.createElement(tracked.Out, null);
return _View;
})();
export { View };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("react"),t=require("suspend-react"),u=require("../core/VideoTexture.cjs.js");function c(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function i(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var u=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,u.get?u:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}require("three"),require("@react-three/fiber"),require("hls.js");var n=c(e),a=i(r);const o=r.forwardRef((({constraints:e={audio:!1,video:{facingMode:"user"}},...c},i)=>{const o=t.suspend((()=>navigator.mediaDevices.getUserMedia(e)),[]);return r.useEffect((()=>()=>{null==o||o.getTracks().forEach((e=>e.stop())),t.clear([])}),[o]),a.createElement(u.VideoTexture,n.default({ref:i},c,{src:o}))}));exports.WebcamVideoTexture=o;
+17
View File
@@ -0,0 +1,17 @@
import * as React from 'react';
import * as THREE from 'three';
import { VideoTextureProps } from '../core/VideoTexture';
export type WebcamVideoTextureProps = Omit<VideoTextureProps, 'src'> & {
constraints?: MediaStreamConstraints;
};
export declare const WebcamVideoTexture: React.ForwardRefExoticComponent<Omit<{
children?: (texture: THREE.VideoTexture) => React.ReactNode;
src: string | MediaProvider | null;
} & {
unsuspend?: keyof HTMLVideoElementEventMap;
start?: boolean;
hls?: Parameters<(userConfig?: Partial<import("hls.js").HlsConfig> | undefined) => Promise<import("hls.js").default | null>>[0];
onVideoFrame?: VideoFrameRequestCallback;
} & Partial<Omit<HTMLVideoElement, "children" | "src" | "srcObject">>, "src"> & {
constraints?: MediaStreamConstraints;
} & React.RefAttributes<THREE.VideoTexture>>;
+33
View File
@@ -0,0 +1,33 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import * as React from 'react';
import { forwardRef, useEffect } from 'react';
import { suspend, clear } from 'suspend-react';
import { VideoTexture } from '../core/VideoTexture.js';
/**
* Create a video texture from [`getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)
*/
const WebcamVideoTexture = /* @__PURE__ */forwardRef(({
constraints = {
audio: false,
video: {
facingMode: 'user'
}
},
...props
}, fref) => {
const mediaStream = suspend(() => navigator.mediaDevices.getUserMedia(constraints), []);
useEffect(() => {
return () => {
mediaStream == null || mediaStream.getTracks().forEach(track => track.stop());
clear([]);
};
}, [mediaStream]);
return /*#__PURE__*/React.createElement(VideoTexture, _extends({
ref: fref
}, props, {
src: mediaStream
}));
});
export { WebcamVideoTexture };
File diff suppressed because one or more lines are too long
+17
View File
@@ -0,0 +1,17 @@
export { Html } from './Html';
export { CycleRaycast } from './CycleRaycast';
export { useCursor } from './useCursor';
export { Loader } from './Loader';
export * from './ScrollControls';
export * from './PresentationControls';
export * from './KeyboardControls';
export * from './Select';
export * from '../core';
export * from './View';
export * from './pivotControls';
export * from './ScreenVideoTexture';
export * from './WebcamVideoTexture';
export * from './FaceControls';
export { DragControls } from './DragControls';
export * from './FaceLandmarker';
export * from './Facemesh';
+176
View File
@@ -0,0 +1,176 @@
export { Html } from './Html.js';
export { CycleRaycast } from './CycleRaycast.js';
export { useCursor } from './useCursor.js';
export { Loader } from './Loader.js';
export { Scroll, ScrollControls, useScroll } from './ScrollControls.js';
export { PresentationControls } from './PresentationControls.js';
export { KeyboardControls, useKeyboardControls } from './KeyboardControls.js';
export { Select, useSelect } from './Select.js';
export { View } from './View.js';
export { PivotControls } from './pivotControls/index.js';
export { ScreenVideoTexture } from './ScreenVideoTexture.js';
export { WebcamVideoTexture } from './WebcamVideoTexture.js';
export { FaceControls, useFaceControls } from './FaceControls.js';
export { DragControls } from './DragControls.js';
export { FaceLandmarker, FaceLandmarkerDefaults, useFaceLandmarker } from './FaceLandmarker.js';
export { Facemesh, FacemeshDatas, FacemeshEye, FacemeshEyeDefaults } from './Facemesh.js';
export { Billboard } from '../core/Billboard.js';
export { ScreenSpace } from '../core/ScreenSpace.js';
export { ScreenSizer } from '../core/ScreenSizer.js';
export { QuadraticBezierLine } from '../core/QuadraticBezierLine.js';
export { CubicBezierLine } from '../core/CubicBezierLine.js';
export { CatmullRomLine } from '../core/CatmullRomLine.js';
export { Line } from '../core/Line.js';
export { PositionalAudio } from '../core/PositionalAudio.js';
export { Text } from '../core/Text.js';
export { Text3D } from '../core/Text3D.js';
export { Effects, isWebGL2Available } from '../core/Effects.js';
export { GradientTexture, GradientType } from '../core/GradientTexture.js';
export { Image } from '../core/Image.js';
export { Edges } from '../core/Edges.js';
export { Outlines } from '../core/Outlines.js';
export { Trail, useTrail } from '../core/Trail.js';
export { Sampler, useSurfaceSampler } from '../core/Sampler.js';
export { ComputedAttribute } from '../core/ComputedAttribute.js';
export { Clone } from '../core/Clone.js';
export { MarchingCube, MarchingCubes, MarchingPlane } from '../core/MarchingCubes.js';
export { Decal } from '../core/Decal.js';
export { Svg } from '../core/Svg.js';
export { Gltf, useGLTF } from '../core/Gltf.js';
export { AsciiRenderer } from '../core/AsciiRenderer.js';
export { Splat } from '../core/Splat.js';
export { OrthographicCamera } from '../core/OrthographicCamera.js';
export { PerspectiveCamera } from '../core/PerspectiveCamera.js';
export { CubeCamera, useCubeCamera } from '../core/CubeCamera.js';
export { DeviceOrientationControls } from '../core/DeviceOrientationControls.js';
export { FlyControls } from '../core/FlyControls.js';
export { MapControls } from '../core/MapControls.js';
export { OrbitControls } from '../core/OrbitControls.js';
export { TrackballControls } from '../core/TrackballControls.js';
export { ArcballControls } from '../core/ArcballControls.js';
export { TransformControls } from '../core/TransformControls.js';
export { PointerLockControls } from '../core/PointerLockControls.js';
export { FirstPersonControls } from '../core/FirstPersonControls.js';
export { CameraControls } from '../core/CameraControls.js';
export { default as CameraControlsImpl } from 'camera-controls';
export { MotionPathControls, useMotion } from '../core/MotionPathControls.js';
export { GizmoHelper, useGizmoContext } from '../core/GizmoHelper.js';
export { GizmoViewcube } from '../core/GizmoViewcube.js';
export { GizmoViewport } from '../core/GizmoViewport.js';
export { Grid } from '../core/Grid.js';
export { CubeTexture, useCubeTexture } from '../core/CubeTexture.js';
export { Fbx, useFBX } from '../core/Fbx.js';
export { Ktx2, useKTX2 } from '../core/Ktx2.js';
export { Progress, useProgress } from '../core/Progress.js';
export { IsObject, Texture, useTexture } from '../core/Texture.js';
export { VideoTexture, useVideoTexture } from '../core/VideoTexture.js';
export { useFont } from '../core/useFont.js';
export { checkIfFrameIsEmpty, getFirstFrame, useSpriteLoader } from '../core/useSpriteLoader.js';
export { Helper, useHelper } from '../core/Helper.js';
export { Stats } from '../core/Stats.js';
export { StatsGl } from '../core/StatsGl.js';
export { useDepthBuffer } from '../core/useDepthBuffer.js';
export { useAspect } from '../core/useAspect.js';
export { useCamera } from '../core/useCamera.js';
export { DetectGPU, useDetectGPU } from '../core/DetectGPU.js';
export { Bvh, useBVH } from '../core/Bvh.js';
export { useContextBridge } from '../core/useContextBridge.js';
export { useAnimations } from '../core/useAnimations.js';
export { Fbo, useFBO } from '../core/Fbo.js';
export { useIntersect } from '../core/useIntersect.js';
export { useBoxProjectedEnv } from '../core/useBoxProjectedEnv.js';
export { BBAnchor } from '../core/BBAnchor.js';
export { TrailTexture, useTrailTexture } from '../core/TrailTexture.js';
export { Example } from '../core/Example.js';
export { SpriteAnimator, useSpriteAnimator } from '../core/SpriteAnimator.js';
export { CurveModifier } from '../core/CurveModifier.js';
export { MeshDistortMaterial } from '../core/MeshDistortMaterial.js';
export { MeshWobbleMaterial } from '../core/MeshWobbleMaterial.js';
export { MeshReflectorMaterial } from '../core/MeshReflectorMaterial.js';
export { MeshRefractionMaterial } from '../core/MeshRefractionMaterial.js';
export { MeshTransmissionMaterial } from '../core/MeshTransmissionMaterial.js';
export { MeshDiscardMaterial } from '../core/MeshDiscardMaterial.js';
export { MultiMaterial } from '../core/MultiMaterial.js';
export { PointMaterial, PointMaterialImpl } from '../core/PointMaterial.js';
export { shaderMaterial } from '../core/shaderMaterial.js';
export { SoftShadows } from '../core/softShadows.js';
export { Box, Capsule, Circle, Cone, Cylinder, Dodecahedron, Extrude, Icosahedron, Lathe, Octahedron, Plane, Polyhedron, Ring, Shape, Sphere, Tetrahedron, Torus, TorusKnot, Tube } from '../core/shapes.js';
export { RoundedBox, RoundedBoxGeometry } from '../core/RoundedBox.js';
export { ScreenQuad } from '../core/ScreenQuad.js';
export { Center } from '../core/Center.js';
export { Resize } from '../core/Resize.js';
export { Bounds, useBounds } from '../core/Bounds.js';
export { CameraShake } from '../core/CameraShake.js';
export { Float } from '../core/Float.js';
export { Stage } from '../core/Stage.js';
export { Backdrop } from '../core/Backdrop.js';
export { Shadow } from '../core/Shadow.js';
export { Caustics } from '../core/Caustics.js';
export { ContactShadows } from '../core/ContactShadows.js';
export { AccumulativeShadows, RandomizedLight, accumulativeContext } from '../core/AccumulativeShadows.js';
export { SpotLight, SpotLightShadow } from '../core/SpotLight.js';
export { Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal } from '../core/Environment.js';
export { Lightformer } from '../core/Lightformer.js';
export { Sky, calcPosFromAngles } from '../core/Sky.js';
export { Stars } from '../core/Stars.js';
export { Cloud, CloudInstance, Clouds } from '../core/Cloud.js';
export { Sparkles } from '../core/Sparkles.js';
export { useEnvironment } from '../core/useEnvironment.js';
export { MatcapTexture, useMatcapTexture } from '../core/MatcapTexture.js';
export { NormalTexture, useNormalTexture } from '../core/NormalTexture.js';
export { Wireframe } from '../core/Wireframe.js';
export { ShadowAlpha } from '../core/ShadowAlpha.js';
export { Point, Points, PointsBuffer, PositionPoint } from '../core/Points.js';
export { Instance, InstancedAttribute, Instances, Merged, PositionMesh, createInstances } from '../core/Instances.js';
export { Segment, SegmentObject, Segments } from '../core/Segments.js';
export { Detailed } from '../core/Detailed.js';
export { Preload } from '../core/Preload.js';
export { BakeShadows } from '../core/BakeShadows.js';
export { meshBounds } from '../core/meshBounds.js';
export { AdaptiveDpr } from '../core/AdaptiveDpr.js';
export { AdaptiveEvents } from '../core/AdaptiveEvents.js';
export { PerformanceMonitor, usePerformanceMonitor } from '../core/PerformanceMonitor.js';
export { RenderTexture } from '../core/RenderTexture.js';
export { RenderCubeTexture } from '../core/RenderCubeTexture.js';
export { Mask, useMask } from '../core/Mask.js';
export { Hud } from '../core/Hud.js';
export { Fisheye } from '../core/Fisheye.js';
export { MeshPortalMaterial } from '../core/MeshPortalMaterial.js';
export { calculateScaleFactor } from '../core/calculateScaleFactor.js';
import '@babel/runtime/helpers/esm/extends';
import 'react';
import 'react-dom/client';
import 'three';
import '@react-three/fiber';
import 'zustand';
import 'maath';
import '@use-gesture/react';
import 'zustand/middleware';
import 'three-stdlib';
import 'zustand/shallow';
import 'tunnel-rat';
import './pivotControls/AxisArrow.js';
import './pivotControls/context.js';
import './pivotControls/AxisRotator.js';
import './pivotControls/PlaneSlider.js';
import './pivotControls/ScalingSphere.js';
import 'suspend-react';
import 'hls.js';
import 'troika-three-text';
import '../helpers/constants.js';
import 'meshline';
import 'stats.js';
import '../helpers/useEffectfulState.js';
import 'stats-gl';
import 'detect-gpu';
import 'three-mesh-bvh';
import '../helpers/deprecated.js';
import '../materials/BlurPass.js';
import '../materials/ConvolutionMaterial.js';
import '../materials/MeshReflectorMaterial.js';
import '../materials/MeshRefractionMaterial.js';
import '../materials/DiscardMaterial.js';
import '@monogrid/gainmap-js';
import '../helpers/environment-assets.js';
import '../materials/SpotLightMaterial.js';
import '../materials/WireframeMaterial.js';
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("three"),r=require("@react-three/fiber"),n=require("../../core/Line.cjs.js"),o=require("../Html.cjs.js"),a=require("./context.cjs.js");function i(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}require("@babel/runtime/helpers/extends"),require("three-stdlib"),require("react-dom/client");var c=i(e),l=i(t);const s=new l.Vector3,u=new l.Vector3,d=(e,t,r,n)=>{const o=t.dot(t),a=t.dot(e)-t.dot(r),i=t.dot(n);if(0===i)return-a/o;s.copy(n).multiplyScalar(o/i).sub(t),u.copy(n).multiplyScalar(a/i).add(r).sub(e);return-s.dot(u)/s.dot(s)},p=new l.Vector3(0,1,0),m=new l.Matrix4;exports.AxisArrow=({direction:e,axis:t})=>{const{translation:i,translationLimits:s,annotations:u,annotationsClass:f,depthTest:x,scale:y,lineWidth:g,fixed:h,axisColors:b,hoveredColor:O,opacity:P,renderOrder:w,onDragStart:v,onDrag:j,onDragEnd:E,userData:M}=c.useContext(a.context),k=r.useThree((e=>e.controls)),C=c.useRef(null),q=c.useRef(null),L=c.useRef(null),D=c.useRef(0),[F,R]=c.useState(!1),T=c.useCallback((r=>{u&&(C.current.innerText=`${i.current[t].toFixed(2)}`,C.current.style.display="block"),r.stopPropagation();const n=(new l.Matrix4).extractRotation(q.current.matrixWorld),o=r.point.clone(),a=(new l.Vector3).setFromMatrixPosition(q.current.matrixWorld),c=e.clone().applyMatrix4(n).normalize();L.current={clickPoint:o,dir:c},D.current=i.current[t],v({component:"Arrow",axis:t,origin:a,directions:[c]}),k&&(k.enabled=!1),r.target.setPointerCapture(r.pointerId)}),[u,e,k,v,i,t]),S=c.useCallback((e=>{if(e.stopPropagation(),F||R(!0),L.current){const{clickPoint:r,dir:n}=L.current,[o,a]=(null==s?void 0:s[t])||[void 0,void 0];let c=d(r,n,e.ray.origin,e.ray.direction);void 0!==o&&(c=Math.max(c,o-D.current)),void 0!==a&&(c=Math.min(c,a-D.current)),i.current[t]=D.current+c,u&&(C.current.innerText=`${i.current[t].toFixed(2)}`),m.makeTranslation(n.x*c,n.y*c,n.z*c),j(m)}}),[u,j,F,i,s,t]),W=c.useCallback((e=>{u&&(C.current.style.display="none"),e.stopPropagation(),L.current=null,E(),k&&(k.enabled=!0),e.target.releasePointerCapture(e.pointerId)}),[u,k,E]),V=c.useCallback((e=>{e.stopPropagation(),R(!1)}),[]),{cylinderLength:z,coneWidth:A,coneLength:_,matrixL:U}=c.useMemo((()=>{const t=h?g/y*1.6:y/20,r=h?.2:y/5,n=h?1-r:y-r,o=(new l.Quaternion).setFromUnitVectors(p,e.clone().normalize());return{cylinderLength:n,coneWidth:t,coneLength:r,matrixL:(new l.Matrix4).makeRotationFromQuaternion(o)}}),[e,y,g,h]),G=F?O:b[t];return c.createElement("group",{ref:q},c.createElement("group",{matrix:U,matrixAutoUpdate:!1,onPointerDown:T,onPointerMove:S,onPointerUp:W,onPointerOut:V},u&&c.createElement(o.Html,{position:[0,-_,0]},c.createElement("div",{style:{display:"none",background:"#151520",color:"white",padding:"6px 8px",borderRadius:7,whiteSpace:"nowrap"},className:f,ref:C})),c.createElement("mesh",{visible:!1,position:[0,(z+_)/2,0],userData:M},c.createElement("cylinderGeometry",{args:[1.4*A,1.4*A,z+_,8,1]})),c.createElement(n.Line,{transparent:!0,raycast:()=>null,depthTest:x,points:[0,0,0,0,z,0],lineWidth:g,side:l.DoubleSide,color:G,opacity:P,polygonOffset:!0,renderOrder:w,polygonOffsetFactor:-10,fog:!1}),c.createElement("mesh",{raycast:()=>null,position:[0,z+_/2,0],renderOrder:w},c.createElement("coneGeometry",{args:[A,_,24,1]}),c.createElement("meshBasicMaterial",{transparent:!0,depthTest:x,color:G,opacity:P,polygonOffset:!0,polygonOffsetFactor:-10,fog:!1}))))},exports.calculateOffset=d;
+7
View File
@@ -0,0 +1,7 @@
import * as React from 'react';
import * as THREE from 'three';
export declare const calculateOffset: (clickPoint: THREE.Vector3, normal: THREE.Vector3, rayStart: THREE.Vector3, rayDir: THREE.Vector3) => number;
export declare const AxisArrow: React.FC<{
direction: THREE.Vector3;
axis: 0 | 1 | 2;
}>;
+193
View File
@@ -0,0 +1,193 @@
import * as React from 'react';
import * as THREE from 'three';
import { useThree } from '@react-three/fiber';
import { Line } from '../../core/Line.js';
import { Html } from '../Html.js';
import { context } from './context.js';
const vec1 = /* @__PURE__ */new THREE.Vector3();
const vec2 = /* @__PURE__ */new THREE.Vector3();
const calculateOffset = (clickPoint, normal, rayStart, rayDir) => {
const e1 = normal.dot(normal);
const e2 = normal.dot(clickPoint) - normal.dot(rayStart);
const e3 = normal.dot(rayDir);
if (e3 === 0) {
return -e2 / e1;
}
vec1.copy(rayDir).multiplyScalar(e1 / e3).sub(normal);
vec2.copy(rayDir).multiplyScalar(e2 / e3).add(rayStart).sub(clickPoint);
const offset = -vec1.dot(vec2) / vec1.dot(vec1);
return offset;
};
const upV = /* @__PURE__ */new THREE.Vector3(0, 1, 0);
const offsetMatrix = /* @__PURE__ */new THREE.Matrix4();
const AxisArrow = ({
direction,
axis
}) => {
const {
translation,
translationLimits,
annotations,
annotationsClass,
depthTest,
scale,
lineWidth,
fixed,
axisColors,
hoveredColor,
opacity,
renderOrder,
onDragStart,
onDrag,
onDragEnd,
userData
} = React.useContext(context);
const camControls = useThree(state => state.controls);
const divRef = React.useRef(null);
const objRef = React.useRef(null);
const clickInfo = React.useRef(null);
const offset0 = React.useRef(0);
const [isHovered, setIsHovered] = React.useState(false);
const onPointerDown = React.useCallback(e => {
if (annotations) {
divRef.current.innerText = `${translation.current[axis].toFixed(2)}`;
divRef.current.style.display = 'block';
}
e.stopPropagation();
const rotation = new THREE.Matrix4().extractRotation(objRef.current.matrixWorld);
const clickPoint = e.point.clone();
const origin = new THREE.Vector3().setFromMatrixPosition(objRef.current.matrixWorld);
const dir = direction.clone().applyMatrix4(rotation).normalize();
clickInfo.current = {
clickPoint,
dir
};
offset0.current = translation.current[axis];
onDragStart({
component: 'Arrow',
axis,
origin,
directions: [dir]
});
camControls && (camControls.enabled = false);
// @ts-ignore - setPointerCapture is not in the type definition
e.target.setPointerCapture(e.pointerId);
}, [annotations, direction, camControls, onDragStart, translation, axis]);
const onPointerMove = React.useCallback(e => {
e.stopPropagation();
if (!isHovered) setIsHovered(true);
if (clickInfo.current) {
const {
clickPoint,
dir
} = clickInfo.current;
const [min, max] = (translationLimits == null ? void 0 : translationLimits[axis]) || [undefined, undefined];
let offset = calculateOffset(clickPoint, dir, e.ray.origin, e.ray.direction);
if (min !== undefined) {
offset = Math.max(offset, min - offset0.current);
}
if (max !== undefined) {
offset = Math.min(offset, max - offset0.current);
}
translation.current[axis] = offset0.current + offset;
if (annotations) {
divRef.current.innerText = `${translation.current[axis].toFixed(2)}`;
}
offsetMatrix.makeTranslation(dir.x * offset, dir.y * offset, dir.z * offset);
onDrag(offsetMatrix);
}
}, [annotations, onDrag, isHovered, translation, translationLimits, axis]);
const onPointerUp = React.useCallback(e => {
if (annotations) {
divRef.current.style.display = 'none';
}
e.stopPropagation();
clickInfo.current = null;
onDragEnd();
camControls && (camControls.enabled = true);
// @ts-ignore - releasePointerCapture & PointerEvent#pointerId is not in the type definition
e.target.releasePointerCapture(e.pointerId);
}, [annotations, camControls, onDragEnd]);
const onPointerOut = React.useCallback(e => {
e.stopPropagation();
setIsHovered(false);
}, []);
const {
cylinderLength,
coneWidth,
coneLength,
matrixL
} = React.useMemo(() => {
const coneWidth = fixed ? lineWidth / scale * 1.6 : scale / 20;
const coneLength = fixed ? 0.2 : scale / 5;
const cylinderLength = fixed ? 1 - coneLength : scale - coneLength;
const quaternion = new THREE.Quaternion().setFromUnitVectors(upV, direction.clone().normalize());
const matrixL = new THREE.Matrix4().makeRotationFromQuaternion(quaternion);
return {
cylinderLength,
coneWidth,
coneLength,
matrixL
};
}, [direction, scale, lineWidth, fixed]);
const color_ = isHovered ? hoveredColor : axisColors[axis];
return /*#__PURE__*/React.createElement("group", {
ref: objRef
}, /*#__PURE__*/React.createElement("group", {
matrix: matrixL,
matrixAutoUpdate: false,
onPointerDown: onPointerDown,
onPointerMove: onPointerMove,
onPointerUp: onPointerUp,
onPointerOut: onPointerOut
}, annotations && /*#__PURE__*/React.createElement(Html, {
position: [0, -coneLength, 0]
}, /*#__PURE__*/React.createElement("div", {
style: {
display: 'none',
background: '#151520',
color: 'white',
padding: '6px 8px',
borderRadius: 7,
whiteSpace: 'nowrap'
},
className: annotationsClass,
ref: divRef
})), /*#__PURE__*/React.createElement("mesh", {
visible: false,
position: [0, (cylinderLength + coneLength) / 2.0, 0],
userData: userData
}, /*#__PURE__*/React.createElement("cylinderGeometry", {
args: [coneWidth * 1.4, coneWidth * 1.4, cylinderLength + coneLength, 8, 1]
})), /*#__PURE__*/React.createElement(Line, {
transparent: true,
raycast: () => null,
depthTest: depthTest,
points: [0, 0, 0, 0, cylinderLength, 0],
lineWidth: lineWidth,
side: THREE.DoubleSide,
color: color_,
opacity: opacity,
polygonOffset: true,
renderOrder: renderOrder,
polygonOffsetFactor: -10,
fog: false
}), /*#__PURE__*/React.createElement("mesh", {
raycast: () => null,
position: [0, cylinderLength + coneLength / 2.0, 0],
renderOrder: renderOrder
}, /*#__PURE__*/React.createElement("coneGeometry", {
args: [coneWidth, coneLength, 24, 1]
}), /*#__PURE__*/React.createElement("meshBasicMaterial", {
transparent: true,
depthTest: depthTest,
color: color_,
opacity: opacity,
polygonOffset: true,
polygonOffsetFactor: -10,
fog: false
}))));
};
export { AxisArrow, calculateOffset };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("three"),r=require("@react-three/fiber"),n=require("../../core/Line.cjs.js"),o=require("../Html.cjs.js"),a=require("./context.cjs.js");function i(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}require("@babel/runtime/helpers/extends"),require("three-stdlib"),require("react-dom/client");var c=i(e),s=i(t);const l=new s.Vector3,u=new s.Vector3,d=e=>180*e/Math.PI,p=e=>{let t=((e,t)=>{let r=Math.floor(e/t);return r=r<0?r+1:r,e-r*t})(e,2*Math.PI);return Math.abs(t)<1e-6?0:(t<0&&(t+=2*Math.PI),t)},m=new s.Matrix4,h=new s.Vector3,x=new s.Ray,P=new s.Vector3;exports.AxisRotator=({dir1:e,dir2:t,axis:i})=>{const{rotationLimits:M,annotations:f,annotationsClass:b,depthTest:g,scale:y,lineWidth:w,fixed:v,axisColors:C,hoveredColor:j,renderOrder:I,opacity:O,onDragStart:k,onDrag:R,onDragEnd:q,userData:V}=c.useContext(a.context),D=r.useThree((e=>e.controls)),F=c.useRef(null),E=c.useRef(null),W=c.useRef(0),z=c.useRef(0),T=c.useRef(null),[A,L]=c.useState(!1),S=c.useCallback((e=>{f&&(F.current.innerText=`${d(z.current).toFixed(0)}º`,F.current.style.display="block"),e.stopPropagation();const t=e.point.clone(),r=(new s.Vector3).setFromMatrixPosition(E.current.matrixWorld),n=(new s.Vector3).setFromMatrixColumn(E.current.matrixWorld,0).normalize(),o=(new s.Vector3).setFromMatrixColumn(E.current.matrixWorld,1).normalize(),a=(new s.Vector3).setFromMatrixColumn(E.current.matrixWorld,2).normalize(),c=(new s.Plane).setFromNormalAndCoplanarPoint(a,r);T.current={clickPoint:t,origin:r,e1:n,e2:o,normal:a,plane:c},k({component:"Rotator",axis:i,origin:r,directions:[n,o,a]}),D&&(D.enabled=!1),e.target.setPointerCapture(e.pointerId)}),[f,D,k,i]),_=c.useCallback((e=>{if(e.stopPropagation(),A||L(!0),T.current){const{clickPoint:t,origin:r,e1:n,e2:o,normal:a,plane:c}=T.current,[b,g]=(null==M?void 0:M[i])||[void 0,void 0];x.copy(e.ray),x.intersectPlane(c,P),x.direction.negate(),x.intersectPlane(c,P);let y=((e,t,r,n,o)=>{l.copy(e).sub(r),u.copy(t).sub(r);const a=n.dot(n),i=o.dot(o),c=l.dot(n)/a,s=l.dot(o)/i,d=u.dot(n)/a,p=u.dot(o)/i,m=Math.atan2(s,c);return Math.atan2(p,d)-m})(t,P,r,n,o),w=d(y);e.shiftKey&&(w=10*Math.round(w/10),y=(e=>e*Math.PI/180)(w)),void 0!==b&&void 0!==g&&g-b<2*Math.PI?(y=p(y),y=y>Math.PI?y-2*Math.PI:y,y=s.MathUtils.clamp(y,b-W.current,g-W.current),z.current=W.current+y):(z.current=p(W.current+y),z.current=z.current>Math.PI?z.current-2*Math.PI:z.current),f&&(w=d(z.current),F.current.innerText=`${w.toFixed(0)}º`),m.makeRotationAxis(a,y),h.copy(r).applyMatrix4(m).sub(r).negate(),m.setPosition(h),R(m)}}),[f,R,A,M,i]),U=c.useCallback((e=>{f&&(F.current.style.display="none"),e.stopPropagation(),W.current=z.current,T.current=null,q(),D&&(D.enabled=!0),e.target.releasePointerCapture(e.pointerId)}),[f,D,q]),H=c.useCallback((e=>{e.stopPropagation(),L(!1)}),[]),N=c.useMemo((()=>{const r=e.clone().normalize(),n=t.clone().normalize();return(new s.Matrix4).makeBasis(r,n,r.clone().cross(n))}),[e,t]),$=v?.65:.65*y,B=c.useMemo((()=>{const e=[];for(let t=0;t<=32;t++){const r=t*(Math.PI/2)/32;e.push(new s.Vector3(Math.cos(r)*$,Math.sin(r)*$,0))}return e}),[$]);return c.createElement("group",{ref:E,onPointerDown:S,onPointerMove:_,onPointerUp:U,onPointerOut:H,matrix:N,matrixAutoUpdate:!1},f&&c.createElement(o.Html,{position:[$,$,0]},c.createElement("div",{style:{display:"none",background:"#151520",color:"white",padding:"6px 8px",borderRadius:7,whiteSpace:"nowrap"},className:b,ref:F})),c.createElement(n.Line,{points:B,lineWidth:4*w,visible:!1,userData:V}),c.createElement(n.Line,{transparent:!0,raycast:()=>null,depthTest:g,points:B,lineWidth:w,side:s.DoubleSide,color:A?j:C[i],opacity:O,polygonOffset:!0,polygonOffsetFactor:-10,renderOrder:I,fog:!1}))};
+7
View File
@@ -0,0 +1,7 @@
import * as React from 'react';
import * as THREE from 'three';
export declare const AxisRotator: React.FC<{
dir1: THREE.Vector3;
dir2: THREE.Vector3;
axis: 0 | 1 | 2;
}>;
+220
View File
@@ -0,0 +1,220 @@
import * as React from 'react';
import * as THREE from 'three';
import { useThree } from '@react-three/fiber';
import { Line } from '../../core/Line.js';
import { Html } from '../Html.js';
import { context } from './context.js';
const clickDir = /* @__PURE__ */new THREE.Vector3();
const intersectionDir = /* @__PURE__ */new THREE.Vector3();
const toDegrees = radians => radians * 180 / Math.PI;
const toRadians = degrees => degrees * Math.PI / 180;
const calculateAngle = (clickPoint, intersectionPoint, origin, e1, e2) => {
clickDir.copy(clickPoint).sub(origin);
intersectionDir.copy(intersectionPoint).sub(origin);
const dote1e1 = e1.dot(e1);
const dote2e2 = e2.dot(e2);
const uClick = clickDir.dot(e1) / dote1e1;
const vClick = clickDir.dot(e2) / dote2e2;
const uIntersection = intersectionDir.dot(e1) / dote1e1;
const vIntersection = intersectionDir.dot(e2) / dote2e2;
const angleClick = Math.atan2(vClick, uClick);
const angleIntersection = Math.atan2(vIntersection, uIntersection);
return angleIntersection - angleClick;
};
const fmod = (num, denom) => {
let k = Math.floor(num / denom);
k = k < 0 ? k + 1 : k;
return num - k * denom;
};
const minimizeAngle = angle => {
let result = fmod(angle, 2 * Math.PI);
if (Math.abs(result) < 1e-6) {
return 0.0;
}
if (result < 0.0) {
result += 2 * Math.PI;
}
return result;
};
const rotMatrix = /* @__PURE__ */new THREE.Matrix4();
const posNew = /* @__PURE__ */new THREE.Vector3();
const ray = /* @__PURE__ */new THREE.Ray();
const intersection = /* @__PURE__ */new THREE.Vector3();
const AxisRotator = ({
dir1,
dir2,
axis
}) => {
const {
rotationLimits,
annotations,
annotationsClass,
depthTest,
scale,
lineWidth,
fixed,
axisColors,
hoveredColor,
renderOrder,
opacity,
onDragStart,
onDrag,
onDragEnd,
userData
} = React.useContext(context);
const camControls = useThree(state => state.controls);
const divRef = React.useRef(null);
const objRef = React.useRef(null);
const angle0 = React.useRef(0);
const angle = React.useRef(0);
const clickInfo = React.useRef(null);
const [isHovered, setIsHovered] = React.useState(false);
const onPointerDown = React.useCallback(e => {
if (annotations) {
divRef.current.innerText = `${toDegrees(angle.current).toFixed(0)}º`;
divRef.current.style.display = 'block';
}
e.stopPropagation();
const clickPoint = e.point.clone();
const origin = new THREE.Vector3().setFromMatrixPosition(objRef.current.matrixWorld);
const e1 = new THREE.Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 0).normalize();
const e2 = new THREE.Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 1).normalize();
const normal = new THREE.Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 2).normalize();
const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(normal, origin);
clickInfo.current = {
clickPoint,
origin,
e1,
e2,
normal,
plane
};
onDragStart({
component: 'Rotator',
axis,
origin,
directions: [e1, e2, normal]
});
camControls && (camControls.enabled = false);
// @ts-ignore
e.target.setPointerCapture(e.pointerId);
}, [annotations, camControls, onDragStart, axis]);
const onPointerMove = React.useCallback(e => {
e.stopPropagation();
if (!isHovered) setIsHovered(true);
if (clickInfo.current) {
const {
clickPoint,
origin,
e1,
e2,
normal,
plane
} = clickInfo.current;
const [min, max] = (rotationLimits == null ? void 0 : rotationLimits[axis]) || [undefined, undefined];
ray.copy(e.ray);
ray.intersectPlane(plane, intersection);
ray.direction.negate();
ray.intersectPlane(plane, intersection);
let deltaAngle = calculateAngle(clickPoint, intersection, origin, e1, e2);
let degrees = toDegrees(deltaAngle);
// @ts-ignore
if (e.shiftKey) {
degrees = Math.round(degrees / 10) * 10;
deltaAngle = toRadians(degrees);
}
if (min !== undefined && max !== undefined && max - min < 2 * Math.PI) {
deltaAngle = minimizeAngle(deltaAngle);
deltaAngle = deltaAngle > Math.PI ? deltaAngle - 2 * Math.PI : deltaAngle;
deltaAngle = THREE.MathUtils.clamp(deltaAngle, min - angle0.current, max - angle0.current);
angle.current = angle0.current + deltaAngle;
} else {
angle.current = minimizeAngle(angle0.current + deltaAngle);
angle.current = angle.current > Math.PI ? angle.current - 2 * Math.PI : angle.current;
}
if (annotations) {
degrees = toDegrees(angle.current);
divRef.current.innerText = `${degrees.toFixed(0)}º`;
}
rotMatrix.makeRotationAxis(normal, deltaAngle);
posNew.copy(origin).applyMatrix4(rotMatrix).sub(origin).negate();
rotMatrix.setPosition(posNew);
onDrag(rotMatrix);
}
}, [annotations, onDrag, isHovered, rotationLimits, axis]);
const onPointerUp = React.useCallback(e => {
if (annotations) {
divRef.current.style.display = 'none';
}
e.stopPropagation();
angle0.current = angle.current;
clickInfo.current = null;
onDragEnd();
camControls && (camControls.enabled = true);
// @ts-ignore
e.target.releasePointerCapture(e.pointerId);
}, [annotations, camControls, onDragEnd]);
const onPointerOut = React.useCallback(e => {
e.stopPropagation();
setIsHovered(false);
}, []);
const matrixL = React.useMemo(() => {
const dir1N = dir1.clone().normalize();
const dir2N = dir2.clone().normalize();
return new THREE.Matrix4().makeBasis(dir1N, dir2N, dir1N.clone().cross(dir2N));
}, [dir1, dir2]);
const r = fixed ? 0.65 : scale * 0.65;
const arc = React.useMemo(() => {
const segments = 32;
const points = [];
for (let j = 0; j <= segments; j++) {
const angle = j * (Math.PI / 2) / segments;
points.push(new THREE.Vector3(Math.cos(angle) * r, Math.sin(angle) * r, 0));
}
return points;
}, [r]);
return /*#__PURE__*/React.createElement("group", {
ref: objRef,
onPointerDown: onPointerDown,
onPointerMove: onPointerMove,
onPointerUp: onPointerUp,
onPointerOut: onPointerOut,
matrix: matrixL,
matrixAutoUpdate: false
}, annotations && /*#__PURE__*/React.createElement(Html, {
position: [r, r, 0]
}, /*#__PURE__*/React.createElement("div", {
style: {
display: 'none',
background: '#151520',
color: 'white',
padding: '6px 8px',
borderRadius: 7,
whiteSpace: 'nowrap'
},
className: annotationsClass,
ref: divRef
})), /*#__PURE__*/React.createElement(Line, {
points: arc,
lineWidth: lineWidth * 4,
visible: false,
userData: userData
}), /*#__PURE__*/React.createElement(Line, {
transparent: true,
raycast: () => null,
depthTest: depthTest,
points: arc,
lineWidth: lineWidth,
side: THREE.DoubleSide,
color: isHovered ? hoveredColor : axisColors[axis],
opacity: opacity,
polygonOffset: true,
polygonOffsetFactor: -10,
renderOrder: renderOrder,
fog: false
}));
};
export { AxisRotator };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("three"),r=require("@react-three/fiber"),n=require("../../core/Line.cjs.js"),o=require("../Html.cjs.js"),a=require("./context.cjs.js");function i(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}require("@babel/runtime/helpers/extends"),require("three-stdlib"),require("react-dom/client");var s=i(e),c=i(t);const l=new c.Ray,u=new c.Vector3,d=new c.Matrix4;exports.PlaneSlider=({dir1:e,dir2:t,axis:i})=>{const{translation:p,translationLimits:m,annotations:x,annotationsClass:b,depthTest:g,scale:f,lineWidth:h,fixed:M,axisColors:y,hoveredColor:C,opacity:P,renderOrder:v,onDragStart:w,onDrag:O,onDragEnd:j,userData:k}=s.useContext(a.context),F=r.useThree((e=>e.controls)),z=s.useRef(null),E=s.useRef(null),V=s.useRef(null),q=s.useRef(0),D=s.useRef(0),[R,T]=s.useState(!1),S=s.useCallback((e=>{x&&(z.current.innerText=`${p.current[(i+1)%3].toFixed(2)}, ${p.current[(i+2)%3].toFixed(2)}`,z.current.style.display="block"),e.stopPropagation();const t=e.point.clone(),r=(new c.Vector3).setFromMatrixPosition(E.current.matrixWorld),n=(new c.Vector3).setFromMatrixColumn(E.current.matrixWorld,0).normalize(),o=(new c.Vector3).setFromMatrixColumn(E.current.matrixWorld,1).normalize(),a=(new c.Vector3).setFromMatrixColumn(E.current.matrixWorld,2).normalize(),s=(new c.Plane).setFromNormalAndCoplanarPoint(a,r);V.current={clickPoint:t,e1:n,e2:o,plane:s},q.current=p.current[(i+1)%3],D.current=p.current[(i+2)%3],w({component:"Slider",axis:i,origin:r,directions:[n,o,a]}),F&&(F.enabled=!1),e.target.setPointerCapture(e.pointerId)}),[x,F,w,i]),W=s.useCallback((e=>{if(e.stopPropagation(),R||T(!0),V.current){const{clickPoint:t,e1:r,e2:n,plane:o}=V.current,[a,s]=(null==m?void 0:m[(i+1)%3])||[void 0,void 0],[c,b]=(null==m?void 0:m[(i+2)%3])||[void 0,void 0];l.copy(e.ray),l.intersectPlane(o,u),l.direction.negate(),l.intersectPlane(o,u),u.sub(t);let[g,f]=((e,t,r)=>{const n=Math.abs(e.x)>=Math.abs(e.y)&&Math.abs(e.x)>=Math.abs(e.z)?0:Math.abs(e.y)>=Math.abs(e.x)&&Math.abs(e.y)>=Math.abs(e.z)?1:2,o=[0,1,2].sort(((e,r)=>Math.abs(t.getComponent(r))-Math.abs(t.getComponent(e)))),a=n===o[0]?o[1]:o[0],i=e.getComponent(n),s=e.getComponent(a),c=t.getComponent(n),l=t.getComponent(a),u=r.getComponent(n),d=(r.getComponent(a)-u*(s/i))/(l-c*(s/i));return[(u-d*c)/i,d]})(r,n,u);void 0!==a&&(g=Math.max(g,a-q.current)),void 0!==s&&(g=Math.min(g,s-q.current)),void 0!==c&&(f=Math.max(f,c-D.current)),void 0!==b&&(f=Math.min(f,b-D.current)),p.current[(i+1)%3]=q.current+g,p.current[(i+2)%3]=D.current+f,x&&(z.current.innerText=`${p.current[(i+1)%3].toFixed(2)}, ${p.current[(i+2)%3].toFixed(2)}`),d.makeTranslation(g*r.x+f*n.x,g*r.y+f*n.y,g*r.z+f*n.z),O(d)}}),[x,O,R,p,m,i]),$=s.useCallback((e=>{x&&(z.current.style.display="none"),e.stopPropagation(),V.current=null,j(),F&&(F.enabled=!0),e.target.releasePointerCapture(e.pointerId)}),[x,F,j]),_=s.useCallback((e=>{e.stopPropagation(),T(!1)}),[]),L=s.useMemo((()=>{const r=e.clone().normalize(),n=t.clone().normalize();return(new c.Matrix4).makeBasis(r,n,r.clone().cross(n))}),[e,t]),A=M?1/7:f/7,B=M?.225:.225*f,H=R?C:y[i],I=s.useMemo((()=>[new c.Vector3(0,0,0),new c.Vector3(0,B,0),new c.Vector3(B,B,0),new c.Vector3(B,0,0),new c.Vector3(0,0,0)]),[B]);return s.createElement("group",{ref:E,matrix:L,matrixAutoUpdate:!1},x&&s.createElement(o.Html,{position:[0,0,0]},s.createElement("div",{style:{display:"none",background:"#151520",color:"white",padding:"6px 8px",borderRadius:7,whiteSpace:"nowrap"},className:b,ref:z})),s.createElement("group",{position:[1.7*A,1.7*A,0]},s.createElement("mesh",{visible:!0,onPointerDown:S,onPointerMove:W,onPointerUp:$,onPointerOut:_,scale:B,userData:k,renderOrder:v},s.createElement("planeGeometry",null),s.createElement("meshBasicMaterial",{transparent:!0,depthTest:g,color:H,polygonOffset:!0,polygonOffsetFactor:-10,side:c.DoubleSide,fog:!1})),s.createElement(n.Line,{position:[-B/2,-B/2,0],transparent:!0,depthTest:g,points:I,lineWidth:h,color:H,opacity:P,polygonOffset:!0,polygonOffsetFactor:-10,userData:k,fog:!1,renderOrder:v})))};
+7
View File
@@ -0,0 +1,7 @@
import * as React from 'react';
import * as THREE from 'three';
export declare const PlaneSlider: React.FC<{
dir1: THREE.Vector3;
dir2: THREE.Vector3;
axis: 0 | 1 | 2;
}>;
+202
View File
@@ -0,0 +1,202 @@
import * as React from 'react';
import * as THREE from 'three';
import { useThree } from '@react-three/fiber';
import { Line } from '../../core/Line.js';
import { Html } from '../Html.js';
import { context } from './context.js';
const decomposeIntoBasis = (e1, e2, offset) => {
const i1 = Math.abs(e1.x) >= Math.abs(e1.y) && Math.abs(e1.x) >= Math.abs(e1.z) ? 0 : Math.abs(e1.y) >= Math.abs(e1.x) && Math.abs(e1.y) >= Math.abs(e1.z) ? 1 : 2;
const e2DegrowthOrder = [0, 1, 2].sort((a, b) => Math.abs(e2.getComponent(b)) - Math.abs(e2.getComponent(a)));
const i2 = i1 === e2DegrowthOrder[0] ? e2DegrowthOrder[1] : e2DegrowthOrder[0];
const a1 = e1.getComponent(i1);
const a2 = e1.getComponent(i2);
const b1 = e2.getComponent(i1);
const b2 = e2.getComponent(i2);
const c1 = offset.getComponent(i1);
const c2 = offset.getComponent(i2);
const y = (c2 - c1 * (a2 / a1)) / (b2 - b1 * (a2 / a1));
const x = (c1 - y * b1) / a1;
return [x, y];
};
const ray = /* @__PURE__ */new THREE.Ray();
const intersection = /* @__PURE__ */new THREE.Vector3();
const offsetMatrix = /* @__PURE__ */new THREE.Matrix4();
const PlaneSlider = ({
dir1,
dir2,
axis
}) => {
const {
translation,
translationLimits,
annotations,
annotationsClass,
depthTest,
scale,
lineWidth,
fixed,
axisColors,
hoveredColor,
opacity,
renderOrder,
onDragStart,
onDrag,
onDragEnd,
userData
} = React.useContext(context);
const camControls = useThree(state => state.controls);
const divRef = React.useRef(null);
const objRef = React.useRef(null);
const clickInfo = React.useRef(null);
const offsetX0 = React.useRef(0);
const offsetY0 = React.useRef(0);
const [isHovered, setIsHovered] = React.useState(false);
const onPointerDown = React.useCallback(e => {
if (annotations) {
divRef.current.innerText = `${translation.current[(axis + 1) % 3].toFixed(2)}, ${translation.current[(axis + 2) % 3].toFixed(2)}`;
divRef.current.style.display = 'block';
}
e.stopPropagation();
const clickPoint = e.point.clone();
const origin = new THREE.Vector3().setFromMatrixPosition(objRef.current.matrixWorld);
const e1 = new THREE.Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 0).normalize();
const e2 = new THREE.Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 1).normalize();
const normal = new THREE.Vector3().setFromMatrixColumn(objRef.current.matrixWorld, 2).normalize();
const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(normal, origin);
clickInfo.current = {
clickPoint,
e1,
e2,
plane
};
offsetX0.current = translation.current[(axis + 1) % 3];
offsetY0.current = translation.current[(axis + 2) % 3];
onDragStart({
component: 'Slider',
axis,
origin,
directions: [e1, e2, normal]
});
camControls && (camControls.enabled = false);
// @ts-ignore
e.target.setPointerCapture(e.pointerId);
}, [annotations, camControls, onDragStart, axis]);
const onPointerMove = React.useCallback(e => {
e.stopPropagation();
if (!isHovered) setIsHovered(true);
if (clickInfo.current) {
const {
clickPoint,
e1,
e2,
plane
} = clickInfo.current;
const [minX, maxX] = (translationLimits == null ? void 0 : translationLimits[(axis + 1) % 3]) || [undefined, undefined];
const [minY, maxY] = (translationLimits == null ? void 0 : translationLimits[(axis + 2) % 3]) || [undefined, undefined];
ray.copy(e.ray);
ray.intersectPlane(plane, intersection);
ray.direction.negate();
ray.intersectPlane(plane, intersection);
intersection.sub(clickPoint);
let [offsetX, offsetY] = decomposeIntoBasis(e1, e2, intersection);
/* let offsetY = (intersection.y - (intersection.x * e1.y) / e1.x) / (e2.y - (e2.x * e1.y) / e1.x)
let offsetX = (intersection.x - offsetY * e2.x) / e1.x */
if (minX !== undefined) {
offsetX = Math.max(offsetX, minX - offsetX0.current);
}
if (maxX !== undefined) {
offsetX = Math.min(offsetX, maxX - offsetX0.current);
}
if (minY !== undefined) {
offsetY = Math.max(offsetY, minY - offsetY0.current);
}
if (maxY !== undefined) {
offsetY = Math.min(offsetY, maxY - offsetY0.current);
}
translation.current[(axis + 1) % 3] = offsetX0.current + offsetX;
translation.current[(axis + 2) % 3] = offsetY0.current + offsetY;
if (annotations) {
divRef.current.innerText = `${translation.current[(axis + 1) % 3].toFixed(2)}, ${translation.current[(axis + 2) % 3].toFixed(2)}`;
}
offsetMatrix.makeTranslation(offsetX * e1.x + offsetY * e2.x, offsetX * e1.y + offsetY * e2.y, offsetX * e1.z + offsetY * e2.z);
onDrag(offsetMatrix);
}
}, [annotations, onDrag, isHovered, translation, translationLimits, axis]);
const onPointerUp = React.useCallback(e => {
if (annotations) {
divRef.current.style.display = 'none';
}
e.stopPropagation();
clickInfo.current = null;
onDragEnd();
camControls && (camControls.enabled = true);
// @ts-ignore
e.target.releasePointerCapture(e.pointerId);
}, [annotations, camControls, onDragEnd]);
const onPointerOut = React.useCallback(e => {
e.stopPropagation();
setIsHovered(false);
}, []);
const matrixL = React.useMemo(() => {
const dir1N = dir1.clone().normalize();
const dir2N = dir2.clone().normalize();
return new THREE.Matrix4().makeBasis(dir1N, dir2N, dir1N.clone().cross(dir2N));
}, [dir1, dir2]);
const pos1 = fixed ? 1 / 7 : scale / 7;
const length = fixed ? 0.225 : scale * 0.225;
const color = isHovered ? hoveredColor : axisColors[axis];
const points = React.useMemo(() => [new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, length, 0), new THREE.Vector3(length, length, 0), new THREE.Vector3(length, 0, 0), new THREE.Vector3(0, 0, 0)], [length]);
return /*#__PURE__*/React.createElement("group", {
ref: objRef,
matrix: matrixL,
matrixAutoUpdate: false
}, annotations && /*#__PURE__*/React.createElement(Html, {
position: [0, 0, 0]
}, /*#__PURE__*/React.createElement("div", {
style: {
display: 'none',
background: '#151520',
color: 'white',
padding: '6px 8px',
borderRadius: 7,
whiteSpace: 'nowrap'
},
className: annotationsClass,
ref: divRef
})), /*#__PURE__*/React.createElement("group", {
position: [pos1 * 1.7, pos1 * 1.7, 0]
}, /*#__PURE__*/React.createElement("mesh", {
visible: true,
onPointerDown: onPointerDown,
onPointerMove: onPointerMove,
onPointerUp: onPointerUp,
onPointerOut: onPointerOut,
scale: length,
userData: userData,
renderOrder: renderOrder
}, /*#__PURE__*/React.createElement("planeGeometry", null), /*#__PURE__*/React.createElement("meshBasicMaterial", {
transparent: true,
depthTest: depthTest,
color: color,
polygonOffset: true,
polygonOffsetFactor: -10,
side: THREE.DoubleSide,
fog: false
})), /*#__PURE__*/React.createElement(Line, {
position: [-length / 2, -length / 2, 0],
transparent: true,
depthTest: depthTest,
points: points,
lineWidth: lineWidth,
color: color,
opacity: opacity,
polygonOffset: true,
polygonOffsetFactor: -10,
userData: userData,
fog: false,
renderOrder: renderOrder
})));
};
export { PlaneSlider };
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"),t=require("three"),r=require("@react-three/fiber"),n=require("../Html.cjs.js"),o=require("./context.cjs.js"),a=require("../../core/calculateScaleFactor.cjs.js");function i(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}require("@babel/runtime/helpers/extends"),require("react-dom/client");var c=i(e),l=i(t);const s=new l.Vector3,u=new l.Vector3,p=(e,t,r,n)=>{const o=t.dot(t),a=t.dot(e)-t.dot(r),i=t.dot(n);if(0===i)return-a/o;s.copy(n).multiplyScalar(o/i).sub(t),u.copy(n).multiplyScalar(a/i).add(r).sub(e);return-s.dot(u)/s.dot(s)},d=new l.Vector3(0,1,0),m=new l.Vector3,f=new l.Matrix4;exports.ScalingSphere=({direction:e,axis:t})=>{const{scaleLimits:i,annotations:u,annotationsClass:x,depthTest:y,scale:g,lineWidth:h,fixed:b,axisColors:P,hoveredColor:M,opacity:w,renderOrder:v,onDragStart:O,onDrag:j,onDragEnd:k,userData:C}=c.useContext(o.context),S=r.useThree((e=>e.size)),E=r.useThree((e=>e.controls)),R=c.useRef(null),q=c.useRef(null),F=c.useRef(null),D=c.useRef(1),L=c.useRef(1),T=c.useRef(null),[V,z]=c.useState(!1),G=b?1.2:1.2*g,W=c.useCallback((r=>{u&&(R.current.innerText=`${L.current.toFixed(2)}`,R.current.style.display="block"),r.stopPropagation();const n=(new l.Matrix4).extractRotation(q.current.matrixWorld),o=r.point.clone(),i=(new l.Vector3).setFromMatrixPosition(q.current.matrixWorld),c=e.clone().applyMatrix4(n).normalize(),p=q.current.matrixWorld.clone(),d=p.clone().invert(),m=b?1/a.calculateScaleFactor(q.current.getWorldPosition(s),g,r.camera,S):1;T.current={clickPoint:o,dir:c,mPLG:p,mPLGInv:d,offsetMultiplier:m},O({component:"Sphere",axis:t,origin:i,directions:[c]}),E&&(E.enabled=!1),r.target.setPointerCapture(r.pointerId)}),[u,E,e,O,t,b,g,S]),I=c.useCallback((e=>{if(e.stopPropagation(),V||z(!0),T.current){const{clickPoint:r,dir:n,mPLG:o,mPLGInv:a,offsetMultiplier:c}=T.current,[l,s]=(null==i?void 0:i[t])||[1e-5,void 0],d=p(r,n,e.ray.origin,e.ray.direction)*c,x=b?d:d/g;let y=Math.pow(2,.2*x);e.shiftKey&&(y=Math.round(10*y)/10),y=Math.max(y,l/D.current),void 0!==s&&(y=Math.min(y,s/D.current)),L.current=D.current*y,F.current.position.set(0,G+d,0),u&&(R.current.innerText=`${L.current.toFixed(2)}`),m.set(1,1,1),m.setComponent(t,y),f.makeScale(m.x,m.y,m.z).premultiply(o).multiply(a),j(f)}}),[u,G,j,V,i,t]),_=c.useCallback((e=>{u&&(R.current.style.display="none"),e.stopPropagation(),D.current=L.current,T.current=null,F.current.position.set(0,G,0),k(),E&&(E.enabled=!0),e.target.releasePointerCapture(e.pointerId)}),[u,E,k,G]),U=c.useCallback((e=>{e.stopPropagation(),z(!1)}),[]),{radius:H,matrixL:Q}=c.useMemo((()=>{const t=b?h/g*1.8:g/22.5,r=(new l.Quaternion).setFromUnitVectors(d,e.clone().normalize());return{radius:t,matrixL:(new l.Matrix4).makeRotationFromQuaternion(r)}}),[e,g,h,b]),$=V?M:P[t];return c.createElement("group",{ref:q},c.createElement("group",{matrix:Q,matrixAutoUpdate:!1,onPointerDown:W,onPointerMove:I,onPointerUp:_,onPointerOut:U},u&&c.createElement(n.Html,{position:[0,G/2,0]},c.createElement("div",{style:{display:"none",background:"#151520",color:"white",padding:"6px 8px",borderRadius:7,whiteSpace:"nowrap"},className:x,ref:R})),c.createElement("mesh",{ref:F,position:[0,G,0],renderOrder:v,userData:C},c.createElement("sphereGeometry",{args:[H,12,12]}),c.createElement("meshBasicMaterial",{transparent:!0,depthTest:y,color:$,opacity:w,polygonOffset:!0,polygonOffsetFactor:-10}))))},exports.calculateOffset=p;
+7
View File
@@ -0,0 +1,7 @@
import * as React from 'react';
import * as THREE from 'three';
export declare const calculateOffset: (clickPoint: THREE.Vector3, normal: THREE.Vector3, rayStart: THREE.Vector3, rayDir: THREE.Vector3) => number;
export declare const ScalingSphere: React.FC<{
direction: THREE.Vector3;
axis: 0 | 1 | 2;
}>;
+192
View File
@@ -0,0 +1,192 @@
import * as React from 'react';
import * as THREE from 'three';
import { useThree } from '@react-three/fiber';
import { Html } from '../Html.js';
import { context } from './context.js';
import { calculateScaleFactor } from '../../core/calculateScaleFactor.js';
const vec1 = /* @__PURE__ */new THREE.Vector3();
const vec2 = /* @__PURE__ */new THREE.Vector3();
const calculateOffset = (clickPoint, normal, rayStart, rayDir) => {
const e1 = normal.dot(normal);
const e2 = normal.dot(clickPoint) - normal.dot(rayStart);
const e3 = normal.dot(rayDir);
if (e3 === 0) {
return -e2 / e1;
}
vec1.copy(rayDir).multiplyScalar(e1 / e3).sub(normal);
vec2.copy(rayDir).multiplyScalar(e2 / e3).add(rayStart).sub(clickPoint);
const offset = -vec1.dot(vec2) / vec1.dot(vec1);
return offset;
};
const upV = /* @__PURE__ */new THREE.Vector3(0, 1, 0);
const scaleV = /* @__PURE__ */new THREE.Vector3();
const scaleMatrix = /* @__PURE__ */new THREE.Matrix4();
const ScalingSphere = ({
direction,
axis
}) => {
const {
scaleLimits,
annotations,
annotationsClass,
depthTest,
scale,
lineWidth,
fixed,
axisColors,
hoveredColor,
opacity,
renderOrder,
onDragStart,
onDrag,
onDragEnd,
userData
} = React.useContext(context);
const size = useThree(state => state.size);
const camControls = useThree(state => state.controls);
const divRef = React.useRef(null);
const objRef = React.useRef(null);
const meshRef = React.useRef(null);
const scale0 = React.useRef(1);
const scaleCur = React.useRef(1);
const clickInfo = React.useRef(null);
const [isHovered, setIsHovered] = React.useState(false);
const position = fixed ? 1.2 : 1.2 * scale;
const onPointerDown = React.useCallback(e => {
if (annotations) {
divRef.current.innerText = `${scaleCur.current.toFixed(2)}`;
divRef.current.style.display = 'block';
}
e.stopPropagation();
const rotation = new THREE.Matrix4().extractRotation(objRef.current.matrixWorld);
const clickPoint = e.point.clone();
const origin = new THREE.Vector3().setFromMatrixPosition(objRef.current.matrixWorld);
const dir = direction.clone().applyMatrix4(rotation).normalize();
const mPLG = objRef.current.matrixWorld.clone();
const mPLGInv = mPLG.clone().invert();
const offsetMultiplier = fixed ? 1 / calculateScaleFactor(objRef.current.getWorldPosition(vec1), scale, e.camera, size) : 1;
clickInfo.current = {
clickPoint,
dir,
mPLG,
mPLGInv,
offsetMultiplier
};
onDragStart({
component: 'Sphere',
axis,
origin,
directions: [dir]
});
camControls && (camControls.enabled = false);
// @ts-ignore - setPointerCapture is not in the type definition
e.target.setPointerCapture(e.pointerId);
}, [annotations, camControls, direction, onDragStart, axis, fixed, scale, size]);
const onPointerMove = React.useCallback(e => {
e.stopPropagation();
if (!isHovered) setIsHovered(true);
if (clickInfo.current) {
const {
clickPoint,
dir,
mPLG,
mPLGInv,
offsetMultiplier
} = clickInfo.current;
const [min, max] = (scaleLimits == null ? void 0 : scaleLimits[axis]) || [1e-5, undefined]; // always limit the minimal value, since setting it very low might break the transform
const offsetW = calculateOffset(clickPoint, dir, e.ray.origin, e.ray.direction);
const offsetL = offsetW * offsetMultiplier;
const offsetH = fixed ? offsetL : offsetL / scale;
let upscale = Math.pow(2, offsetH * 0.2);
// @ts-ignore
if (e.shiftKey) {
upscale = Math.round(upscale * 10) / 10;
}
upscale = Math.max(upscale, min / scale0.current);
if (max !== undefined) {
upscale = Math.min(upscale, max / scale0.current);
}
scaleCur.current = scale0.current * upscale;
meshRef.current.position.set(0, position + offsetL, 0);
if (annotations) {
divRef.current.innerText = `${scaleCur.current.toFixed(2)}`;
}
scaleV.set(1, 1, 1);
scaleV.setComponent(axis, upscale);
scaleMatrix.makeScale(scaleV.x, scaleV.y, scaleV.z).premultiply(mPLG).multiply(mPLGInv);
onDrag(scaleMatrix);
}
}, [annotations, position, onDrag, isHovered, scaleLimits, axis]);
const onPointerUp = React.useCallback(e => {
if (annotations) {
divRef.current.style.display = 'none';
}
e.stopPropagation();
scale0.current = scaleCur.current;
clickInfo.current = null;
meshRef.current.position.set(0, position, 0);
onDragEnd();
camControls && (camControls.enabled = true);
// @ts-ignore - releasePointerCapture & PointerEvent#pointerId is not in the type definition
e.target.releasePointerCapture(e.pointerId);
}, [annotations, camControls, onDragEnd, position]);
const onPointerOut = React.useCallback(e => {
e.stopPropagation();
setIsHovered(false);
}, []);
const {
radius,
matrixL
} = React.useMemo(() => {
const radius = fixed ? lineWidth / scale * 1.8 : scale / 22.5;
const quaternion = new THREE.Quaternion().setFromUnitVectors(upV, direction.clone().normalize());
const matrixL = new THREE.Matrix4().makeRotationFromQuaternion(quaternion);
return {
radius,
matrixL
};
}, [direction, scale, lineWidth, fixed]);
const color = isHovered ? hoveredColor : axisColors[axis];
return /*#__PURE__*/React.createElement("group", {
ref: objRef
}, /*#__PURE__*/React.createElement("group", {
matrix: matrixL,
matrixAutoUpdate: false,
onPointerDown: onPointerDown,
onPointerMove: onPointerMove,
onPointerUp: onPointerUp,
onPointerOut: onPointerOut
}, annotations && /*#__PURE__*/React.createElement(Html, {
position: [0, position / 2, 0]
}, /*#__PURE__*/React.createElement("div", {
style: {
display: 'none',
background: '#151520',
color: 'white',
padding: '6px 8px',
borderRadius: 7,
whiteSpace: 'nowrap'
},
className: annotationsClass,
ref: divRef
})), /*#__PURE__*/React.createElement("mesh", {
ref: meshRef,
position: [0, position, 0],
renderOrder: renderOrder,
userData: userData
}, /*#__PURE__*/React.createElement("sphereGeometry", {
args: [radius, 12, 12]
}), /*#__PURE__*/React.createElement("meshBasicMaterial", {
transparent: true,
depthTest: depthTest,
color: color,
opacity: opacity,
polygonOffset: true,
polygonOffsetFactor: -10
}))));
};
export { ScalingSphere, calculateOffset };
+1
View File
@@ -0,0 +1 @@
"use strict";function e(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}Object.defineProperty(exports,"__esModule",{value:!0});const t=e(require("react")).createContext(null);exports.context=t;
+33
View File
@@ -0,0 +1,33 @@
import * as THREE from 'three';
import * as React from 'react';
export type OnDragStartProps = {
component: 'Arrow' | 'Slider' | 'Rotator' | 'Sphere';
axis: 0 | 1 | 2;
origin: THREE.Vector3;
directions: THREE.Vector3[];
};
export type PivotContext = {
onDragStart: (props: OnDragStartProps) => void;
onDrag: (mdW: THREE.Matrix4) => void;
onDragEnd: () => void;
translation: {
current: [number, number, number];
};
translationLimits?: [[number, number] | undefined, [number, number] | undefined, [number, number] | undefined];
rotationLimits?: [[number, number] | undefined, [number, number] | undefined, [number, number] | undefined];
scaleLimits?: [[number, number] | undefined, [number, number] | undefined, [number, number] | undefined];
axisColors: [string | number, string | number, string | number];
hoveredColor: string | number;
opacity: number;
scale: number;
lineWidth: number;
fixed: boolean;
depthTest: boolean;
renderOrder: number;
userData?: {
[key: string]: any;
};
annotations?: boolean;
annotationsClass?: string;
};
export declare const context: React.Context<PivotContext>;
+5
View File
@@ -0,0 +1,5 @@
import * as React from 'react';
const context = /* @__PURE__ */React.createContext(null);
export { context };
+1
View File
@@ -0,0 +1 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("@babel/runtime/helpers/extends"),r=require("@react-three/fiber"),t=require("react"),i=require("three"),a=require("./AxisArrow.cjs.js"),n=require("./AxisRotator.cjs.js"),o=require("./PlaneSlider.cjs.js"),c=require("./ScalingSphere.cjs.js"),l=require("./context.cjs.js"),s=require("../../core/calculateScaleFactor.cjs.js");function u(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function d(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var i=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,i.get?i:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}require("../../core/Line.cjs.js"),require("three-stdlib"),require("../Html.cjs.js"),require("react-dom/client");var m=u(e),x=d(t),p=d(i);const f=new p.Matrix4,y=new p.Matrix4,w=new p.Matrix4,g=new p.Matrix4,b=new p.Matrix4,E=new p.Matrix4,j=new p.Matrix4,S=new p.Matrix4,h=new p.Matrix4,v=new p.Box3,M=new p.Box3,A=new p.Vector3,q=new p.Vector3,R=new p.Vector3,V=new p.Vector3,P=new p.Vector3,W=new p.Vector3(1,0,0),D=new p.Vector3(0,1,0),O=new p.Vector3(0,0,1),C=x.forwardRef((({enabled:e=!0,matrix:t,onDragStart:i,onDrag:u,onDragEnd:d,autoTransform:C=!0,anchor:L,disableAxes:B=!1,disableSliders:F=!1,disableRotations:z=!1,disableScaling:T=!1,activeAxes:_=[!0,!0,!0],offset:k=[0,0,0],rotation:H=[0,0,0],scale:I=1,lineWidth:U=4,fixed:G=!1,translationLimits:J,rotationLimits:K,scaleLimits:N,depthTest:Q=!0,renderOrder:X=500,axisColors:Y=["#ff2060","#20df80","#2080ff"],hoveredColor:Z="#ffff40",annotations:$=!1,annotationsClass:ee,opacity:re=1,visible:te=!0,userData:ie,children:ae,...ne},oe)=>{const ce=r.useThree((e=>e.invalidate)),le=x.useRef(null),se=x.useRef(null),ue=x.useRef(null),de=x.useRef(null),me=x.useRef([0,0,0]),xe=x.useRef(new p.Vector3(1,1,1)),pe=x.useRef(new p.Vector3(1,1,1));x.useLayoutEffect((()=>{L&&(de.current.updateWorldMatrix(!0,!0),g.copy(de.current.matrixWorld).invert(),v.makeEmpty(),de.current.traverse((e=>{e.geometry&&(e.geometry.boundingBox||e.geometry.computeBoundingBox(),E.copy(e.matrixWorld).premultiply(g),M.copy(e.geometry.boundingBox),M.applyMatrix4(E),v.union(M))})),A.copy(v.max).add(v.min).multiplyScalar(.5),q.copy(v.max).sub(v.min).multiplyScalar(.5),R.copy(q).multiply(new p.Vector3(...L)).add(A),V.set(...k).add(R),ue.current.position.copy(V),ce())}));const fe=x.useMemo((()=>({onDragStart:e=>{f.copy(se.current.matrix),y.copy(se.current.matrixWorld),i&&i(e),ce()},onDrag:e=>{w.copy(le.current.matrixWorld),g.copy(w).invert(),b.copy(y).premultiply(e),E.copy(b).premultiply(g),j.copy(f).invert(),S.copy(E).multiply(j),C&&se.current.matrix.copy(E),u&&u(E,S,b,e),ce()},onDragEnd:()=>{d&&d(),ce()},translation:me,translationLimits:J,rotationLimits:K,axisColors:Y,hoveredColor:Z,opacity:re,scale:I,lineWidth:U,fixed:G,depthTest:Q,renderOrder:X,userData:ie,annotations:$,annotationsClass:ee})),[i,u,d,me,J,K,N,Q,I,U,G,...Y,Z,re,ie,C,$,ee]),ye=new p.Vector3;return r.useFrame((e=>{if(G){const r=s.calculateScaleFactor(ue.current.getWorldPosition(ye),I,e.camera,e.size);xe.current.setScalar(r)}t&&t instanceof p.Matrix4&&(se.current.matrix=t),se.current.updateWorldMatrix(!0,!0),h.makeRotationFromEuler(ue.current.rotation).setPosition(ue.current.position).premultiply(se.current.matrixWorld),pe.current.setFromMatrixScale(h),P.copy(xe.current).divide(pe.current),(Math.abs(ue.current.scale.x-P.x)>1e-4||Math.abs(ue.current.scale.y-P.y)>1e-4||Math.abs(ue.current.scale.z-P.z)>1e-4)&&(ue.current.scale.copy(P),e.invalidate())})),x.useImperativeHandle(oe,(()=>se.current),[]),x.createElement(l.context.Provider,{value:fe},x.createElement("group",{ref:le},x.createElement("group",m.default({ref:se,matrix:t,matrixAutoUpdate:!1},ne),x.createElement("group",{visible:te,ref:ue,position:k,rotation:H},e&&x.createElement(x.Fragment,null,!B&&_[0]&&x.createElement(a.AxisArrow,{axis:0,direction:W}),!B&&_[1]&&x.createElement(a.AxisArrow,{axis:1,direction:D}),!B&&_[2]&&x.createElement(a.AxisArrow,{axis:2,direction:O}),!F&&_[0]&&_[1]&&x.createElement(o.PlaneSlider,{axis:2,dir1:W,dir2:D}),!F&&_[0]&&_[2]&&x.createElement(o.PlaneSlider,{axis:1,dir1:O,dir2:W}),!F&&_[2]&&_[1]&&x.createElement(o.PlaneSlider,{axis:0,dir1:D,dir2:O}),!z&&_[0]&&_[1]&&x.createElement(n.AxisRotator,{axis:2,dir1:W,dir2:D}),!z&&_[0]&&_[2]&&x.createElement(n.AxisRotator,{axis:1,dir1:O,dir2:W}),!z&&_[2]&&_[1]&&x.createElement(n.AxisRotator,{axis:0,dir1:D,dir2:O}),!T&&_[0]&&x.createElement(c.ScalingSphere,{axis:0,direction:W}),!T&&_[1]&&x.createElement(c.ScalingSphere,{axis:1,direction:D}),!T&&_[2]&&x.createElement(c.ScalingSphere,{axis:2,direction:O}))),x.createElement("group",{ref:de},ae))))}));exports.PivotControls=C;
+39
View File
@@ -0,0 +1,39 @@
import * as React from 'react';
import * as THREE from 'three';
import { ForwardRefComponent } from '../../helpers/ts-utils';
import { OnDragStartProps } from './context';
export type PivotControlsProps = {
enabled?: boolean;
scale?: number;
lineWidth?: number;
fixed?: boolean;
offset?: [number, number, number];
rotation?: [number, number, number];
matrix?: THREE.Matrix4;
anchor?: [number, number, number];
autoTransform?: boolean;
activeAxes?: [boolean, boolean, boolean];
disableAxes?: boolean;
disableSliders?: boolean;
disableRotations?: boolean;
disableScaling?: boolean;
translationLimits?: [[number, number] | undefined, [number, number] | undefined, [number, number] | undefined];
rotationLimits?: [[number, number] | undefined, [number, number] | undefined, [number, number] | undefined];
scaleLimits?: [[number, number] | undefined, [number, number] | undefined, [number, number] | undefined];
axisColors?: [string | number, string | number, string | number];
hoveredColor?: string | number;
annotations?: boolean;
annotationsClass?: string;
onDragStart?: (props: OnDragStartProps) => void;
onDrag?: (l: THREE.Matrix4, deltaL: THREE.Matrix4, w: THREE.Matrix4, deltaW: THREE.Matrix4) => void;
onDragEnd?: () => void;
depthTest?: boolean;
renderOrder?: number;
opacity?: number;
visible?: boolean;
userData?: {
[key: string]: any;
};
children?: React.ReactNode;
};
export declare const PivotControls: ForwardRefComponent<PivotControlsProps, THREE.Group>;
+213
View File
@@ -0,0 +1,213 @@
import _extends from '@babel/runtime/helpers/esm/extends';
import { useThree, useFrame } from '@react-three/fiber';
import * as React from 'react';
import * as THREE from 'three';
import { AxisArrow } from './AxisArrow.js';
import { AxisRotator } from './AxisRotator.js';
import { PlaneSlider } from './PlaneSlider.js';
import { ScalingSphere } from './ScalingSphere.js';
import { context } from './context.js';
import { calculateScaleFactor } from '../../core/calculateScaleFactor.js';
const mL0 = /* @__PURE__ */new THREE.Matrix4();
const mW0 = /* @__PURE__ */new THREE.Matrix4();
const mP = /* @__PURE__ */new THREE.Matrix4();
const mPInv = /* @__PURE__ */new THREE.Matrix4();
const mW = /* @__PURE__ */new THREE.Matrix4();
const mL = /* @__PURE__ */new THREE.Matrix4();
const mL0Inv = /* @__PURE__ */new THREE.Matrix4();
const mdL = /* @__PURE__ */new THREE.Matrix4();
const mG = /* @__PURE__ */new THREE.Matrix4();
const bb = /* @__PURE__ */new THREE.Box3();
const bbObj = /* @__PURE__ */new THREE.Box3();
const vCenter = /* @__PURE__ */new THREE.Vector3();
const vSize = /* @__PURE__ */new THREE.Vector3();
const vAnchorOffset = /* @__PURE__ */new THREE.Vector3();
const vPosition = /* @__PURE__ */new THREE.Vector3();
const vScale = /* @__PURE__ */new THREE.Vector3();
const xDir = /* @__PURE__ */new THREE.Vector3(1, 0, 0);
const yDir = /* @__PURE__ */new THREE.Vector3(0, 1, 0);
const zDir = /* @__PURE__ */new THREE.Vector3(0, 0, 1);
const PivotControls = /* @__PURE__ */React.forwardRef(({
enabled = true,
matrix,
onDragStart,
onDrag,
onDragEnd,
autoTransform = true,
anchor,
disableAxes = false,
disableSliders = false,
disableRotations = false,
disableScaling = false,
activeAxes = [true, true, true],
offset = [0, 0, 0],
rotation = [0, 0, 0],
scale = 1,
lineWidth = 4,
fixed = false,
translationLimits,
rotationLimits,
scaleLimits,
depthTest = true,
renderOrder = 500,
axisColors = ['#ff2060', '#20df80', '#2080ff'],
hoveredColor = '#ffff40',
annotations = false,
annotationsClass,
opacity = 1,
visible = true,
userData,
children,
...props
}, fRef) => {
const invalidate = useThree(state => state.invalidate);
const parentRef = React.useRef(null);
const ref = React.useRef(null);
const gizmoRef = React.useRef(null);
const childrenRef = React.useRef(null);
const translation = React.useRef([0, 0, 0]);
const cameraScale = React.useRef(new THREE.Vector3(1, 1, 1));
const gizmoScale = React.useRef(new THREE.Vector3(1, 1, 1));
React.useLayoutEffect(() => {
if (!anchor) return;
childrenRef.current.updateWorldMatrix(true, true);
mPInv.copy(childrenRef.current.matrixWorld).invert();
bb.makeEmpty();
childrenRef.current.traverse(obj => {
if (!obj.geometry) return;
if (!obj.geometry.boundingBox) obj.geometry.computeBoundingBox();
mL.copy(obj.matrixWorld).premultiply(mPInv);
bbObj.copy(obj.geometry.boundingBox);
bbObj.applyMatrix4(mL);
bb.union(bbObj);
});
vCenter.copy(bb.max).add(bb.min).multiplyScalar(0.5);
vSize.copy(bb.max).sub(bb.min).multiplyScalar(0.5);
vAnchorOffset.copy(vSize).multiply(new THREE.Vector3(...anchor)).add(vCenter);
vPosition.set(...offset).add(vAnchorOffset);
gizmoRef.current.position.copy(vPosition);
invalidate();
});
const config = React.useMemo(() => ({
onDragStart: props => {
mL0.copy(ref.current.matrix);
mW0.copy(ref.current.matrixWorld);
onDragStart && onDragStart(props);
invalidate();
},
onDrag: mdW => {
mP.copy(parentRef.current.matrixWorld);
mPInv.copy(mP).invert();
// After applying the delta
mW.copy(mW0).premultiply(mdW);
mL.copy(mW).premultiply(mPInv);
mL0Inv.copy(mL0).invert();
mdL.copy(mL).multiply(mL0Inv);
if (autoTransform) {
ref.current.matrix.copy(mL);
}
onDrag && onDrag(mL, mdL, mW, mdW);
invalidate();
},
onDragEnd: () => {
if (onDragEnd) onDragEnd();
invalidate();
},
translation,
translationLimits,
rotationLimits,
axisColors,
hoveredColor,
opacity,
scale,
lineWidth,
fixed,
depthTest,
renderOrder,
userData,
annotations,
annotationsClass
}), [onDragStart, onDrag, onDragEnd, translation, translationLimits, rotationLimits, scaleLimits, depthTest, scale, lineWidth, fixed, ...axisColors, hoveredColor, opacity, userData, autoTransform, annotations, annotationsClass]);
const vec = new THREE.Vector3();
useFrame(state => {
if (fixed) {
const sf = calculateScaleFactor(gizmoRef.current.getWorldPosition(vec), scale, state.camera, state.size);
cameraScale.current.setScalar(sf);
}
if (matrix && matrix instanceof THREE.Matrix4) {
ref.current.matrix = matrix;
}
// Update gizmo scale in accordance with matrix changes
// Without this, there might be noticable turbulences if scaling happens fast enough
ref.current.updateWorldMatrix(true, true);
mG.makeRotationFromEuler(gizmoRef.current.rotation).setPosition(gizmoRef.current.position).premultiply(ref.current.matrixWorld);
gizmoScale.current.setFromMatrixScale(mG);
vScale.copy(cameraScale.current).divide(gizmoScale.current);
if (Math.abs(gizmoRef.current.scale.x - vScale.x) > 1e-4 || Math.abs(gizmoRef.current.scale.y - vScale.y) > 1e-4 || Math.abs(gizmoRef.current.scale.z - vScale.z) > 1e-4) {
gizmoRef.current.scale.copy(vScale);
state.invalidate();
}
});
React.useImperativeHandle(fRef, () => ref.current, []);
return /*#__PURE__*/React.createElement(context.Provider, {
value: config
}, /*#__PURE__*/React.createElement("group", {
ref: parentRef
}, /*#__PURE__*/React.createElement("group", _extends({
ref: ref,
matrix: matrix,
matrixAutoUpdate: false
}, props), /*#__PURE__*/React.createElement("group", {
visible: visible,
ref: gizmoRef,
position: offset,
rotation: rotation
}, enabled && /*#__PURE__*/React.createElement(React.Fragment, null, !disableAxes && activeAxes[0] && /*#__PURE__*/React.createElement(AxisArrow, {
axis: 0,
direction: xDir
}), !disableAxes && activeAxes[1] && /*#__PURE__*/React.createElement(AxisArrow, {
axis: 1,
direction: yDir
}), !disableAxes && activeAxes[2] && /*#__PURE__*/React.createElement(AxisArrow, {
axis: 2,
direction: zDir
}), !disableSliders && activeAxes[0] && activeAxes[1] && /*#__PURE__*/React.createElement(PlaneSlider, {
axis: 2,
dir1: xDir,
dir2: yDir
}), !disableSliders && activeAxes[0] && activeAxes[2] && /*#__PURE__*/React.createElement(PlaneSlider, {
axis: 1,
dir1: zDir,
dir2: xDir
}), !disableSliders && activeAxes[2] && activeAxes[1] && /*#__PURE__*/React.createElement(PlaneSlider, {
axis: 0,
dir1: yDir,
dir2: zDir
}), !disableRotations && activeAxes[0] && activeAxes[1] && /*#__PURE__*/React.createElement(AxisRotator, {
axis: 2,
dir1: xDir,
dir2: yDir
}), !disableRotations && activeAxes[0] && activeAxes[2] && /*#__PURE__*/React.createElement(AxisRotator, {
axis: 1,
dir1: zDir,
dir2: xDir
}), !disableRotations && activeAxes[2] && activeAxes[1] && /*#__PURE__*/React.createElement(AxisRotator, {
axis: 0,
dir1: yDir,
dir2: zDir
}), !disableScaling && activeAxes[0] && /*#__PURE__*/React.createElement(ScalingSphere, {
axis: 0,
direction: xDir
}), !disableScaling && activeAxes[1] && /*#__PURE__*/React.createElement(ScalingSphere, {
axis: 1,
direction: yDir
}), !disableScaling && activeAxes[2] && /*#__PURE__*/React.createElement(ScalingSphere, {
axis: 2,
direction: zDir
}))), /*#__PURE__*/React.createElement("group", {
ref: childrenRef
}, children))));
});
export { PivotControls };
+1
View File
@@ -0,0 +1 @@
"use strict";function e(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach((function(t){if("default"!==t){var u=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,u.get?u:{enumerable:!0,get:function(){return e[t]}})}})),r.default=e,Object.freeze(r)}Object.defineProperty(exports,"__esModule",{value:!0});var r=e(require("react"));exports.useCursor=function(e,t="pointer",u="auto",o=document.body){r.useEffect((()=>{if(e)return o.style.cursor=t,()=>{o.style.cursor=u}}),[e])};
+1
View File
@@ -0,0 +1 @@
export declare function useCursor(hovered: boolean, onPointerOver?: string, onPointerOut?: string, container?: HTMLElement): void;
+12
View File
@@ -0,0 +1,12 @@
import * as React from 'react';
function useCursor(hovered, onPointerOver = 'pointer', onPointerOut = 'auto', container = document.body) {
React.useEffect(() => {
if (hovered) {
container.style.cursor = onPointerOver;
return () => void (container.style.cursor = onPointerOut);
}
}, [hovered]);
}
export { useCursor };