240 lines
6.7 KiB
Go
240 lines
6.7 KiB
Go
package main
|
|
|
|
import (
|
|
"image/color"
|
|
"math/rand/v2"
|
|
)
|
|
|
|
type Palette []color.RGBA
|
|
|
|
var textColors = []color.RGBA{
|
|
// basic bright colors
|
|
{255, 100, 100, 255}, // red
|
|
{100, 255, 100, 255}, // green
|
|
{100, 100, 255, 255}, // blue
|
|
{255, 255, 100, 255}, // yellow
|
|
{255, 100, 255, 255}, // magenta
|
|
{100, 255, 255, 255}, // cyan
|
|
{255, 255, 255, 255}, // white
|
|
{255, 150, 50, 255}, // orange
|
|
{150, 255, 50, 255}, // lime
|
|
{255, 50, 150, 255}, // pink
|
|
{50, 150, 255, 255}, // sky blue
|
|
{200, 200, 255, 255}, // light blue
|
|
|
|
// extended primary variations
|
|
{255, 50, 50, 255}, // bright red
|
|
{255, 150, 150, 255}, // light red
|
|
{50, 255, 50, 255}, // bright green
|
|
{150, 255, 150, 255}, // light green
|
|
{50, 50, 255, 255}, // bright blue
|
|
{150, 150, 255, 255}, // light blue variant
|
|
|
|
// warm colors
|
|
{255, 200, 50, 255}, // golden yellow
|
|
{255, 175, 0, 255}, // amber
|
|
{255, 69, 0, 255}, // red orange
|
|
{255, 20, 147, 255}, // deep pink
|
|
{255, 105, 180, 255}, // hot pink
|
|
{255, 182, 193, 255}, // light pink
|
|
{255, 160, 122, 255}, // light salmon
|
|
{255, 99, 71, 255}, // tomato
|
|
{255, 127, 80, 255}, // coral
|
|
|
|
// cool colors
|
|
{0, 255, 127, 255}, // spring green
|
|
{0, 250, 154, 255}, // medium spring green
|
|
{64, 224, 208, 255}, // turquoise
|
|
{72, 209, 204, 255}, // medium turquoise
|
|
{135, 206, 250, 255}, // light sky blue
|
|
{70, 130, 180, 255}, // steel blue
|
|
{100, 149, 237, 255}, // cornflower blue
|
|
{123, 104, 238, 255}, // medium slate blue
|
|
{138, 43, 226, 255}, // blue violet
|
|
|
|
// purple spectrum
|
|
{147, 112, 219, 255}, // medium purple
|
|
{186, 85, 211, 255}, // medium orchid
|
|
{218, 112, 214, 255}, // orchid
|
|
{221, 160, 221, 255}, // plum
|
|
{238, 130, 238, 255}, // violet
|
|
{255, 0, 255, 255}, // pure magenta
|
|
{199, 21, 133, 255}, // medium violet red
|
|
{219, 112, 147, 255}, // pale violet red
|
|
|
|
// neon/electric colors
|
|
{57, 255, 20, 255}, // electric green
|
|
{255, 20, 147, 255}, // electric pink
|
|
{0, 255, 255, 255}, // electric cyan
|
|
{255, 255, 0, 255}, // electric yellow
|
|
{255, 0, 127, 255}, // electric rose
|
|
{127, 255, 0, 255}, // electric lime
|
|
{255, 127, 0, 255}, // electric orange
|
|
{0, 127, 255, 255}, // electric blue
|
|
|
|
// pastel variants
|
|
{255, 218, 185, 255}, // peach puff
|
|
{255, 228, 196, 255}, // bisque
|
|
{255, 239, 213, 255}, // papaya whip
|
|
{240, 248, 255, 255}, // alice blue
|
|
{230, 230, 250, 255}, // lavender
|
|
{255, 240, 245, 255}, // lavender blush
|
|
{255, 228, 225, 255}, // misty rose
|
|
{245, 255, 250, 255}, // mint cream
|
|
|
|
// earth tones (brighter versions)
|
|
{210, 180, 140, 255}, // tan
|
|
{222, 184, 135, 255}, // burlywood
|
|
{238, 203, 173, 255}, // navajo white
|
|
{255, 218, 185, 255}, // peach
|
|
{255, 165, 79, 255}, // sandy brown
|
|
{205, 133, 63, 255}, // peru
|
|
{160, 82, 45, 255}, // saddle brown (lighter)
|
|
{210, 105, 30, 255}, // chocolate (lighter)
|
|
|
|
// jewel tones
|
|
{50, 205, 50, 255}, // lime green
|
|
{220, 20, 60, 255}, // crimson
|
|
{75, 0, 130, 255}, // indigo (brightened)
|
|
{128, 0, 128, 255}, // purple (brightened)
|
|
{165, 42, 42, 255}, // brown (brightened)
|
|
{128, 128, 0, 255}, // olive (brightened)
|
|
{0, 128, 128, 255}, // teal (brightened)
|
|
{128, 0, 0, 255}, // maroon (brightened)
|
|
|
|
// unique/exotic colors
|
|
{255, 215, 0, 255}, // gold
|
|
{192, 192, 192, 255}, // silver
|
|
{255, 20, 147, 255}, // deep pink
|
|
{0, 191, 255, 255}, // deep sky blue
|
|
{30, 144, 255, 255}, // dodger blue
|
|
{255, 69, 0, 255}, // orange red
|
|
{154, 205, 50, 255}, // yellow green
|
|
{32, 178, 170, 255}, // light sea green
|
|
{60, 179, 113, 255}, // medium sea green
|
|
|
|
// vibrant spectrum
|
|
{127, 255, 212, 255}, // aquamarine
|
|
{240, 230, 140, 255}, // khaki
|
|
{238, 232, 170, 255}, // pale goldenrod
|
|
{250, 240, 230, 255}, // linen
|
|
{253, 245, 230, 255}, // old lace
|
|
{255, 250, 240, 255}, // floral white
|
|
{248, 248, 255, 255}, // ghost white
|
|
{245, 245, 220, 255}, // beige
|
|
}
|
|
|
|
var themePalettes = map[string]Palette{
|
|
"vibrant": {
|
|
{255, 0, 150, 255}, // hot pink
|
|
{255, 100, 0, 255}, // orange
|
|
{255, 255, 0, 255}, // yellow
|
|
{0, 255, 100, 255}, // lime
|
|
{0, 150, 255, 255}, // sky blue
|
|
{150, 0, 255, 255}, // purple
|
|
},
|
|
"sunset": {
|
|
{255, 94, 77, 255}, // coral
|
|
{255, 154, 0, 255}, // orange
|
|
{255, 206, 84, 255}, // yellow
|
|
{255, 118, 117, 255}, // light coral
|
|
{240, 147, 43, 255}, // dark orange
|
|
{235, 77, 75, 255}, // red
|
|
},
|
|
"ocean": {
|
|
{0, 123, 255, 255}, // blue
|
|
{0, 200, 255, 255}, // light blue
|
|
{0, 255, 200, 255}, // cyan
|
|
{100, 200, 255, 255}, // sky blue
|
|
{0, 150, 200, 255}, // dark blue
|
|
{50, 255, 150, 255}, // aqua
|
|
},
|
|
"neon": {
|
|
{255, 0, 255, 255}, // magenta
|
|
{0, 255, 255, 255}, // cyan
|
|
{255, 255, 0, 255}, // yellow
|
|
{255, 0, 100, 255}, // hot pink
|
|
{100, 255, 0, 255}, // lime
|
|
{150, 0, 255, 255}, // purple
|
|
},
|
|
"forest": {
|
|
{34, 139, 34, 255}, // forest green
|
|
{107, 142, 35, 255}, // olive
|
|
{154, 205, 50, 255}, // yellow green
|
|
{50, 205, 50, 255}, // lime green
|
|
{0, 128, 0, 255}, // green
|
|
{85, 107, 47, 255}, // dark olive
|
|
},
|
|
"cosmic": {
|
|
{138, 43, 226, 255}, // blue violet
|
|
{75, 0, 130, 255}, // indigo
|
|
{148, 0, 211, 255}, // dark violet
|
|
{255, 20, 147, 255}, // deep pink
|
|
{255, 0, 255, 255}, // magenta
|
|
{72, 61, 139, 255}, // dark slate blue
|
|
},
|
|
}
|
|
|
|
func getRandomTextColors() (color.RGBA, color.RGBA) {
|
|
textColor := textColors[rand.IntN(len(textColors))]
|
|
|
|
// calculate perceived brightness using luminance formula
|
|
// std. weights for human eye sensitivity: 0.299*R + 0.587*G + 0.114*B
|
|
brightness := 0.299*float64(textColor.R) + 0.587*float64(textColor.G) + 0.114*float64(textColor.B)
|
|
|
|
var outlineColor color.RGBA
|
|
if brightness < 128 { // Dark text - use white outline
|
|
outlineColor = color.RGBA{255, 255, 255, 255}
|
|
} else { // Bright text - use black outline
|
|
outlineColor = color.RGBA{0, 0, 0, 255}
|
|
}
|
|
|
|
return textColor, outlineColor
|
|
}
|
|
|
|
func getThemePalette(name string) Palette {
|
|
if palette, exists := themePalettes[name]; exists {
|
|
return palette
|
|
}
|
|
return themePalettes["vibrant"] // default
|
|
}
|
|
|
|
func getRandomThemePalette() (Palette, string) {
|
|
name := config.ColorThemes[rand.IntN(len(config.ColorThemes))]
|
|
return getThemePalette(name), name
|
|
}
|
|
|
|
func (p Palette) interpolate(t float64) color.RGBA {
|
|
if len(p) == 0 {
|
|
return color.RGBA{128, 128, 128, 255}
|
|
}
|
|
|
|
// clamp to to [0, 1]
|
|
if t < 0 {
|
|
t = 0
|
|
}
|
|
if t > 1 {
|
|
t = 1
|
|
}
|
|
|
|
// calculate which colors to interpolate between
|
|
scaledT := t * float64(len(p)-1)
|
|
index := int(scaledT)
|
|
localT := scaledT - float64(index)
|
|
|
|
if index >= len(p)-1 {
|
|
return p[len(p)-1]
|
|
}
|
|
|
|
c1 := p[index]
|
|
c2 := p[index+1]
|
|
|
|
// linear interpolation between the two colors
|
|
r := uint8(float64(c1.R)*(1-localT) + float64(c2.R)*localT)
|
|
g := uint8(float64(c1.G)*(1-localT) + float64(c2.G)*localT)
|
|
b := uint8(float64(c1.B)*(1-localT) + float64(c2.B)*localT)
|
|
a := uint8(float64(c1.A)*(1-localT) + float64(c2.A)*localT)
|
|
|
|
return color.RGBA{r, g, b, a}
|
|
}
|