Drawings

On paper first, then in Metal.

Every surface in bateri began as a written decision. This set is a selection of them: the drawing, the measurements and the reasoning. No number was made up; they come from the source code.

A-01

Exploded axonometric

Under the AppKit window, a frame passes through eight Metal pipelines: backgrounds, the dust and the wave of the dock's arrival, glyphs, emoji, selection, typing effects and the caret. Each draws its own layer; when nothing on screen changes, none of them run.

bateri: exploded axonometric An exploded drawing of a bateri window: the AppKit window and eight Metal pipelines. A AppKit The window and the tabs in its title bar B caret_fragment SDF caret: rounded corners, edge and halo C glyph_fx Typing and erasing effects in the dock D selection Mouse selection with rounded corners E emoji_fragment Colour emoji sampled from its own texture F cell Glyphs from the CoreText atlas, plus rules G wave_fragment The dock's line, rippling as it arrives H dot_fragment Dust drawn onto the dock's line I cell_bg Backgrounds, block marks and quads Z NOTEEight pipelines draw a single frame.When nothing on screen changes, none of them run. N.T.S. PROJECT bateri DRAWING Exploded axonometric CONTENT AppKit + 8 Metal pipelines SHEET A-01

A-02

The tab bar

The tabs are bateri's, not the system's: drawn in the title row, in the theme's colors. The row is 40 points; the strip starts 12 points right of the traffic lights, and each tab is at most 184 points. + is rounded to sit in the window's 20-point corner.

A tab carries one sign, the most urgent: a question waiting, a command running, how a command ended while you were away, a transfer. Failure outranks success, because it's the one you mustn't miss. A marked server is a thin line along the tab's top. A program that reports its own status, as Claude Code does, turns the ring only while it works and shows the question while it waits for you.

The ring doesn't spin, it steps 30° once a second: the clock wakes only when something is about to change, and not at all while the window can't be seen. A window with a single tab shows none of this; its title sits in the middle.

web api ⇄ staging-1 84 184 28 40 pt gap 2 ⇄ prod-web-1 26 184 28 12 + 6 the server's mark transfer progress corner 7 1 question waiting 2 command running 3 ended in failure 4 ended in success 5 transfer 30° a second 0 s 1 s 2 s production staging development the most urgent wins
A-02 The tab bar SCALE N.T.S. bateri

A-03

Split cards

With two or more panes in a tab, every pane is a card on a ground of its own. No line draws a card: it reads as one by depth, with light from above. Its top edge catches the light, a dark card has a faint sheen under it, and its shadow is tucked under its foot instead of spreading over the ground.

The ground isn't a new color but one derived from four: the background lifted a step toward the foreground, leaning toward the accent at the top left and toward the cursor's color at the bottom right. Every theme gets its own.

8 points between the cards and around them, none at the top: they start right under the title row. A card's corner is the window's less the gap, so the gap is as wide at the corners as along the edges. The focused card stands nearer, and no pane is dimmed.

gap
8 pt · 0
corner
20.5 − 8 = 12.5 pt
setting
[appearance] split_style
plan 40 8 8 8 top 0 ground card focus the ground 8% → foreground#111112 38% → accent#394656 28% → cursor#493e29 −45° top left bottom right a card, from the side top edge, 1 pt sheen, 26% cut, 1 pt shadow casts the shadow at rest focused offset914 blur1622 inset810 shadow75%90% cut55%60% depth, not a frame corner, enlarged 8 8 window 20.5 12.5 = 20.5 − 8
A-03 Split cards SCALE N.T.S. bateri

A-04

Moving a pane

Hold ⌥⌘ for 300 milliseconds and the tab's panes lift, 3% smaller (1.5% under the pointer), each with a capsule: its hold, what it's doing, its name and folder, and four tools. As a pane narrows, the capsule drops the folder, then the name, then the split tools.

Carried over another pane, nothing moves until you let go; the place it would take is painted and labelled Left, Right, Above, Below or Swap. More than 28% in from every edge is the middle, a swap; nearer an edge, it goes beside. An 18-point strip along the window's edge makes a full-height column or full-width row, two fifths of the window.

Room is made by shrinking the panes around it, none below 20 × 5. The program is resized once, when it lands; the panes slide there in 200 ms.

hold
⌥⌘ · 300 ms
lift
3% · 1.5%
smallest pane
20 × 5
the capsule npm run dev ~/code/web 38 18 14 28 r 12 hold status name folder tools as the pane narrows where it lands Swap Left Right Above Below 28% at the window's edge 18 pt full height 40% nothing moves until you let go
A-04 Moving a pane SCALE N.T.S. bateri

A-05

Anatomy of a cell

The grid's unit is the cell, not the letter. A letter sits in the middle of its cell on a fixed baseline; open up the line spacing and the letter stays where it is.

Box-drawing lines aren't taken from the font: the terminal draws them itself, from one edge of the cell to the other, so no hairline gap opens between rows. A wide character takes two cells and is never split down the middle.

Example setting: SF Mono 14 pt, line height 1.2. The default is 13 pt and 1.0; the rule doesn't change.

g 界 8.5 pt 17 pt · 2 cells 20 pt 14.25 pt baseline edge to edge
A-05 Anatomy of a cell SCALE 14:1 bateri

A-06

Section through the dock

The dock lives in its own band at the bottom of the window. Locally the band is 72 points: the input row, the context row and the space around them.

Over ssh the band shrinks to one row, 36 points, and its top line takes the color of the server's mark. The terminal's size doesn't change: the grid just moves down, and no program has to redraw.

local ssh · production grid 72 pt grid 36 pt 36 pt input row ~/code/web context row ⇄ prod-web-1 context row top line the mark's color the terminal keeps its size
A-06 Section through the dock SCALE N.T.S. bateri

A-07

The dock's arrival

In a new tab the dock stays empty until the shell gives its first prompt: the folder, branch, prompt mark and caret are held back. Nothing moves for the first 0.18 seconds, so a quick shell never flickers; after that, only the top line ripples faintly.

When the prompt comes, the scene is over in 0.56 seconds: the ripple settles, a wave runs right from the ›, the middle line is drawn from the left, the folder and branch appear, and the caret comes last.

If the shell says nothing for 3 seconds, the dock arrives anyway. A key press, or leaving the window or tab, ends the scene at once; with Reduce Motion it's a 0.12-second fade.

4 choices
ripple · dust · type · off
setting
[motion] dock_arrival
waits for the shell to speak folder, branch, › and caret wait…while the shell startsafter 0.18 s · at most 3 s0.08 s› opensripple settles0.20 swave runs rightmiddle line, from the left~/code/web | main0.28 sfolder and branchcaret~/code/web | main0.56 s0.56 s, then a straight line when the prompt comesripple settleswave runs right› opensmiddle line, from the leftfolder and branchcaretcolor settles00.10.20.30.40.5s0.56
A-07 The dock's arrival SCALE N.T.S. bateri

A-08

The caret's spring

The caret doesn't teleport; it travels on a critically damped spring: it speeds up, slows down, and never overshoots. The stiffness, ω = 30, is a chosen number, not a measured one.

Because the thresholds are absolute, settling time grows with distance: about 230 ms for one cell, about 460 ms for 400 cells. These weren't measured; they were computed from the closed form. The 0.7-second ceiling isn't a duration, it's a seat belt.

the caret, frame by framespring · ζ = 1 · ω = 30git log --oneline --graph --allone caret per frame, 1/60 s apartζ = 0.5 · overshoots · not baterigit log --oneline --graph --alltargetnever passes the targetdistance left1 cell≈ 230 ms400 cells≈ 460 msceiling 0.7 sD0snap0.00.10.20.30.40.5s
A-08 The caret's spring SCALE GRAPH bateri

A-09

The caret's shape

The caret isn't a flat rectangle but a distance field (SDF): rounded corners, a soft edge. Its corner radius is a share of the cell's height, 0.10 by default, so it keeps its proportions at any font size; at 0.5 it becomes a pill.

The halo lives only outside and is as light as a box shadow: two fifths of the side margin, 10% at its darkest. The first version glowed like neon; cursor_glow scales spread and darkness together, as one feeling.

Out of focus the caret is an empty outline. The selection has its own corner, 0.22. Blinking is off by default: on, an idle window would draw two frames a second.

a r = 0.10 h h halo 0.4 · 0.10 the letter beneath takes the background color cursor_radius 0.000.100.250.50 pill cursor blockunderlinebeamhollow unfocused a shadow, not neon
A-09 The caret's shape SCALE 14:1 bateri

A-10

Arrivals and departures

A typed letter arrives in 240 ms. The first choice was 120 ms; in a real window the effect turned out to be invisible, and the duration doubled.

A deleted letter takes a notch longer, 300 ms, to go: the eye reads what was erased, while it already knows what it typed.

9 arrivals
fade · rise · pop · extrude · heat · echo · drop · ink · squeeze
8 departures
iris · undertow · echo · bleed · unravel · recede · sublime · shatter
pop arrival · 240 ms shatter departure · 300 ms a a a a a aaaa aaaa aaaa aaaa aaaa 060120180240ms grows, doesn't bounce
A-10 Arrivals and departures SCALE N.T.S. bateri

A-11

Color

A theme is twelve roles; every key is optional, and a missing one comes from the built-in theme. The caret is the gold of the icon.

Status colors are meaning, not decoration: success green, error red. A server you've marked production is red, staging yellow, development green, unmarked cyan. A running command is blue.

background#000000foreground#d8d9dddim#909093accent#7a9cc6→ running commandcursor#d9b063selection#283042search_match#3a3212search_current#503a0csuccess#8bb58b→ developmenterror#d16d6a→ productioninfo#79b3b3→ unmarkedwarning#d6b16a→ staging the icon's gold
A-11 Color SCALE THEME · bateri bateri

A-12

Details

Small decisions, enlarged: what happens when a letter doesn't fit its cell, what's drawn when the screen is still, and where box-drawing lines come from.

A box, or the whole glyph

A character missing from your font comes from the system, but only if the pixels it paints fit the cell. A half-clipped letter is silent damage; a box is an honest gap.

Quiet when idle

When nothing on screen changes, no new frame is drawn, and your battery and fans notice. It isn't a wish: it's a measured gate, and a change that breaks it turns the test red.

Lines drawn by the terminal

Box drawing, block and Braille characters are drawn by the terminal, not taken from the font. No hairline gaps between rows; htop's frame stays in one piece.

Download bateri

Free and openly licensed. Open it and your zsh arrives as usual; bateri handles the rest.

Download for macOS

macOS 14 or later, Apple silicon · Free software, GPL-3.0