项目文件夹

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

152 行
3.7 KiB
Go

此文件含有不可见的 Unicode 字符
此文件含有人类无法区分的不可见的 Unicode 字符,但可以由计算机进行不同的处理。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
package ui
import (
"math"
"strings"
)
// bandAvg returns the mean of bands[lo:hi], guarded against out-of-range
// arguments. Shared by visualizers that consume "bass / mid / high" subbands
// rather than the full array.
func bandAvg(b []float64, lo, hi int) float64 {
if lo < 0 {
lo = 0
}
if hi > len(b) {
hi = len(b)
}
if hi <= lo {
return 0
}
s := 0.0
for _, x := range b[lo:hi] {
s += x
}
return s / float64(hi-lo)
}
// renderFirefly draws a meadow at dusk: a low silhouette of grass at the
// bottom and many fireflies drifting above. Each firefly traces a slow Lissajous
// curve seeded per index so they never collide rigidly. High-frequency energy
// raises the population's brightness and the chance any given firefly is "lit"
// this frame; bass tilts a gentle wind that nudges them sideways.
func (v *Visualizer) renderFirefly(bands []float64) string {
height := v.Rows
dotRows := height * 4
dotCols := PanelWidth * 2
if dotRows < 4 || dotCols < 8 {
return strings.Repeat("\n", max(0, height-1))
}
bass := bandAvg(bands, 0, len(bands)/3)
high := bandAvg(bands, 2*len(bands)/3, len(bands))
// Grass silhouette: bottom 1-2 rows, ragged edge.
grass := make([]bool, dotRows*dotCols)
for x := 0; x < dotCols; x++ {
// Pseudo-noise heights.
h := 1 + int(2.5+1.5*math.Sin(float64(x)*0.41)+1.0*math.Sin(float64(x)*0.17+2.3))
for d := 0; d < h; d++ {
y := dotRows - 1 - d
if y >= 0 {
grass[y*dotCols+x] = true
}
}
}
// Fireflies.
const numFlies = 26
wind := bass * 1.5
dim := make([]bool, dotRows*dotCols)
bright := make([]bool, dotRows*dotCols)
for i := 0; i < numFlies; i++ {
seed := uint64(i)*2246822519 + 11
// Two slightly incommensurate frequencies for Lissajous-like wandering.
fx := 0.012 + float64(seed%17)/3500.0
fy := 0.018 + float64((seed>>4)%19)/2900.0
phx := float64(seed%1000) / 1000.0 * 2 * math.Pi
phy := float64((seed>>8)%1000) / 1000.0 * 2 * math.Pi
t := float64(v.frame)
baseX := float64(dotCols/2) + math.Cos(t*fx+phx)*float64(dotCols-6)*0.45
baseY := float64(dotRows-4)*0.5 + math.Sin(t*fy+phy)*float64(dotRows-6)*0.4
x := int(baseX + wind*math.Sin(t*0.02+phx))
y := int(baseY)
if x < 0 || x >= dotCols || y < 0 || y >= dotRows-1 {
continue
}
// Skip if it would land in the grass silhouette.
if grass[y*dotCols+x] {
continue
}
// Blink: chance of being "on" depends on per-fly phase plus high band.
blinkPhase := math.Sin(t*0.18+float64(i)*1.31) * 0.5
on := blinkPhase+0.5+high*0.4 > 0.55
if !on {
// Half-brightness halo so the fly is faintly there.
dim[y*dotCols+x] = true
continue
}
bright[y*dotCols+x] = true
// Glow halo (one-dot ring).
for _, d := range [4][2]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}} {
gx := x + d[1]
gy := y + d[0]
if gx >= 0 && gx < dotCols && gy >= 0 && gy < dotRows && !grass[gy*dotCols+gx] {
dim[gy*dotCols+gx] = true
}
}
}
lines := make([]string, height)
for row := 0; row < height; row++ {
var sb, run strings.Builder
tag := -1
for col := 0; col < PanelWidth; col++ {
var braille rune = ''
cellTag := -1
for dr := 0; dr < 4; dr++ {
for dc := 0; dc < 2; dc++ {
y := row*4 + dr
x := col*2 + dc
idx := y*dotCols + x
on := false
t := 0
switch {
case bright[idx]:
on = true
t = 2
case dim[idx]:
on = true
t = 1
case grass[idx]:
on = true
t = 0
}
if on {
braille |= brailleBit[dr][dc]
if t > cellTag {
cellTag = t
}
}
}
}
if cellTag < 0 {
cellTag = 0
}
if cellTag != tag {
flushStyleRun(&sb, &run, tag)
tag = cellTag
}
run.WriteRune(braille)
}
flushStyleRun(&sb, &run, tag)
lines[row] = sb.String()
}
return strings.Join(lines, "\n")
}