Transition map beads: connector-colored elongated pulses

Beads now take their connector's color — accent for internal links,
plain text color for external ones (matching the tconn-exit styling) —
and render as an elongated pulse along the direction of travel instead
of a plain dot: a rounded capsule with a gradient-faded tail, rotated
to the edge's angle (cached per flow). Flow objects carry an 'external'
tag from buildFlows; the gradients live in the svg defs with stop
colors resolved from CSS so theme variables apply.
This commit is contained in:
LeoVasanko committed 2026-09-25 20:23:20 +00:00
1 parent fb2914d853
commit 3c9ef04ffd
3 files changed
+52 -12

No files matched your search

+11 -6
View File
@@ -149,8 +149,10 @@ const MIN_WMID = 0.4
// from real time to keep the animation lightweight. The component
// simulates every bead independently in JS with a constant traversal
// time per edge (speed relative to span length), with no limit on beads
// in flight.
// in flight. A bead renders as an elongated pulse trailing its direction
// of travel: BEAD_R is its half-thickness, BEAD_LEN its full length.
export const BEAD_R = 3.2
export const BEAD_LEN = BEAD_R * 5.5
const BEAD_RATE = 0.0084 // beads per second per hit/day
const FLOW_OFFSET = 3 // lane offset to the right of the travel direction
@@ -638,10 +640,12 @@ function buildRibbon(a, b, ab, ba, wMid, external = false) {
* at the surround), plus the emission interval (seconds between beads,
* inverse of the daily hit rate * BEAD_RATE). Each segment is offset to the
* right-hand side of its travel direction, so opposing flows on the same
* edge run on parallel lanes instead of colliding. The component turns
* these into independently simulated beads.
* edge run on parallel lanes instead of colliding. `external` tags flows on
* external-link edges so the component can render their beads in the
* connector color (the exit/source connectors use --text, not --accent).
* The component turns these into independently simulated beads.
*/
function buildFlows(a, b, ab, ba, dayScale = 1) {
function buildFlows(a, b, ab, ba, dayScale = 1, external = false) {
const len = Math.hypot(b.x - a.x, b.y - a.y) || 1
const ux = (b.x - a.x) / len
const uy = (b.y - a.y) / len
@@ -665,6 +669,7 @@ function buildFlows(a, b, ab, ba, dayScale = 1) {
y2: a.y + toT * uy + s * ry,
len: span,
interval: 1 / (count * BEAD_RATE * dayScale),
external,
}
}
const flows = []
@@ -894,7 +899,7 @@ function buildExternal({ sources, exits }, byPath, innerBounds, dayScale = 1) {
const wMid = width(p.in)
if (wMid < MIN_WMID) continue
edges.push(buildRibbon(xn, page, p.in, 0, wMid, true))
flows.push(...buildFlows(xn, page, p.in, 0, dayScale))
flows.push(...buildFlows(xn, page, p.in, 0, dayScale, true))
}
})
}
@@ -944,7 +949,7 @@ function buildExternal({ sources, exits }, byPath, innerBounds, dayScale = 1) {
const wMid = width(p.out)
if (wMid < MIN_WMID) continue
edges.push(buildRibbon(page, xn, p.out, 0, wMid, true))
flows.push(...buildFlows(page, xn, p.out, 0, dayScale))
flows.push(...buildFlows(page, xn, p.out, 0, dayScale, true))
}
})
}