KQ-1823 · TEXT/BOTTLE

Text Bottle

A bottle typed on a fixed grid of monospace cells: its glass is one ring of edge glyphs that re-letters itself as it turns, and its water is a density ramp over a shallow-water simulation that conserves volume, so tipping it makes the water lag, run up the glass and slosh back. Dragging turns it 1:1 and a release projects the throw and lands on springs.glide with the release velocity; arrow keys tip it on springs.snap, whose one overshoot slops the water. Past the lip the water pours out of the neck in gulps as a ballistic stream of glyphs into a puddle, and stood upright it refills from a dripping tap.

KQ-1823 · TEXT/BOTTLE

Basinworks Spring Water · Bottle 03

Still water, typed by hand

Drag the bottle round to tip it, or use the arrow keys. Home and End tip it all the way; Enter stands it upright to refill.

still · upright · 70% full

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/text-bottle

Props

tilt / defaultTilt
number
default 0
The bottle's angle in degrees, negative left and positive right; controlled or the uncontrolled start.
onTiltChange
(tilt: number) => void
default —
Fires from the drag release or the key that tipped it, with the new angle in whole degrees.
viscosity
number
default 0.35
How thick the liquid is, 0 (water: quick waves, a fast glug) to 1 (syrup: slow, damped, a slow pour).
charset
"ascii" | "blocks" | "dots" | "binary"
default "ascii"
The glyphs the water is typed in, light to heavy.
ramp
string
default —
A custom density ramp, light to heavy, starting with a space; overrides charset.
fill
number
default 0.7
How full the bottle starts and refills to, 0 to 1.
maxTilt
number
default 135
The furthest it tips either way, 30 to 170 degrees.
refill
number
default 7000
How long an upright bottle takes to refill from empty, ms; 0 never refills.
cellSize
number
default 10
The grid's font size in px; smaller is a finer, denser bottle.
waterColor
string
default "var(--accent-bright)"
The water, any CSS colour, drawn at fixed lightness so it reads on both themes.
glassColor
string
default —
The glass outline, any CSS colour; defaults to the ink at two thirds.
onStateChange
(state: TextBottleState, level: number) => void
default —
Fires when it starts or stops pouring, sloshing or refilling, or runs empty, with the level 0 to 1.
onLevelChange
(level: number) => void
default —
Fires as the level passes each 5% step while it pours or refills.
sound
boolean
default false
A glug loop while it pours, only after a tip by hand or key.
label
string
default "Bottle of water"
The slider's accessible name.
paused
boolean
default false
Freezes the water: no waves, pouring or refilling; the bottle still turns.
disabled
boolean
default false
No tipping by hand or key.
dpr
number
default 2
Cap on the canvas's device pixel ratio, at most 2.
className
string
default —
Sizes the piece; it fills a 448px-tall box by default.