Files
wehub-resource-sync ead81af521
CI / go (push) Waiting to run
CI / build (darwin, macos-14) (push) Waiting to run
CI / build (windows, windows-2025) (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Failing after 0s
chore: import upstream snapshot with attribution
2026-07-13 12:31:13 +08:00

97 lines
2.5 KiB
Go

package ui
import "strings"
// Half-width katakana + digits for the iconic Matrix digital rain.
var matrixChars = []rune{
'ヲ', 'ァ', 'ィ', 'ゥ', 'ェ', 'ォ', 'ャ', 'ュ', 'ョ', 'ッ',
'ー', 'ア', 'イ', 'ウ', 'エ', 'オ', 'カ', 'キ', 'ク', 'ケ', 'コ',
'サ', 'シ', 'ス', 'セ', 'ソ', 'タ', 'チ', 'ツ', 'テ', 'ト',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
}
// renderMatrix draws falling character streams reminiscent of the Matrix
// digital rain. Each column has a fixed fall speed derived from its position.
// Band energy controls how many columns are active (rain density).
func (v *Visualizer) renderMatrix(bands []float64) string {
height := v.Rows
lines := make([]string, height)
bandCount := len(bands)
for row := range height {
var sb, run strings.Builder
tag := -1
col := 0
for b := range bandCount {
w := visBandWidth(bandCount, b)
for range w {
energy := bands[b]
seed := uint64(col)*7919 + 104729
// Column activity: stable gate, changes every ~20 frames.
// Higher energy activates more columns.
if scatterHash(b, 0, col, v.frame/20) > energy*1.5+0.1 {
if tag != -1 {
flushStyleRun(&sb, &run, tag)
tag = -1
}
run.WriteByte(' ')
col++
continue
}
// Fixed speed per column (2-4 frames per row step), derived
// from column position so each drop falls steadily.
speed := 2 + int(seed%3)
// Trail length: 3-5 characters.
trailLen := 3 + int((seed/7)%3)
// Cycle length large enough for a visible gap between drops.
cycleLen := height + trailLen + 4
offset := int((seed / 13) % uint64(cycleLen))
pos := (int(v.frame)/speed + offset) % cycleLen
dist := pos - row
if dist < 0 || dist > trailLen {
if tag != -1 {
flushStyleRun(&sb, &run, tag)
tag = -1
}
run.WriteByte(' ')
} else {
// Character mutates slowly (~every 4 frames).
charSeed := seed ^ (uint64(row)*31 + (v.frame/4)*17)
ch := matrixChars[charSeed%uint64(len(matrixChars))]
var newTag int
switch {
case dist == 0:
newTag = 2
case dist <= 2:
newTag = 1
default:
newTag = 0
}
if newTag != tag {
flushStyleRun(&sb, &run, tag)
tag = newTag
}
run.WriteRune(ch)
}
col++
}
if b < bandCount-1 {
if tag != -1 {
flushStyleRun(&sb, &run, tag)
tag = -1
}
run.WriteByte(' ')
col++
}
}
flushStyleRun(&sb, &run, tag)
lines[row] = sb.String()
}
return strings.Join(lines, "\n")
}