@TODO: add gif
Simple gallery with gravity effect. Main goal was to learn how to use physics engine in web app the React way.
- Framer Motion - animations
- rapier.rs (wasm) - physics engine
- React Router - routing
- Radix UI primitives - modal, portal,
Slot
component - Vite - bundler
- Tailwind CSS- styling
- Images from Unsplash
- Design inspiration
Handles loading rapier.rs, world initalization, updating motion values of all <RigidBody>
s and serves as
PhysicsContext
provider. Rapier.rs is loaded asynchronously using useAsset
meaning it works with React Suspense.
<Suspense fallback={<Loading />}>
<Physics gravity={{ x: 0, y: -200 }}>{/* ... */}</Physics>
</Suspense>
Adds rigid body and collider to physics world. It's also a wrapper for <motion.div>
component, but accepts asChild
prop (using Radix UI Slot
component), so transfroms are applied to the child (which needs to be motion
component - checked at runtime by RigidBody
component)
<RigidBody>
is added to physics world on mount and removed on unmount. But this can controlled externally via ref. Which is useful when DOM element (children of <RigidBody>
) coresponding to rigid body is loading (it' size will change after loading) - in this case rigid body should be added to physics world after loading.
const rigidBodyRef = useRef(null);
return (
<RigidBody asChild ref={rigidBodyRef}>
<motion.img
class="w-[40%]"
onLoad={() => rigidBodyRef.current?.initialize()}
/>
</RigidBody>
);