quintodrome/desktop/scripts/gen_icon.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

104 lines
2.3 KiB
Go
Raw Normal View History

2026-08-24 20:49:04 -08:00
//go:build ignore
// gen_icon generates a 1024x1024 source icon for the Quintodrome app.
// Run: go run desktop/scripts/gen_icon.go
package main
import (
"image"
"image/color"
"image/png"
"os"
)
const size = 1024
const ss = 4 // supersampling factor per axis
func lerp(a, b, t float64) float64 { return a + (b-a)*t }
type rgb struct{ r, g, b float64 }
func mix(a, b rgb, t float64) rgb {
return rgb{lerp(a.r, b.r, t), lerp(a.g, b.g, t), lerp(a.b, b.b, t)}
}
var (
2026-08-25 05:11:19 -08:00
bgTop = rgb{58, 42, 94}
bgBottom = rgb{23, 21, 28}
2026-08-24 20:49:04 -08:00
circleTop = rgb{168, 85, 247}
circleBottom = rgb{124, 58, 237}
white = rgb{255, 255, 255}
)
func inTriangle(px, py, ax, ay, bx, by, cx, cy float64) bool {
sign := func(x1, y1, x2, y2, x3, y3 float64) float64 {
return (x1-x3)*(y2-y3) - (x2-x3)*(y1-y3)
}
d1 := sign(px, py, ax, ay, bx, by)
d2 := sign(px, py, bx, by, cx, cy)
d3 := sign(px, py, cx, cy, ax, ay)
neg := d1 < 0 || d2 < 0 || d3 < 0
pos := d1 > 0 || d2 > 0 || d3 > 0
return !(neg && pos)
}
func sample(x, y float64) rgb {
// background vertical gradient
c := mix(bgTop, bgBottom, y/size)
// centered circle
cx, cy, cr := float64(size)/2, float64(size)/2, float64(size)*0.31
dx, dy := x-cx, y-cy
if d := dx*dx + dy*dy; d <= cr*cr {
t := (y - (cy - cr)) / (2 * cr)
circle := mix(circleTop, circleBottom, t)
c = circle
}
// play triangle
2026-08-25 05:11:19 -08:00
tx := float64(size) * 0.512
2026-08-24 20:49:04 -08:00
ax, ay := tx-float64(size)*0.145, float64(size)*0.342
bx, by := tx-float64(size)*0.145, float64(size)*0.658
cxv, cyv := tx+float64(size)*0.165, float64(size)*0.5
if inTriangle(x, y, ax, ay, bx, by, cxv, cyv) {
c = white
}
return c
}
func main() {
img := image.NewRGBA(image.Rect(0, 0, size, size))
for y := 0; y < size; y++ {
for x := 0; x < size; x++ {
var acc rgb
for sy := 0; sy < ss; sy++ {
for sx := 0; sx < ss; sx++ {
fx := float64(x) + (float64(sx)+0.5)/ss
fy := float64(y) + (float64(sy)+0.5)/ss
s := sample(fx, fy)
acc.r += s.r
acc.g += s.g
acc.b += s.b
}
}
n := float64(ss * ss)
img.SetRGBA(x, y, color.RGBA{
R: uint8(acc.r / n),
G: uint8(acc.g / n),
B: uint8(acc.b / n),
A: 255,
})
}
}
f, err := os.Create(os.Args[len(os.Args)-1])
if err != nil {
panic(err)
}
defer f.Close()
if err := png.Encode(f, img); err != nil {
panic(err)
}
}