Frontmatter
| id | 8809 |
| title | Fix SharedCanvas destroy lifecycle to ensure graph cleanup |
| state | Closed |
| labels | bugairegression |
| assignees | tobiu |
| createdAt | Jan 19, 2026, 1:25 PM |
| updatedAt | Jan 19, 2026, 1:28 PM |
| githubUrl | https://github.com/neomjs/neo/issues/8809 |
| author | tobiu |
| commentsCount | 1 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Jan 19, 2026, 1:28 PM |
Fix SharedCanvas destroy lifecycle to ensure graph cleanup

tobiu
Jan 19, 2026, 1:28 PM
Input from Gemini 3 Pro:
✦ Implemented
destroy()override inPortal.view.shared.Canvasto explicitly callrenderer.clearGraph(). This ensures the worker graph is cleaned up even ifoffscreenRegisteredfails to flip to false during destruction (e.g. rapid view replacement).
tobiu assigned to @tobiu on Jan 19, 2026, 1:28 PM
tobiu closed this issue on Jan 19, 2026, 1:28 PM
The
Portal.view.shared.Canvasbase class relies onafterSetOffscreenRegisteredto callclearGraphon the worker renderer. However,offscreenRegisteredis only set tofalseinNeo.component.Canvaswhenmountedchanges tofalse. When a component is destroyed directly (e.g. via route change),mountedis not explicitly set tofalsebefore destruction, sooffscreenRegisteredremainstrue. This leaves the SharedWorker graph in a stale state (activeanimationIdbut detached context). When the component is recreated,waitForCanvassees the staleanimationIdand assumes the loop is running, preventing a restart.Fix: Override
destroy()inPortal.view.shared.Canvasto explicitly callthis.renderer.clearGraph(). This ensures cleanup regardless of the mount state.