@expertrees/core 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +249 -178
- package/dist/index.js.map +1 -1
- package/package.json +17 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/graph/SkillGraphModel.ts","../src/graph/NavigationController.ts","../src/lod/LodController.ts","../src/layout/ForceLayout.ts","../src/theme/default.ts","../src/theme/merge.ts","../src/renderer/CanvasRenderer.ts","../src/renderer/InteractionController.ts","../src/SkillTreeEngine.ts"],"sourcesContent":["import Graph from 'graphology'\nimport type { SkillGraph, SkillNode, SkillEdge, NodeState, Evidence } from '../types/index.js'\n\ntype GraphEvents = {\n nodeStateChanged: { nodeId: string; state: NodeState }\n nodeAdded: { node: SkillNode }\n nodeRemoved: { nodeId: string }\n edgeAdded: { edge: SkillEdge }\n edgeRemoved: { edgeId: string }\n evidenceAdded: { nodeId: string; evidence: Evidence }\n evidenceRemoved: { nodeId: string; evidenceId: string }\n changed: void\n}\n\ntype EventListener<T> = T extends void ? () => void : (payload: T) => void\n\nexport class SkillGraphModel {\n private _graph: Graph\n private _meta: SkillGraph['meta']\n private _label: string\n private _id: string\n private _listeners: Map<keyof GraphEvents, Set<EventListener<unknown>>> = new Map()\n\n constructor(data: SkillGraph) {\n this._id = data.id\n this._label = data.label\n this._meta = data.meta\n\n this._graph = new Graph({ multi: false, allowSelfLoops: false })\n\n for (const node of data.nodes) {\n this._graph.addNode(node.id, { ...node })\n }\n\n for (const edge of data.edges) {\n if (edge.directed) {\n this._graph.addDirectedEdge(edge.source, edge.target, { ...edge })\n } else {\n this._graph.addUndirectedEdge(edge.source, edge.target, { ...edge })\n }\n }\n }\n\n // ─── Accessors ──────────────────────────────────────────────────────────────\n\n get id() { return this._id }\n get label() { return this._label }\n get meta() { return this._meta }\n\n getNode(id: string): SkillNode | undefined {\n if (!this._graph.hasNode(id)) return undefined\n return this._graph.getNodeAttributes(id) as SkillNode\n }\n\n getEdge(id: string): SkillEdge | undefined {\n if (!this._graph.hasEdge(id)) return undefined\n return this._graph.getEdgeAttributes(id) as SkillEdge\n }\n\n getNodes(): SkillNode[] {\n return this._graph.nodes().map(id => this._graph.getNodeAttributes(id) as SkillNode)\n }\n\n getEdges(): SkillEdge[] {\n return this._graph.edges().map(id => this._graph.getEdgeAttributes(id) as SkillEdge)\n }\n\n getChildren(nodeId: string): SkillNode[] {\n const node = this.getNode(nodeId)\n if (!node?.childIds) return []\n return node.childIds.flatMap(id => {\n const child = this.getNode(id)\n return child ? [child] : []\n })\n }\n\n getNodesAtDepth(depth: number): SkillNode[] {\n return this.getNodes().filter(n => n.depth === depth)\n }\n\n getNodesUpToDepth(depth: number): SkillNode[] {\n return this.getNodes().filter(n => n.depth <= depth)\n }\n\n // ─── Mutations ──────────────────────────────────────────────────────────────\n\n setNodeState(nodeId: string, state: NodeState): void {\n if (!this._graph.hasNode(nodeId)) return\n this._graph.mergeNodeAttributes(nodeId, { state })\n this._emit('nodeStateChanged', { nodeId, state })\n this._emit('changed', undefined)\n }\n\n addNode(node: SkillNode): void {\n this._graph.addNode(node.id, { ...node })\n this._emit('nodeAdded', { node })\n this._emit('changed', undefined)\n }\n\n removeNode(nodeId: string): void {\n if (!this._graph.hasNode(nodeId)) return\n this._graph.dropNode(nodeId)\n this._emit('nodeRemoved', { nodeId })\n this._emit('changed', undefined)\n }\n\n addEdge(edge: SkillEdge): void {\n if (edge.directed) {\n this._graph.addDirectedEdge(edge.source, edge.target, { ...edge })\n } else {\n this._graph.addUndirectedEdge(edge.source, edge.target, { ...edge })\n }\n this._emit('edgeAdded', { edge })\n this._emit('changed', undefined)\n }\n\n removeEdge(edgeId: string): void {\n if (!this._graph.hasEdge(edgeId)) return\n this._graph.dropEdge(edgeId)\n this._emit('edgeRemoved', { edgeId })\n this._emit('changed', undefined)\n }\n\n addEvidence(nodeId: string, evidence: Evidence): void {\n if (!this._graph.hasNode(nodeId)) return\n const node = this.getNode(nodeId)!\n const existing = node.evidence ?? []\n this._graph.mergeNodeAttributes(nodeId, { evidence: [...existing, evidence] })\n this._emit('evidenceAdded', { nodeId, evidence })\n this._emit('changed', undefined)\n }\n\n removeEvidence(nodeId: string, evidenceId: string): void {\n if (!this._graph.hasNode(nodeId)) return\n const node = this.getNode(nodeId)!\n const evidence = (node.evidence ?? []).filter(e => e.id !== evidenceId)\n this._graph.mergeNodeAttributes(nodeId, { evidence })\n this._emit('evidenceRemoved', { nodeId, evidenceId })\n this._emit('changed', undefined)\n }\n\n // ─── Serialization ──────────────────────────────────────────────────────────\n\n toJSON(): SkillGraph {\n const result: SkillGraph = {\n id: this._id,\n label: this._label,\n nodes: this.getNodes(),\n edges: this.getEdges(),\n }\n if (this._meta !== undefined) result.meta = this._meta\n return result\n }\n\n static fromJSON(data: SkillGraph): SkillGraphModel {\n return new SkillGraphModel(data)\n }\n\n // ─── Events ─────────────────────────────────────────────────────────────────\n\n on<K extends keyof GraphEvents>(event: K, listener: EventListener<GraphEvents[K]>): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n const set = this._listeners.get(event)!\n set.add(listener as EventListener<unknown>)\n return () => set.delete(listener as EventListener<unknown>)\n }\n\n private _emit<K extends keyof GraphEvents>(event: K, payload: GraphEvents[K]): void {\n const listeners = this._listeners.get(event)\n if (!listeners) return\n for (const listener of listeners) {\n if (payload === undefined) {\n (listener as () => void)()\n } else {\n (listener as (p: unknown) => void)(payload)\n }\n }\n }\n}\n","import type { NavigationFrame } from '../types/index.js'\n\nexport class NavigationController {\n private _stack: NavigationFrame[]\n private _listeners: Set<(stack: readonly NavigationFrame[]) => void> = new Set()\n\n constructor(root: NavigationFrame = { nodeId: null, label: 'Root' }) {\n this._stack = [root]\n }\n\n get current(): NavigationFrame {\n return this._stack[this._stack.length - 1]!\n }\n\n get stack(): readonly NavigationFrame[] {\n return this._stack\n }\n\n get canGoBack(): boolean {\n return this._stack.length > 1\n }\n\n push(frame: NavigationFrame): void {\n this._stack.push(frame)\n this._notify()\n }\n\n pop(): NavigationFrame | undefined {\n if (!this.canGoBack) return undefined\n const popped = this._stack.pop()\n this._notify()\n return popped\n }\n\n reset(): void {\n this._stack = [this._stack[0]!]\n this._notify()\n }\n\n onChange(listener: (stack: readonly NavigationFrame[]) => void): () => void {\n this._listeners.add(listener)\n return () => this._listeners.delete(listener)\n }\n\n private _notify(): void {\n for (const l of this._listeners) l(this._stack)\n }\n}\n","import type { LodThreshold } from '../types/index.js'\n\nconst DEFAULT_THRESHOLDS: LodThreshold[] = [\n { depth: 0, minZoom: 0, maxZoom: 0.3 },\n { depth: 1, minZoom: 0.3, maxZoom: 0.6 },\n { depth: 2, minZoom: 0.6, maxZoom: 1.2 },\n { depth: 3, minZoom: 1.2, maxZoom: 2.5 },\n { depth: 4, minZoom: 2.5, maxZoom: Infinity },\n]\n\nexport class LodController {\n private _thresholds: LodThreshold[]\n private _zoom: number = 1\n private _listeners: Set<(zoom: number) => void> = new Set()\n\n constructor(thresholds?: LodThreshold[]) {\n this._thresholds = thresholds ?? DEFAULT_THRESHOLDS\n }\n\n get zoom() { return this._zoom }\n\n get thresholds(): readonly LodThreshold[] { return this._thresholds }\n\n setZoom(zoom: number): void {\n this._zoom = Math.max(0.01, zoom)\n this._notify()\n }\n\n onChange(listener: (zoom: number) => void): () => void {\n this._listeners.add(listener)\n return () => this._listeners.delete(listener)\n }\n\n private _notify(): void {\n for (const listener of this._listeners) listener(this._zoom)\n }\n}\n","import {\n forceSimulation,\n forceLink,\n forceManyBody,\n forceCenter,\n forceCollide,\n type Simulation,\n type SimulationNodeDatum,\n type SimulationLinkDatum,\n} from 'd3-force'\nimport type { SkillNode, SkillEdge, Position } from '../types/index.js'\n\nexport interface LayoutNode extends SimulationNodeDatum {\n id: string\n depth: number\n x: number\n y: number\n}\n\nexport interface LayoutLink extends SimulationLinkDatum<LayoutNode> {\n id: string\n}\n\nexport interface ForceLayoutOptions {\n width: number\n height: number\n /** Charge strength — negative = repulsion */\n chargeStrength?: number\n /** Collision radius multiplier relative to node size */\n collisionPadding?: number\n alphaDecay?: number\n onTick?: (positions: Map<string, Position>) => void\n onEnd?: (positions: Map<string, Position>) => void\n}\n\nexport class ForceLayout {\n private _simulation: Simulation<LayoutNode, LayoutLink> | null = null\n\n run(nodes: SkillNode[], edges: SkillEdge[], options: ForceLayoutOptions): void {\n this.stop()\n\n const { width, height, chargeStrength = -200, collisionPadding = 16, alphaDecay = 0.02 } = options\n\n const layoutNodes: LayoutNode[] = nodes.map(n => ({\n id: n.id,\n depth: n.depth,\n // Seed from manual position if provided, else random near world origin.\n // World (0,0) maps to canvas center given the initial pan of (width/2, height/2).\n x: n.position?.x ?? (Math.random() - 0.5) * 100,\n y: n.position?.y ?? (Math.random() - 0.5) * 100,\n }))\n\n const nodeIndex = new Map(layoutNodes.map(n => [n.id, n]))\n\n const layoutLinks: LayoutLink[] = []\n\n // Parent-child edges for layout purposes\n for (const node of nodes) {\n if (node.parentId) {\n const source = nodeIndex.get(node.parentId)\n const target = nodeIndex.get(node.id)\n if (source && target) {\n layoutLinks.push({ id: `${node.parentId}->${node.id}`, source, target })\n }\n }\n }\n\n // Explicit cross-depth edges\n for (const edge of edges) {\n const source = nodeIndex.get(edge.source)\n const target = nodeIndex.get(edge.target)\n if (source && target) {\n layoutLinks.push({ id: edge.id, source, target })\n }\n }\n\n const emit = (positions: Map<string, Position>) => {\n options.onTick?.(positions)\n }\n\n this._simulation = forceSimulation<LayoutNode, LayoutLink>(layoutNodes)\n .alphaDecay(alphaDecay)\n .force('link', forceLink<LayoutNode, LayoutLink>(layoutLinks)\n .id(d => d.id)\n .distance(d => {\n const s = d.source as LayoutNode\n const t = d.target as LayoutNode\n // Deeper nodes cluster closer\n return 80 + (Math.abs(s.depth - t.depth) * 20)\n })\n .strength(0.4)\n )\n .force('charge', forceManyBody().strength(chargeStrength))\n .force('center', forceCenter(0, 0))\n .force('collide', forceCollide<LayoutNode>().radius(collisionPadding))\n .on('tick', () => {\n const positions = this._collectPositions(layoutNodes)\n emit(positions)\n })\n .on('end', () => {\n const positions = this._collectPositions(layoutNodes)\n options.onEnd?.(positions)\n })\n }\n\n stop(): void {\n this._simulation?.stop()\n this._simulation = null\n }\n\n reheat(): void {\n this._simulation?.alpha(0.3).restart()\n }\n\n private _collectPositions(nodes: LayoutNode[]): Map<string, Position> {\n const positions = new Map<string, Position>()\n for (const n of nodes) {\n positions.set(n.id, { x: n.x, y: n.y })\n }\n return positions\n }\n}\n","import type { Theme } from '../types/index.js'\n\nexport const defaultTheme: Theme = {\n background: '#050a1a',\n node: {\n color: '#4a9eff',\n glowColor: '#4a9eff',\n glowRadius: 12,\n size: 8,\n shape: 'circle',\n opacity: 1,\n labelColor: '#c8d8f0',\n labelSize: 12,\n labelFont: 'system-ui, sans-serif',\n },\n edge: {\n color: '#1e3a5f',\n width: 1.5,\n opacity: 0.6,\n animated: false,\n },\n states: {\n default: {},\n active: {\n color: '#7fcdff',\n glowColor: '#7fcdff',\n glowRadius: 20,\n },\n locked: {\n color: '#2a3a4a',\n glowColor: '#2a3a4a',\n glowRadius: 4,\n opacity: 0.5,\n labelColor: '#4a5a6a',\n },\n unlocked: {\n color: '#50fa7b',\n glowColor: '#50fa7b',\n glowRadius: 16,\n },\n highlighted: {\n color: '#ffb86c',\n glowColor: '#ffb86c',\n glowRadius: 24,\n },\n },\n}\n","import type { Theme, ThemeInput } from '../types/index.js'\nimport { defaultTheme } from './default.js'\n\nexport function mergeTheme(overrides?: ThemeInput): Theme {\n if (!overrides) return defaultTheme\n\n return {\n background: overrides.background ?? defaultTheme.background,\n node: { ...defaultTheme.node, ...overrides.node },\n edge: { ...defaultTheme.edge, ...overrides.edge },\n states: {\n default: { ...defaultTheme.states.default, ...overrides.states?.['default'] },\n active: { ...defaultTheme.states.active, ...overrides.states?.active },\n locked: { ...defaultTheme.states.locked, ...overrides.states?.locked },\n unlocked: { ...defaultTheme.states.unlocked, ...overrides.states?.unlocked },\n highlighted: { ...defaultTheme.states.highlighted, ...overrides.states?.highlighted },\n },\n }\n}\n","import type {\n SkillNode,\n SkillEdge,\n NodeStyle,\n EdgeStyle,\n Theme,\n ThemeInput,\n Position,\n InternalNodeState,\n} from '../types/index.js'\nimport { mergeTheme } from '../theme/merge.js'\n\nexport interface RenderState {\n positions: Map<string, Position>\n internalStates: Map<string, InternalNodeState>\n contextFadeAlpha: number\n pan: Position\n zoom: number\n}\n\nexport const BUBBLE_WORLD_RADIUS = 40\n\n// ─── Background star field ────────────────────────────────────────────────────\n\ninterface BgStar {\n x: number // 0–1 normalized CSS position\n y: number\n r: number // base radius (CSS px)\n phase: number\n speed: number // twinkle speed (radians/sec)\n}\n\nfunction generateBgStars(count: number): BgStar[] {\n return Array.from({ length: count }, () => ({\n x: Math.random(),\n y: Math.random(),\n r: 0.4 + Math.random() * 1.2,\n phase: Math.random() * Math.PI * 2,\n speed: 0.4 + Math.random() * 1.2,\n }))\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/** Deterministic phase from a node id — avoids all nodes twinkling in sync. */\nfunction hashPhase(id: string): number {\n let h = 0\n for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) >>> 0\n return ((h % 1000) / 1000) * Math.PI * 2\n}\n\nexport class CanvasRenderer {\n private _canvas: HTMLCanvasElement\n private _ctx: CanvasRenderingContext2D\n private _theme: Theme\n private _dpr: number\n private _bgStars: BgStar[]\n\n // Burst animation state (entry)\n private _burst: { startTime: number; center: Position; color: string } | null = null\n private readonly _burstDuration = 450\n\n // Implode animation state (exit)\n private _implode: { startTime: number; center: Position } | null = null\n private readonly _implodeDuration = 420\n\n constructor(canvas: HTMLCanvasElement, theme?: ThemeInput) {\n this._canvas = canvas\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('Could not get 2D context from canvas')\n this._ctx = ctx\n this._theme = mergeTheme(theme)\n this._dpr = window.devicePixelRatio ?? 1\n this._bgStars = generateBgStars(150)\n this._resize()\n }\n\n get canvas(): HTMLCanvasElement { return this._canvas }\n\n get isBurstActive(): boolean { return this._burst !== null }\n\n /** Sync canvas physical pixel size to its CSS size. Call when the container resizes. */\n resize(): void { this._resize() }\n\n /** Returns the resolved fill color for a node (used for burst color matching). */\n resolveNodeColor(node: SkillNode): string {\n return this._resolveStyle(node).color\n }\n\n updateTheme(theme: ThemeInput): void {\n this._theme = mergeTheme(theme)\n }\n\n triggerBurst(centerCanvas: Position, color: string): void {\n this._burst = { startTime: performance.now(), center: centerCanvas, color }\n }\n\n triggerImplode(centerCanvas: Position): void {\n this._implode = { startTime: performance.now(), center: centerCanvas }\n }\n\n render(nodes: SkillNode[], edges: SkillEdge[], state: RenderState): void {\n const ctx = this._ctx\n const t = performance.now() / 1000 // seconds — drives all animations\n const { pan, zoom, contextFadeAlpha, positions, internalStates } = state\n\n const cssW = this._canvas.width / this._dpr\n const cssH = this._canvas.height / this._dpr\n\n // ── Background ───────────────────────────────────────────────────────────\n ctx.clearRect(0, 0, this._canvas.width, this._canvas.height)\n ctx.fillStyle = this._theme.background\n ctx.fillRect(0, 0, this._canvas.width, this._canvas.height)\n\n // ── DPR scale (all CSS-pixel drawing lives inside here) ──────────────────\n ctx.save()\n ctx.scale(this._dpr, this._dpr)\n\n // Background star field — screen space, doesn't pan/zoom\n this._renderBgStars(ctx, cssW, cssH, t)\n\n // ── World transform ───────────────────────────────────────────────────────\n ctx.save()\n ctx.translate(pan.x, pan.y)\n ctx.scale(zoom, zoom)\n\n // Edges (solid) + animated particles\n for (const edge of edges) {\n const sourcePos = positions.get(edge.source)\n const targetPos = positions.get(edge.target)\n if (!sourcePos || !targetPos) continue\n this._drawEdge(ctx, sourcePos, targetPos, edge.style)\n if (edge.style?.animated ?? this._theme.edge.animated) {\n this._renderEdgeParticles(ctx, sourcePos, targetPos, edge, t, zoom)\n }\n }\n\n // Parent-child connectors\n for (const node of nodes) {\n if (!node.parentId) continue\n const parentPos = positions.get(node.parentId)\n const childPos = positions.get(node.id)\n if (!parentPos || !childPos) continue\n ctx.save()\n ctx.globalAlpha = contextFadeAlpha * 0.35\n ctx.strokeStyle = this._theme.edge.color\n ctx.lineWidth = this._theme.edge.width / zoom\n ctx.setLineDash([4, 8])\n ctx.beginPath()\n ctx.moveTo(parentPos.x, parentPos.y)\n ctx.lineTo(childPos.x, childPos.y)\n ctx.stroke()\n ctx.restore()\n }\n\n // Nodes — bubbles first so stars sit on top\n const bubbles = nodes.filter(n => n.childIds && n.childIds.length > 0)\n const stars = nodes.filter(n => !n.childIds || n.childIds.length === 0)\n\n for (const node of [...bubbles, ...stars]) {\n const pos = positions.get(node.id)\n if (!pos) continue\n const internal = internalStates.get(node.id) ?? 'idle'\n const isBubble = !!(node.childIds && node.childIds.length > 0)\n this._drawNode(ctx, node, pos, internal, contextFadeAlpha, zoom, isBubble, t)\n }\n\n ctx.restore() // undo world transform\n ctx.restore() // undo DPR scale\n\n // Overlays — physical pixels, screen space\n this._renderBurst()\n this._renderImplode()\n }\n\n // ─── Background stars ─────────────────────────────────────────────────────\n\n private _renderBgStars(ctx: CanvasRenderingContext2D, w: number, h: number, t: number): void {\n for (const star of this._bgStars) {\n const brightness = 0.5 + 0.5 * Math.sin(t * star.speed + star.phase)\n const alpha = 0.08 + 0.25 * brightness\n const r = star.r * (0.7 + 0.3 * brightness)\n ctx.beginPath()\n ctx.arc(star.x * w, star.y * h, r, 0, Math.PI * 2)\n ctx.fillStyle = `rgba(255,255,255,${alpha.toFixed(3)})`\n ctx.fill()\n }\n }\n\n // ─── Node rendering ───────────────────────────────────────────────────────\n\n private _drawNode(\n ctx: CanvasRenderingContext2D,\n node: SkillNode,\n pos: Position,\n internal: InternalNodeState,\n alpha: number,\n zoom: number,\n isBubble: boolean,\n t: number,\n ): void {\n if (isBubble) {\n this._drawBubble(ctx, node, pos, internal, alpha, zoom, t)\n } else {\n this._drawStar(ctx, node, pos, internal, alpha, zoom, t)\n }\n }\n\n private _drawBubble(\n ctx: CanvasRenderingContext2D,\n node: SkillNode,\n pos: Position,\n internal: InternalNodeState,\n alpha: number,\n zoom: number,\n t: number,\n ): void {\n const style = this._resolveStyle(node)\n const phase = hashPhase(node.id)\n // Bubbles breathe very slowly; selected breathes a bit more\n const breatheAmp = internal === 'selected' ? 0.08 : 0.04\n const breathe = 1 + breatheAmp * Math.sin(t * 0.6 + phase)\n const r = BUBBLE_WORLD_RADIUS * breathe * (internal === 'hovered' ? 1.1 : 1)\n const isSelected = internal === 'selected'\n\n ctx.save()\n ctx.globalAlpha = style.opacity * alpha\n\n // Outer halo — brighter when selected\n const haloOuter = isSelected ? r * 2.8 : r * 2.2\n const haloStop0 = isSelected ? style.glowColor + '55' : style.glowColor + '30'\n const halo = ctx.createRadialGradient(pos.x, pos.y, r * 0.5, pos.x, pos.y, haloOuter)\n halo.addColorStop(0, haloStop0)\n halo.addColorStop(1, style.glowColor + '00')\n ctx.fillStyle = halo\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, haloOuter, 0, Math.PI * 2)\n ctx.fill()\n\n // Inner fill\n const fill = ctx.createRadialGradient(pos.x, pos.y - r * 0.3, r * 0.1, pos.x, pos.y, r)\n fill.addColorStop(0, style.color + (isSelected ? '70' : '50'))\n fill.addColorStop(1, style.color + (isSelected ? '28' : '18'))\n ctx.fillStyle = fill\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, r, 0, Math.PI * 2)\n ctx.fill()\n\n // Border ring\n ctx.strokeStyle = isSelected ? style.glowColor : style.color\n ctx.lineWidth = (isSelected ? 2.5 : 1.5) / zoom\n ctx.globalAlpha = style.opacity * alpha * (isSelected ? 1 : 0.7)\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, r, 0, Math.PI * 2)\n ctx.stroke()\n\n // Selected: spinning dashed outer ring\n if (isSelected) {\n const spinAngle = t * 0.7 + phase\n ctx.strokeStyle = style.glowColor\n ctx.lineWidth = 1.5 / zoom\n ctx.globalAlpha = style.opacity * alpha * 0.85\n ctx.setLineDash([10 / zoom, 7 / zoom])\n ctx.lineDashOffset = -spinAngle * 18\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, r * 1.3, 0, Math.PI * 2)\n ctx.stroke()\n ctx.setLineDash([])\n }\n\n // Child-count dots orbiting inside\n if (node.childIds && node.childIds.length > 0) {\n const count = Math.min(node.childIds.length, 8)\n const dotOrbit = r * 0.55\n const dotSize = Math.max(1.5, r * 0.06)\n const orbit = t * 0.15 + phase // slow rotation\n ctx.globalAlpha = style.opacity * alpha * 0.6\n ctx.fillStyle = style.color + '90'\n for (let i = 0; i < count; i++) {\n const angle = orbit + (i / count) * Math.PI * 2\n ctx.beginPath()\n ctx.arc(\n pos.x + dotOrbit * Math.cos(angle),\n pos.y + dotOrbit * Math.sin(angle),\n dotSize, 0, Math.PI * 2,\n )\n ctx.fill()\n }\n }\n\n // Label\n ctx.globalAlpha = style.opacity * alpha\n ctx.fillStyle = style.labelColor\n ctx.font = `bold ${(style.labelSize * 1.2) / zoom}px ${style.labelFont}`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.fillText(node.label, pos.x, pos.y)\n\n ctx.restore()\n }\n\n private _drawStar(\n ctx: CanvasRenderingContext2D,\n node: SkillNode,\n pos: Position,\n internal: InternalNodeState,\n alpha: number,\n zoom: number,\n t: number,\n ): void {\n const style = this._resolveStyle(node)\n const phase = hashPhase(node.id)\n // Two independent sine waves for a natural twinkle\n const isSelected = internal === 'selected'\n // Selected nodes twinkle more dramatically\n const twinkleAmp = isSelected ? 0.4 : 0.22\n const twinkle = 1 + twinkleAmp * Math.sin(t * 1.7 + phase)\n + 0.08 * Math.sin(t * 3.1 + phase * 1.3)\n const glowPulse = style.glowRadius * twinkle\n const size = style.size * (internal === 'hovered' ? 1.4 : 1)\n\n ctx.save()\n ctx.globalAlpha = style.opacity * alpha\n\n // Selected: pulsing rings that radiate outward and fade\n if (isSelected) {\n const ringPeriod = 1.8\n for (let i = 0; i < 2; i++) {\n const offset = i * (ringPeriod / 2)\n const pulse = ((t + offset) % ringPeriod) / ringPeriod // 0→1\n const pulseR = (size + glowPulse * 0.6) * (1 + pulse * 2.2)\n const ringAlpha = (1 - pulse) * 0.6\n ctx.strokeStyle = style.glowColor\n ctx.lineWidth = (1.5 / zoom) * (1 - pulse * 0.5)\n ctx.globalAlpha = ringAlpha * style.opacity * alpha\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, pulseR, 0, Math.PI * 2)\n ctx.stroke()\n }\n ctx.globalAlpha = style.opacity * alpha\n }\n\n // Glow\n if (glowPulse > 0) {\n const grad = ctx.createRadialGradient(pos.x, pos.y, 0, pos.x, pos.y, glowPulse + size)\n grad.addColorStop(0, style.glowColor + (isSelected ? 'ff' : 'cc'))\n grad.addColorStop(0.4, style.glowColor + (isSelected ? '88' : '55'))\n grad.addColorStop(1, style.glowColor + '00')\n ctx.fillStyle = grad\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, glowPulse + size, 0, Math.PI * 2)\n ctx.fill()\n }\n\n // Body\n ctx.fillStyle = isSelected ? style.glowColor : style.color\n ctx.beginPath()\n this._drawShape(ctx, pos, size, style.shape)\n ctx.fill()\n\n // Label\n if (size * zoom > 4) {\n ctx.fillStyle = style.labelColor\n ctx.font = `${style.labelSize / zoom}px ${style.labelFont}`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'top'\n ctx.fillText(node.label, pos.x, pos.y + size + 4 / zoom)\n }\n\n ctx.restore()\n }\n\n // ─── Edge particles ───────────────────────────────────────────────────────\n\n private _renderEdgeParticles(\n ctx: CanvasRenderingContext2D,\n from: Position,\n to: Position,\n edge: SkillEdge,\n t: number,\n zoom: number,\n ): void {\n const dx = to.x - from.x\n const dy = to.y - from.y\n const len = Math.sqrt(dx * dx + dy * dy)\n if (len < 1) return\n\n const particleCount = 3\n const speed = 0.2 // edge traversals per second\n const particleR = 2.5 / zoom\n const color = edge.style?.color ?? this._theme.edge.color\n\n for (let i = 0; i < particleCount; i++) {\n const progress = ((t * speed + i / particleCount) % 1)\n const x = from.x + dx * progress\n const y = from.y + dy * progress\n const fade = Math.sin(progress * Math.PI) // fade at both ends\n\n ctx.save()\n ctx.globalAlpha = fade * 0.85\n\n const grad = ctx.createRadialGradient(x, y, 0, x, y, particleR * 2.5)\n grad.addColorStop(0, color + 'ff')\n grad.addColorStop(0.4, color + '99')\n grad.addColorStop(1, color + '00')\n ctx.fillStyle = grad\n ctx.beginPath()\n ctx.arc(x, y, particleR * 2.5, 0, Math.PI * 2)\n ctx.fill()\n\n ctx.restore()\n }\n }\n\n // ─── Burst animation ──────────────────────────────────────────────────────\n\n private _renderBurst(): void {\n if (!this._burst) return\n const ctx = this._ctx\n const elapsed = performance.now() - this._burst.startTime\n const t = elapsed / this._burstDuration\n if (t >= 1) { this._burst = null; return }\n\n const eased = 1 - Math.pow(1 - t, 3)\n const maxR = Math.hypot(this._canvas.width, this._canvas.height)\n const r = eased * maxR\n const alpha = (1 - eased) * 0.35\n\n ctx.save()\n ctx.globalAlpha = alpha\n ctx.fillStyle = this._burst.color\n ctx.beginPath()\n ctx.arc(\n this._burst.center.x * this._dpr,\n this._burst.center.y * this._dpr,\n r, 0, Math.PI * 2,\n )\n ctx.fill()\n ctx.restore()\n }\n\n // ─── Implode animation ────────────────────────────────────────────────────\n\n private _renderImplode(): void {\n if (!this._implode) return\n const ctx = this._ctx\n const elapsed = performance.now() - this._implode.startTime\n const t = elapsed / this._implodeDuration\n if (t >= 1) { this._implode = null; return }\n\n // Cubic ease-in: ring starts at full radius and slowly at first,\n // then accelerates sharply as it collapses to center\n const eased = t * t * t\n const maxR = Math.hypot(this._canvas.width, this._canvas.height)\n const r = (1 - eased) * maxR\n const alpha = (1 - t) * 0.55\n const lineWidth = (1 - eased) * 40 * this._dpr\n\n const cx = this._implode.center.x * this._dpr\n const cy = this._implode.center.y * this._dpr\n\n ctx.save()\n ctx.globalAlpha = alpha\n ctx.strokeStyle = '#9b5de5'\n ctx.lineWidth = lineWidth\n ctx.shadowColor = '#9b5de5'\n ctx.shadowBlur = 30 * this._dpr\n ctx.beginPath()\n ctx.arc(cx, cy, Math.max(0, r), 0, Math.PI * 2)\n ctx.stroke()\n ctx.restore()\n }\n\n // ─── Shapes ───────────────────────────────────────────────────────────────\n\n private _resolveStyle(node: SkillNode): NodeStyle {\n const base = this._theme.node\n const stateOverride = node.state ? this._theme.states[node.state] : {}\n const nodeOverride = node.style ?? {}\n return { ...base, ...stateOverride, ...nodeOverride }\n }\n\n private _drawShape(\n ctx: CanvasRenderingContext2D,\n pos: Position,\n size: number,\n shape: NodeStyle['shape'],\n ): void {\n switch (shape) {\n case 'circle':\n ctx.arc(pos.x, pos.y, size, 0, Math.PI * 2)\n break\n case 'hexagon':\n this._polygon(ctx, pos, size, 6, Math.PI / 6)\n break\n case 'diamond':\n this._polygon(ctx, pos, size, 4, 0)\n break\n case 'star':\n this._star(ctx, pos, size)\n break\n }\n }\n\n private _polygon(ctx: CanvasRenderingContext2D, pos: Position, r: number, sides: number, offset: number): void {\n ctx.moveTo(pos.x + r * Math.cos(offset), pos.y + r * Math.sin(offset))\n for (let i = 1; i < sides; i++) {\n const angle = offset + (i * 2 * Math.PI) / sides\n ctx.lineTo(pos.x + r * Math.cos(angle), pos.y + r * Math.sin(angle))\n }\n ctx.closePath()\n }\n\n private _star(ctx: CanvasRenderingContext2D, pos: Position, r: number): void {\n const inner = r * 0.4\n const points = 5\n for (let i = 0; i < points * 2; i++) {\n const angle = (i * Math.PI) / points - Math.PI / 2\n const radius = i % 2 === 0 ? r : inner\n const x = pos.x + radius * Math.cos(angle)\n const y = pos.y + radius * Math.sin(angle)\n i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)\n }\n ctx.closePath()\n }\n\n private _drawEdge(\n ctx: CanvasRenderingContext2D,\n from: Position,\n to: Position,\n styleOverride?: Partial<EdgeStyle>,\n ): void {\n const style = { ...this._theme.edge, ...styleOverride }\n ctx.save()\n ctx.strokeStyle = style.color\n ctx.lineWidth = style.width\n ctx.globalAlpha = style.opacity\n if (style.dashPattern) ctx.setLineDash(style.dashPattern)\n ctx.beginPath()\n ctx.moveTo(from.x, from.y)\n ctx.lineTo(to.x, to.y)\n ctx.stroke()\n ctx.restore()\n }\n\n private _resize(): void {\n const rect = this._canvas.getBoundingClientRect()\n const w = Math.floor(rect.width * this._dpr)\n const h = Math.floor(rect.height * this._dpr)\n if (this._canvas.width !== w || this._canvas.height !== h) {\n this._canvas.width = w\n this._canvas.height = h\n }\n }\n\n dispose(): void { /* nothing to clean up */ }\n}\n","import type { SkillNode, Position } from '../types/index.js'\nimport { BUBBLE_WORLD_RADIUS } from './CanvasRenderer.js'\n\nexport interface InteractionState {\n pan: Position\n zoom: number\n hoveredNodeId: string | null\n selectedNodeId: string | null\n}\n\nexport type InteractionEvent =\n | { type: 'node:click'; nodeId: string }\n | { type: 'node:hover'; nodeId: string }\n | { type: 'node:blur'; nodeId: string }\n | { type: 'canvas:click' }\n | { type: 'zoom:change'; zoom: number }\n | { type: 'pan:change'; pan: Position }\n\nexport class InteractionController {\n private _canvas: HTMLCanvasElement\n private _state: InteractionState\n private _isPanning = false\n private _lastPan: Position = { x: 0, y: 0 }\n private _listeners: Set<(event: InteractionEvent) => void> = new Set()\n private _nodes: SkillNode[] = []\n private _positions: Map<string, Position> = new Map()\n private _nodeSize = 8\n private _dpr: number\n\n // Smooth zoom (lerp)\n private _targetZoom: number = 1\n private _zoomAnchor: Position | null = null\n private readonly _zoomLerpAlpha = 0.14\n\n // Timed zoom — takes priority over lerp when active\n private _timedZoom: {\n startZoom: number\n target: number\n anchor: Position | null\n startTime: number\n duration: number\n easing: 'in' | 'out'\n } | null = null\n\n // Multi-touch tracking\n private _activePointers: Map<number, Position> = new Map()\n private _lastPinchDist: number | null = null\n // Separate from _lastPan (which is updated on every move) — used for drag vs click detection\n private _pointerDownPos: Position = { x: 0, y: 0 }\n\n private _onPointerDown: (e: PointerEvent) => void\n private _onPointerMove: (e: PointerEvent) => void\n private _onPointerUp: (e: PointerEvent) => void\n private _onPointerCancel: (e: PointerEvent) => void\n private _onWheel: (e: WheelEvent) => void\n\n constructor(canvas: HTMLCanvasElement) {\n this._canvas = canvas\n this._dpr = window.devicePixelRatio ?? 1\n this._state = {\n pan: { x: canvas.width / (2 * this._dpr), y: canvas.height / (2 * this._dpr) },\n zoom: 1,\n hoveredNodeId: null,\n selectedNodeId: null,\n }\n\n this._onPointerDown = this._handlePointerDown.bind(this)\n this._onPointerMove = this._handlePointerMove.bind(this)\n this._onPointerUp = this._handlePointerUp.bind(this)\n this._onPointerCancel = this._handlePointerCancel.bind(this)\n this._onWheel = this._handleWheel.bind(this)\n\n canvas.addEventListener('pointerdown', this._onPointerDown)\n canvas.addEventListener('pointermove', this._onPointerMove)\n canvas.addEventListener('pointerup', this._onPointerUp)\n canvas.addEventListener('pointercancel', this._onPointerCancel)\n canvas.addEventListener('wheel', this._onWheel, { passive: false })\n }\n\n get state(): Readonly<InteractionState> { return this._state }\n get targetZoom(): number { return this._targetZoom }\n get zoomAnchor(): Position | null { return this._zoomAnchor }\n\n setTargetZoom(value: number, anchor?: Position): void {\n this._timedZoom = null\n this._targetZoom = value\n if (anchor !== undefined) this._zoomAnchor = anchor\n }\n\n /**\n * Animate zoom to `target` over `duration` ms.\n * `easing: 'in'` — cubic ease-in (slow start, accelerates toward target).\n * `easing: 'out'` — cubic ease-out (fast start, decelerates toward target).\n */\n startTimedZoom(target: number, duration: number, anchor?: Position, easing: 'in' | 'out' = 'in'): void {\n this._timedZoom = {\n startZoom: this._state.zoom,\n target,\n anchor: anchor ?? null,\n startTime: performance.now(),\n duration,\n easing,\n }\n this._targetZoom = target\n this._zoomAnchor = anchor ?? null\n }\n\n /** Instantly snap zoom and pan to a new center — used on navigation transitions. */\n resetToCenter(zoom: number, cx: number, cy: number): void {\n this._timedZoom = null\n this._targetZoom = zoom\n this._state.zoom = zoom\n this._state.pan = { x: cx, y: cy }\n this._zoomAnchor = null\n }\n\n updateNodes(nodes: SkillNode[], positions: Map<string, Position>, nodeSize: number): void {\n this._nodes = nodes\n this._positions = positions\n this._nodeSize = nodeSize\n }\n\n onChange(listener: (event: InteractionEvent) => void): () => void {\n this._listeners.add(listener)\n return () => this._listeners.delete(listener)\n }\n\n /**\n * Advance zoom animation one frame. Called every RAF frame by the engine.\n * Returns true while the animation is still in progress.\n */\n tick(): boolean {\n const prevZoom = this._state.zoom\n\n if (this._timedZoom) {\n const { startZoom, target, anchor, startTime, duration, easing } = this._timedZoom\n const t = Math.min(1, (performance.now() - startTime) / duration)\n // ease-in: t³ — slow start, accelerates toward target\n // ease-out: 1-(1-t)³ — fast start, decelerates toward target\n const eased = easing === 'out' ? 1 - Math.pow(1 - t, 3) : t * t * t\n this._state.zoom = startZoom + (target - startZoom) * eased\n\n if (t >= 1) {\n this._timedZoom = null\n this._zoomAnchor = null\n } else {\n this._zoomAnchor = anchor\n }\n } else {\n // Fallback: standard lerp toward target\n const dz = this._targetZoom - this._state.zoom\n if (Math.abs(dz) < 0.0001) {\n this._zoomAnchor = null\n return false\n }\n this._state.zoom += dz * this._zoomLerpAlpha\n }\n\n // Keep the zoom anchor point fixed in world space\n if (this._zoomAnchor) {\n const { x: ax, y: ay } = this._zoomAnchor\n this._state.pan = {\n x: ax - (ax - this._state.pan.x) * (this._state.zoom / prevZoom),\n y: ay - (ay - this._state.pan.y) * (this._state.zoom / prevZoom),\n }\n }\n\n return true\n }\n\n dispose(): void {\n this._canvas.removeEventListener('pointerdown', this._onPointerDown)\n this._canvas.removeEventListener('pointermove', this._onPointerMove)\n this._canvas.removeEventListener('pointerup', this._onPointerUp)\n this._canvas.removeEventListener('pointercancel', this._onPointerCancel)\n this._canvas.removeEventListener('wheel', this._onWheel)\n }\n\n // ─── Canvas → world coordinate transform ────────────────────────────────────\n\n canvasToWorld(canvasX: number, canvasY: number): Position {\n return {\n x: (canvasX - this._state.pan.x) / this._state.zoom,\n y: (canvasY - this._state.pan.y) / this._state.zoom,\n }\n }\n\n private _getCanvasPos(e: MouseEvent): Position {\n const rect = this._canvas.getBoundingClientRect()\n return { x: e.clientX - rect.left, y: e.clientY - rect.top }\n }\n\n private _hitTest(worldPos: Position): string | null {\n let closest: string | null = null\n let closestDist = Infinity\n\n for (const node of this._nodes) {\n const pos = this._positions.get(node.id)\n if (!pos) continue\n const isBubble = !!(node.childIds && node.childIds.length > 0)\n // Bubbles: match visual radius. Stars: generous touch target covering label.\n const hitRadius = isBubble ? BUBBLE_WORLD_RADIUS * 1.3 : this._nodeSize * 4\n const dx = worldPos.x - pos.x\n const dy = worldPos.y - pos.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < hitRadius && dist < closestDist) {\n closestDist = dist\n closest = node.id\n }\n }\n return closest\n }\n\n private _emit(event: InteractionEvent): void {\n for (const listener of this._listeners) listener(event)\n }\n\n // ─── Pointer handlers ────────────────────────────────────────────────────────\n\n private _handlePointerDown(e: PointerEvent): void {\n this._canvas.setPointerCapture(e.pointerId)\n const pos = this._getCanvasPos(e)\n this._activePointers.set(e.pointerId, pos)\n\n if (this._activePointers.size === 1) {\n // Single pointer — prepare for pan or click\n this._isPanning = true\n this._lastPan = pos\n this._pointerDownPos = pos // fixed reference for drag vs click detection\n } else {\n // Second finger arrived — switch to pinch mode\n this._isPanning = false\n this._lastPinchDist = null\n }\n }\n\n private _handlePointerMove(e: PointerEvent): void {\n const canvasPos = this._getCanvasPos(e)\n this._activePointers.set(e.pointerId, canvasPos)\n\n // ── Pinch zoom (two fingers) ──────────────────────────────────────────────\n if (this._activePointers.size >= 2) {\n const pts = [...this._activePointers.values()]\n const dist = Math.hypot(pts[1]!.x - pts[0]!.x, pts[1]!.y - pts[0]!.y)\n\n if (this._lastPinchDist !== null && dist > 0) {\n const scale = dist / this._lastPinchDist\n const midX = (pts[0]!.x + pts[1]!.x) / 2\n const midY = (pts[0]!.y + pts[1]!.y) / 2\n this._targetZoom = Math.max(0.05, Math.min(20, this._targetZoom * scale))\n this._zoomAnchor = { x: midX, y: midY }\n this._emit({ type: 'zoom:change', zoom: this._targetZoom })\n }\n this._lastPinchDist = dist\n return\n }\n\n // ── Single-pointer pan ───────────────────────────────────────────────────\n if (this._isPanning) {\n const dx = canvasPos.x - this._lastPan.x\n const dy = canvasPos.y - this._lastPan.y\n this._lastPan = canvasPos\n this._state.pan = { x: this._state.pan.x + dx, y: this._state.pan.y + dy }\n this._emit({ type: 'pan:change', pan: this._state.pan })\n return\n }\n\n // ── Hover detection (mouse / stylus, not bare touch) ─────────────────────\n if (e.pointerType !== 'touch') {\n const worldPos = this.canvasToWorld(canvasPos.x, canvasPos.y)\n const hit = this._hitTest(worldPos)\n if (hit !== this._state.hoveredNodeId) {\n if (this._state.hoveredNodeId) {\n this._emit({ type: 'node:blur', nodeId: this._state.hoveredNodeId })\n }\n this._state.hoveredNodeId = hit\n if (hit) this._emit({ type: 'node:hover', nodeId: hit })\n }\n }\n }\n\n private _handlePointerUp(e: PointerEvent): void {\n const canvasPos = this._getCanvasPos(e)\n const wasMultiTouch = this._activePointers.size >= 2\n const dragOrigin = this._pointerDownPos // original down position, not the moving _lastPan\n this._activePointers.delete(e.pointerId)\n this._lastPinchDist = null\n\n if (wasMultiTouch) {\n // Came back to single touch — resume pan from current remaining finger\n if (this._activePointers.size === 1) {\n this._isPanning = true\n this._lastPan = [...this._activePointers.values()][0]!\n }\n return\n }\n\n this._isPanning = false\n\n // Fire click if pointer didn't travel (not a drag)\n const dx = Math.abs(canvasPos.x - dragOrigin.x)\n const dy = Math.abs(canvasPos.y - dragOrigin.y)\n if (dx < 4 && dy < 4) {\n const worldPos = this.canvasToWorld(canvasPos.x, canvasPos.y)\n const hit = this._hitTest(worldPos)\n if (hit) {\n this._state.selectedNodeId = hit === this._state.selectedNodeId ? null : hit\n this._emit({ type: 'node:click', nodeId: hit })\n } else {\n this._state.selectedNodeId = null\n this._emit({ type: 'canvas:click' })\n }\n }\n }\n\n private _handlePointerCancel(e: PointerEvent): void {\n this._activePointers.delete(e.pointerId)\n this._lastPinchDist = null\n if (this._activePointers.size === 0) {\n this._isPanning = false\n }\n }\n\n // ── Wheel (mouse / trackpad) ─────────────────────────────────────────────────\n\n private _handleWheel(e: WheelEvent): void {\n e.preventDefault()\n const canvasPos = this._getCanvasPos(e)\n const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1\n this._targetZoom = Math.max(0.05, Math.min(20, this._targetZoom * factor))\n this._zoomAnchor = canvasPos\n this._emit({ type: 'zoom:change', zoom: this._targetZoom })\n }\n}\n","import type {\n SkillGraph,\n SkillNode,\n SkillEdge,\n NodeState,\n Evidence,\n ThemeInput,\n LodThreshold,\n SkillTreeEvents,\n InternalNodeState,\n Position,\n NavigationFrame,\n} from './types/index.js'\nimport { SkillGraphModel } from './graph/SkillGraphModel.js'\nimport { NavigationController } from './graph/NavigationController.js'\nimport { LodController } from './lod/LodController.js'\nimport { ForceLayout } from './layout/ForceLayout.js'\nimport { CanvasRenderer, BUBBLE_WORLD_RADIUS } from './renderer/CanvasRenderer.js'\nimport { InteractionController } from './renderer/InteractionController.js'\n\nconst ENTER_ZOOM_THRESHOLD = 2.5 // zoom target must exceed this to enter a bubble\nconst EXIT_ZOOM_THRESHOLD = 0.35 // zoom target must drop below this to exit context\nconst NAV_COOLDOWN_MS = 700 // prevent rapid enter/exit toggling\n\nexport interface SkillTreeEngineOptions {\n canvas: HTMLCanvasElement\n data: SkillGraph\n theme?: ThemeInput\n lod?: LodThreshold[]\n on?: Partial<SkillTreeEvents>\n /** Silently start inside this bubble node's context — no burst or fade animation */\n initialContextNodeId?: string\n}\n\nexport class SkillTreeEngine {\n private _model: SkillGraphModel\n private _nav: NavigationController\n private _lod: LodController\n private _layout: ForceLayout\n private _renderer: CanvasRenderer\n private _interaction: InteractionController\n private _positions: Map<string, Position> = new Map()\n private _internalStates: Map<string, InternalNodeState> = new Map()\n private _eventHandlers: Partial<SkillTreeEvents>\n private _rafId: number | null = null\n private _pendingEnter: ReturnType<typeof setTimeout> | null = null\n private _pendingExit: ReturnType<typeof setTimeout> | null = null\n private _unsubscribers: Array<() => void> = []\n private _resizeObserver: ResizeObserver\n\n // Cached visible node/edge lists — rebuilt on navigation and model changes\n private _visibleNodes: SkillNode[] = []\n private _visibleEdges: SkillEdge[] = []\n\n // Context fade-in\n private _contextFadeAlpha = 1.0\n private _contextFadeStart = 0\n private readonly _contextFadeDuration = 400\n\n // Navigation cooldown\n private _navCooldownUntil = 0\n\n constructor(options: SkillTreeEngineOptions) {\n const { canvas, data, theme, lod, on = {} } = options\n\n this._eventHandlers = on\n this._model = new SkillGraphModel(data)\n this._nav = new NavigationController({ nodeId: null, label: data.label })\n this._lod = new LodController(lod)\n this._layout = new ForceLayout()\n this._renderer = new CanvasRenderer(canvas, theme ?? data.theme)\n this._interaction = new InteractionController(canvas)\n\n if (options.initialContextNodeId) {\n const initNode = this._model.getNode(options.initialContextNodeId)\n if (initNode && this._isBubble(initNode)) {\n this._nav.push({ nodeId: initNode.id, label: initNode.label })\n }\n }\n\n this._rebuildVisibleCache()\n this._wireEvents()\n this._runLayout()\n this._startRenderLoop()\n\n this._resizeObserver = new ResizeObserver(() => {\n this._renderer.resize()\n this._runLayout()\n })\n this._resizeObserver.observe(canvas)\n\n this._eventHandlers['graph:ready']?.(data)\n }\n\n // ─── Public API ─────────────────────────────────────────────────────────────\n\n setNodeState(nodeId: string, state: NodeState): void {\n this._model.setNodeState(nodeId, state)\n }\n\n addEvidence(nodeId: string, evidence: Evidence): void {\n this._model.addEvidence(nodeId, evidence)\n }\n\n removeEvidence(nodeId: string, evidenceId: string): void {\n this._model.removeEvidence(nodeId, evidenceId)\n }\n\n updateTheme(theme: ThemeInput): void {\n this._renderer.updateTheme(theme)\n }\n\n zoomIn(): void {\n this._interaction.setTargetZoom(Math.min(20, this._interaction.targetZoom * 1.3))\n }\n\n zoomOut(): void {\n this._interaction.setTargetZoom(Math.max(0.05, this._interaction.targetZoom / 1.3))\n }\n\n goBack(): void {\n if (this._nav.canGoBack) this._exitWithAnimation()\n }\n\n /**\n * Atomically jump to a specific nav stack depth, firing a single animation.\n * `targetLength` is the desired `stack.length` after the jump.\n * Silently pops intermediate frames; plays one implode + fade transition.\n */\n jumpToNavDepth(targetLength: number): void {\n if (this._nav.stack.length <= targetLength) return\n\n // Cancel any in-flight transitions\n if (this._pendingEnter !== null) { clearTimeout(this._pendingEnter); this._pendingEnter = null }\n if (this._pendingExit !== null) { clearTimeout(this._pendingExit); this._pendingExit = null }\n\n // Silently pop all excess frames; capture the last one for the event\n let lastPopped: NavigationFrame | undefined\n while (this._nav.stack.length > targetLength && this._nav.canGoBack) {\n lastPopped = this._nav.pop()\n }\n if (!lastPopped) return\n\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n const center = { x: rect.width / 2, y: rect.height / 2 }\n\n this._navCooldownUntil = Date.now() + NAV_COOLDOWN_MS\n this._rebuildVisibleCache()\n this._renderer.triggerImplode(center)\n this._interaction.resetToCenter(1.0, center.x, center.y)\n this._lod.setZoom(1.0)\n\n for (const n of this._visibleNodes) {\n this._positions.set(n.id, { x: (Math.random() - 0.5) * 80, y: (Math.random() - 0.5) * 80 })\n }\n\n this._contextFadeAlpha = 0\n this._contextFadeStart = performance.now()\n this._runLayout()\n this._eventHandlers['context:exit']?.(lastPopped, this._nav.stack)\n }\n\n private _exitWithAnimation(): void {\n if (!this._nav.canGoBack) return\n\n // Cancel any pending enter transition\n if (this._pendingEnter !== null) {\n clearTimeout(this._pendingEnter)\n this._pendingEnter = null\n }\n\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n const center = { x: rect.width / 2, y: rect.height / 2 }\n const duration = 480\n\n // Ease-out: camera pulls back fast, then settles\n this._interaction.startTimedZoom(0.45, duration, undefined, 'out')\n\n this._pendingExit = setTimeout(() => {\n this._pendingExit = null\n this._renderer.triggerImplode(center)\n this._exitContext()\n }, duration)\n }\n\n enterContext(nodeId: string): void {\n const node = this._model.getNode(nodeId)\n if (!node || !this._isBubble(node)) return\n\n // Cancel any previous pending transition\n if (this._pendingEnter !== null) {\n clearTimeout(this._pendingEnter)\n this._pendingEnter = null\n }\n\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n const burstPos = { x: rect.width / 2, y: rect.height / 2 }\n\n // Cubic ease-in zoom toward the node, then transition exactly when it peaks\n const nodePos = this._positions.get(nodeId)\n const anchor = nodePos ? (() => {\n const { zoom, pan } = this._interaction.state\n return { x: nodePos.x * zoom + pan.x, y: nodePos.y * zoom + pan.y }\n })() : undefined\n\n const duration = 480\n this._interaction.startTimedZoom(2.5, duration, anchor)\n\n this._pendingEnter = setTimeout(() => {\n this._pendingEnter = null\n this._enterContext(node, burstPos)\n }, duration)\n }\n\n getGraph(): SkillGraph { return this._model.toJSON() }\n\n getNavigationStack(): readonly NavigationFrame[] { return this._nav.stack }\n\n dispose(): void {\n if (this._rafId !== null) cancelAnimationFrame(this._rafId)\n if (this._pendingEnter !== null) clearTimeout(this._pendingEnter)\n if (this._pendingExit !== null) clearTimeout(this._pendingExit)\n this._resizeObserver.disconnect()\n this._layout.stop()\n this._renderer.dispose()\n this._interaction.dispose()\n for (const unsub of this._unsubscribers) unsub()\n }\n\n // ─── Visible node cache ──────────────────────────────────────────────────────\n\n private _rebuildVisibleCache(): void {\n const currentId = this._nav.current.nodeId\n this._visibleNodes = this._model.getNodes().filter(n =>\n currentId === null ? !n.parentId : n.parentId === currentId\n )\n const ids = new Set(this._visibleNodes.map(n => n.id))\n this._visibleEdges = this._model.getEdges().filter(\n e => ids.has(e.source) && ids.has(e.target)\n )\n }\n\n // ─── Navigation ─────────────────────────────────────────────────────────────\n\n private _isBubble(node: SkillNode): boolean {\n return !!(node.childIds && node.childIds.length > 0)\n }\n\n private _enterContext(node: SkillNode, burstCanvasPos: Position): void {\n this._nav.push({ nodeId: node.id, label: node.label })\n this._navCooldownUntil = Date.now() + NAV_COOLDOWN_MS\n this._rebuildVisibleCache()\n\n this._renderer.triggerBurst(burstCanvasPos, this._renderer.resolveNodeColor(node))\n\n // Reset zoom/pan to center\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n this._interaction.resetToCenter(1.0, rect.width / 2, rect.height / 2)\n this._lod.setZoom(1.0)\n\n // Seed visible nodes near world origin\n for (const n of this._visibleNodes) {\n this._positions.set(n.id, {\n x: (Math.random() - 0.5) * 80,\n y: (Math.random() - 0.5) * 80,\n })\n }\n\n this._contextFadeAlpha = 0\n this._contextFadeStart = performance.now()\n\n this._runLayout()\n this._eventHandlers['context:enter']?.(node, this._nav.stack)\n }\n\n private _exitContext(): void {\n const exited = this._nav.pop()\n if (!exited) return\n this._navCooldownUntil = Date.now() + NAV_COOLDOWN_MS\n this._rebuildVisibleCache()\n\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n this._interaction.resetToCenter(1.0, rect.width / 2, rect.height / 2)\n this._lod.setZoom(1.0)\n\n for (const n of this._visibleNodes) {\n this._positions.set(n.id, {\n x: (Math.random() - 0.5) * 80,\n y: (Math.random() - 0.5) * 80,\n })\n }\n\n this._contextFadeAlpha = 0\n this._contextFadeStart = performance.now()\n\n this._runLayout()\n this._eventHandlers['context:exit']?.(exited, this._nav.stack)\n }\n\n private _checkNavigation(): void {\n if (Date.now() < this._navCooldownUntil) return\n\n const targetZoom = this._interaction.targetZoom\n const anchor = this._interaction.zoomAnchor\n\n if (targetZoom > ENTER_ZOOM_THRESHOLD && anchor) {\n const { zoom, pan } = this._interaction.state\n const bubble = this._findBubbleAtCanvas(anchor, pan, zoom)\n if (bubble) {\n this._enterContext(bubble, anchor)\n return\n }\n }\n\n if (targetZoom < EXIT_ZOOM_THRESHOLD && this._nav.canGoBack) {\n this._exitContext()\n }\n }\n\n private _findBubbleAtCanvas(canvasPos: Position, pan: Position, zoom: number): SkillNode | null {\n const worldX = (canvasPos.x - pan.x) / zoom\n const worldY = (canvasPos.y - pan.y) / zoom\n\n for (const node of this._visibleNodes) {\n if (!this._isBubble(node)) continue\n const pos = this._positions.get(node.id)\n if (!pos) continue\n const dx = worldX - pos.x\n const dy = worldY - pos.y\n if (Math.sqrt(dx * dx + dy * dy) <= BUBBLE_WORLD_RADIUS * 1.3) {\n return node\n }\n }\n return null\n }\n\n // ─── Events ─────────────────────────────────────────────────────────────────\n\n private _wireEvents(): void {\n this._unsubscribers.push(\n this._model.on('changed', () => {\n this._rebuildVisibleCache()\n })\n )\n\n this._unsubscribers.push(\n this._interaction.onChange(event => {\n switch (event.type) {\n case 'zoom:change':\n case 'pan:change':\n break\n case 'node:hover': {\n this._internalStates.set(event.nodeId, 'hovered')\n const node = this._model.getNode(event.nodeId)\n if (node) this._eventHandlers['node:hover']?.(node)\n break\n }\n case 'node:blur': {\n const prev = this._internalStates.get(event.nodeId)\n if (prev === 'hovered') this._internalStates.set(event.nodeId, 'idle')\n const node = this._model.getNode(event.nodeId)\n if (node) this._eventHandlers['node:blur']?.(node)\n break\n }\n case 'canvas:click': {\n // Clear any selected node\n for (const [id, s] of this._internalStates) {\n if (s === 'selected') this._internalStates.set(id, 'idle')\n }\n this._eventHandlers['canvas:click']?.()\n break\n }\n\n case 'node:click': {\n const node = this._model.getNode(event.nodeId)\n if (!node) break\n\n // Toggle selection internal state for all nodes\n const prev = this._internalStates.get(event.nodeId)\n const isSelected = prev === 'selected'\n if (isSelected) {\n this._internalStates.set(event.nodeId, 'idle')\n } else {\n for (const [id, s] of this._internalStates) {\n if (s === 'selected') this._internalStates.set(id, 'idle')\n }\n this._internalStates.set(event.nodeId, 'selected')\n }\n\n this._eventHandlers['node:click']?.(node)\n break\n }\n }\n })\n )\n }\n\n // ─── Layout ─────────────────────────────────────────────────────────────────\n\n private _runLayout(): void {\n const rect = this._renderer.canvas.getBoundingClientRect()\n\n this._layout.run(this._visibleNodes, this._visibleEdges, {\n width: rect.width || 800,\n height: rect.height || 600,\n onTick: positions => {\n for (const [id, pos] of positions) this._positions.set(id, pos)\n this._interaction.updateNodes(this._visibleNodes, this._positions, 8)\n },\n })\n }\n\n // ─── Render loop ────────────────────────────────────────────────────────────\n\n private _startRenderLoop(): void {\n const loop = () => {\n const zooming = this._interaction.tick()\n if (zooming) {\n const z = this._interaction.state.zoom\n this._lod.setZoom(z)\n this._eventHandlers['zoom:change']?.(z)\n }\n\n if (this._contextFadeAlpha < 1) {\n const elapsed = performance.now() - this._contextFadeStart\n this._contextFadeAlpha = Math.min(1, elapsed / this._contextFadeDuration)\n }\n\n this._checkNavigation()\n this._draw()\n\n this._rafId = requestAnimationFrame(loop)\n }\n this._rafId = requestAnimationFrame(loop)\n }\n\n private _draw(): void {\n const { pan, zoom } = this._interaction.state\n\n this._renderer.render(this._visibleNodes, this._visibleEdges, {\n positions: this._positions,\n internalStates: this._internalStates,\n contextFadeAlpha: this._contextFadeAlpha,\n pan,\n zoom,\n })\n }\n}\n"],"names":["SkillGraphModel","data","Graph","node","edge","id","nodeId","child","depth","n","state","edgeId","evidence","existing","evidenceId","e","result","event","listener","set","payload","listeners","NavigationController","root","frame","popped","l","DEFAULT_THRESHOLDS","LodController","thresholds","zoom","ForceLayout","nodes","edges","options","width","height","chargeStrength","collisionPadding","alphaDecay","layoutNodes","_a","_b","nodeIndex","layoutLinks","source","target","emit","positions","forceSimulation","forceLink","d","s","t","forceManyBody","forceCenter","forceCollide","defaultTheme","mergeTheme","overrides","_c","_d","_e","BUBBLE_WORLD_RADIUS","generateBgStars","count","hashPhase","h","i","CanvasRenderer","canvas","theme","ctx","centerCanvas","color","pan","contextFadeAlpha","internalStates","cssW","cssH","sourcePos","targetPos","parentPos","childPos","bubbles","stars","pos","internal","isBubble","w","star","brightness","alpha","r","style","phase","breathe","isSelected","haloOuter","haloStop0","halo","fill","spinAngle","dotOrbit","dotSize","orbit","angle","twinkle","glowPulse","size","offset","pulse","pulseR","ringAlpha","grad","from","to","dx","dy","particleCount","speed","particleR","progress","x","y","fade","eased","maxR","lineWidth","cx","cy","base","stateOverride","nodeOverride","shape","sides","inner","points","radius","styleOverride","rect","InteractionController","value","anchor","duration","easing","nodeSize","prevZoom","startZoom","startTime","dz","ax","ay","canvasX","canvasY","worldPos","closest","closestDist","hitRadius","dist","canvasPos","pts","scale","midX","midY","hit","wasMultiTouch","dragOrigin","factor","ENTER_ZOOM_THRESHOLD","EXIT_ZOOM_THRESHOLD","NAV_COOLDOWN_MS","SkillTreeEngine","lod","on","initNode","targetLength","lastPopped","center","burstPos","nodePos","unsub","currentId","ids","burstCanvasPos","exited","targetZoom","bubble","worldX","worldY","_f","_h","_g","loop","z","elapsed"],"mappings":";;AAgBO,MAAMA,EAAgB;AAAA,EAO3B,YAAYC,GAAkB;AAF9B,SAAQ,iCAAsE,IAAA,GAG5E,KAAK,MAAMA,EAAK,IAChB,KAAK,SAASA,EAAK,OACnB,KAAK,QAAQA,EAAK,MAElB,KAAK,SAAS,IAAIC,EAAM,EAAE,OAAO,IAAO,gBAAgB,IAAO;AAE/D,eAAWC,KAAQF,EAAK;AACtB,WAAK,OAAO,QAAQE,EAAK,IAAI,EAAE,GAAGA,GAAM;AAG1C,eAAWC,KAAQH,EAAK;AACtB,MAAIG,EAAK,WACP,KAAK,OAAO,gBAAgBA,EAAK,QAAQA,EAAK,QAAQ,EAAE,GAAGA,GAAM,IAEjE,KAAK,OAAO,kBAAkBA,EAAK,QAAQA,EAAK,QAAQ,EAAE,GAAGA,GAAM;AAAA,EAGzE;AAAA;AAAA,EAIA,IAAI,KAAK;AAAE,WAAO,KAAK;AAAA,EAAI;AAAA,EAC3B,IAAI,QAAQ;AAAE,WAAO,KAAK;AAAA,EAAO;AAAA,EACjC,IAAI,OAAO;AAAE,WAAO,KAAK;AAAA,EAAM;AAAA,EAE/B,QAAQC,GAAmC;AACzC,QAAK,KAAK,OAAO,QAAQA,CAAE;AAC3B,aAAO,KAAK,OAAO,kBAAkBA,CAAE;AAAA,EACzC;AAAA,EAEA,QAAQA,GAAmC;AACzC,QAAK,KAAK,OAAO,QAAQA,CAAE;AAC3B,aAAO,KAAK,OAAO,kBAAkBA,CAAE;AAAA,EACzC;AAAA,EAEA,WAAwB;AACtB,WAAO,KAAK,OAAO,MAAA,EAAQ,IAAI,OAAM,KAAK,OAAO,kBAAkBA,CAAE,CAAc;AAAA,EACrF;AAAA,EAEA,WAAwB;AACtB,WAAO,KAAK,OAAO,MAAA,EAAQ,IAAI,OAAM,KAAK,OAAO,kBAAkBA,CAAE,CAAc;AAAA,EACrF;AAAA,EAEA,YAAYC,GAA6B;AACvC,UAAMH,IAAO,KAAK,QAAQG,CAAM;AAChC,WAAKH,KAAA,QAAAA,EAAM,WACJA,EAAK,SAAS,QAAQ,CAAAE,MAAM;AACjC,YAAME,IAAQ,KAAK,QAAQF,CAAE;AAC7B,aAAOE,IAAQ,CAACA,CAAK,IAAI,CAAA;AAAA,IAC3B,CAAC,IAJ2B,CAAA;AAAA,EAK9B;AAAA,EAEA,gBAAgBC,GAA4B;AAC1C,WAAO,KAAK,SAAA,EAAW,OAAO,CAAAC,MAAKA,EAAE,UAAUD,CAAK;AAAA,EACtD;AAAA,EAEA,kBAAkBA,GAA4B;AAC5C,WAAO,KAAK,SAAA,EAAW,OAAO,CAAAC,MAAKA,EAAE,SAASD,CAAK;AAAA,EACrD;AAAA;AAAA,EAIA,aAAaF,GAAgBI,GAAwB;AACnD,IAAK,KAAK,OAAO,QAAQJ,CAAM,MAC/B,KAAK,OAAO,oBAAoBA,GAAQ,EAAE,OAAAI,GAAO,GACjD,KAAK,MAAM,oBAAoB,EAAE,QAAAJ,GAAQ,OAAAI,GAAO,GAChD,KAAK,MAAM,WAAW,MAAS;AAAA,EACjC;AAAA,EAEA,QAAQP,GAAuB;AAC7B,SAAK,OAAO,QAAQA,EAAK,IAAI,EAAE,GAAGA,GAAM,GACxC,KAAK,MAAM,aAAa,EAAE,MAAAA,EAAA,CAAM,GAChC,KAAK,MAAM,WAAW,MAAS;AAAA,EACjC;AAAA,EAEA,WAAWG,GAAsB;AAC/B,IAAK,KAAK,OAAO,QAAQA,CAAM,MAC/B,KAAK,OAAO,SAASA,CAAM,GAC3B,KAAK,MAAM,eAAe,EAAE,QAAAA,EAAA,CAAQ,GACpC,KAAK,MAAM,WAAW,MAAS;AAAA,EACjC;AAAA,EAEA,QAAQF,GAAuB;AAC7B,IAAIA,EAAK,WACP,KAAK,OAAO,gBAAgBA,EAAK,QAAQA,EAAK,QAAQ,EAAE,GAAGA,GAAM,IAEjE,KAAK,OAAO,kBAAkBA,EAAK,QAAQA,EAAK,QAAQ,EAAE,GAAGA,GAAM,GAErE,KAAK,MAAM,aAAa,EAAE,MAAAA,EAAA,CAAM,GAChC,KAAK,MAAM,WAAW,MAAS;AAAA,EACjC;AAAA,EAEA,WAAWO,GAAsB;AAC/B,IAAK,KAAK,OAAO,QAAQA,CAAM,MAC/B,KAAK,OAAO,SAASA,CAAM,GAC3B,KAAK,MAAM,eAAe,EAAE,QAAAA,EAAA,CAAQ,GACpC,KAAK,MAAM,WAAW,MAAS;AAAA,EACjC;AAAA,EAEA,YAAYL,GAAgBM,GAA0B;AACpD,QAAI,CAAC,KAAK,OAAO,QAAQN,CAAM,EAAG;AAElC,UAAMO,IADO,KAAK,QAAQP,CAAM,EACV,YAAY,CAAA;AAClC,SAAK,OAAO,oBAAoBA,GAAQ,EAAE,UAAU,CAAC,GAAGO,GAAUD,CAAQ,GAAG,GAC7E,KAAK,MAAM,iBAAiB,EAAE,QAAAN,GAAQ,UAAAM,GAAU,GAChD,KAAK,MAAM,WAAW,MAAS;AAAA,EACjC;AAAA,EAEA,eAAeN,GAAgBQ,GAA0B;AACvD,QAAI,CAAC,KAAK,OAAO,QAAQR,CAAM,EAAG;AAElC,UAAMM,KADO,KAAK,QAAQN,CAAM,EACT,YAAY,CAAA,GAAI,OAAO,CAAAS,MAAKA,EAAE,OAAOD,CAAU;AACtE,SAAK,OAAO,oBAAoBR,GAAQ,EAAE,UAAAM,GAAU,GACpD,KAAK,MAAM,mBAAmB,EAAE,QAAAN,GAAQ,YAAAQ,GAAY,GACpD,KAAK,MAAM,WAAW,MAAS;AAAA,EACjC;AAAA;AAAA,EAIA,SAAqB;AACnB,UAAME,IAAqB;AAAA,MACzB,IAAI,KAAK;AAAA,MACT,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK,SAAA;AAAA,MACZ,OAAO,KAAK,SAAA;AAAA,IAAS;AAEvB,WAAI,KAAK,UAAU,WAAWA,EAAO,OAAO,KAAK,QAC1CA;AAAA,EACT;AAAA,EAEA,OAAO,SAASf,GAAmC;AACjD,WAAO,IAAID,EAAgBC,CAAI;AAAA,EACjC;AAAA;AAAA,EAIA,GAAgCgB,GAAUC,GAAqD;AAC7F,IAAK,KAAK,WAAW,IAAID,CAAK,KAC5B,KAAK,WAAW,IAAIA,GAAO,oBAAI,KAAK;AAEtC,UAAME,IAAM,KAAK,WAAW,IAAIF,CAAK;AACrC,WAAAE,EAAI,IAAID,CAAkC,GACnC,MAAMC,EAAI,OAAOD,CAAkC;AAAA,EAC5D;AAAA,EAEQ,MAAmCD,GAAUG,GAA+B;AAClF,UAAMC,IAAY,KAAK,WAAW,IAAIJ,CAAK;AAC3C,QAAKI;AACL,iBAAWH,KAAYG;AACrB,QAAID,MAAY,SACbF,EAAA,IAEAA,EAAkCE,CAAO;AAAA,EAGhD;AACF;AClLO,MAAME,EAAqB;AAAA,EAIhC,YAAYC,IAAwB,EAAE,QAAQ,MAAM,OAAO,UAAU;AAFrE,SAAQ,iCAAmE,IAAA,GAGzE,KAAK,SAAS,CAACA,CAAI;AAAA,EACrB;AAAA,EAEA,IAAI,UAA2B;AAC7B,WAAO,KAAK,OAAO,KAAK,OAAO,SAAS,CAAC;AAAA,EAC3C;AAAA,EAEA,IAAI,QAAoC;AACtC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK,OAAO,SAAS;AAAA,EAC9B;AAAA,EAEA,KAAKC,GAA8B;AACjC,SAAK,OAAO,KAAKA,CAAK,GACtB,KAAK,QAAA;AAAA,EACP;AAAA,EAEA,MAAmC;AACjC,QAAI,CAAC,KAAK,UAAW;AACrB,UAAMC,IAAS,KAAK,OAAO,IAAA;AAC3B,gBAAK,QAAA,GACEA;AAAA,EACT;AAAA,EAEA,QAAc;AACZ,SAAK,SAAS,CAAC,KAAK,OAAO,CAAC,CAAE,GAC9B,KAAK,QAAA;AAAA,EACP;AAAA,EAEA,SAASP,GAAmE;AAC1E,gBAAK,WAAW,IAAIA,CAAQ,GACrB,MAAM,KAAK,WAAW,OAAOA,CAAQ;AAAA,EAC9C;AAAA,EAEQ,UAAgB;AACtB,eAAWQ,KAAK,KAAK,WAAY,CAAAA,EAAE,KAAK,MAAM;AAAA,EAChD;AACF;AC7CA,MAAMC,IAAqC;AAAA,EACzC,EAAE,OAAO,GAAG,SAAS,GAAM,SAAS,IAAA;AAAA,EACpC,EAAE,OAAO,GAAG,SAAS,KAAM,SAAS,IAAA;AAAA,EACpC,EAAE,OAAO,GAAG,SAAS,KAAM,SAAS,IAAA;AAAA,EACpC,EAAE,OAAO,GAAG,SAAS,KAAM,SAAS,IAAA;AAAA,EACpC,EAAE,OAAO,GAAG,SAAS,KAAM,SAAS,MAAA;AACtC;AAEO,MAAMC,EAAc;AAAA,EAKzB,YAAYC,GAA6B;AAHzC,SAAQ,QAAgB,GACxB,KAAQ,iCAA8C,IAAA,GAGpD,KAAK,cAAcA,KAAcF;AAAA,EACnC;AAAA,EAEA,IAAI,OAAO;AAAE,WAAO,KAAK;AAAA,EAAM;AAAA,EAE/B,IAAI,aAAsC;AAAE,WAAO,KAAK;AAAA,EAAY;AAAA,EAEpE,QAAQG,GAAoB;AAC1B,SAAK,QAAQ,KAAK,IAAI,MAAMA,CAAI,GAChC,KAAK,QAAA;AAAA,EACP;AAAA,EAEA,SAASZ,GAA8C;AACrD,gBAAK,WAAW,IAAIA,CAAQ,GACrB,MAAM,KAAK,WAAW,OAAOA,CAAQ;AAAA,EAC9C;AAAA,EAEQ,UAAgB;AACtB,eAAWA,KAAY,KAAK,WAAY,CAAAA,EAAS,KAAK,KAAK;AAAA,EAC7D;AACF;ACDO,MAAMa,EAAY;AAAA,EAAlB,cAAA;AACL,SAAQ,cAAyD;AAAA,EAAA;AAAA,EAEjE,IAAIC,GAAoBC,GAAoBC,GAAmC;AAC7E,SAAK,KAAA;AAEL,UAAM,EAAE,OAAAC,GAAO,QAAAC,GAAQ,gBAAAC,IAAiB,MAAM,kBAAAC,IAAmB,IAAI,YAAAC,IAAa,KAAA,IAASL,GAErFM,IAA4BR,EAAM,IAAI,CAAAvB,MAAA;;AAAM;AAAA,QAChD,IAAIA,EAAE;AAAA,QACN,OAAOA,EAAE;AAAA;AAAA;AAAA,QAGT,KAAGgC,IAAAhC,EAAE,aAAF,gBAAAgC,EAAY,OAAM,KAAK,OAAA,IAAW,OAAO;AAAA,QAC5C,KAAGC,IAAAjC,EAAE,aAAF,gBAAAiC,EAAY,OAAM,KAAK,OAAA,IAAW,OAAO;AAAA,MAAA;AAAA,KAC5C,GAEIC,IAAY,IAAI,IAAIH,EAAY,IAAI,CAAA/B,MAAK,CAACA,EAAE,IAAIA,CAAC,CAAC,CAAC,GAEnDmC,IAA4B,CAAA;AAGlC,eAAWzC,KAAQ6B;AACjB,UAAI7B,EAAK,UAAU;AACjB,cAAM0C,IAASF,EAAU,IAAIxC,EAAK,QAAQ,GACpC2C,IAASH,EAAU,IAAIxC,EAAK,EAAE;AACpC,QAAI0C,KAAUC,KACZF,EAAY,KAAK,EAAE,IAAI,GAAGzC,EAAK,QAAQ,KAAKA,EAAK,EAAE,IAAI,QAAA0C,GAAQ,QAAAC,EAAA,CAAQ;AAAA,MAE3E;AAIF,eAAW1C,KAAQ6B,GAAO;AACxB,YAAMY,IAASF,EAAU,IAAIvC,EAAK,MAAM,GAClC0C,IAASH,EAAU,IAAIvC,EAAK,MAAM;AACxC,MAAIyC,KAAUC,KACZF,EAAY,KAAK,EAAE,IAAIxC,EAAK,IAAI,QAAAyC,GAAQ,QAAAC,GAAQ;AAAA,IAEpD;AAEA,UAAMC,IAAO,CAACC,MAAqC;;AACjD,OAAAP,IAAAP,EAAQ,WAAR,QAAAO,EAAA,KAAAP,GAAiBc;AAAA,IACnB;AAEA,SAAK,cAAcC,EAAwCT,CAAW,EACnE,WAAWD,CAAU,EACrB;AAAA,MAAM;AAAA,MAAQW,EAAkCN,CAAW,EACzD,GAAG,OAAKO,EAAE,EAAE,EACZ,SAAS,CAAAA,MAAK;AACb,cAAMC,IAAID,EAAE,QACNE,IAAIF,EAAE;AAEZ,eAAO,KAAM,KAAK,IAAIC,EAAE,QAAQC,EAAE,KAAK,IAAI;AAAA,MAC7C,CAAC,EACA,SAAS,GAAG;AAAA,IAAA,EAEd,MAAM,UAAUC,IAAgB,SAASjB,CAAc,CAAC,EACxD,MAAM,UAAUkB,EAAY,GAAG,CAAC,CAAC,EACjC,MAAM,WAAWC,EAAA,EAA2B,OAAOlB,CAAgB,CAAC,EACpE,GAAG,QAAQ,MAAM;AAChB,YAAMU,IAAY,KAAK,kBAAkBR,CAAW;AACpD,MAAAO,EAAKC,CAAS;AAAA,IAChB,CAAC,EACA,GAAG,OAAO,MAAM;;AACf,YAAMA,IAAY,KAAK,kBAAkBR,CAAW;AACpD,OAAAC,IAAAP,EAAQ,UAAR,QAAAO,EAAA,KAAAP,GAAgBc;AAAA,IAClB,CAAC;AAAA,EACL;AAAA,EAEA,OAAa;;AACX,KAAAP,IAAA,KAAK,gBAAL,QAAAA,EAAkB,QAClB,KAAK,cAAc;AAAA,EACrB;AAAA,EAEA,SAAe;;AACb,KAAAA,IAAA,KAAK,gBAAL,QAAAA,EAAkB,MAAM,KAAK;AAAA,EAC/B;AAAA,EAEQ,kBAAkBT,GAA4C;AACpE,UAAMgB,wBAAgB,IAAA;AACtB,eAAWvC,KAAKuB;AACd,MAAAgB,EAAU,IAAIvC,EAAE,IAAI,EAAE,GAAGA,EAAE,GAAG,GAAGA,EAAE,EAAA,CAAG;AAExC,WAAOuC;AAAA,EACT;AACF;ACvHO,MAAMS,IAAsB;AAAA,EACjC,YAAY;AAAA,EACZ,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,EAAA;AAAA,EAEb,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,SAAS;AAAA,IACT,UAAU;AAAA,EAAA;AAAA,EAEZ,QAAQ;AAAA,IACN,SAAS,CAAA;AAAA,IACT,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,WAAW;AAAA,MACX,YAAY;AAAA,IAAA;AAAA,IAEd,QAAQ;AAAA,MACN,OAAO;AAAA,MACP,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,IAAA;AAAA,IAEd,UAAU;AAAA,MACR,OAAO;AAAA,MACP,WAAW;AAAA,MACX,YAAY;AAAA,IAAA;AAAA,IAEd,aAAa;AAAA,MACX,OAAO;AAAA,MACP,WAAW;AAAA,MACX,YAAY;AAAA,IAAA;AAAA,EACd;AAEJ;AC3CO,SAASC,EAAWC,GAA+B;;AACxD,SAAKA,IAEE;AAAA,IACL,YAAYA,EAAU,cAAcF,EAAa;AAAA,IACjD,MAAM,EAAE,GAAGA,EAAa,MAAM,GAAGE,EAAU,KAAA;AAAA,IAC3C,MAAM,EAAE,GAAGF,EAAa,MAAM,GAAGE,EAAU,KAAA;AAAA,IAC3C,QAAQ;AAAA,MACN,SAAS,EAAE,GAAGF,EAAa,OAAO,SAAS,IAAGhB,IAAAkB,EAAU,WAAV,gBAAAlB,EAAmB,QAAS;AAAA,MAC1E,QAAQ,EAAE,GAAGgB,EAAa,OAAO,QAAQ,IAAGf,IAAAiB,EAAU,WAAV,gBAAAjB,EAAkB,OAAA;AAAA,MAC9D,QAAQ,EAAE,GAAGe,EAAa,OAAO,QAAQ,IAAGG,IAAAD,EAAU,WAAV,gBAAAC,EAAkB,OAAA;AAAA,MAC9D,UAAU,EAAE,GAAGH,EAAa,OAAO,UAAU,IAAGI,IAAAF,EAAU,WAAV,gBAAAE,EAAkB,SAAA;AAAA,MAClE,aAAa,EAAE,GAAGJ,EAAa,OAAO,aAAa,IAAGK,IAAAH,EAAU,WAAV,gBAAAG,EAAkB,YAAA;AAAA,IAAY;AAAA,EACtF,IAZqBL;AAczB;ACEO,MAAMM,IAAsB;AAYnC,SAASC,EAAgBC,GAAyB;AAChD,SAAO,MAAM,KAAK,EAAE,QAAQA,EAAA,GAAS,OAAO;AAAA,IAC1C,GAAO,KAAK,OAAA;AAAA,IACZ,GAAO,KAAK,OAAA;AAAA,IACZ,GAAO,MAAM,KAAK,OAAA,IAAW;AAAA,IAC7B,OAAO,KAAK,OAAA,IAAW,KAAK,KAAK;AAAA,IACjC,OAAO,MAAM,KAAK,WAAW;AAAA,EAAA,EAC7B;AACJ;AAKA,SAASC,EAAU7D,GAAoB;AACrC,MAAI8D,IAAI;AACR,WAASC,IAAI,GAAGA,IAAI/D,EAAG,QAAQ+D,IAAK,CAAAD,IAAKA,IAAI,KAAK9D,EAAG,WAAW+D,CAAC,MAAO;AACxE,SAASD,IAAI,MAAQ,MAAQ,KAAK,KAAK;AACzC;AAEO,MAAME,EAAe;AAAA,EAe1B,YAAYC,GAA2BC,GAAoB;AAP3D,SAAQ,SAAwE,MAChF,KAAiB,iBAAiB,KAGlC,KAAQ,WAA2D,MACnE,KAAiB,mBAAmB,KAGlC,KAAK,UAAUD;AACf,UAAME,IAAMF,EAAO,WAAW,IAAI;AAClC,QAAI,CAACE,EAAK,OAAM,IAAI,MAAM,sCAAsC;AAChE,SAAK,OAAOA,GACZ,KAAK,SAASd,EAAWa,CAAK,GAC9B,KAAK,OAAO,OAAO,oBAAoB,GACvC,KAAK,WAAWP,EAAgB,GAAG,GACnC,KAAK,QAAA;AAAA,EACP;AAAA,EAEA,IAAI,SAA4B;AAAE,WAAO,KAAK;AAAA,EAAQ;AAAA,EAEtD,IAAI,gBAAyB;AAAE,WAAO,KAAK,WAAW;AAAA,EAAK;AAAA;AAAA,EAG3D,SAAe;AAAE,SAAK,QAAA;AAAA,EAAU;AAAA;AAAA,EAGhC,iBAAiB7D,GAAyB;AACxC,WAAO,KAAK,cAAcA,CAAI,EAAE;AAAA,EAClC;AAAA,EAEA,YAAYoE,GAAyB;AACnC,SAAK,SAASb,EAAWa,CAAK;AAAA,EAChC;AAAA,EAEA,aAAaE,GAAwBC,GAAqB;AACxD,SAAK,SAAS,EAAE,WAAW,YAAY,OAAO,QAAQD,GAAc,OAAAC,EAAA;AAAA,EACtE;AAAA,EAEA,eAAeD,GAA8B;AAC3C,SAAK,WAAW,EAAE,WAAW,YAAY,IAAA,GAAO,QAAQA,EAAA;AAAA,EAC1D;AAAA,EAEA,OAAOzC,GAAoBC,GAAoBvB,GAA0B;;AACvE,UAAM8D,IAAM,KAAK,MACXnB,IAAI,YAAY,IAAA,IAAQ,KACxB,EAAE,KAAAsB,GAAK,MAAA7C,GAAM,kBAAA8C,GAAkB,WAAA5B,GAAW,gBAAA6B,MAAmBnE,GAE7DoE,IAAO,KAAK,QAAQ,QAAS,KAAK,MAClCC,IAAO,KAAK,QAAQ,SAAS,KAAK;AAGxC,IAAAP,EAAI,UAAU,GAAG,GAAG,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM,GAC3DA,EAAI,YAAY,KAAK,OAAO,YAC5BA,EAAI,SAAS,GAAG,GAAG,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM,GAG1DA,EAAI,KAAA,GACJA,EAAI,MAAM,KAAK,MAAM,KAAK,IAAI,GAG9B,KAAK,eAAeA,GAAKM,GAAMC,GAAM1B,CAAC,GAGtCmB,EAAI,KAAA,GACJA,EAAI,UAAUG,EAAI,GAAGA,EAAI,CAAC,GAC1BH,EAAI,MAAM1C,GAAMA,CAAI;AAGpB,eAAW1B,KAAQ6B,GAAO;AACxB,YAAM+C,IAAYhC,EAAU,IAAI5C,EAAK,MAAM,GACrC6E,IAAYjC,EAAU,IAAI5C,EAAK,MAAM;AAC3C,MAAI,CAAC4E,KAAa,CAACC,MACnB,KAAK,UAAUT,GAAKQ,GAAWC,GAAW7E,EAAK,KAAK,MAChDqC,IAAArC,EAAK,UAAL,gBAAAqC,EAAY,aAAY,KAAK,OAAO,KAAK,aAC3C,KAAK,qBAAqB+B,GAAKQ,GAAWC,GAAW7E,GAAMiD,GAAGvB,CAAI;AAAA,IAEtE;AAGA,eAAW3B,KAAQ6B,GAAO;AACxB,UAAI,CAAC7B,EAAK,SAAU;AACpB,YAAM+E,IAAYlC,EAAU,IAAI7C,EAAK,QAAQ,GACvCgF,IAAYnC,EAAU,IAAI7C,EAAK,EAAE;AACvC,MAAI,CAAC+E,KAAa,CAACC,MACnBX,EAAI,KAAA,GACJA,EAAI,cAAcI,IAAmB,MACrCJ,EAAI,cAAc,KAAK,OAAO,KAAK,OACnCA,EAAI,YAAc,KAAK,OAAO,KAAK,QAAQ1C,GAC3C0C,EAAI,YAAY,CAAC,GAAG,CAAC,CAAC,GACtBA,EAAI,UAAA,GACJA,EAAI,OAAOU,EAAU,GAAGA,EAAU,CAAC,GACnCV,EAAI,OAAOW,EAAS,GAAIA,EAAS,CAAC,GAClCX,EAAI,OAAA,GACJA,EAAI,QAAA;AAAA,IACN;AAGA,UAAMY,IAAUpD,EAAM,OAAO,CAAAvB,MAAMA,EAAE,YAAYA,EAAE,SAAS,SAAS,CAAC,GAChE4E,IAAUrD,EAAM,OAAO,CAAAvB,MAAK,CAACA,EAAE,YAAYA,EAAE,SAAS,WAAW,CAAC;AAExE,eAAWN,KAAQ,CAAC,GAAGiF,GAAS,GAAGC,CAAK,GAAG;AACzC,YAAMC,IAAMtC,EAAU,IAAI7C,EAAK,EAAE;AACjC,UAAI,CAACmF,EAAK;AACV,YAAMC,IAAWV,EAAe,IAAI1E,EAAK,EAAE,KAAK,QAC1CqF,IAAW,CAAC,EAAErF,EAAK,YAAYA,EAAK,SAAS,SAAS;AAC5D,WAAK,UAAUqE,GAAKrE,GAAMmF,GAAKC,GAAUX,GAAkB9C,GAAM0D,GAAUnC,CAAC;AAAA,IAC9E;AAEA,IAAAmB,EAAI,QAAA,GACJA,EAAI,QAAA,GAGJ,KAAK,aAAA,GACL,KAAK,eAAA;AAAA,EACP;AAAA;AAAA,EAIQ,eAAeA,GAA+BiB,GAAWtB,GAAWd,GAAiB;AAC3F,eAAWqC,KAAQ,KAAK,UAAU;AAChC,YAAMC,IAAa,MAAM,MAAM,KAAK,IAAItC,IAAIqC,EAAK,QAAQA,EAAK,KAAK,GAC7DE,IAAQ,OAAO,OAAOD,GACtBE,IAAIH,EAAK,KAAK,MAAM,MAAMC;AAChC,MAAAnB,EAAI,UAAA,GACJA,EAAI,IAAIkB,EAAK,IAAID,GAAGC,EAAK,IAAIvB,GAAG0B,GAAG,GAAG,KAAK,KAAK,CAAC,GACjDrB,EAAI,YAAY,oBAAoBoB,EAAM,QAAQ,CAAC,CAAC,KACpDpB,EAAI,KAAA;AAAA,IACN;AAAA,EACF;AAAA;AAAA,EAIQ,UACNA,GACArE,GACAmF,GACAC,GACAK,GACA9D,GACA0D,GACAnC,GACM;AACN,IAAImC,IACF,KAAK,YAAYhB,GAAKrE,GAAMmF,GAAKC,GAAUK,GAAO9D,GAAMuB,CAAC,IAEzD,KAAK,UAAUmB,GAAKrE,GAAMmF,GAAKC,GAAUK,GAAO9D,GAAMuB,CAAC;AAAA,EAE3D;AAAA,EAEQ,YACNmB,GACArE,GACAmF,GACAC,GACAK,GACA9D,GACAuB,GACM;AACN,UAAMyC,IAAQ,KAAK,cAAc3F,CAAI,GAC/B4F,IAAQ7B,EAAU/D,EAAK,EAAE,GAGzB6F,IAAU,KADGT,MAAa,aAAa,OAAO,QACnB,KAAK,IAAIlC,IAAI,MAAM0C,CAAK,GACnDF,IAAI9B,IAAsBiC,KAAWT,MAAa,YAAY,MAAM,IACpEU,IAAaV,MAAa;AAEhC,IAAAf,EAAI,KAAA,GACJA,EAAI,cAAcsB,EAAM,UAAUF;AAGlC,UAAMM,IAAYD,IAAaJ,IAAI,MAAMA,IAAI,KACvCM,IAAYF,IAAaH,EAAM,YAAY,OAAOA,EAAM,YAAY,MACpEM,IAAO5B,EAAI,qBAAqBc,EAAI,GAAGA,EAAI,GAAGO,IAAI,KAAKP,EAAI,GAAGA,EAAI,GAAGY,CAAS;AACpF,IAAAE,EAAK,aAAa,GAAGD,CAAS,GAC9BC,EAAK,aAAa,GAAGN,EAAM,YAAY,IAAI,GAC3CtB,EAAI,YAAY4B,GAChB5B,EAAI,UAAA,GACJA,EAAI,IAAIc,EAAI,GAAGA,EAAI,GAAGY,GAAW,GAAG,KAAK,KAAK,CAAC,GAC/C1B,EAAI,KAAA;AAGJ,UAAM6B,IAAO7B,EAAI,qBAAqBc,EAAI,GAAGA,EAAI,IAAIO,IAAI,KAAKA,IAAI,KAAKP,EAAI,GAAGA,EAAI,GAAGO,CAAC;AAiBtF,QAhBAQ,EAAK,aAAa,GAAGP,EAAM,SAASG,IAAa,OAAO,KAAK,GAC7DI,EAAK,aAAa,GAAGP,EAAM,SAASG,IAAa,OAAO,KAAK,GAC7DzB,EAAI,YAAY6B,GAChB7B,EAAI,UAAA,GACJA,EAAI,IAAIc,EAAI,GAAGA,EAAI,GAAGO,GAAG,GAAG,KAAK,KAAK,CAAC,GACvCrB,EAAI,KAAA,GAGJA,EAAI,cAAeyB,IAAaH,EAAM,YAAYA,EAAM,OACxDtB,EAAI,aAAgByB,IAAa,MAAM,OAAOnE,GAC9C0C,EAAI,cAAesB,EAAM,UAAUF,KAASK,IAAa,IAAI,MAC7DzB,EAAI,UAAA,GACJA,EAAI,IAAIc,EAAI,GAAGA,EAAI,GAAGO,GAAG,GAAG,KAAK,KAAK,CAAC,GACvCrB,EAAI,OAAA,GAGAyB,GAAY;AACd,YAAMK,IAAYjD,IAAI,MAAM0C;AAC5B,MAAAvB,EAAI,cAAesB,EAAM,WACzBtB,EAAI,YAAe,MAAM1C,GACzB0C,EAAI,cAAesB,EAAM,UAAUF,IAAQ,MAC3CpB,EAAI,YAAY,CAAC,KAAK1C,GAAM,IAAIA,CAAI,CAAC,GACrC0C,EAAI,iBAAiB,CAAC8B,IAAY,IAClC9B,EAAI,UAAA,GACJA,EAAI,IAAIc,EAAI,GAAGA,EAAI,GAAGO,IAAI,KAAK,GAAG,KAAK,KAAK,CAAC,GAC7CrB,EAAI,OAAA,GACJA,EAAI,YAAY,EAAE;AAAA,IACpB;AAGA,QAAIrE,EAAK,YAAYA,EAAK,SAAS,SAAS,GAAG;AAC7C,YAAM8D,IAAW,KAAK,IAAI9D,EAAK,SAAS,QAAQ,CAAC,GAC3CoG,IAAWV,IAAI,MACfW,IAAW,KAAK,IAAI,KAAKX,IAAI,IAAI,GACjCY,IAAWpD,IAAI,OAAO0C;AAC5B,MAAAvB,EAAI,cAAcsB,EAAM,UAAUF,IAAQ,KAC1CpB,EAAI,YAAcsB,EAAM,QAAQ;AAChC,eAAS1B,IAAI,GAAGA,IAAIH,GAAOG,KAAK;AAC9B,cAAMsC,IAAQD,IAASrC,IAAIH,IAAS,KAAK,KAAK;AAC9C,QAAAO,EAAI,UAAA,GACJA,EAAI;AAAA,UACFc,EAAI,IAAIiB,IAAW,KAAK,IAAIG,CAAK;AAAA,UACjCpB,EAAI,IAAIiB,IAAW,KAAK,IAAIG,CAAK;AAAA,UACjCF;AAAA,UAAS;AAAA,UAAG,KAAK,KAAK;AAAA,QAAA,GAExBhC,EAAI,KAAA;AAAA,MACN;AAAA,IACF;AAGA,IAAAA,EAAI,cAAiBsB,EAAM,UAAUF,GACrCpB,EAAI,YAAiBsB,EAAM,YAC3BtB,EAAI,OAAiB,QAASsB,EAAM,YAAY,MAAOhE,CAAI,MAAMgE,EAAM,SAAS,IAChFtB,EAAI,YAAiB,UACrBA,EAAI,eAAiB,UACrBA,EAAI,SAASrE,EAAK,OAAOmF,EAAI,GAAGA,EAAI,CAAC,GAErCd,EAAI,QAAA;AAAA,EACN;AAAA,EAEQ,UACNA,GACArE,GACAmF,GACAC,GACAK,GACA9D,GACAuB,GACM;AACN,UAAMyC,IAAQ,KAAK,cAAc3F,CAAI,GAC/B4F,IAAU7B,EAAU/D,EAAK,EAAE,GAE3B8F,IAAaV,MAAa,YAG1BoB,IAAU,KADGV,IAAa,MAAM,QACL,KAAK,IAAI5C,IAAI,MAAM0C,CAAK,IACrC,OAAO,KAAK,IAAI1C,IAAI,MAAM0C,IAAQ,GAAG,GACnDa,IAAYd,EAAM,aAAaa,GAC/BE,IAAOf,EAAM,QAAQP,MAAa,YAAY,MAAM;AAM1D,QAJAf,EAAI,KAAA,GACJA,EAAI,cAAcsB,EAAM,UAAUF,GAG9BK,GAAY;AAEd,eAAS7B,IAAI,GAAGA,IAAI,GAAGA,KAAK;AAC1B,cAAM0C,IAAU1C,IAAK,KACf2C,KAAY1D,IAAIyD,KAAU,MAAc,KACxCE,KAAWH,IAAOD,IAAY,QAAQ,IAAIG,IAAQ,MAClDE,KAAa,IAAIF,KAAS;AAChC,QAAAvC,EAAI,cAAesB,EAAM,WACzBtB,EAAI,YAAgB,MAAM1C,KAAS,IAAIiF,IAAQ,MAC/CvC,EAAI,cAAeyC,IAAYnB,EAAM,UAAUF,GAC/CpB,EAAI,UAAA,GACJA,EAAI,IAAIc,EAAI,GAAGA,EAAI,GAAG0B,GAAQ,GAAG,KAAK,KAAK,CAAC,GAC5CxC,EAAI,OAAA;AAAA,MACN;AACA,MAAAA,EAAI,cAAcsB,EAAM,UAAUF;AAAA,IACpC;AAGA,QAAIgB,IAAY,GAAG;AACjB,YAAMM,IAAO1C,EAAI,qBAAqBc,EAAI,GAAGA,EAAI,GAAG,GAAGA,EAAI,GAAGA,EAAI,GAAGsB,IAAYC,CAAI;AACrF,MAAAK,EAAK,aAAa,GAAGpB,EAAM,aAAaG,IAAa,OAAO,KAAK,GACjEiB,EAAK,aAAa,KAAKpB,EAAM,aAAaG,IAAa,OAAO,KAAK,GACnEiB,EAAK,aAAa,GAAKpB,EAAM,YAAY,IAAI,GAC7CtB,EAAI,YAAY0C,GAChB1C,EAAI,UAAA,GACJA,EAAI,IAAIc,EAAI,GAAGA,EAAI,GAAGsB,IAAYC,GAAM,GAAG,KAAK,KAAK,CAAC,GACtDrC,EAAI,KAAA;AAAA,IACN;AAGA,IAAAA,EAAI,YAAYyB,IAAaH,EAAM,YAAYA,EAAM,OACrDtB,EAAI,UAAA,GACJ,KAAK,WAAWA,GAAKc,GAAKuB,GAAMf,EAAM,KAAK,GAC3CtB,EAAI,KAAA,GAGAqC,IAAO/E,IAAO,MAChB0C,EAAI,YAAiBsB,EAAM,YAC3BtB,EAAI,OAAiB,GAAGsB,EAAM,YAAYhE,CAAI,MAAMgE,EAAM,SAAS,IACnEtB,EAAI,YAAiB,UACrBA,EAAI,eAAiB,OACrBA,EAAI,SAASrE,EAAK,OAAOmF,EAAI,GAAGA,EAAI,IAAIuB,IAAO,IAAI/E,CAAI,IAGzD0C,EAAI,QAAA;AAAA,EACN;AAAA;AAAA,EAIQ,qBACNA,GACA2C,GACAC,GACAhH,GACAiD,GACAvB,GACM;;AACN,UAAMuF,IAAMD,EAAG,IAAID,EAAK,GAClBG,IAAMF,EAAG,IAAID,EAAK;AAExB,QADY,KAAK,KAAKE,IAAKA,IAAKC,IAAKA,CAAE,IAC7B,EAAG;AAEb,UAAMC,IAAgB,GAChBC,IAAgB,KAChBC,IAAgB,MAAM3F,GACtB4C,MAAgBjC,IAAArC,EAAK,UAAL,gBAAAqC,EAAY,UAAS,KAAK,OAAO,KAAK;AAE5D,aAAS2B,IAAI,GAAGA,IAAImD,GAAenD,KAAK;AACtC,YAAMsD,KAAarE,IAAImE,IAAQpD,IAAImD,KAAiB,GAC9CI,IAAIR,EAAK,IAAIE,IAAKK,GAClBE,IAAIT,EAAK,IAAIG,IAAKI,GAClBG,IAAO,KAAK,IAAIH,IAAW,KAAK,EAAE;AAExC,MAAAlD,EAAI,KAAA,GACJA,EAAI,cAAcqD,IAAO;AAEzB,YAAMX,IAAO1C,EAAI,qBAAqBmD,GAAGC,GAAG,GAAGD,GAAGC,GAAGH,IAAY,GAAG;AACpE,MAAAP,EAAK,aAAa,GAAGxC,IAAQ,IAAI,GACjCwC,EAAK,aAAa,KAAKxC,IAAQ,IAAI,GACnCwC,EAAK,aAAa,GAAKxC,IAAQ,IAAI,GACnCF,EAAI,YAAY0C,GAChB1C,EAAI,UAAA,GACJA,EAAI,IAAImD,GAAGC,GAAGH,IAAY,KAAK,GAAG,KAAK,KAAK,CAAC,GAC7CjD,EAAI,KAAA,GAEJA,EAAI,QAAA;AAAA,IACN;AAAA,EACF;AAAA;AAAA,EAIQ,eAAqB;AAC3B,QAAI,CAAC,KAAK,OAAQ;AAClB,UAAMA,IAAM,KAAK,MAEXnB,KADU,YAAY,IAAA,IAAQ,KAAK,OAAO,aAC5B,KAAK;AACzB,QAAIA,KAAK,GAAG;AAAE,WAAK,SAAS;AAAM;AAAA,IAAO;AAEzC,UAAMyE,IAAQ,IAAI,KAAK,IAAI,IAAIzE,GAAG,CAAC,GAC7B0E,IAAS,KAAK,MAAM,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM,GAC3DlC,IAASiC,IAAQC,GACjBnC,KAAU,IAAIkC,KAAS;AAE7B,IAAAtD,EAAI,KAAA,GACJA,EAAI,cAAcoB,GAClBpB,EAAI,YAAc,KAAK,OAAO,OAC9BA,EAAI,UAAA,GACJA,EAAI;AAAA,MACF,KAAK,OAAO,OAAO,IAAI,KAAK;AAAA,MAC5B,KAAK,OAAO,OAAO,IAAI,KAAK;AAAA,MAC5BqB;AAAA,MAAG;AAAA,MAAG,KAAK,KAAK;AAAA,IAAA,GAElBrB,EAAI,KAAA,GACJA,EAAI,QAAA;AAAA,EACN;AAAA;AAAA,EAIQ,iBAAuB;AAC7B,QAAI,CAAC,KAAK,SAAU;AACpB,UAAMA,IAAM,KAAK,MAEXnB,KADU,YAAY,IAAA,IAAQ,KAAK,SAAS,aAC9B,KAAK;AACzB,QAAIA,KAAK,GAAG;AAAE,WAAK,WAAW;AAAM;AAAA,IAAO;AAI3C,UAAMyE,IAAYzE,IAAIA,IAAIA,GACpB0E,IAAY,KAAK,MAAM,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM,GAC9DlC,KAAa,IAAIiC,KAASC,GAC1BnC,KAAa,IAAIvC,KAAK,MACtB2E,KAAa,IAAIF,KAAS,KAAK,KAAK,MAEpCG,IAAK,KAAK,SAAS,OAAO,IAAI,KAAK,MACnCC,IAAK,KAAK,SAAS,OAAO,IAAI,KAAK;AAEzC,IAAA1D,EAAI,KAAA,GACJA,EAAI,cAAeoB,GACnBpB,EAAI,cAAe,WACnBA,EAAI,YAAewD,GACnBxD,EAAI,cAAe,WACnBA,EAAI,aAAe,KAAK,KAAK,MAC7BA,EAAI,UAAA,GACJA,EAAI,IAAIyD,GAAIC,GAAI,KAAK,IAAI,GAAGrC,CAAC,GAAG,GAAG,KAAK,KAAK,CAAC,GAC9CrB,EAAI,OAAA,GACJA,EAAI,QAAA;AAAA,EACN;AAAA;AAAA,EAIQ,cAAcrE,GAA4B;AAChD,UAAMgI,IAAgB,KAAK,OAAO,MAC5BC,IAAgBjI,EAAK,QAAQ,KAAK,OAAO,OAAOA,EAAK,KAAK,IAAI,CAAA,GAC9DkI,IAAgBlI,EAAK,SAAS,CAAA;AACpC,WAAO,EAAE,GAAGgI,GAAM,GAAGC,GAAe,GAAGC,EAAA;AAAA,EACzC;AAAA,EAEQ,WACN7D,GACAc,GACAuB,GACAyB,GACM;AACN,YAAQA,GAAA;AAAA,MACN,KAAK;AACH,QAAA9D,EAAI,IAAIc,EAAI,GAAGA,EAAI,GAAGuB,GAAM,GAAG,KAAK,KAAK,CAAC;AAC1C;AAAA,MACF,KAAK;AACH,aAAK,SAASrC,GAAKc,GAAKuB,GAAM,GAAG,KAAK,KAAK,CAAC;AAC5C;AAAA,MACF,KAAK;AACH,aAAK,SAASrC,GAAKc,GAAKuB,GAAM,GAAG,CAAC;AAClC;AAAA,MACF,KAAK;AACH,aAAK,MAAMrC,GAAKc,GAAKuB,CAAI;AACzB;AAAA,IAAA;AAAA,EAEN;AAAA,EAEQ,SAASrC,GAA+Bc,GAAeO,GAAW0C,GAAezB,GAAsB;AAC7G,IAAAtC,EAAI,OAAOc,EAAI,IAAIO,IAAI,KAAK,IAAIiB,CAAM,GAAGxB,EAAI,IAAIO,IAAI,KAAK,IAAIiB,CAAM,CAAC;AACrE,aAAS1C,IAAI,GAAGA,IAAImE,GAAOnE,KAAK;AAC9B,YAAMsC,IAAQI,IAAU1C,IAAI,IAAI,KAAK,KAAMmE;AAC3C,MAAA/D,EAAI,OAAOc,EAAI,IAAIO,IAAI,KAAK,IAAIa,CAAK,GAAGpB,EAAI,IAAIO,IAAI,KAAK,IAAIa,CAAK,CAAC;AAAA,IACrE;AACA,IAAAlC,EAAI,UAAA;AAAA,EACN;AAAA,EAEQ,MAAMA,GAA+Bc,GAAeO,GAAiB;AAC3E,UAAM2C,IAAS3C,IAAI,KACb4C,IAAS;AACf,aAASrE,IAAI,GAAGA,IAAIqE,IAAS,GAAGrE,KAAK;AACnC,YAAMsC,IAAUtC,IAAI,KAAK,KAAMqE,IAAS,KAAK,KAAK,GAC5CC,IAAStE,IAAI,MAAM,IAAIyB,IAAI2C,GAC3Bb,IAAIrC,EAAI,IAAIoD,IAAS,KAAK,IAAIhC,CAAK,GACnCkB,IAAItC,EAAI,IAAIoD,IAAS,KAAK,IAAIhC,CAAK;AACzC,MAAAtC,MAAM,IAAII,EAAI,OAAOmD,GAAGC,CAAC,IAAIpD,EAAI,OAAOmD,GAAGC,CAAC;AAAA,IAC9C;AACA,IAAApD,EAAI,UAAA;AAAA,EACN;AAAA,EAEQ,UACNA,GACA2C,GACAC,GACAuB,GACM;AACN,UAAM7C,IAAQ,EAAE,GAAG,KAAK,OAAO,MAAM,GAAG6C,EAAA;AACxC,IAAAnE,EAAI,KAAA,GACJA,EAAI,cAAcsB,EAAM,OACxBtB,EAAI,YAAcsB,EAAM,OACxBtB,EAAI,cAAcsB,EAAM,SACpBA,EAAM,eAAatB,EAAI,YAAYsB,EAAM,WAAW,GACxDtB,EAAI,UAAA,GACJA,EAAI,OAAO2C,EAAK,GAAGA,EAAK,CAAC,GACzB3C,EAAI,OAAO4C,EAAG,GAAKA,EAAG,CAAC,GACvB5C,EAAI,OAAA,GACJA,EAAI,QAAA;AAAA,EACN;AAAA,EAEQ,UAAgB;AACtB,UAAMoE,IAAO,KAAK,QAAQ,sBAAA,GACpBnD,IAAI,KAAK,MAAMmD,EAAK,QAAS,KAAK,IAAI,GACtCzE,IAAI,KAAK,MAAMyE,EAAK,SAAS,KAAK,IAAI;AAC5C,KAAI,KAAK,QAAQ,UAAUnD,KAAK,KAAK,QAAQ,WAAWtB,OACtD,KAAK,QAAQ,QAASsB,GACtB,KAAK,QAAQ,SAAStB;AAAA,EAE1B;AAAA,EAEA,UAAgB;AAAA,EAA4B;AAC9C;AC1hBO,MAAM0E,EAAsB;AAAA,EAsCjC,YAAYvE,GAA2B;AAnCvC,SAAQ,aAAa,IACrB,KAAQ,WAAqB,EAAE,GAAG,GAAG,GAAG,EAAA,GACxC,KAAQ,iCAAyD,IAAA,GACjE,KAAQ,SAAsB,CAAA,GAC9B,KAAQ,iCAAwC,IAAA,GAChD,KAAQ,YAAY,GAIpB,KAAQ,cAAsB,GAC9B,KAAQ,cAA+B,MACvC,KAAiB,iBAAiB,MAGlC,KAAQ,aAOG,MAGX,KAAQ,sCAA6C,IAAA,GACrD,KAAQ,iBAAgC,MAExC,KAAQ,kBAA4B,EAAE,GAAG,GAAG,GAAG,EAAA,GAS7C,KAAK,UAAUA,GACf,KAAK,OAAO,OAAO,oBAAoB,GACvC,KAAK,SAAS;AAAA,MACZ,KAAK,EAAE,GAAGA,EAAO,SAAS,IAAI,KAAK,OAAO,GAAGA,EAAO,UAAU,IAAI,KAAK,MAAA;AAAA,MACvE,MAAM;AAAA,MACN,eAAe;AAAA,MACf,gBAAgB;AAAA,IAAA,GAGlB,KAAK,iBAAmB,KAAK,mBAAmB,KAAK,IAAI,GACzD,KAAK,iBAAmB,KAAK,mBAAmB,KAAK,IAAI,GACzD,KAAK,eAAmB,KAAK,iBAAiB,KAAK,IAAI,GACvD,KAAK,mBAAmB,KAAK,qBAAqB,KAAK,IAAI,GAC3D,KAAK,WAAmB,KAAK,aAAa,KAAK,IAAI,GAEnDA,EAAO,iBAAiB,eAAiB,KAAK,cAAc,GAC5DA,EAAO,iBAAiB,eAAiB,KAAK,cAAc,GAC5DA,EAAO,iBAAiB,aAAiB,KAAK,YAAY,GAC1DA,EAAO,iBAAiB,iBAAiB,KAAK,gBAAgB,GAC9DA,EAAO,iBAAiB,SAAiB,KAAK,UAAU,EAAE,SAAS,IAAO;AAAA,EAC5E;AAAA,EAEA,IAAI,QAAoC;AAAE,WAAO,KAAK;AAAA,EAAO;AAAA,EAC7D,IAAI,aAAqB;AAAE,WAAO,KAAK;AAAA,EAAY;AAAA,EACnD,IAAI,aAA8B;AAAE,WAAO,KAAK;AAAA,EAAY;AAAA,EAE5D,cAAcwE,GAAeC,GAAyB;AACpD,SAAK,aAAc,MACnB,KAAK,cAAcD,GACfC,MAAW,WAAW,KAAK,cAAcA;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAejG,GAAgBkG,GAAkBD,GAAmBE,IAAuB,MAAY;AACrG,SAAK,aAAa;AAAA,MAChB,WAAW,KAAK,OAAO;AAAA,MACvB,QAAAnG;AAAA,MACA,QAAQiG,KAAU;AAAA,MAClB,WAAW,YAAY,IAAA;AAAA,MACvB,UAAAC;AAAA,MACA,QAAAC;AAAA,IAAA,GAEF,KAAK,cAAcnG,GACnB,KAAK,cAAciG,KAAU;AAAA,EAC/B;AAAA;AAAA,EAGA,cAAcjH,GAAcmG,GAAYC,GAAkB;AACxD,SAAK,aAAc,MACnB,KAAK,cAAcpG,GACnB,KAAK,OAAO,OAAOA,GACnB,KAAK,OAAO,MAAO,EAAE,GAAGmG,GAAI,GAAGC,EAAA,GAC/B,KAAK,cAAc;AAAA,EACrB;AAAA,EAEA,YAAYlG,GAAoBgB,GAAkCkG,GAAwB;AACxF,SAAK,SAAalH,GAClB,KAAK,aAAagB,GAClB,KAAK,YAAakG;AAAA,EACpB;AAAA,EAEA,SAAShI,GAAyD;AAChE,gBAAK,WAAW,IAAIA,CAAQ,GACrB,MAAM,KAAK,WAAW,OAAOA,CAAQ;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAgB;AACd,UAAMiI,IAAW,KAAK,OAAO;AAE7B,QAAI,KAAK,YAAY;AACnB,YAAM,EAAE,WAAAC,GAAW,QAAAtG,GAAQ,QAAAiG,GAAQ,WAAAM,GAAW,UAAAL,GAAU,QAAAC,MAAW,KAAK,YAClE5F,IAAI,KAAK,IAAI,IAAI,YAAY,IAAA,IAAQgG,KAAaL,CAAQ,GAG1DlB,IAAQmB,MAAW,QAAQ,IAAI,KAAK,IAAI,IAAI5F,GAAG,CAAC,IAAIA,IAAIA,IAAIA;AAClE,WAAK,OAAO,OAAO+F,KAAatG,IAASsG,KAAatB,GAElDzE,KAAK,KACP,KAAK,aAAc,MACnB,KAAK,cAAc,QAEnB,KAAK,cAAc0F;AAAA,IAEvB,OAAO;AAEL,YAAMO,IAAK,KAAK,cAAc,KAAK,OAAO;AAC1C,UAAI,KAAK,IAAIA,CAAE,IAAI;AACjB,oBAAK,cAAc,MACZ;AAET,WAAK,OAAO,QAAQA,IAAK,KAAK;AAAA,IAChC;AAGA,QAAI,KAAK,aAAa;AACpB,YAAM,EAAE,GAAGC,GAAI,GAAGC,EAAA,IAAO,KAAK;AAC9B,WAAK,OAAO,MAAM;AAAA,QAChB,GAAGD,KAAMA,IAAK,KAAK,OAAO,IAAI,MAAM,KAAK,OAAO,OAAOJ;AAAA,QACvD,GAAGK,KAAMA,IAAK,KAAK,OAAO,IAAI,MAAM,KAAK,OAAO,OAAOL;AAAA,MAAA;AAAA,IAE3D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,UAAgB;AACd,SAAK,QAAQ,oBAAoB,eAAiB,KAAK,cAAc,GACrE,KAAK,QAAQ,oBAAoB,eAAiB,KAAK,cAAc,GACrE,KAAK,QAAQ,oBAAoB,aAAiB,KAAK,YAAY,GACnE,KAAK,QAAQ,oBAAoB,iBAAiB,KAAK,gBAAgB,GACvE,KAAK,QAAQ,oBAAoB,SAAiB,KAAK,QAAQ;AAAA,EACjE;AAAA;AAAA,EAIA,cAAcM,GAAiBC,GAA2B;AACxD,WAAO;AAAA,MACL,IAAID,IAAU,KAAK,OAAO,IAAI,KAAK,KAAK,OAAO;AAAA,MAC/C,IAAIC,IAAU,KAAK,OAAO,IAAI,KAAK,KAAK,OAAO;AAAA,IAAA;AAAA,EAEnD;AAAA,EAEQ,cAAc3I,GAAyB;AAC7C,UAAM6H,IAAO,KAAK,QAAQ,sBAAA;AAC1B,WAAO,EAAE,GAAG7H,EAAE,UAAU6H,EAAK,MAAM,GAAG7H,EAAE,UAAU6H,EAAK,IAAA;AAAA,EACzD;AAAA,EAEQ,SAASe,GAAmC;AAClD,QAAIC,IAAyB,MACzBC,IAAc;AAElB,eAAW1J,KAAQ,KAAK,QAAQ;AAC9B,YAAMmF,IAAM,KAAK,WAAW,IAAInF,EAAK,EAAE;AACvC,UAAI,CAACmF,EAAK;AAGV,YAAMwE,IAFW,CAAC,EAAE3J,EAAK,YAAYA,EAAK,SAAS,SAAS,KAE/B4D,IAAsB,MAAM,KAAK,YAAY,GACpEsD,IAAKsC,EAAS,IAAIrE,EAAI,GACtBgC,IAAKqC,EAAS,IAAIrE,EAAI,GACtByE,IAAO,KAAK,KAAK1C,IAAKA,IAAKC,IAAKA,CAAE;AACxC,MAAIyC,IAAOD,KAAaC,IAAOF,MAC7BA,IAAcE,GACdH,IAAUzJ,EAAK;AAAA,IAEnB;AACA,WAAOyJ;AAAA,EACT;AAAA,EAEQ,MAAM3I,GAA+B;AAC3C,eAAWC,KAAY,KAAK,WAAY,CAAAA,EAASD,CAAK;AAAA,EACxD;AAAA;AAAA,EAIQ,mBAAmBF,GAAuB;AAChD,SAAK,QAAQ,kBAAkBA,EAAE,SAAS;AAC1C,UAAMuE,IAAM,KAAK,cAAcvE,CAAC;AAChC,SAAK,gBAAgB,IAAIA,EAAE,WAAWuE,CAAG,GAErC,KAAK,gBAAgB,SAAS,KAEhC,KAAK,aAAkB,IACvB,KAAK,WAAkBA,GACvB,KAAK,kBAAkBA,MAGvB,KAAK,aAAkB,IACvB,KAAK,iBAAkB;AAAA,EAE3B;AAAA,EAEQ,mBAAmBvE,GAAuB;AAChD,UAAMiJ,IAAY,KAAK,cAAcjJ,CAAC;AAItC,QAHA,KAAK,gBAAgB,IAAIA,EAAE,WAAWiJ,CAAS,GAG3C,KAAK,gBAAgB,QAAQ,GAAG;AAClC,YAAMC,IAAO,CAAC,GAAG,KAAK,gBAAgB,QAAQ,GACxCF,IAAO,KAAK,MAAME,EAAI,CAAC,EAAG,IAAIA,EAAI,CAAC,EAAG,GAAGA,EAAI,CAAC,EAAG,IAAIA,EAAI,CAAC,EAAG,CAAC;AAEpE,UAAI,KAAK,mBAAmB,QAAQF,IAAO,GAAG;AAC5C,cAAMG,IAAQH,IAAO,KAAK,gBACpBI,KAASF,EAAI,CAAC,EAAG,IAAIA,EAAI,CAAC,EAAG,KAAK,GAClCG,KAASH,EAAI,CAAC,EAAG,IAAIA,EAAI,CAAC,EAAG,KAAK;AACxC,aAAK,cAAc,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,cAAcC,CAAK,CAAC,GACxE,KAAK,cAAc,EAAE,GAAGC,GAAM,GAAGC,EAAA,GACjC,KAAK,MAAM,EAAE,MAAM,eAAe,MAAM,KAAK,aAAa;AAAA,MAC5D;AACA,WAAK,iBAAiBL;AACtB;AAAA,IACF;AAGA,QAAI,KAAK,YAAY;AACnB,YAAM1C,IAAK2C,EAAU,IAAI,KAAK,SAAS,GACjC1C,IAAK0C,EAAU,IAAI,KAAK,SAAS;AACvC,WAAK,WAAeA,GACpB,KAAK,OAAO,MAAQ,EAAE,GAAG,KAAK,OAAO,IAAI,IAAI3C,GAAI,GAAG,KAAK,OAAO,IAAI,IAAIC,EAAA,GACxE,KAAK,MAAM,EAAE,MAAM,cAAc,KAAK,KAAK,OAAO,KAAK;AACvD;AAAA,IACF;AAGA,QAAIvG,EAAE,gBAAgB,SAAS;AAC7B,YAAM4I,IAAW,KAAK,cAAcK,EAAU,GAAGA,EAAU,CAAC,GACtDK,IAAW,KAAK,SAASV,CAAQ;AACvC,MAAIU,MAAQ,KAAK,OAAO,kBAClB,KAAK,OAAO,iBACd,KAAK,MAAM,EAAE,MAAM,aAAa,QAAQ,KAAK,OAAO,eAAe,GAErE,KAAK,OAAO,gBAAgBA,GACxBA,UAAU,MAAM,EAAE,MAAM,cAAc,QAAQA,GAAK;AAAA,IAE3D;AAAA,EACF;AAAA,EAEQ,iBAAiBtJ,GAAuB;AAC9C,UAAMiJ,IAAkB,KAAK,cAAcjJ,CAAC,GACtCuJ,IAAkB,KAAK,gBAAgB,QAAQ,GAC/CC,IAAkB,KAAK;AAI7B,QAHA,KAAK,gBAAgB,OAAOxJ,EAAE,SAAS,GACvC,KAAK,iBAAiB,MAElBuJ,GAAe;AAEjB,MAAI,KAAK,gBAAgB,SAAS,MAChC,KAAK,aAAa,IAClB,KAAK,WAAa,CAAC,GAAG,KAAK,gBAAgB,OAAA,CAAQ,EAAE,CAAC;AAExD;AAAA,IACF;AAEA,SAAK,aAAa;AAGlB,UAAMjD,IAAK,KAAK,IAAI2C,EAAU,IAAIO,EAAW,CAAC,GACxCjD,IAAK,KAAK,IAAI0C,EAAU,IAAIO,EAAW,CAAC;AAC9C,QAAIlD,IAAK,KAAKC,IAAK,GAAG;AACpB,YAAMqC,IAAW,KAAK,cAAcK,EAAU,GAAGA,EAAU,CAAC,GACtDK,IAAW,KAAK,SAASV,CAAQ;AACvC,MAAIU,KACF,KAAK,OAAO,iBAAiBA,MAAQ,KAAK,OAAO,iBAAiB,OAAOA,GACzE,KAAK,MAAM,EAAE,MAAM,cAAc,QAAQA,GAAK,MAE9C,KAAK,OAAO,iBAAiB,MAC7B,KAAK,MAAM,EAAE,MAAM,eAAA,CAAgB;AAAA,IAEvC;AAAA,EACF;AAAA,EAEQ,qBAAqBtJ,GAAuB;AAClD,SAAK,gBAAgB,OAAOA,EAAE,SAAS,GACvC,KAAK,iBAAiB,MAClB,KAAK,gBAAgB,SAAS,MAChC,KAAK,aAAa;AAAA,EAEtB;AAAA;AAAA,EAIQ,aAAaA,GAAqB;AACxC,IAAAA,EAAE,eAAA;AACF,UAAMiJ,IAAiB,KAAK,cAAcjJ,CAAC,GACrCyJ,IAAiBzJ,EAAE,SAAS,IAAI,MAAM,IAAI;AAChD,SAAK,cAAkB,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,cAAcyJ,CAAM,CAAC,GAC7E,KAAK,cAAkBR,GACvB,KAAK,MAAM,EAAE,MAAM,eAAe,MAAM,KAAK,aAAa;AAAA,EAC5D;AACF;ACzTA,MAAMS,IAAuB,KACvBC,IAAuB,MACvBC,IAAuB;AAYtB,MAAMC,EAAgB;AAAA,EA4B3B,YAAY1I,GAAiC;;AArB7C,SAAQ,iCAAwC,IAAA,GAChD,KAAQ,sCAAsD,IAAA,GAE9D,KAAQ,SAAwB,MAChC,KAAQ,gBAAsD,MAC9D,KAAQ,eAAsD,MAC9D,KAAQ,iBAAoC,CAAA,GAI5C,KAAQ,gBAA6B,CAAA,GACrC,KAAQ,gBAA6B,CAAA,GAGrC,KAAQ,oBAAoB,GAC5B,KAAQ,oBAAoB,GAC5B,KAAiB,uBAAuB,KAGxC,KAAQ,oBAAoB;AAG1B,UAAM,EAAE,QAAAoC,GAAQ,MAAArE,GAAM,OAAAsE,GAAO,KAAAsG,GAAK,IAAAC,IAAK,CAAA,MAAO5I;AAU9C,QARA,KAAK,iBAAiB4I,GACtB,KAAK,SAAS,IAAI9K,EAAgBC,CAAI,GACtC,KAAK,OAAO,IAAIqB,EAAqB,EAAE,QAAQ,MAAM,OAAOrB,EAAK,OAAO,GACxE,KAAK,OAAO,IAAI2B,EAAciJ,CAAG,GACjC,KAAK,UAAU,IAAI9I,EAAA,GACnB,KAAK,YAAY,IAAIsC,EAAeC,GAAQC,KAAStE,EAAK,KAAK,GAC/D,KAAK,eAAe,IAAI4I,EAAsBvE,CAAM,GAEhDpC,EAAQ,sBAAsB;AAChC,YAAM6I,IAAW,KAAK,OAAO,QAAQ7I,EAAQ,oBAAoB;AACjE,MAAI6I,KAAY,KAAK,UAAUA,CAAQ,KACrC,KAAK,KAAK,KAAK,EAAE,QAAQA,EAAS,IAAI,OAAOA,EAAS,OAAO;AAAA,IAEjE;AAEA,SAAK,qBAAA,GACL,KAAK,YAAA,GACL,KAAK,WAAA,GACL,KAAK,iBAAA,GAEL,KAAK,kBAAkB,IAAI,eAAe,MAAM;AAC9C,WAAK,UAAU,OAAA,GACf,KAAK,WAAA;AAAA,IACP,CAAC,GACD,KAAK,gBAAgB,QAAQzG,CAAM,IAEnC5B,KAAAD,IAAA,KAAK,gBAAe,mBAApB,QAAAC,EAAA,KAAAD,GAAqCxC;AAAA,EACvC;AAAA;AAAA,EAIA,aAAaK,GAAgBI,GAAwB;AACnD,SAAK,OAAO,aAAaJ,GAAQI,CAAK;AAAA,EACxC;AAAA,EAEA,YAAYJ,GAAgBM,GAA0B;AACpD,SAAK,OAAO,YAAYN,GAAQM,CAAQ;AAAA,EAC1C;AAAA,EAEA,eAAeN,GAAgBQ,GAA0B;AACvD,SAAK,OAAO,eAAeR,GAAQQ,CAAU;AAAA,EAC/C;AAAA,EAEA,YAAYyD,GAAyB;AACnC,SAAK,UAAU,YAAYA,CAAK;AAAA,EAClC;AAAA,EAEA,SAAe;AACb,SAAK,aAAa,cAAc,KAAK,IAAI,IAAI,KAAK,aAAa,aAAa,GAAG,CAAC;AAAA,EAClF;AAAA,EAEA,UAAgB;AACd,SAAK,aAAa,cAAc,KAAK,IAAI,MAAM,KAAK,aAAa,aAAa,GAAG,CAAC;AAAA,EACpF;AAAA,EAEA,SAAe;AACb,IAAI,KAAK,KAAK,aAAW,KAAK,mBAAA;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAAeyG,GAA4B;;AACzC,QAAI,KAAK,KAAK,MAAM,UAAUA,EAAc;AAG5C,IAAI,KAAK,kBAAkB,SAAQ,aAAa,KAAK,aAAa,GAAG,KAAK,gBAAgB,OACtF,KAAK,iBAAkB,SAAQ,aAAa,KAAK,YAAY,GAAI,KAAK,eAAgB;AAG1F,QAAIC;AACJ,WAAO,KAAK,KAAK,MAAM,SAASD,KAAgB,KAAK,KAAK;AACxD,MAAAC,IAAa,KAAK,KAAK,IAAA;AAEzB,QAAI,CAACA,EAAY;AAGjB,UAAMrC,IADS,KAAK,UAAU,OACR,sBAAA,GAChBsC,IAAS,EAAE,GAAGtC,EAAK,QAAQ,GAAG,GAAGA,EAAK,SAAS,EAAA;AAErD,SAAK,oBAAoB,KAAK,IAAA,IAAQ+B,GACtC,KAAK,qBAAA,GACL,KAAK,UAAU,eAAeO,CAAM,GACpC,KAAK,aAAa,cAAc,GAAKA,EAAO,GAAGA,EAAO,CAAC,GACvD,KAAK,KAAK,QAAQ,CAAG;AAErB,eAAW,KAAK,KAAK;AACnB,WAAK,WAAW,IAAI,EAAE,IAAI,EAAE,IAAI,KAAK,OAAA,IAAW,OAAO,IAAI,IAAI,KAAK,WAAW,OAAO,IAAI;AAG5F,SAAK,oBAAoB,GACzB,KAAK,oBAAoB,YAAY,IAAA,GACrC,KAAK,WAAA,IACLxI,KAAAD,IAAA,KAAK,gBAAe,oBAApB,QAAAC,EAAA,KAAAD,GAAsCwI,GAAY,KAAK,KAAK;AAAA,EAC9D;AAAA,EAEQ,qBAA2B;AACjC,QAAI,CAAC,KAAK,KAAK,UAAW;AAG1B,IAAI,KAAK,kBAAkB,SACzB,aAAa,KAAK,aAAa,GAC/B,KAAK,gBAAgB;AAIvB,UAAMrC,IADS,KAAK,UAAU,OACV,sBAAA,GACdsC,IAAS,EAAE,GAAGtC,EAAK,QAAQ,GAAG,GAAGA,EAAK,SAAS,EAAA,GAC/CI,IAAW;AAGjB,SAAK,aAAa,eAAe,MAAMA,GAAU,QAAW,KAAK,GAEjE,KAAK,eAAe,WAAW,MAAM;AACnC,WAAK,eAAe,MACpB,KAAK,UAAU,eAAekC,CAAM,GACpC,KAAK,aAAA;AAAA,IACP,GAAGlC,CAAQ;AAAA,EACb;AAAA,EAEA,aAAa1I,GAAsB;AACjC,UAAMH,IAAO,KAAK,OAAO,QAAQG,CAAM;AACvC,QAAI,CAACH,KAAQ,CAAC,KAAK,UAAUA,CAAI,EAAG;AAGpC,IAAI,KAAK,kBAAkB,SACzB,aAAa,KAAK,aAAa,GAC/B,KAAK,gBAAgB;AAIvB,UAAMyI,IADS,KAAK,UAAU,OACV,sBAAA,GACduC,IAAW,EAAE,GAAGvC,EAAK,QAAQ,GAAG,GAAGA,EAAK,SAAS,EAAA,GAGjDwC,IAAU,KAAK,WAAW,IAAI9K,CAAM,GACpCyI,IAASqC,KAAW,MAAM;AAC9B,YAAM,EAAE,MAAAtJ,GAAM,KAAA6C,EAAA,IAAQ,KAAK,aAAa;AACxC,aAAO,EAAE,GAAGyG,EAAQ,IAAItJ,IAAO6C,EAAI,GAAG,GAAGyG,EAAQ,IAAItJ,IAAO6C,EAAI,EAAA;AAAA,IAClE,OAAO,QAEDqE,IAAW;AACjB,SAAK,aAAa,eAAe,KAAKA,GAAUD,CAAM,GAEtD,KAAK,gBAAgB,WAAW,MAAM;AACpC,WAAK,gBAAgB,MACrB,KAAK,cAAc5I,GAAMgL,CAAQ;AAAA,IACnC,GAAGnC,CAAQ;AAAA,EACb;AAAA,EAEA,WAAuB;AAAE,WAAO,KAAK,OAAO,OAAA;AAAA,EAAS;AAAA,EAErD,qBAAiD;AAAE,WAAO,KAAK,KAAK;AAAA,EAAM;AAAA,EAE1E,UAAgB;AACd,IAAI,KAAK,WAAW,QAAM,qBAAqB,KAAK,MAAM,GACtD,KAAK,kBAAkB,QAAM,aAAa,KAAK,aAAa,GAC5D,KAAK,iBAAkB,QAAM,aAAa,KAAK,YAAY,GAC/D,KAAK,gBAAgB,WAAA,GACrB,KAAK,QAAQ,KAAA,GACb,KAAK,UAAU,QAAA,GACf,KAAK,aAAa,QAAA;AAClB,eAAWqC,KAAS,KAAK,eAAgB,CAAAA,EAAA;AAAA,EAC3C;AAAA;AAAA,EAIQ,uBAA6B;AACnC,UAAMC,IAAY,KAAK,KAAK,QAAQ;AACpC,SAAK,gBAAgB,KAAK,OAAO,SAAA,EAAW;AAAA,MAAO,OACjDA,MAAc,OAAO,CAAC7K,EAAE,WAAWA,EAAE,aAAa6K;AAAA,IAAA;AAEpD,UAAMC,IAAM,IAAI,IAAI,KAAK,cAAc,IAAI,CAAA9K,MAAKA,EAAE,EAAE,CAAC;AACrD,SAAK,gBAAgB,KAAK,OAAO,SAAA,EAAW;AAAA,MAC1C,CAAAM,MAAKwK,EAAI,IAAIxK,EAAE,MAAM,KAAKwK,EAAI,IAAIxK,EAAE,MAAM;AAAA,IAAA;AAAA,EAE9C;AAAA;AAAA,EAIQ,UAAUZ,GAA0B;AAC1C,WAAO,CAAC,EAAEA,EAAK,YAAYA,EAAK,SAAS,SAAS;AAAA,EACpD;AAAA,EAEQ,cAAcA,GAAiBqL,GAAgC;;AACrE,SAAK,KAAK,KAAK,EAAE,QAAQrL,EAAK,IAAI,OAAOA,EAAK,OAAO,GACrD,KAAK,oBAAoB,KAAK,IAAA,IAAQwK,GACtC,KAAK,qBAAA,GAEL,KAAK,UAAU,aAAaa,GAAgB,KAAK,UAAU,iBAAiBrL,CAAI,CAAC;AAIjF,UAAMyI,IADS,KAAK,UAAU,OACV,sBAAA;AACpB,SAAK,aAAa,cAAc,GAAKA,EAAK,QAAQ,GAAGA,EAAK,SAAS,CAAC,GACpE,KAAK,KAAK,QAAQ,CAAG;AAGrB,eAAWnI,KAAK,KAAK;AACnB,WAAK,WAAW,IAAIA,EAAE,IAAI;AAAA,QACxB,IAAI,KAAK,OAAA,IAAW,OAAO;AAAA,QAC3B,IAAI,KAAK,OAAA,IAAW,OAAO;AAAA,MAAA,CAC5B;AAGH,SAAK,oBAAoB,GACzB,KAAK,oBAAoB,YAAY,IAAA,GAErC,KAAK,WAAA,IACLiC,KAAAD,IAAA,KAAK,gBAAe,qBAApB,QAAAC,EAAA,KAAAD,GAAuCtC,GAAM,KAAK,KAAK;AAAA,EACzD;AAAA,EAEQ,eAAqB;;AAC3B,UAAMsL,IAAS,KAAK,KAAK,IAAA;AACzB,QAAI,CAACA,EAAQ;AACb,SAAK,oBAAoB,KAAK,IAAA,IAAQd,GACtC,KAAK,qBAAA;AAGL,UAAM/B,IADS,KAAK,UAAU,OACV,sBAAA;AACpB,SAAK,aAAa,cAAc,GAAKA,EAAK,QAAQ,GAAGA,EAAK,SAAS,CAAC,GACpE,KAAK,KAAK,QAAQ,CAAG;AAErB,eAAWnI,KAAK,KAAK;AACnB,WAAK,WAAW,IAAIA,EAAE,IAAI;AAAA,QACxB,IAAI,KAAK,OAAA,IAAW,OAAO;AAAA,QAC3B,IAAI,KAAK,OAAA,IAAW,OAAO;AAAA,MAAA,CAC5B;AAGH,SAAK,oBAAoB,GACzB,KAAK,oBAAoB,YAAY,IAAA,GAErC,KAAK,WAAA,IACLiC,KAAAD,IAAA,KAAK,gBAAe,oBAApB,QAAAC,EAAA,KAAAD,GAAsCgJ,GAAQ,KAAK,KAAK;AAAA,EAC1D;AAAA,EAEQ,mBAAyB;AAC/B,QAAI,KAAK,QAAQ,KAAK,kBAAmB;AAEzC,UAAMC,IAAa,KAAK,aAAa,YAC/B3C,IAAS,KAAK,aAAa;AAEjC,QAAI2C,IAAajB,KAAwB1B,GAAQ;AAC/C,YAAM,EAAE,MAAAjH,GAAM,KAAA6C,EAAA,IAAQ,KAAK,aAAa,OAClCgH,IAAS,KAAK,oBAAoB5C,GAAQpE,GAAK7C,CAAI;AACzD,UAAI6J,GAAQ;AACV,aAAK,cAAcA,GAAQ5C,CAAM;AACjC;AAAA,MACF;AAAA,IACF;AAEA,IAAI2C,IAAahB,KAAuB,KAAK,KAAK,aAChD,KAAK,aAAA;AAAA,EAET;AAAA,EAEQ,oBAAoBV,GAAqBrF,GAAe7C,GAAgC;AAC9F,UAAM8J,KAAU5B,EAAU,IAAIrF,EAAI,KAAK7C,GACjC+J,KAAU7B,EAAU,IAAIrF,EAAI,KAAK7C;AAEvC,eAAW3B,KAAQ,KAAK,eAAe;AACrC,UAAI,CAAC,KAAK,UAAUA,CAAI,EAAG;AAC3B,YAAMmF,IAAM,KAAK,WAAW,IAAInF,EAAK,EAAE;AACvC,UAAI,CAACmF,EAAK;AACV,YAAM+B,IAAKuE,IAAStG,EAAI,GAClBgC,IAAKuE,IAASvG,EAAI;AACxB,UAAI,KAAK,KAAK+B,IAAKA,IAAKC,IAAKA,CAAE,KAAKvD,IAAsB;AACxD,eAAO5D;AAAA,IAEX;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAIQ,cAAoB;AAC1B,SAAK,eAAe;AAAA,MAClB,KAAK,OAAO,GAAG,WAAW,MAAM;AAC9B,aAAK,qBAAA;AAAA,MACP,CAAC;AAAA,IAAA,GAGH,KAAK,eAAe;AAAA,MAClB,KAAK,aAAa,SAAS,CAAAc,MAAS;;AAClC,gBAAQA,EAAM,MAAA;AAAA,UACZ,KAAK;AAAA,UACL,KAAK;AACH;AAAA,UACF,KAAK,cAAc;AACjB,iBAAK,gBAAgB,IAAIA,EAAM,QAAQ,SAAS;AAChD,kBAAMd,IAAO,KAAK,OAAO,QAAQc,EAAM,MAAM;AAC7C,YAAId,OAAMuC,KAAAD,IAAA,KAAK,gBAAe,kBAApB,QAAAC,EAAA,KAAAD,GAAoCtC;AAC9C;AAAA,UACF;AAAA,UACA,KAAK,aAAa;AAEhB,YADa,KAAK,gBAAgB,IAAIc,EAAM,MAAM,MACrC,aAAW,KAAK,gBAAgB,IAAIA,EAAM,QAAQ,MAAM;AACrE,kBAAMd,IAAO,KAAK,OAAO,QAAQc,EAAM,MAAM;AAC7C,YAAId,OAAM0D,KAAAD,IAAA,KAAK,gBAAe,iBAApB,QAAAC,EAAA,KAAAD,GAAmCzD;AAC7C;AAAA,UACF;AAAA,UACA,KAAK,gBAAgB;AAEnB,uBAAW,CAACE,GAAI+C,CAAC,KAAK,KAAK;AACzB,cAAIA,MAAM,cAAY,KAAK,gBAAgB,IAAI/C,GAAI,MAAM;AAE3D,aAAAyL,KAAAhI,IAAA,KAAK,gBAAe,oBAApB,QAAAgI,EAAA,KAAAhI;AACA;AAAA,UACF;AAAA,UAEA,KAAK,cAAc;AACjB,kBAAM3D,IAAO,KAAK,OAAO,QAAQc,EAAM,MAAM;AAC7C,gBAAI,CAACd,EAAM;AAKX,gBAFa,KAAK,gBAAgB,IAAIc,EAAM,MAAM,MACtB;AAE1B,mBAAK,gBAAgB,IAAIA,EAAM,QAAQ,MAAM;AAAA,iBACxC;AACL,yBAAW,CAACZ,GAAI+C,CAAC,KAAK,KAAK;AACzB,gBAAIA,MAAM,cAAY,KAAK,gBAAgB,IAAI/C,GAAI,MAAM;AAE3D,mBAAK,gBAAgB,IAAIY,EAAM,QAAQ,UAAU;AAAA,YACnD;AAEA,aAAA8K,KAAAC,IAAA,KAAK,gBAAe,kBAApB,QAAAD,EAAA,KAAAC,GAAoC7L;AACpC;AAAA,UACF;AAAA,QAAA;AAAA,MAEJ,CAAC;AAAA,IAAA;AAAA,EAEL;AAAA;AAAA,EAIQ,aAAmB;AACzB,UAAMyI,IAAO,KAAK,UAAU,OAAO,sBAAA;AAEnC,SAAK,QAAQ,IAAI,KAAK,eAAe,KAAK,eAAe;AAAA,MACvD,OAAOA,EAAK,SAAS;AAAA,MACrB,QAAQA,EAAK,UAAU;AAAA,MACvB,QAAQ,CAAA5F,MAAa;AACnB,mBAAW,CAAC3C,GAAIiF,CAAG,KAAKtC,EAAW,MAAK,WAAW,IAAI3C,GAAIiF,CAAG;AAC9D,aAAK,aAAa,YAAY,KAAK,eAAe,KAAK,YAAY,CAAC;AAAA,MACtE;AAAA,IAAA,CACD;AAAA,EACH;AAAA;AAAA,EAIQ,mBAAyB;AAC/B,UAAM2G,IAAO,MAAM;;AAEjB,UADgB,KAAK,aAAa,KAAA,GACrB;AACX,cAAMC,IAAI,KAAK,aAAa,MAAM;AAClC,aAAK,KAAK,QAAQA,CAAC,IACnBxJ,KAAAD,IAAA,KAAK,gBAAe,mBAApB,QAAAC,EAAA,KAAAD,GAAqCyJ;AAAA,MACvC;AAEA,UAAI,KAAK,oBAAoB,GAAG;AAC9B,cAAMC,IAAU,YAAY,IAAA,IAAQ,KAAK;AACzC,aAAK,oBAAoB,KAAK,IAAI,GAAGA,IAAU,KAAK,oBAAoB;AAAA,MAC1E;AAEA,WAAK,iBAAA,GACL,KAAK,MAAA,GAEL,KAAK,SAAS,sBAAsBF,CAAI;AAAA,IAC1C;AACA,SAAK,SAAS,sBAAsBA,CAAI;AAAA,EAC1C;AAAA,EAEQ,QAAc;AACpB,UAAM,EAAE,KAAAtH,GAAK,MAAA7C,EAAA,IAAS,KAAK,aAAa;AAExC,SAAK,UAAU,OAAO,KAAK,eAAe,KAAK,eAAe;AAAA,MAC5D,WAAW,KAAK;AAAA,MAChB,gBAAgB,KAAK;AAAA,MACrB,kBAAkB,KAAK;AAAA,MACvB,KAAA6C;AAAA,MACA,MAAA7C;AAAA,IAAA,CACD;AAAA,EACH;AACF;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/graph/SkillGraphModel.ts","../src/graph/NavigationController.ts","../src/lod/LodController.ts","../src/layout/ForceLayout.ts","../src/theme/default.ts","../src/theme/merge.ts","../src/renderer/CanvasRenderer.ts","../src/renderer/InteractionController.ts","../src/SkillTreeEngine.ts"],"sourcesContent":["import Graph from 'graphology'\nimport type { SkillGraph, SkillNode, SkillEdge, NodeState, Evidence } from '../types/index.js'\n\ntype GraphEvents = {\n nodeStateChanged: { nodeId: string; state: NodeState }\n nodeAdded: { node: SkillNode }\n nodeRemoved: { nodeId: string }\n edgeAdded: { edge: SkillEdge }\n edgeRemoved: { edgeId: string }\n evidenceAdded: { nodeId: string; evidence: Evidence }\n evidenceRemoved: { nodeId: string; evidenceId: string }\n changed: void\n}\n\ntype EventListener<T> = T extends void ? () => void : (payload: T) => void\n\nexport class SkillGraphModel {\n private _graph: Graph\n private _meta: SkillGraph['meta']\n private _label: string\n private _id: string\n private _listeners: Map<keyof GraphEvents, Set<EventListener<unknown>>> = new Map()\n\n constructor(data: SkillGraph) {\n this._id = data.id\n this._label = data.label\n this._meta = data.meta\n\n this._graph = new Graph({ multi: false, allowSelfLoops: false })\n\n for (const node of data.nodes) {\n this._graph.addNode(node.id, { ...node })\n }\n\n for (const edge of data.edges) {\n if (edge.directed) {\n this._graph.addDirectedEdge(edge.source, edge.target, { ...edge })\n } else {\n this._graph.addUndirectedEdge(edge.source, edge.target, { ...edge })\n }\n }\n }\n\n // ─── Accessors ──────────────────────────────────────────────────────────────\n\n get id() { return this._id }\n get label() { return this._label }\n get meta() { return this._meta }\n\n getNode(id: string): SkillNode | undefined {\n if (!this._graph.hasNode(id)) return undefined\n return this._graph.getNodeAttributes(id) as SkillNode\n }\n\n getEdge(id: string): SkillEdge | undefined {\n if (!this._graph.hasEdge(id)) return undefined\n return this._graph.getEdgeAttributes(id) as SkillEdge\n }\n\n getNodes(): SkillNode[] {\n return this._graph.nodes().map(id => this._graph.getNodeAttributes(id) as SkillNode)\n }\n\n getEdges(): SkillEdge[] {\n return this._graph.edges().map(id => this._graph.getEdgeAttributes(id) as SkillEdge)\n }\n\n getChildren(nodeId: string): SkillNode[] {\n const node = this.getNode(nodeId)\n if (!node?.childIds) return []\n return node.childIds.flatMap(id => {\n const child = this.getNode(id)\n return child ? [child] : []\n })\n }\n\n getNodesAtDepth(depth: number): SkillNode[] {\n return this.getNodes().filter(n => n.depth === depth)\n }\n\n getNodesUpToDepth(depth: number): SkillNode[] {\n return this.getNodes().filter(n => n.depth <= depth)\n }\n\n // ─── Mutations ──────────────────────────────────────────────────────────────\n\n setNodeState(nodeId: string, state: NodeState): void {\n if (!this._graph.hasNode(nodeId)) return\n this._graph.mergeNodeAttributes(nodeId, { state })\n this._emit('nodeStateChanged', { nodeId, state })\n this._emit('changed', undefined)\n }\n\n addNode(node: SkillNode): void {\n this._graph.addNode(node.id, { ...node })\n this._emit('nodeAdded', { node })\n this._emit('changed', undefined)\n }\n\n removeNode(nodeId: string): void {\n if (!this._graph.hasNode(nodeId)) return\n this._graph.dropNode(nodeId)\n this._emit('nodeRemoved', { nodeId })\n this._emit('changed', undefined)\n }\n\n addEdge(edge: SkillEdge): void {\n if (edge.directed) {\n this._graph.addDirectedEdge(edge.source, edge.target, { ...edge })\n } else {\n this._graph.addUndirectedEdge(edge.source, edge.target, { ...edge })\n }\n this._emit('edgeAdded', { edge })\n this._emit('changed', undefined)\n }\n\n removeEdge(edgeId: string): void {\n if (!this._graph.hasEdge(edgeId)) return\n this._graph.dropEdge(edgeId)\n this._emit('edgeRemoved', { edgeId })\n this._emit('changed', undefined)\n }\n\n addEvidence(nodeId: string, evidence: Evidence): void {\n if (!this._graph.hasNode(nodeId)) return\n const node = this.getNode(nodeId)!\n const existing = node.evidence ?? []\n this._graph.mergeNodeAttributes(nodeId, { evidence: [...existing, evidence] })\n this._emit('evidenceAdded', { nodeId, evidence })\n this._emit('changed', undefined)\n }\n\n removeEvidence(nodeId: string, evidenceId: string): void {\n if (!this._graph.hasNode(nodeId)) return\n const node = this.getNode(nodeId)!\n const evidence = (node.evidence ?? []).filter(e => e.id !== evidenceId)\n this._graph.mergeNodeAttributes(nodeId, { evidence })\n this._emit('evidenceRemoved', { nodeId, evidenceId })\n this._emit('changed', undefined)\n }\n\n // ─── Serialization ──────────────────────────────────────────────────────────\n\n toJSON(): SkillGraph {\n const result: SkillGraph = {\n id: this._id,\n label: this._label,\n nodes: this.getNodes(),\n edges: this.getEdges(),\n }\n if (this._meta !== undefined) result.meta = this._meta\n return result\n }\n\n static fromJSON(data: SkillGraph): SkillGraphModel {\n return new SkillGraphModel(data)\n }\n\n // ─── Events ─────────────────────────────────────────────────────────────────\n\n on<K extends keyof GraphEvents>(event: K, listener: EventListener<GraphEvents[K]>): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set())\n }\n const set = this._listeners.get(event)!\n set.add(listener as EventListener<unknown>)\n return () => set.delete(listener as EventListener<unknown>)\n }\n\n private _emit<K extends keyof GraphEvents>(event: K, payload: GraphEvents[K]): void {\n const listeners = this._listeners.get(event)\n if (!listeners) return\n for (const listener of listeners) {\n if (payload === undefined) {\n (listener as () => void)()\n } else {\n (listener as (p: unknown) => void)(payload)\n }\n }\n }\n}\n","import type { NavigationFrame } from '../types/index.js'\n\nexport class NavigationController {\n private _stack: NavigationFrame[]\n private _listeners: Set<(stack: readonly NavigationFrame[]) => void> = new Set()\n\n constructor(root: NavigationFrame = { nodeId: null, label: 'Root' }) {\n this._stack = [root]\n }\n\n get current(): NavigationFrame {\n return this._stack[this._stack.length - 1]!\n }\n\n get stack(): readonly NavigationFrame[] {\n return this._stack\n }\n\n get canGoBack(): boolean {\n return this._stack.length > 1\n }\n\n push(frame: NavigationFrame): void {\n this._stack.push(frame)\n this._notify()\n }\n\n pop(): NavigationFrame | undefined {\n if (!this.canGoBack) return undefined\n const popped = this._stack.pop()\n this._notify()\n return popped\n }\n\n reset(): void {\n this._stack = [this._stack[0]!]\n this._notify()\n }\n\n onChange(listener: (stack: readonly NavigationFrame[]) => void): () => void {\n this._listeners.add(listener)\n return () => this._listeners.delete(listener)\n }\n\n private _notify(): void {\n for (const l of this._listeners) l(this._stack)\n }\n}\n","import type { LodThreshold } from '../types/index.js'\n\nconst DEFAULT_THRESHOLDS: LodThreshold[] = [\n { depth: 0, minZoom: 0, maxZoom: 0.3 },\n { depth: 1, minZoom: 0.3, maxZoom: 0.6 },\n { depth: 2, minZoom: 0.6, maxZoom: 1.2 },\n { depth: 3, minZoom: 1.2, maxZoom: 2.5 },\n { depth: 4, minZoom: 2.5, maxZoom: Infinity },\n]\n\nexport class LodController {\n private _thresholds: LodThreshold[]\n private _zoom: number = 1\n private _listeners: Set<(zoom: number) => void> = new Set()\n\n constructor(thresholds?: LodThreshold[]) {\n this._thresholds = thresholds ?? DEFAULT_THRESHOLDS\n }\n\n get zoom() { return this._zoom }\n\n get thresholds(): readonly LodThreshold[] { return this._thresholds }\n\n setZoom(zoom: number): void {\n this._zoom = Math.max(0.01, zoom)\n this._notify()\n }\n\n onChange(listener: (zoom: number) => void): () => void {\n this._listeners.add(listener)\n return () => this._listeners.delete(listener)\n }\n\n private _notify(): void {\n for (const listener of this._listeners) listener(this._zoom)\n }\n}\n","import {\n forceSimulation,\n forceLink,\n forceManyBody,\n forceCenter,\n forceCollide,\n type Simulation,\n type SimulationNodeDatum,\n type SimulationLinkDatum,\n} from 'd3-force'\nimport type { SkillNode, SkillEdge, Position } from '../types/index.js'\n\nexport interface LayoutNode extends SimulationNodeDatum {\n id: string\n depth: number\n x: number\n y: number\n}\n\nexport interface LayoutLink extends SimulationLinkDatum<LayoutNode> {\n id: string\n}\n\nexport interface ForceLayoutOptions {\n width: number\n height: number\n /** Charge strength — negative = repulsion */\n chargeStrength?: number\n /** Collision radius multiplier relative to node size */\n collisionPadding?: number\n alphaDecay?: number\n onTick?: (positions: Map<string, Position>) => void\n onEnd?: (positions: Map<string, Position>) => void\n}\n\nexport class ForceLayout {\n private _simulation: Simulation<LayoutNode, LayoutLink> | null = null\n\n run(nodes: SkillNode[], edges: SkillEdge[], options: ForceLayoutOptions): void {\n this.stop()\n\n const { width, height, chargeStrength = -200, collisionPadding = 16, alphaDecay = 0.02 } = options\n\n const layoutNodes: LayoutNode[] = nodes.map(n => ({\n id: n.id,\n depth: n.depth,\n // Seed from manual position if provided, else random near world origin.\n // World (0,0) maps to canvas center given the initial pan of (width/2, height/2).\n x: n.position?.x ?? (Math.random() - 0.5) * 100,\n y: n.position?.y ?? (Math.random() - 0.5) * 100,\n }))\n\n const nodeIndex = new Map(layoutNodes.map(n => [n.id, n]))\n\n const layoutLinks: LayoutLink[] = []\n\n // Parent-child edges for layout purposes\n for (const node of nodes) {\n if (node.parentId) {\n const source = nodeIndex.get(node.parentId)\n const target = nodeIndex.get(node.id)\n if (source && target) {\n layoutLinks.push({ id: `${node.parentId}->${node.id}`, source, target })\n }\n }\n }\n\n // Explicit cross-depth edges\n for (const edge of edges) {\n const source = nodeIndex.get(edge.source)\n const target = nodeIndex.get(edge.target)\n if (source && target) {\n layoutLinks.push({ id: edge.id, source, target })\n }\n }\n\n const emit = (positions: Map<string, Position>) => {\n options.onTick?.(positions)\n }\n\n this._simulation = forceSimulation<LayoutNode, LayoutLink>(layoutNodes)\n .alphaDecay(alphaDecay)\n .force('link', forceLink<LayoutNode, LayoutLink>(layoutLinks)\n .id(d => d.id)\n .distance(d => {\n const s = d.source as LayoutNode\n const t = d.target as LayoutNode\n // Deeper nodes cluster closer\n return 80 + (Math.abs(s.depth - t.depth) * 20)\n })\n .strength(0.4)\n )\n .force('charge', forceManyBody().strength(chargeStrength))\n .force('center', forceCenter(0, 0))\n .force('collide', forceCollide<LayoutNode>().radius(collisionPadding))\n .on('tick', () => {\n const positions = this._collectPositions(layoutNodes)\n emit(positions)\n })\n .on('end', () => {\n const positions = this._collectPositions(layoutNodes)\n options.onEnd?.(positions)\n })\n }\n\n stop(): void {\n this._simulation?.stop()\n this._simulation = null\n }\n\n reheat(): void {\n this._simulation?.alpha(0.3).restart()\n }\n\n private _collectPositions(nodes: LayoutNode[]): Map<string, Position> {\n const positions = new Map<string, Position>()\n for (const n of nodes) {\n positions.set(n.id, { x: n.x, y: n.y })\n }\n return positions\n }\n}\n","import type { Theme } from '../types/index.js'\n\nexport const defaultTheme: Theme = {\n background: '#050a1a',\n node: {\n color: '#4a9eff',\n glowColor: '#4a9eff',\n glowRadius: 12,\n size: 8,\n shape: 'circle',\n opacity: 1,\n labelColor: '#c8d8f0',\n labelSize: 12,\n labelFont: 'system-ui, sans-serif',\n },\n edge: {\n color: '#1e3a5f',\n width: 1.5,\n opacity: 0.6,\n animated: false,\n },\n states: {\n default: {},\n active: {\n color: '#7fcdff',\n glowColor: '#7fcdff',\n glowRadius: 20,\n },\n locked: {\n color: '#2a3a4a',\n glowColor: '#2a3a4a',\n glowRadius: 4,\n opacity: 0.5,\n labelColor: '#4a5a6a',\n },\n unlocked: {\n color: '#50fa7b',\n glowColor: '#50fa7b',\n glowRadius: 16,\n },\n highlighted: {\n color: '#ffb86c',\n glowColor: '#ffb86c',\n glowRadius: 24,\n },\n },\n}\n","import type { Theme, ThemeInput } from '../types/index.js'\nimport { defaultTheme } from './default.js'\n\nexport function mergeTheme(overrides?: ThemeInput): Theme {\n if (!overrides) return defaultTheme\n\n return {\n background: overrides.background ?? defaultTheme.background,\n node: { ...defaultTheme.node, ...overrides.node },\n edge: { ...defaultTheme.edge, ...overrides.edge },\n states: {\n default: { ...defaultTheme.states.default, ...overrides.states?.['default'] },\n active: { ...defaultTheme.states.active, ...overrides.states?.active },\n locked: { ...defaultTheme.states.locked, ...overrides.states?.locked },\n unlocked: { ...defaultTheme.states.unlocked, ...overrides.states?.unlocked },\n highlighted: { ...defaultTheme.states.highlighted, ...overrides.states?.highlighted },\n },\n }\n}\n","import type {\n SkillNode,\n SkillEdge,\n NodeStyle,\n EdgeStyle,\n Theme,\n ThemeInput,\n Position,\n InternalNodeState,\n} from '../types/index.js'\nimport { mergeTheme } from '../theme/merge.js'\n\nexport interface RenderState {\n positions: Map<string, Position>\n internalStates: Map<string, InternalNodeState>\n contextFadeAlpha: number\n pan: Position\n zoom: number\n}\n\nexport const BUBBLE_WORLD_RADIUS = 40\n\n// ─── Background star field ────────────────────────────────────────────────────\n\ninterface BgStar {\n x: number // 0–1 normalized CSS position\n y: number\n r: number // base radius (CSS px)\n phase: number\n speed: number // twinkle speed (radians/sec)\n}\n\nfunction generateBgStars(count: number): BgStar[] {\n return Array.from({ length: count }, () => ({\n x: Math.random(),\n y: Math.random(),\n r: 0.4 + Math.random() * 1.2,\n phase: Math.random() * Math.PI * 2,\n speed: 0.4 + Math.random() * 1.2,\n }))\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/** Deterministic phase from a node id — avoids all nodes twinkling in sync. */\nfunction hashPhase(id: string): number {\n let h = 0\n for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) >>> 0\n return ((h % 1000) / 1000) * Math.PI * 2\n}\n\nexport class CanvasRenderer {\n private _canvas: HTMLCanvasElement\n private _ctx: CanvasRenderingContext2D\n private _theme: Theme\n private _dpr: number\n private _bgStars: BgStar[]\n\n // Burst animation state (entry)\n private _burst: { startTime: number; center: Position; color: string } | null = null\n private readonly _burstDuration = 450\n\n // Implode animation state (exit)\n private _implode: { startTime: number; center: Position } | null = null\n private readonly _implodeDuration = 420\n\n constructor(canvas: HTMLCanvasElement, theme?: ThemeInput) {\n this._canvas = canvas\n const ctx = canvas.getContext('2d')\n if (!ctx) throw new Error('Could not get 2D context from canvas')\n this._ctx = ctx\n this._theme = mergeTheme(theme)\n this._dpr = window.devicePixelRatio ?? 1\n this._bgStars = generateBgStars(150)\n this._resize()\n }\n\n get canvas(): HTMLCanvasElement { return this._canvas }\n\n get isBurstActive(): boolean { return this._burst !== null }\n\n /** Sync canvas physical pixel size to its CSS size. Call when the container resizes. */\n resize(): void { this._resize() }\n\n /** Returns the resolved fill color for a node (used for burst color matching). */\n resolveNodeColor(node: SkillNode): string {\n return this._resolveStyle(node).color\n }\n\n updateTheme(theme: ThemeInput): void {\n this._theme = mergeTheme(theme)\n }\n\n triggerBurst(centerCanvas: Position, color: string): void {\n this._burst = { startTime: performance.now(), center: centerCanvas, color }\n }\n\n triggerImplode(centerCanvas: Position): void {\n this._implode = { startTime: performance.now(), center: centerCanvas }\n }\n\n render(nodes: SkillNode[], edges: SkillEdge[], state: RenderState): void {\n const ctx = this._ctx\n const t = performance.now() / 1000 // seconds — drives all animations\n const { pan, zoom, contextFadeAlpha, positions, internalStates } = state\n\n const cssW = this._canvas.width / this._dpr\n const cssH = this._canvas.height / this._dpr\n\n // ── Background ───────────────────────────────────────────────────────────\n ctx.clearRect(0, 0, this._canvas.width, this._canvas.height)\n ctx.fillStyle = this._theme.background\n ctx.fillRect(0, 0, this._canvas.width, this._canvas.height)\n\n // ── DPR scale (all CSS-pixel drawing lives inside here) ──────────────────\n ctx.save()\n ctx.scale(this._dpr, this._dpr)\n\n // Background star field — screen space, doesn't pan/zoom\n this._renderBgStars(ctx, cssW, cssH, t)\n\n // ── World transform ───────────────────────────────────────────────────────\n ctx.save()\n ctx.translate(pan.x, pan.y)\n ctx.scale(zoom, zoom)\n\n // Edges (solid) + animated particles\n for (const edge of edges) {\n const sourcePos = positions.get(edge.source)\n const targetPos = positions.get(edge.target)\n if (!sourcePos || !targetPos) continue\n this._drawEdge(ctx, sourcePos, targetPos, edge.style)\n if (edge.style?.animated ?? this._theme.edge.animated) {\n this._renderEdgeParticles(ctx, sourcePos, targetPos, edge, t, zoom)\n }\n }\n\n // Parent-child connectors\n for (const node of nodes) {\n if (!node.parentId) continue\n const parentPos = positions.get(node.parentId)\n const childPos = positions.get(node.id)\n if (!parentPos || !childPos) continue\n ctx.save()\n ctx.globalAlpha = contextFadeAlpha * 0.35\n ctx.strokeStyle = this._theme.edge.color\n ctx.lineWidth = this._theme.edge.width / zoom\n ctx.setLineDash([4, 8])\n ctx.beginPath()\n ctx.moveTo(parentPos.x, parentPos.y)\n ctx.lineTo(childPos.x, childPos.y)\n ctx.stroke()\n ctx.restore()\n }\n\n // Nodes — bubbles first so stars sit on top\n const bubbles = nodes.filter(n => n.childIds && n.childIds.length > 0)\n const stars = nodes.filter(n => !n.childIds || n.childIds.length === 0)\n\n for (const node of [...bubbles, ...stars]) {\n const pos = positions.get(node.id)\n if (!pos) continue\n const internal = internalStates.get(node.id) ?? 'idle'\n const isBubble = !!(node.childIds && node.childIds.length > 0)\n this._drawNode(ctx, node, pos, internal, contextFadeAlpha, zoom, isBubble, t)\n }\n\n ctx.restore() // undo world transform\n ctx.restore() // undo DPR scale\n\n // Overlays — physical pixels, screen space\n this._renderBurst()\n this._renderImplode()\n }\n\n // ─── Background stars ─────────────────────────────────────────────────────\n\n private _renderBgStars(ctx: CanvasRenderingContext2D, w: number, h: number, t: number): void {\n for (const star of this._bgStars) {\n const brightness = 0.5 + 0.5 * Math.sin(t * star.speed + star.phase)\n const alpha = 0.08 + 0.25 * brightness\n const r = star.r * (0.7 + 0.3 * brightness)\n ctx.beginPath()\n ctx.arc(star.x * w, star.y * h, r, 0, Math.PI * 2)\n ctx.fillStyle = `rgba(255,255,255,${alpha.toFixed(3)})`\n ctx.fill()\n }\n }\n\n // ─── Node rendering ───────────────────────────────────────────────────────\n\n private _drawNode(\n ctx: CanvasRenderingContext2D,\n node: SkillNode,\n pos: Position,\n internal: InternalNodeState,\n alpha: number,\n zoom: number,\n isBubble: boolean,\n t: number,\n ): void {\n if (isBubble) {\n this._drawBubble(ctx, node, pos, internal, alpha, zoom, t)\n } else {\n this._drawStar(ctx, node, pos, internal, alpha, zoom, t)\n }\n }\n\n private _drawBubble(\n ctx: CanvasRenderingContext2D,\n node: SkillNode,\n pos: Position,\n internal: InternalNodeState,\n alpha: number,\n zoom: number,\n t: number,\n ): void {\n const style = this._resolveStyle(node)\n const phase = hashPhase(node.id)\n // Bubbles breathe very slowly; selected breathes a bit more\n const breatheAmp = internal === 'selected' ? 0.08 : 0.04\n const breathe = 1 + breatheAmp * Math.sin(t * 0.6 + phase)\n const r = BUBBLE_WORLD_RADIUS * breathe * (internal === 'hovered' ? 1.1 : 1)\n const isSelected = internal === 'selected'\n\n ctx.save()\n ctx.globalAlpha = style.opacity * alpha\n\n // Outer halo — brighter when selected\n const haloOuter = isSelected ? r * 2.8 : r * 2.2\n const haloStop0 = isSelected ? style.glowColor + '55' : style.glowColor + '30'\n const halo = ctx.createRadialGradient(pos.x, pos.y, r * 0.5, pos.x, pos.y, haloOuter)\n halo.addColorStop(0, haloStop0)\n halo.addColorStop(1, style.glowColor + '00')\n ctx.fillStyle = halo\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, haloOuter, 0, Math.PI * 2)\n ctx.fill()\n\n // Inner fill\n const fill = ctx.createRadialGradient(pos.x, pos.y - r * 0.3, r * 0.1, pos.x, pos.y, r)\n fill.addColorStop(0, style.color + (isSelected ? '70' : '50'))\n fill.addColorStop(1, style.color + (isSelected ? '28' : '18'))\n ctx.fillStyle = fill\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, r, 0, Math.PI * 2)\n ctx.fill()\n\n // Border ring\n ctx.strokeStyle = isSelected ? style.glowColor : style.color\n ctx.lineWidth = (isSelected ? 2.5 : 1.5) / zoom\n ctx.globalAlpha = style.opacity * alpha * (isSelected ? 1 : 0.7)\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, r, 0, Math.PI * 2)\n ctx.stroke()\n\n // Selected: spinning dashed outer ring\n if (isSelected) {\n const spinAngle = t * 0.7 + phase\n ctx.strokeStyle = style.glowColor\n ctx.lineWidth = 1.5 / zoom\n ctx.globalAlpha = style.opacity * alpha * 0.85\n ctx.setLineDash([10 / zoom, 7 / zoom])\n ctx.lineDashOffset = -spinAngle * 18\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, r * 1.3, 0, Math.PI * 2)\n ctx.stroke()\n ctx.setLineDash([])\n }\n\n // Child-count dots orbiting inside\n if (node.childIds && node.childIds.length > 0) {\n const count = Math.min(node.childIds.length, 8)\n const dotOrbit = r * 0.55\n const dotSize = Math.max(1.5, r * 0.06)\n const orbit = t * 0.15 + phase // slow rotation\n ctx.globalAlpha = style.opacity * alpha * 0.6\n ctx.fillStyle = style.color + '90'\n for (let i = 0; i < count; i++) {\n const angle = orbit + (i / count) * Math.PI * 2\n ctx.beginPath()\n ctx.arc(\n pos.x + dotOrbit * Math.cos(angle),\n pos.y + dotOrbit * Math.sin(angle),\n dotSize, 0, Math.PI * 2,\n )\n ctx.fill()\n }\n }\n\n // Label\n ctx.globalAlpha = style.opacity * alpha\n ctx.fillStyle = style.labelColor\n ctx.font = `bold ${(style.labelSize * 1.2) / zoom}px ${style.labelFont}`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.fillText(node.label, pos.x, pos.y)\n\n ctx.restore()\n }\n\n private _drawStar(\n ctx: CanvasRenderingContext2D,\n node: SkillNode,\n pos: Position,\n internal: InternalNodeState,\n alpha: number,\n zoom: number,\n t: number,\n ): void {\n const style = this._resolveStyle(node)\n const phase = hashPhase(node.id)\n // Two independent sine waves for a natural twinkle\n const isSelected = internal === 'selected'\n // Selected nodes twinkle more dramatically\n const twinkleAmp = isSelected ? 0.4 : 0.22\n const twinkle = 1 + twinkleAmp * Math.sin(t * 1.7 + phase)\n + 0.08 * Math.sin(t * 3.1 + phase * 1.3)\n const glowPulse = style.glowRadius * twinkle\n const size = style.size * (internal === 'hovered' ? 1.4 : 1)\n\n ctx.save()\n ctx.globalAlpha = style.opacity * alpha\n\n // Selected: pulsing rings that radiate outward and fade\n if (isSelected) {\n const ringPeriod = 1.8\n for (let i = 0; i < 2; i++) {\n const offset = i * (ringPeriod / 2)\n const pulse = ((t + offset) % ringPeriod) / ringPeriod // 0→1\n const pulseR = (size + glowPulse * 0.6) * (1 + pulse * 2.2)\n const ringAlpha = (1 - pulse) * 0.6\n ctx.strokeStyle = style.glowColor\n ctx.lineWidth = (1.5 / zoom) * (1 - pulse * 0.5)\n ctx.globalAlpha = ringAlpha * style.opacity * alpha\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, pulseR, 0, Math.PI * 2)\n ctx.stroke()\n }\n ctx.globalAlpha = style.opacity * alpha\n }\n\n // Glow\n if (glowPulse > 0) {\n const grad = ctx.createRadialGradient(pos.x, pos.y, 0, pos.x, pos.y, glowPulse + size)\n grad.addColorStop(0, style.glowColor + (isSelected ? 'ff' : 'cc'))\n grad.addColorStop(0.4, style.glowColor + (isSelected ? '88' : '55'))\n grad.addColorStop(1, style.glowColor + '00')\n ctx.fillStyle = grad\n ctx.beginPath()\n ctx.arc(pos.x, pos.y, glowPulse + size, 0, Math.PI * 2)\n ctx.fill()\n }\n\n // Body\n ctx.fillStyle = isSelected ? style.glowColor : style.color\n ctx.beginPath()\n this._drawShape(ctx, pos, size, style.shape)\n ctx.fill()\n\n // Label\n if (size * zoom > 4) {\n ctx.fillStyle = style.labelColor\n ctx.font = `${style.labelSize / zoom}px ${style.labelFont}`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'top'\n ctx.fillText(node.label, pos.x, pos.y + size + 4 / zoom)\n }\n\n ctx.restore()\n }\n\n // ─── Edge particles ───────────────────────────────────────────────────────\n\n private _renderEdgeParticles(\n ctx: CanvasRenderingContext2D,\n from: Position,\n to: Position,\n edge: SkillEdge,\n t: number,\n zoom: number,\n ): void {\n const dx = to.x - from.x\n const dy = to.y - from.y\n const len = Math.sqrt(dx * dx + dy * dy)\n if (len < 1) return\n\n const particleCount = 3\n const speed = 0.2 // edge traversals per second\n const particleR = 2.5 / zoom\n const color = edge.style?.color ?? this._theme.edge.color\n\n for (let i = 0; i < particleCount; i++) {\n const progress = ((t * speed + i / particleCount) % 1)\n const x = from.x + dx * progress\n const y = from.y + dy * progress\n const fade = Math.sin(progress * Math.PI) // fade at both ends\n\n ctx.save()\n ctx.globalAlpha = fade * 0.85\n\n const grad = ctx.createRadialGradient(x, y, 0, x, y, particleR * 2.5)\n grad.addColorStop(0, color + 'ff')\n grad.addColorStop(0.4, color + '99')\n grad.addColorStop(1, color + '00')\n ctx.fillStyle = grad\n ctx.beginPath()\n ctx.arc(x, y, particleR * 2.5, 0, Math.PI * 2)\n ctx.fill()\n\n ctx.restore()\n }\n }\n\n // ─── Burst animation ──────────────────────────────────────────────────────\n\n private _renderBurst(): void {\n if (!this._burst) return\n const ctx = this._ctx\n const elapsed = performance.now() - this._burst.startTime\n const t = elapsed / this._burstDuration\n if (t >= 1) { this._burst = null; return }\n\n const eased = 1 - Math.pow(1 - t, 3)\n const maxR = Math.hypot(this._canvas.width, this._canvas.height)\n const r = eased * maxR\n const alpha = (1 - eased) * 0.35\n\n ctx.save()\n ctx.globalAlpha = alpha\n ctx.fillStyle = this._burst.color\n ctx.beginPath()\n ctx.arc(\n this._burst.center.x * this._dpr,\n this._burst.center.y * this._dpr,\n r, 0, Math.PI * 2,\n )\n ctx.fill()\n ctx.restore()\n }\n\n // ─── Implode animation ────────────────────────────────────────────────────\n\n private _renderImplode(): void {\n if (!this._implode) return\n const ctx = this._ctx\n const elapsed = performance.now() - this._implode.startTime\n const t = elapsed / this._implodeDuration\n if (t >= 1) { this._implode = null; return }\n\n // Cubic ease-in: ring starts at full radius and slowly at first,\n // then accelerates sharply as it collapses to center\n const eased = t * t * t\n const maxR = Math.hypot(this._canvas.width, this._canvas.height)\n const r = (1 - eased) * maxR\n const alpha = (1 - t) * 0.55\n const lineWidth = (1 - eased) * 40 * this._dpr\n\n const cx = this._implode.center.x * this._dpr\n const cy = this._implode.center.y * this._dpr\n\n ctx.save()\n ctx.globalAlpha = alpha\n ctx.strokeStyle = '#9b5de5'\n ctx.lineWidth = lineWidth\n ctx.shadowColor = '#9b5de5'\n ctx.shadowBlur = 30 * this._dpr\n ctx.beginPath()\n ctx.arc(cx, cy, Math.max(0, r), 0, Math.PI * 2)\n ctx.stroke()\n ctx.restore()\n }\n\n // ─── Shapes ───────────────────────────────────────────────────────────────\n\n private _resolveStyle(node: SkillNode): NodeStyle {\n const base = this._theme.node\n const stateOverride = node.state ? this._theme.states[node.state] : {}\n const nodeOverride = node.style ?? {}\n return { ...base, ...stateOverride, ...nodeOverride }\n }\n\n private _drawShape(\n ctx: CanvasRenderingContext2D,\n pos: Position,\n size: number,\n shape: NodeStyle['shape'],\n ): void {\n switch (shape) {\n case 'circle':\n ctx.arc(pos.x, pos.y, size, 0, Math.PI * 2)\n break\n case 'hexagon':\n this._polygon(ctx, pos, size, 6, Math.PI / 6)\n break\n case 'diamond':\n this._polygon(ctx, pos, size, 4, 0)\n break\n case 'star':\n this._star(ctx, pos, size)\n break\n }\n }\n\n private _polygon(ctx: CanvasRenderingContext2D, pos: Position, r: number, sides: number, offset: number): void {\n ctx.moveTo(pos.x + r * Math.cos(offset), pos.y + r * Math.sin(offset))\n for (let i = 1; i < sides; i++) {\n const angle = offset + (i * 2 * Math.PI) / sides\n ctx.lineTo(pos.x + r * Math.cos(angle), pos.y + r * Math.sin(angle))\n }\n ctx.closePath()\n }\n\n private _star(ctx: CanvasRenderingContext2D, pos: Position, r: number): void {\n const inner = r * 0.4\n const points = 5\n for (let i = 0; i < points * 2; i++) {\n const angle = (i * Math.PI) / points - Math.PI / 2\n const radius = i % 2 === 0 ? r : inner\n const x = pos.x + radius * Math.cos(angle)\n const y = pos.y + radius * Math.sin(angle)\n i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)\n }\n ctx.closePath()\n }\n\n private _drawEdge(\n ctx: CanvasRenderingContext2D,\n from: Position,\n to: Position,\n styleOverride?: Partial<EdgeStyle>,\n ): void {\n const style = { ...this._theme.edge, ...styleOverride }\n ctx.save()\n ctx.strokeStyle = style.color\n ctx.lineWidth = style.width\n ctx.globalAlpha = style.opacity\n if (style.dashPattern) ctx.setLineDash(style.dashPattern)\n ctx.beginPath()\n ctx.moveTo(from.x, from.y)\n ctx.lineTo(to.x, to.y)\n ctx.stroke()\n ctx.restore()\n }\n\n private _resize(): void {\n const rect = this._canvas.getBoundingClientRect()\n const w = Math.floor(rect.width * this._dpr)\n const h = Math.floor(rect.height * this._dpr)\n if (this._canvas.width !== w || this._canvas.height !== h) {\n this._canvas.width = w\n this._canvas.height = h\n }\n }\n\n dispose(): void { /* nothing to clean up */ }\n}\n","import type { SkillNode, Position } from '../types/index.js'\nimport { BUBBLE_WORLD_RADIUS } from './CanvasRenderer.js'\n\nexport interface InteractionState {\n pan: Position\n zoom: number\n hoveredNodeId: string | null\n selectedNodeId: string | null\n}\n\nexport type InteractionEvent =\n | { type: 'node:click'; nodeId: string }\n | { type: 'node:hover'; nodeId: string }\n | { type: 'node:blur'; nodeId: string }\n | { type: 'canvas:click' }\n | { type: 'zoom:change'; zoom: number }\n | { type: 'pan:change'; pan: Position }\n\nexport class InteractionController {\n private _canvas: HTMLCanvasElement\n private _state: InteractionState\n private _isPanning = false\n private _lastPan: Position = { x: 0, y: 0 }\n private _listeners: Set<(event: InteractionEvent) => void> = new Set()\n private _nodes: SkillNode[] = []\n private _positions: Map<string, Position> = new Map()\n private _nodeSize = 8\n private _dpr: number\n\n // Smooth zoom (lerp)\n private _targetZoom: number = 1\n private _zoomAnchor: Position | null = null\n private readonly _zoomLerpAlpha = 0.14\n\n // Timed zoom — takes priority over lerp when active\n private _timedZoom: {\n startZoom: number\n target: number\n anchor: Position | null\n startTime: number\n duration: number\n easing: 'in' | 'out'\n } | null = null\n\n // Multi-touch tracking\n private _activePointers: Map<number, Position> = new Map()\n private _lastPinchDist: number | null = null\n // Separate from _lastPan (which is updated on every move) — used for drag vs click detection\n private _pointerDownPos: Position = { x: 0, y: 0 }\n\n private _onPointerDown: (e: PointerEvent) => void\n private _onPointerMove: (e: PointerEvent) => void\n private _onPointerUp: (e: PointerEvent) => void\n private _onPointerCancel: (e: PointerEvent) => void\n private _onWheel: (e: WheelEvent) => void\n\n constructor(canvas: HTMLCanvasElement) {\n this._canvas = canvas\n this._dpr = window.devicePixelRatio ?? 1\n this._state = {\n pan: { x: canvas.width / (2 * this._dpr), y: canvas.height / (2 * this._dpr) },\n zoom: 1,\n hoveredNodeId: null,\n selectedNodeId: null,\n }\n\n this._onPointerDown = this._handlePointerDown.bind(this)\n this._onPointerMove = this._handlePointerMove.bind(this)\n this._onPointerUp = this._handlePointerUp.bind(this)\n this._onPointerCancel = this._handlePointerCancel.bind(this)\n this._onWheel = this._handleWheel.bind(this)\n\n canvas.addEventListener('pointerdown', this._onPointerDown)\n canvas.addEventListener('pointermove', this._onPointerMove)\n canvas.addEventListener('pointerup', this._onPointerUp)\n canvas.addEventListener('pointercancel', this._onPointerCancel)\n canvas.addEventListener('wheel', this._onWheel, { passive: false })\n }\n\n get state(): Readonly<InteractionState> { return this._state }\n get targetZoom(): number { return this._targetZoom }\n get zoomAnchor(): Position | null { return this._zoomAnchor }\n\n setTargetZoom(value: number, anchor?: Position): void {\n this._timedZoom = null\n this._targetZoom = value\n if (anchor !== undefined) this._zoomAnchor = anchor\n }\n\n /**\n * Animate zoom to `target` over `duration` ms.\n * `easing: 'in'` — cubic ease-in (slow start, accelerates toward target).\n * `easing: 'out'` — cubic ease-out (fast start, decelerates toward target).\n */\n startTimedZoom(target: number, duration: number, anchor?: Position, easing: 'in' | 'out' = 'in'): void {\n this._timedZoom = {\n startZoom: this._state.zoom,\n target,\n anchor: anchor ?? null,\n startTime: performance.now(),\n duration,\n easing,\n }\n this._targetZoom = target\n this._zoomAnchor = anchor ?? null\n }\n\n /** Instantly snap zoom and pan to a new center — used on navigation transitions. */\n resetToCenter(zoom: number, cx: number, cy: number): void {\n this._timedZoom = null\n this._targetZoom = zoom\n this._state.zoom = zoom\n this._state.pan = { x: cx, y: cy }\n this._zoomAnchor = null\n }\n\n updateNodes(nodes: SkillNode[], positions: Map<string, Position>, nodeSize: number): void {\n this._nodes = nodes\n this._positions = positions\n this._nodeSize = nodeSize\n }\n\n onChange(listener: (event: InteractionEvent) => void): () => void {\n this._listeners.add(listener)\n return () => this._listeners.delete(listener)\n }\n\n /**\n * Advance zoom animation one frame. Called every RAF frame by the engine.\n * Returns true while the animation is still in progress.\n */\n tick(): boolean {\n const prevZoom = this._state.zoom\n\n if (this._timedZoom) {\n const { startZoom, target, anchor, startTime, duration, easing } = this._timedZoom\n const t = Math.min(1, (performance.now() - startTime) / duration)\n // ease-in: t³ — slow start, accelerates toward target\n // ease-out: 1-(1-t)³ — fast start, decelerates toward target\n const eased = easing === 'out' ? 1 - Math.pow(1 - t, 3) : t * t * t\n this._state.zoom = startZoom + (target - startZoom) * eased\n\n if (t >= 1) {\n this._timedZoom = null\n this._zoomAnchor = null\n } else {\n this._zoomAnchor = anchor\n }\n } else {\n // Fallback: standard lerp toward target\n const dz = this._targetZoom - this._state.zoom\n if (Math.abs(dz) < 0.0001) {\n this._zoomAnchor = null\n return false\n }\n this._state.zoom += dz * this._zoomLerpAlpha\n }\n\n // Keep the zoom anchor point fixed in world space\n if (this._zoomAnchor) {\n const { x: ax, y: ay } = this._zoomAnchor\n this._state.pan = {\n x: ax - (ax - this._state.pan.x) * (this._state.zoom / prevZoom),\n y: ay - (ay - this._state.pan.y) * (this._state.zoom / prevZoom),\n }\n }\n\n return true\n }\n\n dispose(): void {\n this._canvas.removeEventListener('pointerdown', this._onPointerDown)\n this._canvas.removeEventListener('pointermove', this._onPointerMove)\n this._canvas.removeEventListener('pointerup', this._onPointerUp)\n this._canvas.removeEventListener('pointercancel', this._onPointerCancel)\n this._canvas.removeEventListener('wheel', this._onWheel)\n }\n\n // ─── Canvas → world coordinate transform ────────────────────────────────────\n\n canvasToWorld(canvasX: number, canvasY: number): Position {\n return {\n x: (canvasX - this._state.pan.x) / this._state.zoom,\n y: (canvasY - this._state.pan.y) / this._state.zoom,\n }\n }\n\n private _getCanvasPos(e: MouseEvent): Position {\n const rect = this._canvas.getBoundingClientRect()\n return { x: e.clientX - rect.left, y: e.clientY - rect.top }\n }\n\n private _hitTest(worldPos: Position): string | null {\n let closest: string | null = null\n let closestDist = Infinity\n\n for (const node of this._nodes) {\n const pos = this._positions.get(node.id)\n if (!pos) continue\n const isBubble = !!(node.childIds && node.childIds.length > 0)\n // Bubbles: match visual radius. Stars: generous touch target covering label.\n const hitRadius = isBubble ? BUBBLE_WORLD_RADIUS * 1.3 : this._nodeSize * 4\n const dx = worldPos.x - pos.x\n const dy = worldPos.y - pos.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < hitRadius && dist < closestDist) {\n closestDist = dist\n closest = node.id\n }\n }\n return closest\n }\n\n private _emit(event: InteractionEvent): void {\n for (const listener of this._listeners) listener(event)\n }\n\n // ─── Pointer handlers ────────────────────────────────────────────────────────\n\n private _handlePointerDown(e: PointerEvent): void {\n this._canvas.setPointerCapture(e.pointerId)\n const pos = this._getCanvasPos(e)\n this._activePointers.set(e.pointerId, pos)\n\n if (this._activePointers.size === 1) {\n // Single pointer — prepare for pan or click\n this._isPanning = true\n this._lastPan = pos\n this._pointerDownPos = pos // fixed reference for drag vs click detection\n } else {\n // Second finger arrived — switch to pinch mode\n this._isPanning = false\n this._lastPinchDist = null\n }\n }\n\n private _handlePointerMove(e: PointerEvent): void {\n const canvasPos = this._getCanvasPos(e)\n this._activePointers.set(e.pointerId, canvasPos)\n\n // ── Pinch zoom (two fingers) ──────────────────────────────────────────────\n if (this._activePointers.size >= 2) {\n const pts = [...this._activePointers.values()]\n const dist = Math.hypot(pts[1]!.x - pts[0]!.x, pts[1]!.y - pts[0]!.y)\n\n if (this._lastPinchDist !== null && dist > 0) {\n const scale = dist / this._lastPinchDist\n const midX = (pts[0]!.x + pts[1]!.x) / 2\n const midY = (pts[0]!.y + pts[1]!.y) / 2\n this._targetZoom = Math.max(0.05, Math.min(20, this._targetZoom * scale))\n this._zoomAnchor = { x: midX, y: midY }\n this._emit({ type: 'zoom:change', zoom: this._targetZoom })\n }\n this._lastPinchDist = dist\n return\n }\n\n // ── Single-pointer pan ───────────────────────────────────────────────────\n if (this._isPanning) {\n const dx = canvasPos.x - this._lastPan.x\n const dy = canvasPos.y - this._lastPan.y\n this._lastPan = canvasPos\n this._state.pan = { x: this._state.pan.x + dx, y: this._state.pan.y + dy }\n this._emit({ type: 'pan:change', pan: this._state.pan })\n return\n }\n\n // ── Hover detection (mouse / stylus, not bare touch) ─────────────────────\n if (e.pointerType !== 'touch') {\n const worldPos = this.canvasToWorld(canvasPos.x, canvasPos.y)\n const hit = this._hitTest(worldPos)\n if (hit !== this._state.hoveredNodeId) {\n if (this._state.hoveredNodeId) {\n this._emit({ type: 'node:blur', nodeId: this._state.hoveredNodeId })\n }\n this._state.hoveredNodeId = hit\n if (hit) this._emit({ type: 'node:hover', nodeId: hit })\n }\n }\n }\n\n private _handlePointerUp(e: PointerEvent): void {\n const canvasPos = this._getCanvasPos(e)\n const wasMultiTouch = this._activePointers.size >= 2\n const dragOrigin = this._pointerDownPos // original down position, not the moving _lastPan\n this._activePointers.delete(e.pointerId)\n this._lastPinchDist = null\n\n if (wasMultiTouch) {\n // Came back to single touch — resume pan from current remaining finger\n if (this._activePointers.size === 1) {\n this._isPanning = true\n this._lastPan = [...this._activePointers.values()][0]!\n }\n return\n }\n\n this._isPanning = false\n\n // Fire click if pointer didn't travel (not a drag)\n const dx = Math.abs(canvasPos.x - dragOrigin.x)\n const dy = Math.abs(canvasPos.y - dragOrigin.y)\n if (dx < 4 && dy < 4) {\n const worldPos = this.canvasToWorld(canvasPos.x, canvasPos.y)\n const hit = this._hitTest(worldPos)\n if (hit) {\n this._state.selectedNodeId = hit === this._state.selectedNodeId ? null : hit\n this._emit({ type: 'node:click', nodeId: hit })\n } else {\n this._state.selectedNodeId = null\n this._emit({ type: 'canvas:click' })\n }\n }\n }\n\n private _handlePointerCancel(e: PointerEvent): void {\n this._activePointers.delete(e.pointerId)\n this._lastPinchDist = null\n if (this._activePointers.size === 0) {\n this._isPanning = false\n }\n }\n\n // ── Wheel (mouse / trackpad) ─────────────────────────────────────────────────\n\n private _handleWheel(e: WheelEvent): void {\n e.preventDefault()\n const canvasPos = this._getCanvasPos(e)\n const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1\n this._targetZoom = Math.max(0.05, Math.min(20, this._targetZoom * factor))\n this._zoomAnchor = canvasPos\n this._emit({ type: 'zoom:change', zoom: this._targetZoom })\n }\n}\n","import type {\n SkillGraph,\n SkillNode,\n SkillEdge,\n NodeState,\n Evidence,\n ThemeInput,\n LodThreshold,\n SkillTreeEvents,\n InternalNodeState,\n Position,\n NavigationFrame,\n} from './types/index.js'\nimport { SkillGraphModel } from './graph/SkillGraphModel.js'\nimport { NavigationController } from './graph/NavigationController.js'\nimport { LodController } from './lod/LodController.js'\nimport { ForceLayout } from './layout/ForceLayout.js'\nimport { CanvasRenderer, BUBBLE_WORLD_RADIUS } from './renderer/CanvasRenderer.js'\nimport { InteractionController } from './renderer/InteractionController.js'\n\nconst ENTER_ZOOM_THRESHOLD = 2.5 // zoom target must exceed this to enter a bubble\nconst EXIT_ZOOM_THRESHOLD = 0.35 // zoom target must drop below this to exit context\nconst NAV_COOLDOWN_MS = 700 // prevent rapid enter/exit toggling\n\nexport interface SkillTreeEngineOptions {\n canvas: HTMLCanvasElement\n data: SkillGraph\n theme?: ThemeInput\n lod?: LodThreshold[]\n on?: Partial<SkillTreeEvents>\n /** Silently start inside this bubble node's context — no burst or fade animation */\n initialContextNodeId?: string\n}\n\nexport class SkillTreeEngine {\n private _model: SkillGraphModel\n private _nav: NavigationController\n private _lod: LodController\n private _layout: ForceLayout\n private _renderer: CanvasRenderer\n private _interaction: InteractionController\n private _positions: Map<string, Position> = new Map()\n private _internalStates: Map<string, InternalNodeState> = new Map()\n private _eventHandlers: Partial<SkillTreeEvents>\n private _rafId: number | null = null\n private _pendingEnter: ReturnType<typeof setTimeout> | null = null\n private _pendingExit: ReturnType<typeof setTimeout> | null = null\n private _unsubscribers: Array<() => void> = []\n private _resizeObserver: ResizeObserver\n\n // Cached visible node/edge lists — rebuilt on navigation and model changes\n private _visibleNodes: SkillNode[] = []\n private _visibleEdges: SkillEdge[] = []\n\n // Context fade-in\n private _contextFadeAlpha = 1.0\n private _contextFadeStart = 0\n private readonly _contextFadeDuration = 400\n\n // Navigation cooldown\n private _navCooldownUntil = 0\n\n constructor(options: SkillTreeEngineOptions) {\n const { canvas, data, theme, lod, on = {} } = options\n\n this._eventHandlers = on\n this._model = new SkillGraphModel(data)\n this._nav = new NavigationController({ nodeId: null, label: data.label })\n this._lod = new LodController(lod)\n this._layout = new ForceLayout()\n this._renderer = new CanvasRenderer(canvas, theme ?? data.theme)\n this._interaction = new InteractionController(canvas)\n\n if (options.initialContextNodeId) {\n const initNode = this._model.getNode(options.initialContextNodeId)\n if (initNode && this._isBubble(initNode)) {\n this._nav.push({ nodeId: initNode.id, label: initNode.label })\n }\n }\n\n this._rebuildVisibleCache()\n this._wireEvents()\n this._runLayout()\n this._startRenderLoop()\n\n this._resizeObserver = new ResizeObserver(() => {\n this._renderer.resize()\n this._runLayout()\n })\n this._resizeObserver.observe(canvas)\n\n this._eventHandlers['graph:ready']?.(data)\n }\n\n // ─── Public API ─────────────────────────────────────────────────────────────\n\n setNodeState(nodeId: string, state: NodeState): void {\n this._model.setNodeState(nodeId, state)\n }\n\n addEvidence(nodeId: string, evidence: Evidence): void {\n this._model.addEvidence(nodeId, evidence)\n }\n\n removeEvidence(nodeId: string, evidenceId: string): void {\n this._model.removeEvidence(nodeId, evidenceId)\n }\n\n updateTheme(theme: ThemeInput): void {\n this._renderer.updateTheme(theme)\n }\n\n zoomIn(): void {\n this._interaction.setTargetZoom(Math.min(20, this._interaction.targetZoom * 1.3))\n }\n\n zoomOut(): void {\n this._interaction.setTargetZoom(Math.max(0.05, this._interaction.targetZoom / 1.3))\n }\n\n goBack(): void {\n if (this._nav.canGoBack) this._exitWithAnimation()\n }\n\n /**\n * Atomically jump to a specific nav stack depth, firing a single animation.\n * `targetLength` is the desired `stack.length` after the jump.\n * Silently pops intermediate frames; plays one implode + fade transition.\n */\n jumpToNavDepth(targetLength: number): void {\n if (this._nav.stack.length <= targetLength) return\n\n // Cancel any in-flight transitions\n if (this._pendingEnter !== null) { clearTimeout(this._pendingEnter); this._pendingEnter = null }\n if (this._pendingExit !== null) { clearTimeout(this._pendingExit); this._pendingExit = null }\n\n // Silently pop all excess frames; capture the last one for the event\n let lastPopped: NavigationFrame | undefined\n while (this._nav.stack.length > targetLength && this._nav.canGoBack) {\n lastPopped = this._nav.pop()\n }\n if (!lastPopped) return\n\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n const center = { x: rect.width / 2, y: rect.height / 2 }\n\n this._navCooldownUntil = Date.now() + NAV_COOLDOWN_MS\n this._rebuildVisibleCache()\n this._renderer.triggerImplode(center)\n this._interaction.resetToCenter(1.0, center.x, center.y)\n this._lod.setZoom(1.0)\n\n for (const n of this._visibleNodes) {\n this._positions.set(n.id, { x: (Math.random() - 0.5) * 80, y: (Math.random() - 0.5) * 80 })\n }\n\n this._contextFadeAlpha = 0\n this._contextFadeStart = performance.now()\n this._runLayout()\n this._eventHandlers['context:exit']?.(lastPopped, this._nav.stack)\n }\n\n private _exitWithAnimation(): void {\n if (!this._nav.canGoBack) return\n\n // Cancel any pending enter transition\n if (this._pendingEnter !== null) {\n clearTimeout(this._pendingEnter)\n this._pendingEnter = null\n }\n\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n const center = { x: rect.width / 2, y: rect.height / 2 }\n const duration = 480\n\n // Ease-out: camera pulls back fast, then settles\n this._interaction.startTimedZoom(0.45, duration, undefined, 'out')\n\n this._pendingExit = setTimeout(() => {\n this._pendingExit = null\n this._renderer.triggerImplode(center)\n this._exitContext()\n }, duration)\n }\n\n enterContext(nodeId: string): void {\n const node = this._model.getNode(nodeId)\n if (!node || !this._isBubble(node)) return\n\n // Cancel any previous pending transition\n if (this._pendingEnter !== null) {\n clearTimeout(this._pendingEnter)\n this._pendingEnter = null\n }\n\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n const burstPos = { x: rect.width / 2, y: rect.height / 2 }\n\n // Cubic ease-in zoom toward the node, then transition exactly when it peaks\n const nodePos = this._positions.get(nodeId)\n const anchor = nodePos ? (() => {\n const { zoom, pan } = this._interaction.state\n return { x: nodePos.x * zoom + pan.x, y: nodePos.y * zoom + pan.y }\n })() : undefined\n\n const duration = 480\n this._interaction.startTimedZoom(2.5, duration, anchor)\n\n this._pendingEnter = setTimeout(() => {\n this._pendingEnter = null\n this._enterContext(node, burstPos)\n }, duration)\n }\n\n getGraph(): SkillGraph { return this._model.toJSON() }\n\n getNavigationStack(): readonly NavigationFrame[] { return this._nav.stack }\n\n dispose(): void {\n if (this._rafId !== null) cancelAnimationFrame(this._rafId)\n if (this._pendingEnter !== null) clearTimeout(this._pendingEnter)\n if (this._pendingExit !== null) clearTimeout(this._pendingExit)\n this._resizeObserver.disconnect()\n this._layout.stop()\n this._renderer.dispose()\n this._interaction.dispose()\n for (const unsub of this._unsubscribers) unsub()\n }\n\n // ─── Visible node cache ──────────────────────────────────────────────────────\n\n private _rebuildVisibleCache(): void {\n const currentId = this._nav.current.nodeId\n this._visibleNodes = this._model.getNodes().filter(n =>\n currentId === null ? !n.parentId : n.parentId === currentId\n )\n const ids = new Set(this._visibleNodes.map(n => n.id))\n this._visibleEdges = this._model.getEdges().filter(\n e => ids.has(e.source) && ids.has(e.target)\n )\n }\n\n // ─── Navigation ─────────────────────────────────────────────────────────────\n\n private _isBubble(node: SkillNode): boolean {\n return !!(node.childIds && node.childIds.length > 0)\n }\n\n private _enterContext(node: SkillNode, burstCanvasPos: Position): void {\n this._nav.push({ nodeId: node.id, label: node.label })\n this._navCooldownUntil = Date.now() + NAV_COOLDOWN_MS\n this._rebuildVisibleCache()\n\n this._renderer.triggerBurst(burstCanvasPos, this._renderer.resolveNodeColor(node))\n\n // Reset zoom/pan to center\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n this._interaction.resetToCenter(1.0, rect.width / 2, rect.height / 2)\n this._lod.setZoom(1.0)\n\n // Seed visible nodes near world origin\n for (const n of this._visibleNodes) {\n this._positions.set(n.id, {\n x: (Math.random() - 0.5) * 80,\n y: (Math.random() - 0.5) * 80,\n })\n }\n\n this._contextFadeAlpha = 0\n this._contextFadeStart = performance.now()\n\n this._runLayout()\n this._eventHandlers['context:enter']?.(node, this._nav.stack)\n }\n\n private _exitContext(): void {\n const exited = this._nav.pop()\n if (!exited) return\n this._navCooldownUntil = Date.now() + NAV_COOLDOWN_MS\n this._rebuildVisibleCache()\n\n const canvas = this._renderer.canvas\n const rect = canvas.getBoundingClientRect()\n this._interaction.resetToCenter(1.0, rect.width / 2, rect.height / 2)\n this._lod.setZoom(1.0)\n\n for (const n of this._visibleNodes) {\n this._positions.set(n.id, {\n x: (Math.random() - 0.5) * 80,\n y: (Math.random() - 0.5) * 80,\n })\n }\n\n this._contextFadeAlpha = 0\n this._contextFadeStart = performance.now()\n\n this._runLayout()\n this._eventHandlers['context:exit']?.(exited, this._nav.stack)\n }\n\n private _checkNavigation(): void {\n if (Date.now() < this._navCooldownUntil) return\n\n const targetZoom = this._interaction.targetZoom\n const anchor = this._interaction.zoomAnchor\n\n if (targetZoom > ENTER_ZOOM_THRESHOLD && anchor) {\n const { zoom, pan } = this._interaction.state\n const bubble = this._findBubbleAtCanvas(anchor, pan, zoom)\n if (bubble) {\n this._enterContext(bubble, anchor)\n return\n }\n }\n\n if (targetZoom < EXIT_ZOOM_THRESHOLD && this._nav.canGoBack) {\n this._exitContext()\n }\n }\n\n private _findBubbleAtCanvas(canvasPos: Position, pan: Position, zoom: number): SkillNode | null {\n const worldX = (canvasPos.x - pan.x) / zoom\n const worldY = (canvasPos.y - pan.y) / zoom\n\n for (const node of this._visibleNodes) {\n if (!this._isBubble(node)) continue\n const pos = this._positions.get(node.id)\n if (!pos) continue\n const dx = worldX - pos.x\n const dy = worldY - pos.y\n if (Math.sqrt(dx * dx + dy * dy) <= BUBBLE_WORLD_RADIUS * 1.3) {\n return node\n }\n }\n return null\n }\n\n // ─── Events ─────────────────────────────────────────────────────────────────\n\n private _wireEvents(): void {\n this._unsubscribers.push(\n this._model.on('changed', () => {\n this._rebuildVisibleCache()\n })\n )\n\n this._unsubscribers.push(\n this._interaction.onChange(event => {\n switch (event.type) {\n case 'zoom:change':\n case 'pan:change':\n break\n case 'node:hover': {\n this._internalStates.set(event.nodeId, 'hovered')\n const node = this._model.getNode(event.nodeId)\n if (node) this._eventHandlers['node:hover']?.(node)\n break\n }\n case 'node:blur': {\n const prev = this._internalStates.get(event.nodeId)\n if (prev === 'hovered') this._internalStates.set(event.nodeId, 'idle')\n const node = this._model.getNode(event.nodeId)\n if (node) this._eventHandlers['node:blur']?.(node)\n break\n }\n case 'canvas:click': {\n // Clear any selected node\n for (const [id, s] of this._internalStates) {\n if (s === 'selected') this._internalStates.set(id, 'idle')\n }\n this._eventHandlers['canvas:click']?.()\n break\n }\n\n case 'node:click': {\n const node = this._model.getNode(event.nodeId)\n if (!node) break\n\n // Toggle selection internal state for all nodes\n const prev = this._internalStates.get(event.nodeId)\n const isSelected = prev === 'selected'\n if (isSelected) {\n this._internalStates.set(event.nodeId, 'idle')\n } else {\n for (const [id, s] of this._internalStates) {\n if (s === 'selected') this._internalStates.set(id, 'idle')\n }\n this._internalStates.set(event.nodeId, 'selected')\n }\n\n this._eventHandlers['node:click']?.(node)\n break\n }\n }\n })\n )\n }\n\n // ─── Layout ─────────────────────────────────────────────────────────────────\n\n private _runLayout(): void {\n const rect = this._renderer.canvas.getBoundingClientRect()\n\n this._layout.run(this._visibleNodes, this._visibleEdges, {\n width: rect.width || 800,\n height: rect.height || 600,\n onTick: positions => {\n for (const [id, pos] of positions) this._positions.set(id, pos)\n this._interaction.updateNodes(this._visibleNodes, this._positions, 8)\n },\n })\n }\n\n // ─── Render loop ────────────────────────────────────────────────────────────\n\n private _startRenderLoop(): void {\n const loop = () => {\n const zooming = this._interaction.tick()\n if (zooming) {\n const z = this._interaction.state.zoom\n this._lod.setZoom(z)\n this._eventHandlers['zoom:change']?.(z)\n }\n\n if (this._contextFadeAlpha < 1) {\n const elapsed = performance.now() - this._contextFadeStart\n this._contextFadeAlpha = Math.min(1, elapsed / this._contextFadeDuration)\n }\n\n this._checkNavigation()\n this._draw()\n\n this._rafId = requestAnimationFrame(loop)\n }\n this._rafId = requestAnimationFrame(loop)\n }\n\n private _draw(): void {\n const { pan, zoom } = this._interaction.state\n\n this._renderer.render(this._visibleNodes, this._visibleEdges, {\n positions: this._positions,\n internalStates: this._internalStates,\n contextFadeAlpha: this._contextFadeAlpha,\n pan,\n zoom,\n })\n }\n}\n"],"names":["SkillGraphModel","data","__publicField","Graph","node","edge","id","nodeId","child","depth","n","state","edgeId","evidence","existing","evidenceId","e","result","event","listener","set","payload","listeners","NavigationController","root","frame","popped","l","DEFAULT_THRESHOLDS","LodController","thresholds","zoom","ForceLayout","nodes","edges","options","width","height","chargeStrength","collisionPadding","alphaDecay","layoutNodes","_a","_b","nodeIndex","layoutLinks","source","target","emit","positions","forceSimulation","forceLink","d","s","t","forceManyBody","forceCenter","forceCollide","defaultTheme","mergeTheme","overrides","_c","_d","_e","BUBBLE_WORLD_RADIUS","generateBgStars","count","hashPhase","h","i","CanvasRenderer","canvas","theme","ctx","centerCanvas","color","pan","contextFadeAlpha","internalStates","cssW","cssH","sourcePos","targetPos","parentPos","childPos","bubbles","stars","pos","internal","isBubble","w","star","brightness","alpha","r","style","phase","breathe","isSelected","haloOuter","haloStop0","halo","fill","spinAngle","dotOrbit","dotSize","orbit","angle","twinkle","glowPulse","size","offset","pulse","pulseR","ringAlpha","grad","from","to","dx","dy","particleCount","speed","particleR","progress","x","y","fade","eased","maxR","lineWidth","cx","cy","base","stateOverride","nodeOverride","shape","sides","inner","points","radius","styleOverride","rect","InteractionController","value","anchor","duration","easing","nodeSize","prevZoom","startZoom","startTime","dz","ax","ay","canvasX","canvasY","worldPos","closest","closestDist","hitRadius","dist","canvasPos","pts","scale","midX","midY","hit","wasMultiTouch","dragOrigin","factor","ENTER_ZOOM_THRESHOLD","EXIT_ZOOM_THRESHOLD","NAV_COOLDOWN_MS","SkillTreeEngine","lod","on","initNode","targetLength","lastPopped","center","burstPos","nodePos","unsub","currentId","ids","burstCanvasPos","exited","targetZoom","bubble","worldX","worldY","_f","_h","_g","loop","z","elapsed"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expertrees/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Framework-agnostic hierarchical knowledge graph engine — canvas renderer, force layout, and interaction controller",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,11 +14,25 @@
|
|
|
14
14
|
"require": "./dist/index.cjs"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
|
-
"files": [
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/0xMack/expertrees.git",
|
|
24
|
+
"directory": "packages/core"
|
|
25
|
+
},
|
|
18
26
|
"publishConfig": {
|
|
19
27
|
"access": "public"
|
|
20
28
|
},
|
|
21
|
-
"keywords": [
|
|
29
|
+
"keywords": [
|
|
30
|
+
"knowledge-graph",
|
|
31
|
+
"skill-tree",
|
|
32
|
+
"canvas",
|
|
33
|
+
"force-layout",
|
|
34
|
+
"visualization"
|
|
35
|
+
],
|
|
22
36
|
"scripts": {
|
|
23
37
|
"build": "vite build",
|
|
24
38
|
"dev": "vite build --watch",
|