LearnNewsExamplesServices
Frontmatter
id8960
titleFix: Vertical scrolling causes OffscreenCanvas loss in Grid cells
stateClosed
labels
bugai
assigneestobiu
createdAtFeb 3, 2026, 1:36 PM
updatedAtFeb 3, 2026, 1:43 PM
githubUrlhttps://github.com/neomjs/neo/issues/8960
authortobiu
commentsCount1
parentIssue8930
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtFeb 3, 2026, 1:43 PM

Fix: Vertical scrolling causes OffscreenCanvas loss in Grid cells

Closed v12.0.0 bugai
tobiu
tobiu commented on Feb 3, 2026, 1:36 PM

We are observing a glitch where vertically scrolling the grid can cause some OffscreenCanvas instances (like Sparklines) to be "lost" or appear blank.

Analysis: This likely relates to the buffered row range mechanism in Neo.grid.Body. When rows are recycled or moved, the VDOM diffing engine might be generating move operations or destructive updates that interfere with the OffscreenCanvas persistence, similar to the horizontal scrolling issue but on the vertical axis.

Investigation Plan:

  1. Inspect src/grid/Body.mjs and its row recycling/buffering logic.
  2. Analyze VDOM deltas during vertical scrolling to identify if DOM nodes are being destroyed/recreated instead of moved/updated.
  3. Ensure that canvas elements within the recycled rows maintain their worker association.

Goal: Ensure OffscreenCanvas instances remain stable and connected to their workers during vertical scrolling and row recycling.

tobiu added the bug label on Feb 3, 2026, 1:36 PM
tobiu added the ai label on Feb 3, 2026, 1:36 PM
tobiu referenced in commit 71ba8ff - "Fix: Vertical scrolling causes OffscreenCanvas loss in Grid cells (#8960)" on Feb 3, 2026, 1:43 PM
tobiu added parent issue #8930 on Feb 3, 2026, 1:43 PM
tobiu
tobiu Feb 3, 2026, 1:43 PM

Input from Gemini 3 Pro:

✦ I have implemented the fix for the vertical scrolling glitch where OffscreenCanvas instances were being lost.

Root Cause: The mountedRows logic in src/grid/Body.mjs was calculating the render window based strictly on visible + buffer. At the boundaries of the dataset (top and bottom), this window size was smaller than the Recycle Modulus (available rows + 2 * buffer). Because the number of rendered rows fluctuated (e.g., shrinking to 15 at the top vs 20 in the middle), the VDOM engine interpreted the re-appearance of the "spare" rows as new insertions (insertNode), which destroys the DOM node and the associated Worker connection.

Fix Implemented: Modified updateMountedAndVisibleRows to enforce a Constant Window Size equal to the Recycle Modulus.

  • At the top of the grid, the window is "pushed down" to include look-ahead rows, filling the recycle pool.
  • At the bottom, the window is "pulled up" to include look-behind rows.

Outcome: The set of Row IDs {row-0 ... row-N} now remains constant as long as the dataset is large enough. This ensures the VDOM engine always generates moveNode operations for row recycling, preserving the OffscreenCanvas contexts and eliminating the visual glitch during vertical scrolling.

tobiu assigned to @tobiu on Feb 3, 2026, 1:43 PM
tobiu closed this issue on Feb 3, 2026, 1:43 PM