Ideas to fix mobile scroll sync latency issue for DOM to WebGL frameworks - Fixed #75
Replies: 10 comments 23 replies
-
One potential work around to this issue is to try and smooth the positioning over time (tween the position) using a requestAnimationFrame instead of setting it to the exact offset that it should be each time the scroll/resize fires. In summary: move toward the desired position each tick instead of going exactly to the end position. That way it stays smooth even if it's not perfectly synchronized with the DOM elements. I created a basic demo of this sort of approach here (debug view here). It seems to work well on my iPhone though it is not very smooth on my Android device. Perhaps we can figure out why that is and possibly fix it? In a production build this functionality could be enabled/disabled easily. It should also be normalized for devices that have a higher-than-normal RAF rate. |
Beta Was this translation helpful? Give feedback.
-
@zadvorsky brought up another quite different approach that side steps this issue entirely:
The OffscreenCanvas API is perfect for this sort of thing but support is meh. You can do the same sort of approach without it though, just not quite as performantly. This is the approach that web components like the model-viewer component use. At this point I think it's a better approach than the approach I suggested above if it can be done well. |
Beta Was this translation helpful? Give feedback.
-
Before diving too deep into ideas and tests, I was willing to take a little step back to actually see what was happening when we were scrolling on mobile. Here are some console debug screenshots taken with my Android Pocophone. First here's what's happening on each frame while scrolling. We can see the whole task process is quite fast (7ms) and the scroll event is called before the rAF call, which is what we were expecting: Another interesting thing is that we can see the touchmove event is fired at an higher rate than the scroll event/rAF calls. According to this codepen, the touchmove event is fired approximatively every 10ms on my mobile, whereas my rAF is called every 16.6ms (60FPS). So I've tried to update the positions inside the touchmove event instead of the rAF (see this codepen debug view), but the result is unfortunately pretty janky. Besides it would need to handle a lot of extra things, like window edges detection, window resize when the nav bar is hidden/shown, inertia that occurs after the touchmove event, and so on... |
Beta Was this translation helpful? Give feedback.
-
I believe is a lost war from the start 🙂 |
Beta Was this translation helpful? Give feedback.
-
I've managed to solve this with ASScroll. I'll try to put a demo together at some point that demonstrates it but it will retain native mobile scrolling (i.e. inertia) and give you no visible lag between DOM and WebGL elements. But it should be fairly straightforward to stick into your own DOM/WebGL syncing set up. I have tested it on many devices and its currently working on two sites we have in development with no reported issues so far. I haven't tested whether or not the specific CSS I'm using to disable that pesky browser UI showing/hiding as you scroll is a factor in this though. It essentially sets to: position: fixed;
overflow: hidden;
width: 100%;
height: 100%; and the page container (the ASScroll container element) to: position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow-y: auto; Like I said, I'm not sure if these CSS rules make a difference in the DOM/WebGL lag issue, but they're included in those sites to stop the annoying canvas resize due to browser UI shifting anyway. |
Beta Was this translation helpful? Give feedback.
-
Just threw together a quick demo: https://codepen.io/ashthornton/pen/f0db400416fff43ad5096b45f6974de4 Here's the live link so you can view on your touch device without the Codepen UI: https://codepen.io/ashthornton/live/f0db400416fff43ad5096b45f6974de4 The green squares are in WebGL. So through trying to recreate the setup I have on the mentioned sites this is being used on, I found that the key might be to have an element covering the page but with I'd be interested to see if anyone has any problems with that demo! And FYI, virtual scroll is not use on touch devices in ASScroll by default. |
Beta Was this translation helpful? Give feedback.
-
Here's another interesting approach found in this example by @greggman reported in this tweet. The idea is to use an absolute positioned canvas and then translate it with the scroll values. canvas {
position: absolute;
top: -20vh;
left: 0;
width: 100vw;
height: 140vh;
} |
Beta Was this translation helpful? Give feedback.
-
Okay folks, after having spending a bit more time on this with @ashthornton, it looks like we've found a workaround (or at least we're pretty close from it)! In fact the solution is fairly simple. Let me know if it's working on your side as well. |
Beta Was this translation helpful? Give feedback.
-
Hi guys, I have a problem with stuttering in mobile that seems to be relates to this issue. In this site (in development):https://retrospettivi.netlify.app/ I made the hero banner with three.js. On desktop there is no problem. But on mobile if the site is scrolled down totally, and then scrolled up again, it will freeze for a second. I believe it's related to the canvas and webgl context more than three.js, but still.. Has anyone have an idea to fix or mitigate this? |
Beta Was this translation helpful? Give feedback.
-
@martinlaxenaire Hi bro, If possible can we talk, I need to discuss few things about curtain js. Thanks |
Beta Was this translation helpful? Give feedback.
-
Edit: this issue seems to be fixed with a little hack shown here: #75 (comment)
TL;DR:
Instead of listening to the scroll on the window element, the idea is to create a scrollable div the size of the viewport, and to listen to the scroll event of that div.
Calling to all WebGL devs!
This discussion aims to gather informations, documentation and ideas on how to improve scroll latency issue when it comes to sync WebGL elements with DOM elements on mobile.
This issue is, to my knowledge, common to all implementations of DOM to WebGL whatever the framework used, be it three.js, PixiJS, OGL, Babylon.js, curtainsjs or any other.
Currently, there's a noticeable delay between WebGL meshes and DOM elements positions visible when scrolling on mobile. This is more noticeable when going up then down then up, etc. while touching the screen.
The issue is actually easy to reproduce while trying to sync fixed positioned DOM elements and regular ones on scroll, without having to use any WebGL at all.
Here's a CodePen reproducing the issue:
[**Edit : updated the codepen to better reflect our WebGL usage:
**end of edit]
Any suggestion (except for using a virtual scroll), article, documentation, idea and code example is very welcomed here.
Let's solve this!
Beta Was this translation helpful? Give feedback.
All reactions