diff --git a/modules/rflows/components/folk-flow-river.ts b/modules/rflows/components/folk-flow-river.ts index 6fb49137..2f69e263 100644 --- a/modules/rflows/components/folk-flow-river.ts +++ b/modules/rflows/components/folk-flow-river.ts @@ -382,7 +382,10 @@ class FolkFlowRiver extends HTMLElement { private shadow: ShadowRoot; private nodes: FlowNode[] = []; private simulating = false; + private looping = false; private simTimer: ReturnType | null = null; + private initialNodes: FlowNode[] | null = null; + private steadyCount = 0; private dragging = false; private dragStartX = 0; private dragStartY = 0; @@ -430,14 +433,51 @@ class FolkFlowRiver extends HTMLElement { private startSimulation() { if (this.simTimer) return; + // Snapshot initial state for loop reset + if (!this.initialNodes) { + this.initialNodes = this.nodes.map(n => ({ ...n, data: { ...n.data } })); + } + this.steadyCount = 0; this.simTimer = setInterval(() => { + const prev = this.nodes; this.nodes = simulateTick(this.nodes, DEFAULT_CONFIG); + + // Detect steady state: check if values stopped changing + let changed = false; + for (let i = 0; i < this.nodes.length; i++) { + const a = prev[i].data as Record; + const b = this.nodes[i].data as Record; + if (a.currentValue !== b.currentValue || a.fundingReceived !== b.fundingReceived) { + changed = true; + break; + } + } + if (!changed) this.steadyCount++; + else this.steadyCount = 0; + this.render(); + + // If looping and steady for 3 ticks, reset after a brief pause + if (this.looping && this.steadyCount >= 3 && this.initialNodes) { + this.stopSimulation(); + setTimeout(() => { + if (!this.looping) return; + this.nodes = this.initialNodes!.map(n => ({ ...n, data: { ...n.data } })); + this.render(); + setTimeout(() => { + if (!this.looping) return; + this.simulating = true; + this.startSimulation(); + this.render(); + }, 500); + }, 1500); + } }, 500); } private stopSimulation() { if (this.simTimer) { clearInterval(this.simTimer); this.simTimer = null; } + this.simulating = false; } private showAmountPopover(sourceId: string, anchorX: number, anchorY: number) { @@ -535,6 +575,7 @@ class FolkFlowRiver extends HTMLElement {
+
Inflow
@@ -551,6 +592,19 @@ class FolkFlowRiver extends HTMLElement { this.render(); }); + // Event: toggle loop + this.shadow.querySelector("[data-action=toggle-loop]")?.addEventListener("click", () => { + this.looping = !this.looping; + if (this.looping && !this.simulating) { + // Auto-start simulation when enabling loop + this.initialNodes = null; // fresh snapshot + this.simulating = true; + this.startSimulation(); + } + if (!this.looping) this.initialNodes = null; + this.render(); + }); + // Event delegation for interactive elements + drag-to-pan const container = this.shadow.querySelector(".container") as HTMLElement; if (!container) return;