Frontmatter
| id | 8782 |
| title | Prevent duplicate render loops in ServicesCanvas and HomeCanvas |
| state | Closed |
| labels | bugairefactoring |
| assignees | tobiu |
| createdAt | Jan 18, 2026, 5:43 PM |
| updatedAt | Jan 18, 2026, 5:49 PM |
| githubUrl | https://github.com/neomjs/neo/issues/8782 |
| author | tobiu |
| commentsCount | 2 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Jan 18, 2026, 5:49 PM |
Prevent duplicate render loops in ServicesCanvas and HomeCanvas
tobiu assigned to @tobiu on Jan 18, 2026, 5:48 PM

tobiu
Jan 18, 2026, 5:48 PM
Input from Gemini 3 Pro:
✦ Refactoring complete for
HeaderCanvas,HomeCanvas, andServicesCanvas.Changes Applied:
- Reactive Config:
animationIdconverted toanimationId_.- Auto-Cleanup:
afterSetAnimationIdhook implemented to cancel previous frames.- Render Assignment:
me.animationId = requestAnimationFrame(...)added to all render loops.- Reset:
clearGraphnow explicitly nullifiesme.animationId.This unifies the render loop architecture across the entire Portal app, preventing any possibility of parallel/zombie loops.

tobiu
Jan 18, 2026, 5:49 PM
Input from Gemini 3 Pro:
✦ Closing ticket as the fix has been implemented and pushed.
tobiu closed this issue on Jan 18, 2026, 5:49 PM
Following the fix in
TicketCanvas(#8781), we identified thatServicesCanvasandHomeCanvasin the Portal app share the same vulnerability: they do not track theiranimationId, making it possible to spawn parallel render loops ifinitGraphorresumeis called multiple times or during rapid navigation.This ticket covers the proactive refactoring of both classes to:
animationId(or introduce it) as a reactive configanimationId_.afterSetAnimationIdto automatically cancel the previous frame/timeout.renderloop to assign the frame ID to this config.clearGraphproperly nullifies the ID.This ensures robust "single-loop" architecture across all Portal canvases.