From d240fa1f3e6d06ce9968938352f7a985ff4aa7fb Mon Sep 17 00:00:00 2001 From: stroblme Date: Sun, 23 Aug 2026 06:21:26 +0200 Subject: [PATCH] Brain view: slower edge falloff, chase arc in the neuron's gap --brain-decay 90s -> 150s and the wire floor 32% -> 16%, so a quiet connection dims further and takes longer doing it. The pulse ring's inset and band become custom properties (defaults unchanged for the editor's card), and the neuron passes its own ring and gap so the arc runs the full width of the gap; it moves after the disc, which otherwise paints over it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016ZeGnqVsf5VHQqvz4HdUhN --- frontend/src/components/Flow/BrainNode.tsx | 37 ++++++++++++++++------ frontend/src/components/Flow/flow.css | 12 ++++--- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/Flow/BrainNode.tsx b/frontend/src/components/Flow/BrainNode.tsx index 7645435..231a8b9 100644 --- a/frontend/src/components/Flow/BrainNode.tsx +++ b/frontend/src/components/Flow/BrainNode.tsx @@ -1,5 +1,5 @@ import { Handle, type NodeProps, Position } from "@xyflow/react" -import { memo, useEffect, useRef, useState } from "react" +import { type CSSProperties, memo, useEffect, useRef, useState } from "react" import { duration } from "@/lib/motion" import { cn } from "@/lib/utils" @@ -72,14 +72,16 @@ function BrainNodeComponent({ data }: NodeProps) { return () => clearTimeout(timer) }, [emits]) + // The neuron's two bands in pixels: the ring, and the gap the arc runs in. + const ring = Math.round(size * RING) + const gap = Math.round(size * GAP) + return ( - // The pulse ring measures itself from here rather than from the neuron, so - // the thick status ring stays clear of it — see `.node-pulse` in flow.css. + // The pulse ring measures itself from here rather than from the neuron: + // `inset` on an absolute child resolves against the padding box, so an arc + // measured from the neuron would start inside its border rather than at the + // rim — see `.node-pulse` in flow.css. - {/* Remounting on each emit is what restarts the animation, so this is - gated on the pulse rather than on the count: a neuron mounting with a - count already in the store would otherwise play it once for free. */} - {firing ? : null} @@ -153,6 +155,23 @@ function BrainNodeComponent({ data }: NodeProps) { ) : null} + {/* Remounting on each emit is what restarts the animation, so this is + gated on the pulse rather than on the count: a neuron mounting with a + count already in the store would otherwise play it once for free. + After the neuron rather than before it: the arc runs in the gap the + neuron paints, and an earlier sibling would be painted over. */} + {firing ? ( + + ) : null} ) } diff --git a/frontend/src/components/Flow/flow.css b/frontend/src/components/Flow/flow.css index a20575c..faef60b 100644 --- a/frontend/src/components/Flow/flow.css +++ b/frontend/src/components/Flow/flow.css @@ -133,13 +133,15 @@ * is what lets one rule fit both a rounded card and a circle. * * The band is the padding: the content box is cut back out of the mask, which - * leaves a ring rather than the filled shape the gradient paints. + * leaves a ring rather than the filled shape the gradient paints. Both are + * overridable, for a node whose own bands say where the arc belongs — the + * brain's neuron runs it in the gap between its ring and its disc. */ .node-pulse { position: absolute; - inset: -4px; + inset: var(--node-pulse-inset, -4px); border-radius: inherit; - padding: 2px; + padding: var(--node-pulse-band, 2px); pointer-events: none; background: conic-gradient( from var(--node-pulse-angle), @@ -243,7 +245,7 @@ */ .react-flow.brain-flat { --xy-background-color: transparent; - --brain-decay: 90s; + --brain-decay: 150s; /* * Thicker than the editor's, to match the weight the mark draws them at — and * the pulse widens with it, or a message would leave its edge looking thinner @@ -381,7 +383,7 @@ * from another. */ .brain-wire { - --brain-ink: color-mix(in srgb, var(--foreground) 32%, transparent); + --brain-ink: color-mix(in srgb, var(--foreground) 16%, transparent); } .brain-wire.brain-idle {