Captain Claude
auditedFreeCaptain Claude sails a two-masted brig with blood-red sails across a truecolor sunset, in two animated lines. Gerstner wave physics: deep-water dispersion, slope-lit swells, breaking whitecaps, a glinting sun lane. Pure scene, displays nothing. refreshInterval 1 + truecolor.
A purely cosmetic statusline that renders an animated two-line ASCII/Unicode scene: a pirate ship sailing across a truecolor sunset over a wave field. It reads session JSON from stdin but deliberately ignores it, reads the epoch time (via date) and the COLUMNS/BOAT_T/WATER environment variables for layout and animation, then pipes computed parameters into a single awk program that prints ANSI 24-bit color escape sequences. It performs no network activity, writes no files, and spawns no subprocesses beyond awk and date.
Audits are advisory. This script runs on your machine — read it before installing.
The script — read it before you run it
#!/usr/bin/env bash
# Claude Code status line — a sailboat silhouetted against a sunset, in two
# lines. Requires "refreshInterval": 1 (and a terminal with 24-bit color).
#
# line 1 — sky: indigo-to-amber gradient pooling around a low sun, rosy
# clouds drifting slowly westward
# line 2 — sea: rolling swells, whitecaps, the sun's golden reflection
# lane glinting. Pure scene — deliberately displays nothing.
#
# The ship is a two-masted pirate brig spanning both lines: blood-red
# square sails billowed wide at the top (▜█▛│▜█▛) over a walnut plank hull
# (▜███████▛), bow spray ahead, fading wake astern. She sails edge to edge,
# comes about, and crosses the sun on every pass. Clouds drift opposite for
# parallax. Plain single-width text: no emoji anywhere.
#
# No network, no state, no subprocesses beyond jq/awk. Test with:
# echo '{}' | COLUMNS=100 ~/.claude/statuslines/boat-over-sea
# (set BOAT_T to a fixed epoch to render a specific frame)
input=$(cat) # session JSON on stdin — unused; the scene shows nothing
export LC_ALL=en_US.UTF-8
t=${BOAT_T:-$(date +%s)}
# Water styles (preview with WATER=n in a terminal loop):
# 1 rolling — long swells all traveling toward the sunset (calmest)
# 2 crossing — two swell systems moving against each other; foam breaks
# where they collide (default)
# 3 headwind — the sea always streams against the ship's heading, so her
# speed reads in the water rushing past the hull
# 4 squall — fast multi-directional chop, extra whitecaps
# 5 ocean — true wave physics: a Gerstner wave field obeying the
# deep-water dispersion relation ω=√(gk), so long swells
# genuinely outrun short chop; short components get
# trochoidal crest-sharpening, and foam breaks where the
# surface steepness exceeds the spilling threshold.
# Drawn as a filled eighth-block height field (▁▂▃▄▅▆▇), and
# the whole field streams against the ship's heading, so her
# speed reads in the water running past. (default)
# 6 trace — same physics, drawn as a dotted waveform: dots at five
# sub-cell heights (. ∙ · ˙ ˚) trace the slopes, arcs (◡ ◠)
# cap the flat troughs and crests
WATER=${WATER:-5}
W=$(( ${COLUMNS:-80} - 4 )) # margin for Claude Code's own padding
[ "$W" -lt 40 ] && W=40
awk -v W="$W" -v t="$t" -v water="$WATER" 'BEGIN{
# ---- layout ---------------------------------------------------------------
xs = W - 10; # sun disc: 3 cells at xs..xs+2
xsc = xs + 1; # center of the sun / reflection lane
span = W - 9; # hull is 9 cells wide
period = 2 * span;
x = t % period;
fwd = (x < span);
pos = fwd ? x : period - x; # left edge of the hull
# ---- line 1: sky ------------------------------------------------------------
sky = "";
for (c = 0; c < W; c++) {
d = c - xsc;
m = 1 / (1 + (d/16.0)^2); # sunset glow falloff
R = 28 + 222*m;
G = 30 + 118*m;
B = 74 - 20*m;
# two rosy cloud banks drifting west (opposite the sunset glow)
for (k = 0; k < 2; k++) {
cw = 7 - 2*k;
cc = (W + 14) - ((t/3 + k*37) % (W + 28));
cd = c - cc; if (cd < 0) cd = -cd;
if (cd < cw) {
f = (1 - cd/cw) * 0.55 * (1 - 0.5*m);
R = R*(1-f) + 214*f;
G = G*(1-f) + 138*f;
B = B*(1-f) + 152*f;
}
}
ch = " "; fR = R; fG = G; fB = B;
if (c >= xs && c <= xs+2) { # the sun, half-sunk on the horizon
ch = "\xe2\x96\x84"; # ▄
fR = 255; fG = 224; fB = 138;
}
# the rig: two blood-red square sails, billowed wide at the top (▜█▛),
# foremast and mainmast dark between them
i = c - pos;
if (i == 1 || i == 5) { ch = "\xe2\x96\x9c"; fR = 128; fG = 30; fB = 34; } # ▜
if (i == 2 || i == 6) { ch = "\xe2\x96\x88"; fR = 158; fG = 38; fB = 42; } # █
if (i == 3 || i == 7) { ch = "\xe2\x96\x9b"; fR = 128; fG = 30; fB = 34; } # ▛
if (i == 4) { ch = "\xe2\x94\x82"; fR = 46; fG = 30; fB = 24; } # │ mast
sky = sky sprintf("\033[48;2;%d;%d;%dm\033[38;2;%d;%d;%dm%s",
R, G, B, fR, fG, fB, ch);
}
# ---- line 2: sea ------------------------------------------------------------
sea = "";
for (c = 0; c < W; c++) {
d = c - xsc;
lane = 1 / (1 + (d/5.0)^2); # the sun road on the water
R = 12 + 150*lane;
G = 42 + 56*lane;
B = 88 - 36*lane;
# swell field, per water style
foam_at = 0.86; fleck = 2; breaking = 0; # fleck: random whitecap threshold (2 = off)
if (water == 1) { # rolling: everything toward the sunset
h = 0.55*sin(0.42*c - 0.85*t)
+ 0.35*sin(0.19*c - 0.33*t + 1.7)
+ 0.18*sin(0.83*c - 1.70*t + 4.2);
} else if (water == 3) { # headwind: sea streams against the heading
wdir = fwd ? 1 : -1;
h = 0.50*sin(0.45*c + wdir*1.3*t)
+ 0.32*sin(0.21*c + wdir*0.5*t + 1.5)
+ 0.22*sin(0.85*c + wdir*2.4*t + 3.1);
} else if (water == 4) { # squall: fast crosschop, lots of white
h = 0.45*sin(0.50*c - 1.6*t)
+ 0.40*sin(0.33*c + 1.9*t + 2.4)
+ 0.30*sin(1.10*c - 3.4*t + 0.7);
foam_at = 0.78; fleck = 0.90;
} else if (water == 2) { # crossing: opposed swells collide and break
h = 0.48*sin(0.42*c - 1.10*t)
+ 0.42*sin(0.36*c + 0.85*t + 2.1)
+ 0.20*sin(0.90*c - 2.60*t + 1.2);
foam_at = 0.88;
} else { # ocean: Gerstner field with real dispersion
# five components: wavelength L (cols), amplitude a, direction dn.
# each travels at its own phase speed sqrt(g/k) — long waves outrun
# short ones, so the surface never moves as one block. g is scaled to
# keep every component under the 1 fps Nyquist rate.
g = 2.5;
nL[1]=36; na[1]=0.42; nd[1]= 1; np[1]=0.0; # primary swell
nL[2]=17; na[2]=0.27; nd[2]= 1; np[2]=2.1;
nL[3]=8; na[3]=0.16; nd[3]= 1; np[3]=4.0; # wind chop (sharpened)
nL[4]=4.3; na[4]=0.10; nd[4]= 1; np[4]=1.3; # ripple (sharpened)
nL[5]=23; na[5]=0.14; nd[5]=-1; np[5]=5.2; # distant opposing swell
# the field streams against the heading of the ship and flips when
# she comes about — her speed reads in the water running past
wdir = fwd ? -1 : 1;
h = 0; sl = 0;
for (j = 1; j <= 5; j++) {
kk = 6.28319 / nL[j];
om = sqrt(g * kk); # dispersion: omega = sqrt(g k)
th = kk*c - wdir*nd[j]*om*t + np[j];
s = sin(th);
# trochoidal profile for short components: peaked crests, flat troughs
if (nL[j] < 10) { u = (s+1)/2; s = 2*u*u - 1; }
h += na[j] * s;
sl += na[j] * kk * cos(th); # analytic surface slope
}
# spilling breaker: forward face too steep near a crest
slraw = sl;
if (sl < 0 ) sl = -sl;
breaking = (h > 0.15 && sl > 0.30);
foam_at = 0.92;
}
k = (h+1)/2; if (k < 0) k = 0; if (k > 1) k = 1;
R += 16*k; G += 18*k; B += 14*k; # crests catch light: bg swells too
if (water == 6) {
# dotted waveform: the surface as line art. Dots sit at five sub-cell
# heights tracing the slopes; arcs cap flat crests and troughs.
if (slraw > 0.10 || slraw < -0.10) {
lvl = int(k * 4.999);
if (lvl == 0) ch = ".";
else if (lvl == 1) ch = "\xe2\x88\x99"; # ∙
else if (lvl == 2) ch = "\xc2\xb7"; # ·
else if (lvl == 3) ch = "\xcb\x99"; # ˙
else ch = "\xcb\x9a"; # ˚
} else {
if (k > 0.60) ch = "\xe2\x97\xa0"; # ◠ crest
else if (k < 0.40) ch = "\xe2\x97\xa1"; # ◡ trough
else ch = "\xc2\xb7"; # ·
}
# thin glyphs need brighter ink to read against the gradient
fR = 96 + 110*k + 110*lane;
fG = 150 + 90*k + 30*lane;
fB = 195 + 55*k - 55*lane;
} else {
# filled height field: each column is an eighth-block ▁▂▃▄▅▆▇ sized to
# the wave height — the surface as a smooth rolling silhouette.
lvl = int(k * 6.999);
ch = sprintf("\xe2\x96%c", 129 + lvl); # U+2581..2587
fR = 28 + 78*k + 140*lane;
fG = 88 + 112*k + 40*lane;
fB = 150 + 78*k - 60*lane;
}
# directional sunset lighting from the analytic slope: faces tilted
# toward the sun catch amber light, back faces fall into teal shadow.
if (slraw < -0.05) {
lw = -slraw * 3; if (lw > 1) lw = 1;
lw *= 0.30 + 0.70*lane;
fR = fR*(1-lw) + 255*lw; fG = fG*(1-lw) + 186*lw; fB = fB*(1-lw) + 96*lw;
} else if (slraw > 0.05) {
sw = slraw * 2.4; if (sw > 1) sw = 1; sw *= 0.45;
fR = fR*(1-sw) + 18*sw; fG = fG*(1-sw) + 74*sw; fB = fB*(1-sw) + 120*sw;
}
# whitewater: breaking faces and wind-torn crests froth up as ▒
if (h > foam_at || breaking) { ch = "\xe2\x96\x92"; fR = 240; fG = 248; fB = 255; }
# squall mode: stray wind-torn whitecaps off the crests
wc = sin(c*269.5 + t*183.3); wc = wc - int(wc); if (wc < 0) wc += 1;
if (wc > fleck && h > 0) { ch = "\xe2\x88\x98"; fR = 226; fG = 240; fB = 250; } # ∘
# golden sparkle inside the reflection lane. In block modes the glint is
# pure color on the wave itself — never a glyph swap, which would punch
# dot-shaped holes in the surface. Trace mode may brighten its dots.
sp = sin(c*127.1 + t*311.7); sp = sp - int(sp); if (sp < 0) sp += 1;
if (lane > 0.35 && sp > 0.72) {
if (water == 6) { ch = "\xcb\x9a"; } # ˚ glint in line art
fR = 255; fG = 214; fB = 132;
}
# wake and bow spray as whitewater: the wave keeps its shape, the ink
# turns to foam — churned bright at the stern, fading out behind
wd = fwd ? pos - c : c - (pos + 8);
if (wd == 1) { fR = 238; fG = 248; fB = 255; }
if (wd == 2) { fR = 185; fG = 214; fB = 236; }
if (wd == 3) { fR = (fR+200)/2; fG = (fG+222)/2; fB = (fB+240)/2; }
bd = fwd ? c - (pos + 8) : pos - c;
if (bd == 1) { # the bow throws a splash upward
if (water == 6) { ch = "\xcb\x9a"; } # ˚
else { l2 = lvl + 2; if (l2 > 6) l2 = 6; ch = sprintf("\xe2\x96%c", 129 + l2); }
fR = 245; fG = 250; fB = 255;
}
if (c >= pos && c <= pos+8) { # walnut plank hull ▜███████▛
i = c - pos;
ch = (i == 0) ? "\xe2\x96\x9c" : (i == 8) ? "\xe2\x96\x9b" : "\xe2\x96\x88";
if (i == 0 || i == 8) { fR = 56; fG = 34; fB = 24; } # tapered ends
else if (i % 2 == 1) { fR = 96; fG = 60; fB = 40; } # planking
else { fR = 82; fG = 50; fB = 34; }
}
sea = sea sprintf("\033[48;2;%d;%d;%dm\033[38;2;%d;%d;%dm%s",
R, G, B, fR, fG, fB, ch);
}
printf "%s\033[0m\n%s\033[0m", sky, sea;
}'