Real-time terminal line charts for Charm Lip Gloss and Bubble Tea.
Pulse brings rich, responsive time-series visualization to terminal user interfaces (TUIs). Built specifically for the Charm ecosystem (Lip Gloss and Bubble Tea), Pulse features smooth box-drawing curves, high-density Braille sub-pixel rendering, half-tone shaded area fills, and Grafana-style aligned gridlines.
- ╭╯ Smooth Box-Drawing: Continuous lines rendered with rounded arcs (
╭ ╮ ╯ ╰) or bold strokes (┏ ┓ ┛ ┗). - ⠒ Sub-Pixel Braille: High-density 2×4 dot Braille matrix interpolated via cubic Catmull-Rom splines.
- ░ Shaded Area Fill: Half-tone shading beneath curves that cleanly absorbs grid intersections.
- ┼ Aligned Coordinate Grid: Subtle coordinate grid aligned exactly to Y-axis ticks and width quarter-steps.
- 📈 Multi-Series Support: Plot multiple named metrics simultaneously with dedicated styles and swatches.
- 🏷️ Timeline Annotations: Pin events, deploys, and alerts onto the sliding timeline with custom glyphs and vertical guidelines.
- 📦 Live Legend Box: Bordered legend overlay displaying swatches, names, and real-time values.
- ⚖️ Bidirectional & RX/TX Traffic: Grafana-style zero baseline rulings, inverted mirror series, auto-symmetric centering, and adaptive byte rate formatters.
- 🫧 Charm Native: Fully customizable with Lip Gloss styles and built for Bubble Tea event loops.
go get github.com/ingvarch/pulsepackage main
import (
"fmt"
"math"
"github.com/ingvarch/pulse"
"github.com/ingvarch/pulse/theme"
)
func main() {
preset := theme.TokyoNight()
chartW, chartH := 80, 13
chart := pulse.New(chartW, chartH,
pulse.WithRange(0, 100),
pulse.WithTicks(0, 25, 50, 75, 100),
pulse.WithLineWidth(1), // Smooth rounded corners: ╭ ╮ ╯ ╰
pulse.WithAxisStyle(preset.Axis),
pulse.WithLineStyle(preset.LineFor(60)),
)
// Stream 80 data points into the sliding window
for i := 0; i < chartW; i++ {
val := 50 + 38*math.Sin(float64(i)*0.16)
chart.Push(val)
}
fmt.Println(chart.View())
}Pulse is designed from the ground up for Lip Gloss. You can style individual series, axes, borders, and threshold colors:
package main
import (
"fmt"
"charm.land/lipgloss/v2"
"github.com/ingvarch/pulse"
"github.com/ingvarch/pulse/theme"
)
func main() {
preset := theme.TokyoNight()
chart := pulse.New(80, 13,
pulse.WithRange(0, 100),
pulse.WithTicks(0, 25, 50, 75, 100),
pulse.WithLineWidth(2), // Bold curves: ┏ ┓ ┛ ┗
pulse.WithAxisStyle(preset.Axis),
pulse.WithSeriesStyle("cluster-a", preset.LineFor(88.0)), // Red warning threshold
pulse.WithSeriesStyle("cluster-b", lipgloss.NewStyle().Foreground(lipgloss.Color("#bb9af7"))),
)
// Wrap the chart in a Lip Gloss bordered container
box := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#3b4261")).
Padding(1, 2).
Render(chart.View() + "\n" + chart.LegendBox())
fmt.Println(box)
}For ultra-dense metrics, switch to pulse.ModeBraille to enable 2×4 dot matrix sub-pixel resolution powered by cubic Catmull-Rom spline interpolation:
chart.SetMode(pulse.ModeBraille)Monitor inverted network streams, disk I/O, or profit/loss with a central zero baseline ruling (├), smooth bidirectional area fill, and auto-symmetric scaling:
chart := pulse.New(80, 15,
pulse.WithRange(0, 100*MB),
pulse.WithSymmetric(true),
pulse.WithZeroBaseline(true),
pulse.WithSeriesInverted("tx", true),
pulse.WithLabelFormatter(scale.BytesRateFormatter(true)),
)Detailed guides and API references are available in the docs directory:
| Document | Description |
|---|---|
| Getting Started | Constructor options, sliding window buffers, multi-series, and runtime controls |
| Rendering Modes | Box-drawing curves (rounded vs bold), Braille sub-pixel matrix, and area fill |
| Axes & Grid | Adaptive NiceTicks, custom tick quarter-steps, and Grafana grid alignment |
| Zero-Crossing & RX/TX | Grafana-style bidirectional charts, zero baseline rulings, and series inversion |
| Timeline Events | Pin deployments, alerts, and markers (▼, 🚀, ⚡) with guidelines and sliding cards |
| Bubble Tea Integration | Embedding in Bubble Tea models, telemetry ticks, and interactive hotkeys |
Try the included examples directly from your terminal:
# Grafana-style live network traffic (RX / TX) with zero baseline & mode toggles
go run ./examples/rxtxdemo
# Live multi-series stream (CPU, MEM, NET) with hotkeys: t (thickness), m (braille), q (quit)
go run ./examples/multidemo
# Live single-signal generator with thickness & mode toggle
go run ./examples/livedemo
# Real-time hardware telemetry (CPU & RAM) from your machine
go run ./examples/cpulive
# Clean terminal screenshot generator
go run ./examples/cpudemoWe welcome issues and pull requests! Please check our community guidelines:
Pulse is licensed under the MIT License.




