charmbracelet/lipgloss
Style definitions for nice terminal layouts π
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained β safe to depend on.
Has a license, tests, and CI β clean foundation to fork and modify.
Documented and popular β useful reference codebase to read through.
No critical CVEs, sane security posture β runnable as-is.
- βLast commit 2w ago
- β17 active contributors
- βDistributed ownership (top contributor 47% of recent commits)
Show all 6 evidence items βShow less
- βMIT licensed
- βCI configured
- βTests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README β live-updates from the latest cached analysis.
[](https://repopilot.app/r/charmbracelet/lipgloss)Paste at the top of your README.md β renders inline like a shields.io badge.
βΈPreview social card (1200Γ630)
This card auto-renders when someone shares https://repopilot.app/r/charmbracelet/lipgloss on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: charmbracelet/lipgloss
Generated by RepoPilot Β· 2026-05-09 Β· Source
π€Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale β STOP and ask the user to regenerate it before proceeding. - Treat the AI Β· unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/charmbracelet/lipgloss shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything β but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
π―Verdict
GO β Healthy across the board
- Last commit 2w ago
- 17 active contributors
- Distributed ownership (top contributor 47% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
β Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live charmbracelet/lipgloss
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale β regenerate it at
repopilot.app/r/charmbracelet/lipgloss.
What it runs against: a local clone of charmbracelet/lipgloss β the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in charmbracelet/lipgloss | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit β€ 42 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of charmbracelet/lipgloss. If you don't
# have one yet, run these first:
#
# git clone https://github.com/charmbracelet/lipgloss.git
# cd lipgloss
#
# Then paste this script. Every check is read-only β no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of charmbracelet/lipgloss and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "charmbracelet/lipgloss(\\.git)?\\b" \\
&& ok "origin remote is charmbracelet/lipgloss" \\
|| miss "origin remote is not charmbracelet/lipgloss (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift β was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "style.go" \\
&& ok "style.go" \\
|| miss "missing critical file: style.go"
test -f "color.go" \\
&& ok "color.go" \\
|| miss "missing critical file: color.go"
test -f "borders.go" \\
&& ok "borders.go" \\
|| miss "missing critical file: borders.go"
test -f "align.go" \\
&& ok "align.go" \\
|| miss "missing critical file: align.go"
test -f "canvas.go" \\
&& ok "canvas.go" \\
|| miss "missing critical file: canvas.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 42 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~12d)"
else
miss "last commit was $days_since_last days ago β artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) β safe to trust"
else
echo "artifact has $fail stale claim(s) β regenerate at https://repopilot.app/r/charmbracelet/lipgloss"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
β‘TL;DR
Lip Gloss is a Go library that provides declarative, CSS-like styling for terminal UI layouts. It lets developers define colors (ANSI 16, 256, true color, or ASCII), borders, padding, alignment, and blending effects for text output, with automatic color downsampling based on terminal capabilities. Core capability: render beautifully styled terminal output without manual ANSI escape sequences. Modular flat structure: core styling logic in align.go, borders.go, canvas.go, color.go, blending.go; platform-specific ANSI handling in ansi_unix.go / ansi_windows.go; backward compat layer in compat/; extensive examples/ tree with standalone and Bubble Tea variants organized by feature (blending/, brightness/, canvas/, color/). No monorepoβsingle library package at root.
π₯Who it's for
Go developers building terminal user interfaces (TUIs) who want expressive, maintainable stylingβparticularly those using Charm Bracelet's ecosystem (Bubble Tea, Wish). Users familiar with CSS will find the API intuitive.
π±Maturity & risk
Actively maintained and production-ready. The repo shows v2 as current (with v1βv2 upgrade guide in UPGRADE_GUIDE_V2.md), comprehensive test files (*_test.go), well-organized CI workflows (build.yml, coverage.yml, lint.yml, release.yml), and recent dependency updates via Dependabot. Strong signal of active development and stability.
Low risk for core use. Single-language Go codebase with lean dependencies (charmbracelet ecosystem + lucasb-eyer/go-colorful for color math). Main risk: color handling is non-trivial and blending.go + color.go are core files with subtle cross-platform concerns (ansi_unix.go vs ansi_windows.go). Version v2 is relatively new, so edge cases in migration from v1 may exist.
Active areas of work
Active v2 development. The repo is tracking v2.0.0-beta releases with breaking changes documented in UPGRADE_GUIDE_V2.md. Dependabot is actively syncing dependencies (dependabot.yml). Workflows for linting (golangci.yml), coverage, and releases are all in place, suggesting regular maintenance cadence.
πGet running
git clone https://github.com/charmbracelet/lipgloss.git
cd lipgloss
go test ./...
cd examples/canvas && go run main.go
Daily commands:
This is a library, not a runnable app. For examples: cd examples/canvas && go run main.go or cd examples/blending/linear-1d/standalone && go run main.go. For testing: go test ./... at repo root.
πΊοΈMap of the codebase
style.goβ Core Style type and its methodsβthe primary API that all users interact with for rendering terminal stylescolor.goβ Color abstraction and palette handling; foundational for all styling operationsborders.goβ Border definitions and rendering logic; critical styling feature used across examplesalign.goβ Text alignment and positioning logic; essential for layout controlcanvas.goβ Canvas rendering system for composing multiple styled elements; architectural layer for complex layoutsblending.goβ Color blending and gradient operations; enables advanced visual effectsgo.modβ Module definition and version constraints; defines project identity and dependencies
π§©Components & responsibilities
- Style (Go structs, method receivers) β Immutable style container holding color, padding, border, alignment, width, height, and other visual properties; chainable API for composition
- Failure mode: Invalid color values or out-of-range padding cause render errors; no validation enforced
- Render Engine (Go string builders, ANSI escape sequence formatting) β Converts Style + text to ANSI-escaped string; applies padding, borders, alignment, and escape codes
- Failure mode: Incorrect ANSI codes corrupt terminal output; text measurement errors cause misalignment
- Color Module (RGB/HSL color spaces, palette lookups, math operations) β Manages Color type, palette conversions (RGB β ANSI), blending operations, and brightness adjustments
- Failure mode: Palette overflow or invalid color space conversion causes visual artifacts
- Canvas (2D array data structure, cell-by-cell merging) β 2D grid-based rendering layer for composing multiple styled elements; enables z-order layering
- Failure mode: Z-order conflicts or
π οΈHow to make changes
Create a new custom border style
- Define border characters in borders.go as a new Border struct with Top, Bottom, Left, Right, TopLeft, TopRight, BottomLeft, BottomRight fields (
borders.go) - Add a constructor function (e.g., RoundedBorder()) that returns your Border instance (
borders.go) - Use in a Style by calling style.Border(myBorder) (
style.go) - Test rendering with examples/borders/ or create a new example under examples/ (
examples/borders/main.go)
Add a new text alignment mode
- Define alignment constant in align.go (e.g., AlignJustify) (
align.go) - Implement alignment logic in the renderText helper within render.go or align.go (
render.go) - Add getter/setter method to Style type (e.g., Align(Position)) (
style.go) - Add test case in align_test.go (
align_test.go)
Implement a new color blending mode
- Add blending function in blending.go (e.g., BlendMultiply) (
blending.go) - Export the function and document the algorithm (RGB value transformation) (
blending.go) - Add test case in blending_test.go verifying color value outputs (
blending_test.go) - Create example in examples/blending/ showcasing the mode (
examples/blending/linear-2d/standalone/main.go)
Add a helper function for common style patterns
- Create function in style.go or a new helper file returning a pre-configured Style (
style.go) - Chain methods (Bold(), Foreground(), Padding(), etc.) to define the pattern (
style.go) - Add unit test in style_test.go validating output (
style_test.go) - Document via godoc comment and reference in README.md (
README.md)
π§Why these technologies
- Go 1.25 β Type-safe, compiled language ideal for performant terminal rendering; strong Unicode/rune support critical for ANSI escape sequences
- ANSI escape sequences β Universal standard for terminal styling (colors, bold, underline); cross-platform support on Unix/Windows via platform-specific detection
- CSS-inspired API (declarative chaining) β Familiar mental model for web developers; expressive, readable code for composing styles
- Lipgloss module (charm.land) β Part of Charm.sh ecosystem; integrates seamlessly with Bubbletea TUI framework for state-driven rendering
βοΈTrade-offs already made
-
Immutable Style objects (chainable methods return new instances)
- Why: Enables safe concurrent usage, functional composition, and clear intent
- Consequence: Slight memory overhead for style objects; minor performance cost on deeply-chained styles
-
Platform-specific ANSI detection (ansi_unix.go, ansi_windows.go)
- Why: Windows console historically lacked ANSI support; allows graceful fallback
- Consequence: Conditional compilation and OS-specific code paths; Windows users on older consoles may see degraded output
-
Automatic color downsampling based on terminal capability
- Why: Terminal color support varies (16, 256, true color); ensures output renders correctly on limited terminals
- Consequence: Some visual fidelity loss on terminals with fewer color bits; requires runtime detection overhead
-
No built-in state management or reactive updates
- Why: Lipgloss is declarative styling only; state/reactivity handled by Bubbletea framework
- Consequence: Must pair with Bubbletea for TUI interactions; cannot be used standalone for interactive apps
π«Non-goals (don't propose these)
- Interactive input handling (delegated to Bubbletea)
- Animation/transitions (out of scope; would require event loop)
- Mouse event processing (Bubbletea responsibility)
- Real-time screen updates (stateless renderer; user implements loop)
- Unicode emoji size calculations beyond rune count (uses rivo/uniseg for grapheme clusters only)
- 3D or non-rectangular layouts
πͺ€Traps & gotchas
- Color downsampling is automatic but context-dependent (standalone vs Bubble Tea vs logs); the logic differs between Sprint/Println and raw Render(). 2. Windows ANSI handling may require specific terminal/console setup; ansi_windows.go behavior may differ from unix. 3. Rune width calculation (via mattn/go-runewidth) is critical for padding/alignment but can be surprising with East Asian characters. 4. v2 has breaking changes; old v1 code will not compile without UPGRADE_GUIDE_V2.md review. 5. Canvas rendering is sequential and position-sensitive; overlapping elements may have non-obvious z-order behavior.
ποΈArchitecture
π‘Concepts to learn
- ANSI Escape Sequences β Lip Gloss generates ANSI codes to color/bold/style text; understanding ESC codes is essential to debug output or understand why styles don't render.
- Color Space Conversion (RGB β HSL/HSV) β blending.go uses color space math (lucasb-eyer/go-colorful) to blend and rotate colors; understanding color spaces is key to correct blending output.
- Terminal Color Profiles (4-bit, 8-bit, 24-bit) β Lip Gloss auto-detects terminal capabilities and downsamples colors; knowing the 3 profiles and their constraints is critical for reliable cross-platform styling.
- Rune Width & Display Width β align.go and padding use rune width (via mattn/go-runewidth) to calculate visual layout; East Asian characters and zero-width joiners break naive byte/character counting.
- Fluent Builder Pattern β Lip Gloss' API (NewStyle().Bold(true).Foreground(...)) is fluent builder; understanding this pattern is essential to use the library idiomatically.
- Box Model (CSS-inspired) β Padding, margin, borders follow CSS box model; Lip Gloss applies this model to terminal text, so CSS knowledge transfers.
- Z-order & Layering in 2D Rendering β canvas.go renders elements sequentially; understanding paint order and overlap is critical for complex layouts without visual glitches.
πRelated repos
charmbracelet/bubbleteaβ Primary consumer and sibling: Bubble Tea is the TUI framework that Lip Gloss was built alongside; users integrate them together.charmbracelet/wishβ SSH middleware library in same ecosystem; Lip Gloss is often used to style output served over SSH via Wish.charmbracelet/xβ Monorepo of shared utilities (ansi, term, errors, windows) that Lip Gloss depends on (charmbracelet/x/ansi, charmbracelet/x/term).muesli/termenvβ Alternative terminal styling library for Go; shares similar goals but different API and design philosophy for comparison.fatih/colorβ Older, simpler Go color library; Lip Gloss supersedes it for TUI work but worth knowing the historical context.
πͺPR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for blending.go color operations
The blending.go file implements color blending operations which are critical for the visual rendering pipeline, but blending_test.go appears minimal. Given the complexity of color theory (linear blending, brightness adjustments), adding parametric tests for edge cases (transparent colors, out-of-range values, different color spaces) would improve reliability and catch regressions early.
- [ ] Review blending.go implementation and identify untested functions (Blend, LinearBlend, etc.)
- [ ] Create parametric test cases in blending_test.go covering edge cases: pure colors, grayscale, alpha transparency, saturation extremes
- [ ] Add benchmarks for blending operations to establish performance baselines
- [ ] Run coverage tool to verify >90% line coverage for blending.go
Add CI workflow for testing cross-platform ANSI compatibility (ansi_unix.go vs ansi_windows.go)
The repo has platform-specific ANSI implementations (ansi_unix.go and ansi_windows.go) but likely lacks a CI workflow that validates both Windows and Unix rendering behavior. This is critical since terminal styling behaves differently across platforms.
- [ ] Create .github/workflows/test-windows.yml that runs tests on windows-latest runner
- [ ] Create .github/workflows/test-macos.yml that runs tests on macos-latest runner
- [ ] Add integration tests in examples/ that visually validate output on each platform
- [ ] Reference existing build.yml and ensure new workflows run on PR and main branch commits
Add missing documentation and examples for canvas.go 2D rendering capabilities
canvas.go exists and has a test file (canvas_test.go), but there's no dedicated example or detailed documentation showing how to use the canvas API. Given the examples/canvas/main.go exists but may be incomplete, adding comprehensive documentation with multiple use-case examples (grid layouts, ASCII art, complex borders) would help adoption.
- [ ] Review canvas.go API (NewCanvas, SetPixel, etc.) and document all public methods in canvas.go docstrings
- [ ] Enhance examples/canvas/main.go with 3+ distinct use cases: grid layout, ASCII animation, complex border composition
- [ ] Add a CANVAS.md guide in repo root documenting the canvas coordinate system, pixel blending rules, and performance considerations
- [ ] Verify all canvas examples render correctly and add them to the README showcase section
πΏGood first issues
- Add comprehensive tests for blending.go color blend modes (linear, rotational) with edge casesβcurrently blending_test.go may lack coverage for all blend modes and color space boundaries.
- Document the color downsampling algorithm with a how-to guide in docs/ or READMEβusers often misunderstand why colors differ between Sprint() and Render() + manual ANSI handling.
- Create a 'kitchen sink' example in examples/ combining borders, blending, canvas, alignment, and multi-color blocksβwould serve as integration test and onboarding reference.
βTop contributors
Click to expand
Top contributors
- @aymanbagabas β 47 commits
- @lrstanley β 15 commits
- @dependabot[bot] β 10 commits
- @meowgorithm β 5 commits
- @andreynering β 3 commits
πRecent commits
Click to expand
Recent commits
aa91b99β chore: remove CODEOWNERS (andreynering)9cbfe8bβ chore(lint): exclude revive naming linter (aymanbagabas)a4d0b40β docs: restore missing diaereses (#664) (meowgorithm)472d718β fix: Avoid background color query hang (#636) (jedevc)89fafbaβ chore: bump x/ansi to v0.11.7 to fix width calculation bug (aymanbagabas)d6d41e1β chore(deps): bump golang.org/x/sys in the all group (#663) (dependabot[bot])23a1bb1β chore(deps): bump github.com/lucasb-eyer/go-colorful in the all group (#640) (dependabot[bot])cd93a9fβ docs: fix tree comment typo (#634) (Rohan5commit)25c5fb2β chore(deps): bump github.com/charmbracelet/colorprofile in the all group (#630) (dependabot[bot])9e39a0aβ docs: fix README typo (#629) (Rohan5commit)
πSecurity observations
The lipgloss repository demonstrates reasonable security practices with GitHub Actions workflows for build and coverage testing. However, there are concerns regarding the use of beta/development versions and future Go versions in examples. The main library code appears to be a styling utility for terminal layouts with no database, authentication, or network operations, which significantly limits attack surface. No hardcoded secrets, SQL injection risks, or XSS vulnerabilities were detected based on the file structure analysis. Recommendations focus on stabilizing dependencies and implementing enhanced supply chain security measures.
- Medium Β· Outdated Go Version in Examples β
examples/go.mod. The examples/go.mod file specifies 'go 1.25.0', which is a future/unreleased version. This may indicate development against unstable Go versions or incorrect version specification. This could lead to compatibility issues and unexpected behavior. Fix: Update to the latest stable Go version (currently 1.23.x or later stable release). Verify the Go version matches the main module's requirements. - Medium Β· Use of Replace Directive with Beta Dependency β
examples/go.mod. The examples/go.mod uses a replace directive pointing to a beta version of lipgloss (v2.0.0-beta.3.0.20251106192539-4b304240aab7). Beta versions may contain unpatched security vulnerabilities and are not recommended for production use. Fix: Once the lipgloss v2 is released as stable, update to the stable version. For production code, avoid depending on beta/development versions. - Low Β· Additional Replace Directive for Log Package β
examples/go.mod. A replace directive pins github.com/charmbracelet/log to a specific commit hash (v0.4.1-0.20241010222913-47ce960d4847). While this can be useful for consistency, it may prevent automatic security updates to the log package. Fix: Monitor the charmbracelet/log repository for security updates. Consider using a more recent stable version or establishing a process to regularly update pinned dependencies. - Low Β· No SBOM or Dependency Verification β
Repository root configuration. The repository does not appear to have Software Bill of Materials (SBOM) generation or checksum verification mechanisms configured. This makes it harder to detect supply chain attacks or compromised dependencies. Fix: Enable Go's checksum database verification (go mod verify), consider generating SBOMs, and implement dependency scanning in CI/CD workflows (already partially present in .github/workflows/dependabot-sync.yml).
LLM-derived; treat as a starting point, not a security audit.
πWhere to read next
- Open issues β current backlog
- Recent PRs β what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals β see the live page for receipts. Re-run on a new commit to refresh.