Recreate the interactive depth portrait effect popularized by modern portfolio websites using Three.js and WebGL.
The shader needs motion. The input system turns real user movement into a small normalized value that the scene can use.
The project uses one shared shape for all input sources:
type InputState = {
xPosition: number
yPosition: number
active: boolean
}
Both pointer input and gyroscope input write into that same shape.
pointer-input.ts handles desktop interaction.
Its job is to:
-1 to 1 range.When the pointer leaves the hero area, the input becomes inactive so the scene can relax back toward the center.
gyro-input.ts handles mobile device orientation.
Its job is to:
beta and gamma from DeviceOrientationEvent.-1 to 1 range.This keeps the rest of the scene independent from the input source.
input-manager.ts decides which input source to use.
The current strategy is:
destroy function to remove event listeners.The manager receives the hero container so pointer movement can be calculated inside the correct active area.
HeroCanvas creates the input manager and stores it in a ref.
SceneRoot reads that ref during useFrame, takes the current input state and turns it into a target motion value.
The shader does not need to know whether the value came from a mouse or a phone. It only receives motion.
Before moving on, moving the cursor or tilting a supported mobile device should update the motion target used by the scene.
Next: Improving The Experience