Skip to content

Commit 67b653b

Browse files
halfaipgclaude
andcommitted
feat: toned-down splash screen, cross-platform install scripts
- Remove scrolling words from boot animation, reduce plasma saturation and copper bar intensity, make logo/text monochrome white-blue - Keep 3D wireframe cube animation - Speed up boot sequence timing (2.5s vs 4s) - Add install.ps1 for Windows with auto-PATH setup - Update install.sh with PATH detection and shell-specific instructions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2483670 commit 67b653b

3 files changed

Lines changed: 132 additions & 138 deletions

File tree

boot.go

Lines changed: 30 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,16 @@ func init() {
8080
r := math.Sin(t*math.Pi*2)*0.5 + 0.5
8181
g := math.Sin(t*math.Pi*2+2.094)*0.5 + 0.5
8282
b := math.Sin(t*math.Pi*2+4.189)*0.5 + 0.5
83+
// Desaturate: pull toward average
8384
avg := (r + g + b) / 3.0
84-
r = avg + (r-avg)*1.6
85-
g = avg + (g-avg)*1.6
86-
b = avg + (b-avg)*1.6
85+
r = avg + (r-avg)*0.6
86+
g = avg + (g-avg)*0.6
87+
b = avg + (b-avg)*0.6
88+
// Darker overall
8789
plasmaPalette[i] = rgb{
88-
clampU8(r * 200),
89-
clampU8(g * 200),
90-
clampU8(b * 200),
90+
clampU8(r * 90),
91+
clampU8(g * 90),
92+
clampU8(b * 90),
9193
}
9294
}
9395
}
@@ -121,20 +123,17 @@ var glyphMap = map[rune][7]uint8{
121123
' ': {0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000},
122124
}
123125

124-
// ── Scrolling text message ──────────────────────────────────
125-
126-
const scrollMsg = " welcome to codebase ! your local ai coding agent built for the terminal press enter to begin ! "
126+
// (scroller removed — keeping boot clean and minimal)
127127

128128
// ── Boot model ───────────────────────────────────────────────
129129

130130
// Demo phases (frame-based, at 20fps / 50ms per frame)
131131
const (
132-
phPlasmaOnly = 0 // frames 0-29: just plasma + copper (1.5s)
133-
phLogoAppear = 30 // frames 30-69: logo assembles pixel by pixel (2s)
134-
phTextAppear = 70 // frames 70-89: "codebase" text types in (1s)
135-
phCubeAppear = 90 // frames 90-109: cube fades in (1s)
136-
phScrollStart = 60 // frames 60+: scroller starts
137-
phStepsStart = 80 // frames 80+: boot steps begin appearing
132+
phPlasmaOnly = 0 // frames 0-19: just plasma (1s)
133+
phLogoAppear = 20 // frames 20-49: logo assembles pixel by pixel (1.5s)
134+
phTextAppear = 50 // frames 50-64: "codebase" text types in (0.75s)
135+
phCubeAppear = 55 // frames 55+: cube fades in (1s)
136+
phStepsStart = 50 // frames 50+: boot steps begin appearing
138137
)
139138

140139
type bootModel struct {
@@ -220,8 +219,8 @@ func (m bootModel) Init() tea.Cmd {
220219
return bootAudioMsg{player: StartBootMusic()}
221220
},
222221
tea.Tick(fps, func(t time.Time) tea.Msg { return demoTickMsg(t) }),
223-
// First boot step after 4 seconds (drawn-out demo intro)
224-
tea.Tick(4*time.Second, func(t time.Time) tea.Msg { return bootTickMsg{} }),
222+
// First boot step after 2.5 seconds
223+
tea.Tick(2500*time.Millisecond, func(t time.Time) tea.Msg { return bootTickMsg{} }),
225224
)
226225
}
227226

@@ -317,16 +316,10 @@ func (m bootModel) View() string {
317316
cubeSize := float64(min(w, h)) * 0.14
318317
cubeCX := float64(w) * 0.78
319318
cubeCY := float64(h) * 0.35
320-
// Grow from 0 to full size
321319
growT := math.Min(1.0, float64(m.frame-phCubeAppear)/30.0)
322320
m.renderCube(px, w, h, cubeCX, cubeCY, cubeSize*growT, t)
323321
}
324322

325-
// ── Phase: Sine-wave scroller at the bottom ──────────────
326-
if m.frame >= phScrollStart {
327-
m.renderScroller(px, w, h, t)
328-
}
329-
330323
// ── Phase: Boot steps ────────────────────────────────────
331324
if m.frame >= phStepsStart {
332325
m.renderBootInfo(px, w, h, t)
@@ -372,7 +365,7 @@ func (m bootModel) renderCopperBars(px []rgb, w, h int, t float64) {
372365
dist := math.Abs(float64(py) - cy)
373366
inten := math.Max(0, 1.0-dist/barWidth)
374367
inten = inten * inten * inten
375-
boost := inten * 140
368+
boost := inten * 60 // subdued copper bars
376369
for ppx := 0; ppx < w; ppx++ {
377370
p := &px[py*w+ppx]
378371
p.r = clampU8(float64(p.r) + boost*bar[2])
@@ -520,9 +513,12 @@ func (m bootModel) renderLogo(px []rgb, w, h, ox, oy, scale int, t, reveal float
520513
continue
521514
}
522515

523-
hue := float64(ly+lx)/float64(logoW+logoH) + t*0.35
524-
hue -= math.Floor(hue)
525-
cr, cg, cb := hslToRGB(hue, 0.9, 0.75)
516+
// Cool white-blue logo
517+
_ = t
518+
blend := float64(ly) / float64(logoH)
519+
cr := clampU8(200 + blend*55)
520+
cg := clampU8(210 + blend*45)
521+
cb := uint8(255)
526522

527523
for dy := 0; dy < scale; dy++ {
528524
for dx := 0; dx < scale; dx++ {
@@ -577,9 +573,10 @@ func (m bootModel) renderBitmapText(px []rgb, w, h, ox, oy, scale int, text stri
577573
if bits&(1<<(4-col)) == 0 {
578574
continue
579575
}
580-
hue := float64(ci)/float64(max(1, len(text))) + t*0.25
581-
hue -= math.Floor(hue)
582-
cr, cg, cb := hslToRGB(hue, 0.65, 0.82)
576+
// Soft white text
577+
_ = t
578+
_ = ci
579+
cr, cg, cb := uint8(200), uint8(210), uint8(225)
583580
for dy := 0; dy < scale; dy++ {
584581
for dx := 0; dx < scale; dx++ {
585582
x := gx + col*scale + dx
@@ -594,96 +591,7 @@ func (m bootModel) renderBitmapText(px []rgb, w, h, ox, oy, scale int, text stri
594591
}
595592
}
596593

597-
// ── Sine-wave scrolling text (classic Amiga scroller) ────────
598-
599-
func (m bootModel) renderScroller(px []rgb, w, h int, t float64) {
600-
scrollScale := max(1, min(h/30, w/60))
601-
scrollH := 7 * scrollScale
602-
baseY := h - scrollH - 4 // near bottom
603-
604-
// Horizontal scroll position (pixels)
605-
glyphAdv := (5 + 2) * scrollScale
606-
totalScrollW := len(scrollMsg) * glyphAdv
607-
scrollOffset := (m.frame * 2) % totalScrollW
608-
609-
// Darken a band behind the scroller with gradient fade
610-
fadeTop := baseY - scrollScale*4
611-
fadeBot := baseY + scrollH + scrollScale*2
612-
for py := fadeTop; py < fadeBot; py++ {
613-
if py < 0 || py >= h {
614-
continue
615-
}
616-
// Gradient: full darkness at center, fading at edges
617-
centerY := float64(baseY + scrollH/2)
618-
halfRange := float64(fadeBot-fadeTop) / 2.0
619-
distFromCenter := math.Abs(float64(py) - centerY)
620-
fade := math.Max(0, 1.0-distFromCenter/halfRange)
621-
dim := 1.0 - fade*0.7
622-
for ppx := 0; ppx < w; ppx++ {
623-
p := &px[py*w+ppx]
624-
p.r = uint8(float64(p.r) * dim)
625-
p.g = uint8(float64(p.g) * dim)
626-
p.b = uint8(float64(p.b) * dim)
627-
}
628-
}
629-
630-
// Rainbow separator line above scroller
631-
sepY := fadeTop
632-
if sepY >= 0 && sepY < h {
633-
for ppx := 0; ppx < w; ppx++ {
634-
hue := float64(ppx)/float64(w) + t*0.3
635-
hue -= math.Floor(hue)
636-
cr, cg, cb := hslToRGB(hue, 0.9, 0.55)
637-
px[sepY*w+ppx] = rgb{cr, cg, cb}
638-
}
639-
}
640-
641-
// Render each visible character with sine-wave y displacement
642-
for ci := 0; ci < len(scrollMsg); ci++ {
643-
ch := rune(scrollMsg[ci])
644-
glyph, ok := glyphMap[ch]
645-
if !ok {
646-
continue
647-
}
648-
649-
charX := ci*glyphAdv - scrollOffset
650-
// Wrap around
651-
if charX < -glyphAdv {
652-
charX += totalScrollW
653-
}
654-
if charX > w+glyphAdv {
655-
continue
656-
}
657-
658-
// Sine-wave vertical offset per character
659-
sineAngle := float64(ci)*0.4 + t*3.0
660-
sineOffset := math.Sin(sineAngle) * float64(scrollScale*3)
661-
charY := baseY + int(sineOffset)
662-
663-
// Color: rainbow shift along scroll
664-
hue := float64(ci)/float64(len(scrollMsg)) + t*0.15
665-
hue -= math.Floor(hue)
666-
cr, cg, cb := hslToRGB(hue, 0.95, 0.7)
667-
668-
for row := 0; row < 7; row++ {
669-
bits := glyph[row]
670-
for col := 0; col < 5; col++ {
671-
if bits&(1<<(4-col)) == 0 {
672-
continue
673-
}
674-
for dy := 0; dy < scrollScale; dy++ {
675-
for dx := 0; dx < scrollScale; dx++ {
676-
x := charX + col*scrollScale + dx
677-
y := charY + row*scrollScale + dy
678-
if x >= 0 && x < w && y >= 0 && y < h {
679-
px[y*w+x] = rgb{cr, cg, cb}
680-
}
681-
}
682-
}
683-
}
684-
}
685-
}
686-
}
594+
// (scroller removed)
687595

688596
// ── Boot info (overlaid on scroller area) ────────────────────
689597

@@ -693,14 +601,10 @@ func (m bootModel) renderBootInfo(px []rgb, w, h int, t float64) {
693601
return
694602
}
695603

696-
// Position steps just above the scroller band
697-
scrollScale := max(1, min(h/30, w/60))
698-
scrollH := 7 * scrollScale
699-
scrollBaseY := h - scrollH - 4
700-
604+
// Position steps near bottom of screen
701605
stepLineH := 3
702606
totalStepH := len(lines) * stepLineH
703-
startY := scrollBaseY - scrollScale*5 - totalStepH
607+
startY := h - totalStepH - 6
704608

705609
// Gentle gradient darken behind steps
706610
gradTop := startY - 2

install.ps1

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Codebase CLI installer (Windows)
2+
# Usage: irm https://raw.githubusercontent.com/codebase-foundation/codebase-cli/main/install.ps1 | iex
3+
4+
$ErrorActionPreference = "Stop"
5+
6+
$Repo = "codebase-foundation/codebase-cli"
7+
$Binary = "codebase"
8+
9+
# Default install directory: ~/.codebase/bin (no admin needed)
10+
$InstallDir = if ($env:INSTALL_DIR) { $env:INSTALL_DIR } else { Join-Path $env:USERPROFILE ".codebase\bin" }
11+
12+
# Detect architecture
13+
$Arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq "Arm64") { "arm64" } else { "amd64" }
14+
15+
# Get latest release tag
16+
Write-Host "Finding latest release..."
17+
$Release = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" -Headers @{ "User-Agent" = "codebase-installer" }
18+
$Tag = $Release.tag_name
19+
if (-not $Tag) {
20+
Write-Error "Could not find latest release. Check https://github.com/$Repo/releases"
21+
exit 1
22+
}
23+
Write-Host "Latest version: $Tag"
24+
25+
# Download
26+
$Archive = "${Binary}_windows_${Arch}.zip"
27+
$Url = "https://github.com/$Repo/releases/download/$Tag/$Archive"
28+
29+
Write-Host "Downloading $Url..."
30+
$TmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "codebase-install-$(Get-Random)"
31+
New-Item -ItemType Directory -Path $TmpDir -Force | Out-Null
32+
33+
try {
34+
$ZipPath = Join-Path $TmpDir $Archive
35+
Invoke-WebRequest -Uri $Url -OutFile $ZipPath -UseBasicParsing
36+
Expand-Archive -Path $ZipPath -DestinationPath $TmpDir -Force
37+
38+
# Create install directory if needed
39+
if (-not (Test-Path $InstallDir)) {
40+
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
41+
}
42+
43+
# Copy binary
44+
$ExeName = "${Binary}.exe"
45+
$Src = Join-Path $TmpDir $ExeName
46+
if (-not (Test-Path $Src)) {
47+
# goreleaser might nest it differently
48+
$Src = Get-ChildItem -Path $TmpDir -Recurse -Filter $ExeName | Select-Object -First 1 -ExpandProperty FullName
49+
}
50+
Copy-Item -Path $Src -Destination (Join-Path $InstallDir $ExeName) -Force
51+
52+
Write-Host ""
53+
Write-Host "Installed $Binary $Tag to $InstallDir\$ExeName"
54+
55+
# Add to user PATH if not already there
56+
$UserPath = [System.Environment]::GetEnvironmentVariable("PATH", "User")
57+
if ($UserPath -notlike "*$InstallDir*") {
58+
Write-Host ""
59+
Write-Host "Adding $InstallDir to your PATH..."
60+
$NewPath = "$InstallDir;$UserPath"
61+
[System.Environment]::SetEnvironmentVariable("PATH", $NewPath, "User")
62+
$env:PATH = "$InstallDir;$env:PATH"
63+
Write-Host "Done. New terminal windows will have 'codebase' available."
64+
Write-Host "For this terminal, it's already available."
65+
}
66+
67+
Write-Host ""
68+
Write-Host "Run 'codebase' in any project directory to get started."
69+
}
70+
finally {
71+
Remove-Item -Path $TmpDir -Recurse -Force -ErrorAction SilentlyContinue
72+
}

install.sh

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/sh
22
set -e
33

4-
# Codebase CLI installer
4+
# Codebase CLI installer (Linux / macOS)
55
# Usage: curl -sSL https://raw.githubusercontent.com/codebase-foundation/codebase-cli/main/install.sh | sh
66

77
REPO="codebase-foundation/codebase-cli"
@@ -13,7 +13,7 @@ OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
1313
case "$OS" in
1414
linux) OS="linux" ;;
1515
darwin) OS="darwin" ;;
16-
*) echo "Unsupported OS: $OS"; exit 1 ;;
16+
*) echo "Unsupported OS: $OS (use install.ps1 for Windows)"; exit 1 ;;
1717
esac
1818

1919
# Detect architecture
@@ -56,14 +56,32 @@ chmod +x "${INSTALL_DIR}/${BINARY}"
5656

5757
echo ""
5858
echo "Installed ${BINARY} ${TAG} to ${INSTALL_DIR}/${BINARY}"
59+
60+
# Check if INSTALL_DIR is in PATH
61+
case ":${PATH}:" in
62+
*":${INSTALL_DIR}:"*) ;;
63+
*)
64+
echo ""
65+
echo "WARNING: ${INSTALL_DIR} is not in your PATH."
66+
echo ""
67+
SHELL_NAME="$(basename "${SHELL:-/bin/sh}")"
68+
case "$SHELL_NAME" in
69+
zsh) RC="~/.zshrc" ;;
70+
bash) RC="~/.bashrc" ;;
71+
fish) RC="~/.config/fish/config.fish" ;;
72+
*) RC="your shell rc file" ;;
73+
esac
74+
if [ "$SHELL_NAME" = "fish" ]; then
75+
echo "Add this to ${RC}:"
76+
echo " fish_add_path ${INSTALL_DIR}"
77+
else
78+
echo "Add this to ${RC}:"
79+
echo " export PATH=\"${INSTALL_DIR}:\$PATH\""
80+
fi
81+
echo ""
82+
echo "Then restart your terminal or run: source ${RC}"
83+
;;
84+
esac
85+
5986
echo ""
60-
echo "Quick start:"
61-
echo " export OPENAI_API_KEY=sk-..."
62-
echo " cd your-project"
63-
echo " codebase"
64-
echo ""
65-
echo "Or use any OpenAI-compatible provider:"
66-
echo " export OPENAI_BASE_URL=https://api.groq.com/openai/v1"
67-
echo " export OPENAI_API_KEY=gsk-..."
68-
echo " export OPENAI_MODEL=llama-3.3-70b-versatile"
69-
echo " codebase"
87+
echo "Run 'codebase' in any project directory to get started."

0 commit comments

Comments
 (0)