Improve the transcript: tool grouping, report auto-ack, context meter, spinner, Enter to send

This commit is contained in:
Ian Gulliver
2026-10-14 16:03:46 -07:00
parent ca2644374d
commit ab4c3d2c6f
19 changed files with 734 additions and 92 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+89
View File
@@ -0,0 +1,89 @@
//go:build ignore
package main
import (
"image"
"image/color"
"image/gif"
"log"
"math"
"os"
)
const (
width = 16
height = 32
radius = 2.6
levels = 16
samples = 4
delay = 8
)
var frames = []rune("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
var dots = [6][2]float64{{4.5, 8}, {4.5, 16}, {4.5, 24}, {11.5, 8}, {11.5, 16}, {11.5, 24}}
func main() {
render("img/spinner-light.gif", color.RGBA{0x1a, 0x45, 0xbd, 0xff}, color.RGBA{0xfb, 0xfb, 0xfa, 0xff})
render("img/spinner-dark.gif", color.RGBA{0x8a, 0xb4, 0xff, 0xff}, color.RGBA{0x15, 0x17, 0x1a, 0xff})
}
func render(path string, fg, bg color.RGBA) {
palette := color.Palette{color.RGBA{}}
for i := 1; i <= levels; i++ {
palette = append(palette, blend(bg, fg, float64(i)/levels))
}
anim := &gif.GIF{}
for _, r := range frames {
bits := int(r - 0x2800)
img := image.NewPaletted(image.Rect(0, 0, width, height), palette)
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
level := int(math.Round(coverage(bits, x, y) * levels))
img.SetColorIndex(x, y, uint8(level))
}
}
anim.Image = append(anim.Image, img)
anim.Delay = append(anim.Delay, delay)
anim.Disposal = append(anim.Disposal, gif.DisposalBackground)
}
f, err := os.Create(path)
if err != nil {
log.Fatal(err)
}
defer f.Close()
err = gif.EncodeAll(f, anim)
if err != nil {
log.Fatal(err)
}
}
func coverage(bits, x, y int) float64 {
hit := 0
for sy := 0; sy < samples; sy++ {
for sx := 0; sx < samples; sx++ {
px := float64(x) + (float64(sx)+0.5)/samples
py := float64(y) + (float64(sy)+0.5)/samples
for i, d := range dots {
if bits&(1<<i) == 0 {
continue
}
if math.Hypot(px-d[0], py-d[1]) <= radius {
hit++
break
}
}
}
}
return float64(hit) / (samples * samples)
}
func blend(a, b color.RGBA, t float64) color.RGBA {
mix := func(p, q uint8) uint8 {
return uint8(math.Round(float64(p) + (float64(q)-float64(p))*t))
}
return color.RGBA{mix(a.R, b.R), mix(a.G, b.G), mix(a.B, b.B), 0xff}
}