LearnNewsExamplesServices
Frontmatter
id8582
titleFix TimelineCanvas sync drift by adding debounced final alignment check
stateClosed
labels
bugai
assigneestobiu
createdAtJan 13, 2026, 12:18 AM
updatedAtJan 13, 2026, 12:28 AM
githubUrlhttps://github.com/neomjs/neo/issues/8582
authortobiu
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJan 13, 2026, 12:28 AM

Fix TimelineCanvas sync drift by adding debounced final alignment check

Closed v11.21.0 bugai
tobiu
tobiu commented on Jan 13, 2026, 12:18 AM

During the expand/collapse animation of the ticket summary, onResize fires multiple times as expected. However, the canvas nodes often settle at an intermediate position, misaligned with the final DOM elements.

This happens because waitForDomRect captures the element positions during the transition. If the CSS animation finishes after the last ResizeObserver event, or if the browser layout isn't fully settled when the last resize handler runs, the canvas retains the stale coordinates.

Resolution:

  1. Add ensureFinalAlignment to static delayable in TimelineCanvas.mjs (debounce: 100ms).
  2. Inside ensureFinalAlignment, call this.onTimelineDataLoad(this.lastRecords, true).
  3. Inside onResize, call this.ensureFinalAlignment() in addition to the immediate update.

This guarantees a final synchronization pass after the resize activity stabilizes.

tobiu added the bug label on Jan 13, 2026, 12:18 AM
tobiu added the ai label on Jan 13, 2026, 12:18 AM
tobiu referenced in commit d6956bd - "fix(TimelineCanvas): set alignment debounce to 200ms for optimal sync (#8582)" on Jan 13, 2026, 12:27 AM
tobiu assigned to @tobiu on Jan 13, 2026, 12:28 AM
tobiu
tobiu Jan 13, 2026, 12:28 AM

Input from Gemini 3 Pro:

✦ I have fixed the alignment drift by implementing a robust, debounced final check.

The Fix:

  1. Intermediate State: The waitForDomRect method inside onTimelineDataLoad works correctly, but during a CSS animation (like expanding/collapsing the summary), it captures the current animating position, not the final one.
  2. Debounced Alignment: I introduced ensureFinalAlignment as a delayable method with a 200ms debounce.
    • This method re-triggers onTimelineDataLoad with the cached records.
    • Because it is debounced, it waits until the flurry of onResize events settles.
    • The 200ms delay ensures we catch the state after the CSS transition has fully completed (t > 300ms total from start of animation), while avoiding excessive visual lag.

This ensures the canvas nodes snap to their correct final positions once the UI stabilizes.

tobiu closed this issue on Jan 13, 2026, 12:28 AM