refactor: extract PixiJS rendering into pixi/ modules

Phase 5 (behavior-preserving): decompose the ~1000-line onMount into focused
modules coordinated by a plain (non-reactive) controller object:
- pixi/types.ts        LineObject / NodeObject / BackgroundLayers
- pixi/controller.ts   shared mutable pan/zoom state + Pixi refs (NOT $state,
                       which would break PixiJS object identity)
- pixi/background.ts   gradient/nebula/stars/dust/vignette + ambient loops
- pixi/lines.ts        plasma-beam connections
- pixi/nodes.ts        origin + regular nodes; collapses the duplicated pointer
                       handlers into one attachNodeInteraction helper
- pixi/interaction.ts  pan/zoom/parallax + keyboard nav (return cleanups)
- pixi/animation.ts    sequenced entrance animation

onMount is now a thin orchestrator. SkillTree.svelte: 1177 -> 274 lines
(2453 at the start of the refactor). Listener passivity, the hasMoved click
guard, eventMode-until-animated ordering, and the R-reset parallax rebaseline
are all preserved.

svelte-check: 0 errors/0 warnings. lint/test/build clean. Verified onMount runs
with no runtime exceptions (background + stats panel render). NOTE: pan/zoom/
node-click/keyboard need a manual real-browser check (headless can't paint nodes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
TehRiehlDealandClaude Opus 4.8 committed 2026-06-03 10:23:54 -07:00
1 parent f08138718a
commit 84112d8e42
8 files changed
+1057 -946

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
// Mutable controller object shared across the PixiJS modules.
//
// IMPORTANT: this must NOT be wrapped in Svelte's `$state` — the deep proxy
// breaks PixiJS's internal object identity checks. Keep it a plain object so
// the interaction, node, and animation modules can read/write the same
// mutable pan/zoom state by reference (the same single source of truth the
// original onMount closure relied on).
import type { Application, Container } from 'pixi.js';
import type { BackgroundLayers, LineObject, NodeObject } from './types';
export interface SkillTreeController {
app: Application;
treeContainer: Container;
bg: BackgroundLayers;
nodeObjects: NodeObject[];
lineObjects: LineObject[];
// Pan/zoom mutable state (was closure vars in onMount).
isDragging: boolean;
hasMoved: boolean;
dragStartX: number;
dragStartY: number;
containerStartX: number;
containerStartY: number;
lastTouchDistance: number;
isTouchZooming: boolean;
// Parallax baseline (re-set on view reset) + final zoom scale.
initialTreeX: number;
initialTreeY: number;
endScale: number;
}
export function createController(
app: Application,
treeContainer: Container,
bg: BackgroundLayers,
endScale: number
): SkillTreeController {
return {
app,
treeContainer,
bg,
nodeObjects: [],
lineObjects: [],
isDragging: false,
hasMoved: false,
dragStartX: 0,
dragStartY: 0,
containerStartX: 0,
containerStartY: 0,
lastTouchDistance: 0,
isTouchZooming: false,
initialTreeX: treeContainer.x,
initialTreeY: treeContainer.y,
endScale
};
}