diff options
| author | Paul Bütow <1224732+snonux@users.noreply.github.com> | 2025-06-20 21:24:04 +0300 |
|---|---|---|
| committer | Paul Bütow <1224732+snonux@users.noreply.github.com> | 2025-06-20 21:24:04 +0300 |
| commit | 235ff7f34e46553386b2abb9104dd467c2724d70 (patch) | |
| tree | 9ee5e7074f8b2f8c428e4151b8fc1acd44e11377 | |
| parent | 1989b6a3d4339321797a442d2fa2bbee21e23cd1 (diff) | |
Show fireworks on exit
| -rw-r--r-- | cmd/tasksamurai/main.go | 2 | ||||
| -rw-r--r-- | internal/ui/fireworks.go | 120 |
2 files changed, 122 insertions, 0 deletions
diff --git a/cmd/tasksamurai/main.go b/cmd/tasksamurai/main.go index 52263de..a9d1837 100644 --- a/cmd/tasksamurai/main.go +++ b/cmd/tasksamurai/main.go @@ -35,4 +35,6 @@ func main() { fmt.Fprintln(os.Stderr, "error running ui:", err) os.Exit(1) } + + ui.Fireworks() } diff --git a/internal/ui/fireworks.go b/internal/ui/fireworks.go new file mode 100644 index 0000000..c902a67 --- /dev/null +++ b/internal/ui/fireworks.go @@ -0,0 +1,120 @@ +package ui + +import ( + "math/rand" + "strings" + "time" + + tea "github.com/charmbracelet/bubbletea" +) + +type fwModel struct { + width int + height int + start time.Time + fws []firework +} + +type firework struct { + x, y int + frame int +} + +type tickMsg struct{} + +func tick() tea.Cmd { + return tea.Tick(150*time.Millisecond, func(time.Time) tea.Msg { return tickMsg{} }) +} + +func (m fwModel) Init() tea.Cmd { + m.start = time.Now() + return tick() +} + +var frames = [][]string{ + {"*"}, + {" * ", "* *", " * "}, + {" * ", " * * ", "* *", " * * ", " * "}, +} + +func (m fwModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.WindowSizeMsg: + m.width = msg.Width + m.height = msg.Height + return m, nil + case tickMsg: + if time.Since(m.start) > 5*time.Second { + return m, tea.Quit + } + // advance frames + for i := 0; i < len(m.fws); { + m.fws[i].frame++ + if m.fws[i].frame >= len(frames) { + m.fws = append(m.fws[:i], m.fws[i+1:]...) + } else { + i++ + } + } + // maybe create new firework + if m.width > 0 && m.height > 0 { + if rand.Float64() < 0.4 { + x := rand.Intn(m.width) + y := rand.Intn(m.height) + m.fws = append(m.fws, firework{x: x, y: y}) + } + } + return m, tick() + case tea.KeyMsg: + return m, tea.Quit + } + return m, nil +} + +func (m fwModel) View() string { + if m.width == 0 || m.height == 0 { + return "" + } + grid := make([][]rune, m.height) + for i := range grid { + row := make([]rune, m.width) + for j := range row { + row[j] = ' ' + } + grid[i] = row + } + for _, fw := range m.fws { + fr := frames[fw.frame] + oy := fw.y - len(fr)/2 + for dy, line := range fr { + y := oy + dy + if y < 0 || y >= m.height { + continue + } + ox := fw.x - len([]rune(line))/2 + for dx, r := range line { + x := ox + dx + if x < 0 || x >= m.width { + continue + } + if r != ' ' { + grid[y][x] = r + } + } + } + } + var b strings.Builder + for _, row := range grid { + b.WriteString(string(row)) + b.WriteByte('\n') + } + return b.String() +} + +// Fireworks runs a short fireworks animation. It stops after five seconds or +// when a key is pressed. +func Fireworks() { + rand.Seed(time.Now().UnixNano()) + p := tea.NewProgram(fwModel{}, tea.WithAltScreen()) + p.Run() +} |
