Files
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

116 lines
3.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package ui
import (
"math"
"strings"
)
// logoGlyphs holds 5×7 pixel bitmaps for each letter in "CLIAMP".
// Each row is 5 bits wide; bit 4 (0x10) is the leftmost pixel.
var logoGlyphs = [6][7]uint8{
{0x0E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0E}, // C
{0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F}, // L
{0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1F}, // I
{0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11}, // A
{0x11, 0x1B, 0x15, 0x11, 0x11, 0x11, 0x11}, // M
{0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10}, // P
}
const (
logoLetterW = 5 // pixel columns per glyph
logoLetterH = 7 // pixel rows per glyph
logoNumLetters = 6
logoGap = 2 // pixel gap between letters
logoTotalW = logoNumLetters*logoLetterW + (logoNumLetters-1)*logoGap // 40
)
// renderLogo draws "CLIAMP" in pixel art using Braille dots. Individual dots
// within each letter appear and disappear based on the associated frequency
// band's energy — loud passages fill the text solid, silence dissolves it
// into scattered pixels. A gentle bounce and wave keep things alive.
func (v *Visualizer) renderLogo(bands []float64) string {
height := v.Rows
dotRows := height * 4
dotCols := PanelWidth * 2
grid := make([]bool, dotRows*dotCols)
// Scale letters to fill the panel (75% of height for bounce headroom).
scaleX := dotCols / logoTotalW
scaleY := (dotRows * 3 / 4) / logoLetterH
if scaleX < 1 {
scaleX = 1
}
if scaleY < 1 {
scaleY = 1
}
renderedW := logoTotalW * scaleX
renderedH := logoLetterH * scaleY
offsetX := (dotCols - renderedW) / 2
baseOffsetY := (dotRows - renderedH) / 2
// Map 6 letters across the 10 frequency bands.
letterBand := [6]int{0, 2, 4, 5, 7, 9}
for li := range logoNumLetters {
energy := bands[letterBand[li]]
// Gentle traveling wave for life during silence + subtle bounce.
wave := math.Sin(float64(v.frame)*0.06+float64(li)*0.9) * 1.5
bounce := int(energy*float64(baseOffsetY)*0.3 + wave)
letterX := offsetX + li*(logoLetterW+logoGap)*scaleX
letterY := baseOffsetY - bounce
for py := range logoLetterH {
row := logoGlyphs[li][py]
for px := range logoLetterW {
if row&(1<<(logoLetterW-1-px)) == 0 {
continue
}
// Stamp each glyph pixel as a scaled block of dots.
// Each dot's visibility is gated by energy — loud fills
// the text solid, silence dissolves it to scattered pixels.
fill := energy*energy*0.75 + 0.15
for sy := range scaleY {
for sx := range scaleX {
dx := letterX + px*scaleX + sx
dy := letterY + py*scaleY + sy
if dx < 0 || dx >= dotCols || dy < 0 || dy >= dotRows {
continue
}
if scatterHash(li, py*scaleY+sy, px*scaleX+sx, v.frame) > fill {
continue
}
grid[dy*dotCols+dx] = true
}
}
}
}
}
// Convert dot grid to Braille characters.
lines := make([]string, height)
for row := range height {
var content strings.Builder
for ch := range PanelWidth {
var braille rune = '\u2800'
for dr := range 4 {
for dc := range 2 {
if grid[(row*4+dr)*dotCols+ch*2+dc] {
braille |= brailleBit[dr][dc]
}
}
}
content.WriteRune(braille)
}
lines[row] = specWrap(float64(height-1-row)/float64(height), content.String())
}
return strings.Join(lines, "\n")
}