feat(arcade,ui): 80s arcade classics + shared menu theme

Arcade games (PRD §5.1), generalizing the sandboxed-PTY DOOM path into an
external-game registry: Space Invaders (nInvaders), Pac-Man (pacman4console),
Tetris (tint/vitetris), Moon Patrol (moon-buggy). Binaries resolve from
assets/bin, PATH, then /usr/games, so a distro install or a hand-built binary
lights each game up; missing games are skipped with a discovery hint. Installed
on the host via `scripts/fetch-assets.sh --arcade` (apt), wired into setup.sh
behind FETCH_ARCADE (default on).

UI: new shared ui.Theme.MenuItem widget (accent cursor + badge, description
shown only for the focused row) adopted by the hub and arcade menus; the hub
groups rows under Features/Sessions headers and the arcade under
DOOM/ARCADE/BUILT-IN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Anthony Ettinger 2026-06-15 13:58:18 +00:00
parent a8cb7e3182
commit d810356faf
11 changed files with 471 additions and 135 deletions

View file

@ -4,10 +4,10 @@ import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/profullstack/agentbbs/internal/plugin"
"github.com/profullstack/agentbbs/internal/store"
"github.com/profullstack/agentbbs/internal/ui"
)
// board renders the global top scores (PRD §5.1 leaderboards).
@ -42,17 +42,17 @@ func (b *board) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}
func (b *board) View() string {
s := tStyle.Render("Leaderboard — snake") + "\n\n"
s := theme.Title("Leaderboard — snake") + "\n\n"
switch {
case b.err != nil:
s += eStyle.Render("error: " + b.err.Error())
s += ui.Danger.Render("error: " + b.err.Error())
case len(b.scores) == 0:
s += dStyle.Render("no scores yet — be the first")
s += ui.Dim.Render("no scores yet — be the first")
default:
for i, sc := range b.scores {
s += fmt.Sprintf("%2d. %-20s %6d\n", i+1, sc.User, sc.Score)
}
}
s += "\n" + dStyle.Render("any key to return")
return lipgloss.NewStyle().Padding(1, 2).Render(s)
s += "\n" + ui.KeyBar("any-key return to menu")
return ui.Frame.Render(s)
}