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 {