Watch
0
0
Fork
You've already forked hyperhive
0

swarm-ui: test the rain arithmetic and the swarm name loader

The rain's column maths and fade colour move from MatrixRain into
shell/rain.ts, and the request-once swarm name loader from useSwarmName
into shell/swarm-name.ts. Both are plain functions with their input
passed in, so tests cover them; the components keep the DOM and canvas
work.
This commit is contained in:
iris 2026-10-14 16:36:27 +02:00 • committed by mara
commit e32b4172e4

View file

@ -0,0 +1,61 @@
// The digital rain's arithmetic, apart from the canvas: the glyph cell, how a
// column starts and steps, which glyph a column draws, and the translucent
// fade colour that leaves each glyph's trail. Plain functions, with the random
// source passed in, so they can be tested.
export const GLYPHS =
"アイウエオカキクケコサシスセソタチツテト0123456789:=*+-<>¦";
/** The glyph cell size, in px. */
export const CELL = 16;
/** How far above the top a column may start, in cells. */
const MAX_HEAD_START = 40;
/** The chance, once a column has fallen past the bottom, that it restarts at
* the top on a given step. */
const RESTART_ABOVE = 0.975;
/** The fade trail's alpha. */
const FADE_ALPHA = 0.09;
/** How many columns fill a canvas this wide. */
export function columnsFor(width: number): number {
return Math.max(1, Math.ceil(width / CELL));
}
/** Each column's starting row: up to `MAX_HEAD_START` cells above the top, so
* the columns do not all start falling together. */
export function startDrops(cols: number, rand: () => number): number[] {
return Array.from({ length: cols }, () =>
Math.floor(rand() * -MAX_HEAD_START),
);
}
/** One step: every column moves down a row, and one that has fallen past the
* bottom of a canvas `height` tall goes back to the top on a small chance. */
export function stepDrops(
drops: number[],
height: number,
rand: () => number,
): number[] {
return drops.map((row) => {
const restarted = row * CELL > height && rand() > RESTART_ABOVE ? 0 : row;
return restarted + 1;
});
}
/** The glyph a column draws this step. */
export function glyphFor(rand: () => number): string {
return GLYPHS[Math.floor(rand() * GLYPHS.length)] ?? "0";
}
/** The fade colour for a computed background colour: the same channels at a low
* alpha. They are read out numerically, so the trail fades whatever spacing
* `rgb()` or `rgba()` comes back in; a colour with no channels gets the
* default background's, so the trail never fills solid. */
export function fadeColorOf(background: string): string {
const m = background.match(/(\d+)[^\d]+(\d+)[^\d]+(\d+)/);
const [r, g, b] = m ? [m[1], m[2], m[3]] : [30, 30, 46];
return `rgba(${r}, ${g}, ${b}, ${FADE_ALPHA})`;
}