Created
June 28, 2022 11:36
-
-
Save netgfx/3d9abe32bdbc9afc82978cd79df1dde4 to your computer and use it in GitHub Desktop.
Framer ARScene
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Welcome to Code in Framer | |
// Get Started: https://www.framer.com/docs/guides/ | |
import { forwardRef, Suspense, useEffect, useRef } from "react" | |
import { ARCanvas, DefaultXRControllers } from "@react-three/xr" | |
import { useLoader } from "@react-three/fiber" | |
import { Object3D } from "three" | |
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader" | |
import throttle from "lodash.throttle" | |
const INITIAL_SCALE = 20 | |
const Model = forwardRef<Object3D, any>((props: any, ref) => { | |
const gltf = useLoader( | |
GLTFLoader, | |
"https://qsxfdqhsuyovskknxkaj.supabase.co/storage/v1/object/public/threed/models/Chest.glb" | |
) | |
return ( | |
<primitive | |
ref={ref} | |
position={[0, -10, -20]} | |
object={gltf.scene} | |
scale={INITIAL_SCALE} | |
{...props} | |
/> | |
) | |
}) | |
/** | |
* These annotations control how your component sizes | |
* Learn more: https://www.framer.com/docs/guides/auto-sizing | |
* | |
* @framerSupportedLayoutWidth fixed | |
* @framerSupportedLayoutHeight fixed | |
*/ | |
export default function ARScene(props) { | |
const modelRef = useRef<Object3D | null>(null) | |
useEffect(() => { | |
// for swipe gesture | |
let startX = 0 | |
let startRotationX = 0 | |
// for pinch gesture | |
let initialDistance = 0 | |
let initialScale = INITIAL_SCALE | |
const handleTouchStart = (event: TouchEvent) => { | |
if (event.targetTouches.length === 2) { | |
/* store last scale value and initial distance between 2 fingers */ | |
initialDistance = Math.abs( | |
event.targetTouches[1].pageX - event.targetTouches[0].pageX | |
) | |
initialScale = modelRef.current?.scale.x || INITIAL_SCALE | |
} else { | |
/* store last rotation value */ | |
const touchX = event.changedTouches[0].pageX | |
startX = touchX | |
startRotationX = modelRef.current?.rotation.y || 0 | |
} | |
} | |
const handleTouchMove = (event: TouchEvent) => { | |
if (modelRef.current) { | |
if (event.changedTouches.length === 2) { | |
/* 2 touches move -> scale object */ | |
const currDistance = Math.abs( | |
event.changedTouches[1].pageX - | |
event.changedTouches[0].pageX | |
) | |
const diffDistance = currDistance - initialDistance | |
const diffDistanceScale = diffDistance / 10 | |
modelRef.current.scale.setX( | |
initialScale + diffDistanceScale | |
) | |
modelRef.current.scale.setY( | |
initialScale + diffDistanceScale | |
) | |
modelRef.current.scale.setZ( | |
initialScale + diffDistanceScale | |
) | |
} else { | |
/* 1 touch move -> rotate object on Y axis */ | |
const touchX = event.changedTouches[0].pageX | |
const diffX = (touchX - startX) / window.innerWidth | |
modelRef.current.rotation.y = startRotationX + diffX | |
} | |
} | |
} | |
const throttledTouchStart = throttle(handleTouchStart, 100) | |
const throttledTouchMove = throttle(handleTouchMove, 100) | |
window.addEventListener("touchstart", throttledTouchStart) | |
window.addEventListener("touchmove", throttledTouchMove) | |
return () => { | |
window.removeEventListener("touchstart", throttledTouchStart) | |
window.removeEventListener("touchmove", throttledTouchMove) | |
} | |
}, []) | |
return ( | |
<div style={containerStyle}> | |
<ARCanvas> | |
<Suspense fallback={null}> | |
<Model ref={modelRef} /> | |
</Suspense> | |
<pointLight position={[10, 10, 10]} /> | |
<DefaultXRControllers /> | |
</ARCanvas> | |
</div> | |
) | |
} | |
// Styles are written in object syntax | |
// Learn more: https://reactjs.org/docs/dom-elements.html#style | |
const containerStyle = { | |
height: "100%", | |
display: "flex", | |
justifyContent: "center", | |
alignItems: "center", | |
overflow: "hidden", | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment