Frontmatter
| id | 9387 |
| title | E2E: Implement Main Thread Optical Pinning for Grid Scrolling |
| state | Closed |
| labels | enhancementarchitectureperformancegrid |
| assignees | tobiu |
| createdAt | Mar 8, 2026, 12:51 AM |
| updatedAt | Mar 8, 2026, 1:07 PM |
| githubUrl | https://github.com/neomjs/neo/issues/9387 |
| author | tobiu |
| commentsCount | 1 |
| parentIssue | 9380 |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [x] 9388 E2E: Enhance VDOM Update Pipeline with Meta Payload Support |
| blocking | [] |
| closedAt | Mar 8, 2026, 1:07 PM |
E2E: Implement Main Thread Optical Pinning for Grid Scrolling
tobiu added parent issue #9380 on Mar 8, 2026, 12:51 AM
tobiu assigned to @tobiu on Mar 8, 2026, 12:54 AM
tobiu marked this issue as being blocked by #9388 on Mar 8, 2026, 12:08 PM

tobiu
Mar 8, 2026, 1:07 PM
Input from Gemini 3.1 Pro:
✦ I have implemented the
GridRowScrollPinningMain Thread addon. It successfully parses themetapayload to determine the worker's baselinescrollTop, calculates the delta, and mutates thetranslate3dCSS string inside the VDOM delta stream before it hits the DOM.This successfully resolves the scroll thrashing/jitter issue by visually aligning the row data with the current scroll position, regardless of worker latency.
Closing this ticket. The next step is to remove the legacy predictive heuristics.
tobiu closed this issue on Mar 8, 2026, 1:07 PM
This ticket details the shift in strategy for resolving the "Stale Render Gap" during high-velocity Grid scrolling, based on empirical data gathered during E2E performance testing.
What We Learned (The Failure of Predictive Math)
Initially, we attempted to solve the "blank screen during fast drag" problem by predicting the future
scrollTopusing velocity and pipeline lag (RTT). We passed thispredictedScrollToptoGridBodyto render rows ahead of the user.This failed completely for two reasons:
scrollTopdictates the physicaltranslate3dcoordinate of the DOM pool. If we predict the user will be atY=20000and paint the 29 rows there, but the native viewport is currently moving throughY=15000, the prediction literally paints the rows off-screen.The New Strategy: Main Thread Optical Pinning ("Spring-Loaded Camera")
We must accept that during a massive teleport (e.g., jumping 500 rows instantly), the App Worker pipeline (30-50ms) will always be behind. We cannot fix this in the App Worker because it is out of sync with the physical reality of the screen.
Instead of predicting the future, we must force the stale data to stay on screen until the new data arrives.
The Implementation Plan:
Neo.main.DomAccess.applyDeltasmust fire a synchronous event (e.g.,beforeApplyDeltas) when a new batch of VDOM patches arrives.Neo.main.addon.ScrollSyncaddon (or a dedicated grid addon) subscribes to this event.translate3d(Y)of the incoming grid rows (what the App Worker thinks the scroll position is) and compares it to the exact, real-time nativescrollTopof the wrapper container.transform: translateY(gap)to the GridBody container itself.scrollTop, the gap becomes 0, and the container'stranslateYoffset is removed seamlessly.Future Cleanup Considerations
Neo.util.Performancetracker we built is highly valuable. While the predictive math failed, we can still use the RTT tracker to dynamically adjust thesyncGridBodythrottle (currently a static 16ms) to prevent App Worker queue starvation on slower machines.scrollVelocityprediction math fromScrollManager.mjs.