pmndrs / drei

🥉 useful helpers for react-three-fiber
https://drei.pmnd.rs/
MIT License
7.86k stars 642 forks source link

Safari Scrolling List of Views Jittery #1890

Open rossrossp opened 3 months ago

rossrossp commented 3 months ago

Problem description:

Scrolling a list of Views and letting go so that the inertia continues, on Safari (iPhone or macOS), results in jittering of the Views, and a slight difference in offset between the View elements and the normal UI elements.

https://github.com/pmndrs/drei/assets/6325131/cea12a4b-ad0b-44df-b719-46574797097f

Relevant code:

import React from 'react'
import { Link } from 'react-router-dom';
import { Canvas, useFrame, ThreeElements } from '@react-three/fiber'
import { View, PerspectiveCamera } from '@react-three/drei';

import { motion } from 'framer-motion';

const ScrollingList: React.FC = () => {

  return (
    <motion.div initial={{opacity: 0}} animate={{opacity: 1, transition: {duration: 1 }}} exit={{opacity: 0, transition: {duration: 1 }}} className="w-screen h-screen flex flex-col overflow-y-scroll overflow-x-hidden bg-white">
      <h1 className="text-2xl font-black text-yellow-500 mt-12 ml-8">My Boxes</h1>
      <div className="flex-grow">
        {Array.apply(null, Array(20)).map(function(x, i) {
          return (
            <div className="h-48" key={"a"+i}>
              <div className="flex flex-row pb-10 justify-center">
                  {Array.apply(null, Array(3)).map(function(xx, ii) {
                    return (
                      <div className="flex flex-col" key={"b"+ii}>
                        <div className="w-32 h-36 overflow-hidden">
                          <View className="w-full h-full inline-block overflow-hidden">
                            <PerspectiveCamera makeDefault fov={40} position={[0, 5, 20]} />
                            <mesh position={[0, 0, 0]} scale={[3, 3, 3]}>
                              <boxGeometry />
                              <meshStandardMaterial color="#adadad" />
                            </mesh>
                          </View>
                        </div>
                        <div className="text-center">
                          <Link to={"/bla/"+i+"-"+ii} className="m-auto">
                            <h1 className="text-xl font-black text-yellow-500">Box</h1>
                            <h1 className="text-sm font-black text-gray-500">500</h1>
                          </Link>
                        </div>
                      </div>
                    )
                  })}
              </div>
            </div>
          )
        })}
        <Canvas
          style={{ position: 'fixed', top: 0, bottom: 0, left: 0, right: 0, overflow: 'hidden' }}
          eventSource={document.getElementById('root')!}>
          <View.Port />
        </Canvas>
      </div>
    </motion.div>
  );
};

export default ScrollingList;

Suggested solution:

The effect isn't as pronounced in Chrome and Firefox, so perhaps analysis could start with the difference between them. Edit: Chrome on an iPhone has some jitter, where chrome in macOS doesn't.

benhylak commented 3 months ago

Just found this as well. ScrollControls is super noticeable.

rossrossp commented 3 months ago

For easy replication, try this in Safari: https://codesandbox.io/p/sandbox/useintersect-and-scrollcontrols-gsm1y?file=%2Fsrc%2Findex.js

benhylak commented 3 months ago

fwiw on ScrollControls I'm only seeing this jitter on iOS

mrcleandean commented 1 month ago

Just discovered this as well. I was getting jitter in Safari and inertia in Chrome. After doing some digging and looking at a few examples I noticed something. Have a look at the following Code Sandbox:

https://codesandbox.io/s/bp6tmc

Notice the App.js uses a smooth scrolling package called @studio-freight/lenis, and it calls addEffect from @react-three/fiber to implement the Lenis instance. Also notice that the Lenis instance has { syncTouch: true } set.

The example has no jitter and no inertia, but as soon as you comment the two lines out with the Lenis instance and the addEffect, the jitter/inertia then become visible. I'm not sure why Lenis makes the jitter go away, but it's a fix for anyone looking.

I managed to fix the jitter and inertia in my own application by using ReactLenis with the useLenis hook instead of regular lenis. Hopefully this gets you further!