blockfont

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 3, 2026 License: MIT Imports: 6 Imported by: 0

README

blockfont

Block letter rendering for terminal applications using ASCII block characters.

blockfont demo

                                                     ██     ████                 ██      ◢███                  ██
                                                     ██       ██                 ██ ◢█◤  ██                    ██
                                                     █████◣   ██   ◢████◣ ◢████◣ ███◤   ████   ◢████◣ █████◣ ██████
                                                     ██  ◢█   ██   ██  ██ ██     ██◥█◣   ██    ██  ██ ██  ██   ██
                                                     █████◤ ██████ ◥████◤ ◥████◤ ██  ◥█  ██    ◥████◤ ██  ██   ◥███

Features

  • Block Letter Rendering: Convert text to beautiful block letters using ASCII block characters █ ◢ ◣ ◤ ◥
  • Full Character Set: Lowercase, uppercase, numbers, and common punctuation
  • Vim-Style Editing: Full vim buffer with normal/insert modes and common operations
  • Character Highlighting: Color individual characters for typing games, diffs, etc.
  • Spring Animations: Smooth physics-based transitions using harmonica
  • Word Wrapping: Intelligent word-boundary wrapping with cursor tracking
  • Lipgloss Integration: Full charmbracelet/lipgloss styling support
  • Bubbletea Widget: Ready-to-use tea.Model for easy integration
  • Layout Utilities: Centering, alignment, and positioning helpers

Installation

go get github.com/timlinux/blockfont

Quick Start

Simple Rendering
package main

import (
    "fmt"
    "github.com/timlinux/blockfont"
)

func main() {
    // Render text as block letters
    text := blockfont.RenderText("hello")
    fmt.Println(text)
}
Widget with Bubbletea
package main

import (
    tea "github.com/charmbracelet/bubbletea"
    "github.com/timlinux/blockfont"
)

type model struct {
    widget *blockfont.Widget
}

func (m model) Init() tea.Cmd { return nil }

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    w, cmd := m.widget.Update(msg)
    m.widget = w
    return m, cmd
}

func (m model) View() string {
    return m.widget.View()
}

func main() {
    opts := blockfont.DefaultWidgetOptions()
    opts.Width = 80
    opts.VimMode = true
    opts.Theme = blockfont.KartozaTheme

    widget := blockfont.NewWidget(opts)
    widget.SetText("edit me")
    widget.Focus()

    tea.NewProgram(model{widget: widget}).Run()
}
Character Highlighting

Perfect for typing games and diffs:

text := "typing"
highlights := []blockfont.CharHighlight{
    blockfont.HighlightCorrect,   // t - green
    blockfont.HighlightCorrect,   // y - green
    blockfont.HighlightIncorrect, // p - red
    blockfont.HighlightPending,   // i - dim
    blockfont.HighlightPending,   // n - dim
    blockfont.HighlightPending,   // g - dim
}

lines := blockfont.RenderWithCursor(
    text, -1, highlights, false, 0, blockfont.DefaultTheme)

Run the Demo

Try out all features interactively:

# Clone the repository
git clone https://github.com/timlinux/blockfont
cd blockfont

# Run with make
make demo

# Or with nix
nix run

The demo includes 10 screens showcasing:

  • Full lowercase alphabet
  • Full uppercase alphabet
  • Mixed characters and numbers
  • Character highlighting
  • Vim-style editing
  • Spring animations
  • Word wrapping
  • Theme options

Development

# Enter nix development shell
nix develop

# Build and test
make build
make test

# Run demo
make demo

# Start documentation server
make docs-dev

# Record a demo
nix run .#demo-record

# Play recorded demo
nix run .#demo-play

API Reference

Core Functions
Function Description
RenderText(text string) string Render text with newlines
RenderWord(word string) [][]string Render as 2D array
RenderWithCursor(...) Full rendering with cursor and highlights
RenderPlainText(text, color string) Simple colored rendering
GetLetterWidth(char rune) int Character width
GetTotalWidth(word string) int Word width
Widget
Method Description
NewWidget(opts WidgetOptions) *Widget Create widget
SetText(text string) Set content
Text() string Get content
View() string Render (tea.Model)
Update(msg tea.Msg) Handle input (tea.Model)
Focus() / Blur() Manage keyboard focus
Mode() Mode Get vim mode
Layout
Function Description
CenterLines(lines, width) Center text
LeftJustify(lines, margin) Left-align
RightJustify(lines, width) Right-align
WrapOnWordBoundaries(text, width) Word wrap
Animation
Method Description
NewAnimator() Create animator
TriggerTransition(type) Start animation
Update() bool Advance frame
GetOpacity() float64 Current opacity
GetOffset() int Current offset

Supported Characters

  • Lowercase: a-z
  • Uppercase: A-Z
  • Digits: 0-9
  • Punctuation: . , ; : ! ? - ' " ( ) [ ] { } < > / \ | _ + = * & @ # $ % ^ ~`
  • Space

Themes

// Default theme (green/red/cyan)
opts.Theme = blockfont.DefaultTheme

// Kartoza theme (orange/blue)
opts.Theme = blockfont.KartozaTheme

// Custom theme
opts.Theme = blockfont.Theme{
    Correct:   blockfont.ANSIGreen,
    Incorrect: blockfont.ANSIRed,
    Cursor:    blockfont.ANSICyan,
    Pending:   blockfont.ANSIDim,
}

Documentation

Full documentation is available at the documentation site.

Used In The Wild

Projects using blockfont:

Project Description
Macaco A terminal typing tutor with block letter display
Cheetah Speed typing game with animated block fonts
Baboon Terminal-based text editor with block letter headers

Using blockfont in your project? Open a PR to add it here!

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE for details.


Made with ❤ by Kartoza | Donate! | GitHub

Documentation

Overview

Package blockfont provides block letter rendering for terminal applications using ASCII block characters. It includes high-level widgets for charmbracelet/bubbletea integration, vim-style text editing, animations, and comprehensive styling support.

Index

Constants

View Source
const (
	ANSIReset     = "\033[0m"
	ANSIRed       = "\033[1;31m"
	ANSIGreen     = "\033[1;32m"
	ANSIOrange    = "\033[1;33m"
	ANSIYellow    = "\033[1;33m" // Alias for orange
	ANSIBlue      = "\033[1;34m"
	ANSIMagenta   = "\033[1;35m"
	ANSICyan      = "\033[1;36m"
	ANSIWhite     = "\033[1;37m"
	ANSIInverse   = "\033[7m"
	ANSIDim       = "\033[2m"
	ANSIBold      = "\033[1m"
	ANSIItalic    = "\033[3m"
	ANSIUnderline = "\033[4m"
)

ANSI escape code constants for terminal styling

View Source
const AnimationInterval = 50 * time.Millisecond

AnimationInterval is the default tick interval for animations

View Source
const LetterHeight = 6

LetterHeight is the height of all block letters in lines

View Source
const LetterSpacing = 1

LetterSpacing is the spacing between letters in characters

Variables

View Source
var BlockLetters = map[rune][]string{
	'a': {
		"      ",
		"      ",
		"██████",
		"██  ██",
		"████◤█",
		"      ",
	},
	'b': {
		"██    ",
		"██    ",
		"█████◣",
		"██  ◢█",
		"█████◤",
		"      ",
	},
	'c': {
		"      ",
		"      ",
		"◢████◣",
		"██    ",
		"◥████◤",
		"      ",
	},
	'd': {
		"    ██",
		"    ██",
		"◢█████",
		"██  ◢█",
		"◥█████",
		"      ",
	},
	'e': {
		"      ",
		"      ",
		"◢████◣",
		"███ ◢█",
		"◥███  ",
		"      ",
	},
	'f': {
		" ◢███ ",
		" ██   ",
		"████  ",
		" ██   ",
		" ██   ",
		"      ",
	},
	'g': {
		"      ",
		"◢█████",
		"██  ██",
		"◥█████",
		"    ██",
		"◥████◤",
	},
	'h': {
		"██    ",
		"██    ",
		"█████◣",
		"██  ██",
		"██  ██",
		"      ",
	},
	'i': {
		"  ██  ",
		"      ",
		"████  ",
		"  ██  ",
		"██████",
		"      ",
	},
	'j': {
		"    ██",
		"      ",
		"  ████",
		"    ██",
		"◢█  ██",
		"◥████◤",
	},
	'k': {
		"██    ",
		"██◢█◤ ",
		"███◤  ",
		"██◥█◣ ",
		"██ ◥█ ",
		"      ",
	},
	'l': {
		"████  ",
		"  ██  ",
		"  ██  ",
		"  ██  ",
		"██████",
		"      ",
	},
	'm': {
		"       ",
		"       ",
		"██◣◢██◣",
		"███████",
		"██ █ ██",
		"       ",
	},
	'n': {
		"      ",
		"      ",
		"█████◣",
		"██  ██",
		"██  ██",
		"      ",
	},
	'o': {
		"      ",
		"      ",
		"◢████◣",
		"██  ██",
		"◥████◤",
		"      ",
	},
	'p': {
		"      ",
		"      ",
		"█████◣",
		"██  ██",
		"█████◤",
		"██    ",
	},
	'q': {
		"      ",
		"      ",
		"◢█████",
		"██  ██",
		"◥█████",
		"    ██",
	},
	'r': {
		"      ",
		"      ",
		"██◢██ ",
		"███◤  ",
		"██    ",
		"      ",
	},
	's': {
		"      ",
		"◢████ ",
		"◥██◣  ",
		"  ◥█◣ ",
		"████◤ ",
		"      ",
	},
	't': {
		"      ",
		"  ██  ",
		"██████",
		"  ██  ",
		"  ◥███",
		"      ",
	},
	'u': {
		"      ",
		"      ",
		"██  ██",
		"██  ██",
		"◥█████",
		"      ",
	},
	'v': {
		"      ",
		"      ",
		"██  ██",
		" ◥██◤ ",
		"  ██  ",
		"      ",
	},
	'w': {
		"       ",
		"       ",
		"██ █ ██",
		"███████",
		"◥█◤ ◥█◤",
		"       ",
	},
	'x': {
		"      ",
		"      ",
		"◥█◣◢█◤",
		" ◥██◤ ",
		"◢█◤◥█◣",
		"      ",
	},
	'y': {
		"      ",
		"      ",
		"██  ██",
		"◥█  █◤",
		" ◥██◤ ",
		" ◢█◤  ",
	},
	'z': {
		"      ",
		"      ",
		"██████",
		" ◢██◤ ",
		"██████",
		"      ",
	},
	'A': {
		" ◢██◣ ",
		"◢█  █◣",
		"██████",
		"██  ██",
		"██  ██",
		"      ",
	},
	'B': {
		"█████◣",
		"██  ◥█",
		"██████",
		"██  ◢█",
		"█████◤",
		"      ",
	},
	'C': {
		" ◢████",
		"◢█    ",
		"██    ",
		"◥█    ",
		" ◥████",
		"      ",
	},
	'D': {
		"█████◣",
		"██  ◥█",
		"██   █",
		"██  ◢█",
		"█████◤",
		"      ",
	},
	'E': {
		"██████",
		"██    ",
		"████  ",
		"██    ",
		"██████",
		"      ",
	},
	'F': {
		"██████",
		"██    ",
		"████  ",
		"██    ",
		"██    ",
		"      ",
	},
	'G': {
		"◢█████",
		"██    ",
		"██ ███",
		"██  ██",
		"◥████◤",
		"      ",
	},
	'H': {
		"██  ██",
		"██  ██",
		"██████",
		"██  ██",
		"██  ██",
		"      ",
	},
	'I': {
		"██████",
		"  ██  ",
		"  ██  ",
		"  ██  ",
		"██████",
		"      ",
	},
	'J': {
		"██████",
		"    ██",
		"    ██",
		"██  ██",
		"◥████◤",
		"      ",
	},
	'K': {
		"██ ◢█◤",
		"██◢█◤ ",
		"███◣  ",
		"██◥█◣ ",
		"██ ◥█◣",
		"      ",
	},
	'L': {
		"██    ",
		"██    ",
		"██    ",
		"██    ",
		"██████",
		"      ",
	},
	'M': {
		"██◣◢██",
		"██████",
		"██ █ █",
		"██   █",
		"██   █",
		"      ",
	},
	'N': {
		"██◣ ██",
		"███◣██",
		"██◥███",
		"██ ◥██",
		"██  ██",
		"      ",
	},
	'O': {
		"◢████◣",
		"██  ██",
		"██  ██",
		"██  ██",
		"◥████◤",
		"      ",
	},
	'P': {
		"█████◣",
		"██  ◥█",
		"█████◤",
		"██    ",
		"██    ",
		"      ",
	},
	'Q': {
		"◢████◣",
		"██  ██",
		"██  ██",
		"██ ◥█◤",
		"◥███◤█",
		"      ",
	},
	'R': {
		"█████◣",
		"██  ◥█",
		"█████◤",
		"██◥█◣ ",
		"██ ◥█◣",
		"      ",
	},
	'S': {
		"◢████◣",
		"██    ",
		"◥████◣",
		"    ██",
		"◥████◤",
		"      ",
	},
	'T': {
		"██████",
		"  ██  ",
		"  ██  ",
		"  ██  ",
		"  ██  ",
		"      ",
	},
	'U': {
		"██  ██",
		"██  ██",
		"██  ██",
		"██  ██",
		"◥████◤",
		"      ",
	},
	'V': {
		"██  ██",
		"██  ██",
		"◥█  █◤",
		" ◥██◤ ",
		"  ◥◤  ",
		"      ",
	},
	'W': {
		"██   ██",
		"██   ██",
		"██ █ ██",
		"███████",
		"◥█◤ ◥█◤",
		"       ",
	},
	'X': {
		"██  ██",
		" ◥██◤ ",
		"  ██  ",
		" ◢██◣ ",
		"██  ██",
		"      ",
	},
	'Y': {
		"◥█  █◤",
		" ◥██◤ ",
		"  ██  ",
		"  ██  ",
		"  ██  ",
		"      ",
	},
	'Z': {
		"█████◤",
		"  ◢█◤ ",
		" ◢█◤  ",
		"◢█◤   ",
		"██████",
		"      ",
	},
	' ': {
		"   ",
		"   ",
		"   ",
		"   ",
		"   ",
		"   ",
	},
	',': {
		"    ",
		"    ",
		"    ",
		" ██ ",
		" ◥█ ",
		"    ",
	},
	'.': {
		"    ",
		"    ",
		"    ",
		"    ",
		" ██ ",
		"    ",
	},
	';': {
		"    ",
		" ██ ",
		"    ",
		" ██ ",
		" ◥█ ",
		"    ",
	},
	':': {
		"    ",
		" ██ ",
		"    ",
		" ██ ",
		"    ",
		"    ",
	},
	'!': {
		" ██ ",
		" ██ ",
		" ██ ",
		"    ",
		" ██ ",
		"    ",
	},
	'?': {
		"◢████◣",
		"██ ◢█◤",
		"  ◢█◤ ",
		"      ",
		"  ██  ",
		"      ",
	},
	'-': {
		"      ",
		"      ",
		"██████",
		"      ",
		"      ",
		"      ",
	},
	'\'': {
		" ██ ",
		" ◥█ ",
		"    ",
		"    ",
		"    ",
		"    ",
	},
	'"': {
		"██ ██",
		"◥█ ◥█",
		"     ",
		"     ",
		"     ",
		"     ",
	},
	'(': {
		" ◢█",
		"◢█ ",
		"██ ",
		"◥█ ",
		" ◥█",
		"   ",
	},
	')': {
		"█◣ ",
		" █◣",
		" ██",
		" █◤",
		"█◤ ",
		"   ",
	},
	'[': {
		"███",
		"██ ",
		"██ ",
		"██ ",
		"███",
		"   ",
	},
	']': {
		"███",
		" ██",
		" ██",
		" ██",
		"███",
		"   ",
	},
	'{': {
		" ◢█",
		" ██",
		"◢█ ",
		" ██",
		" ◥█",
		"   ",
	},
	'}': {
		"█◣ ",
		"██ ",
		" █◣",
		"██ ",
		"█◤ ",
		"   ",
	},
	'<': {
		"  ◢█",
		" ◢█ ",
		"◢█  ",
		" ◥█ ",
		"  ◥█",
		"    ",
	},
	'>': {
		"█◣  ",
		" █◣ ",
		"  █◣",
		" █◤ ",
		"█◤  ",
		"    ",
	},
	'/': {
		"      ",
		"   ◢█◤",
		"  ◢█◤ ",
		" ◢█◤  ",
		"◢█◤   ",
		"      ",
	},
	'\\': {
		"      ",
		"◥█◣   ",
		" ◥█◣  ",
		"  ◥█◣ ",
		"   ◥█◣",
		"      ",
	},
	'|': {
		" ██ ",
		" ██ ",
		" ██ ",
		" ██ ",
		" ██ ",
		"    ",
	},
	'_': {
		"      ",
		"      ",
		"      ",
		"      ",
		"██████",
		"      ",
	},
	'+': {
		"      ",
		"  ██  ",
		"██████",
		"  ██  ",
		"      ",
		"      ",
	},
	'=': {
		"      ",
		"██████",
		"      ",
		"██████",
		"      ",
		"      ",
	},
	'*': {
		"      ",
		"◥█  █◤",
		" ████ ",
		"◢█  █◣",
		"      ",
		"      ",
	},
	'&': {
		" ◢██◣ ",
		"◢█  █◣",
		"◥█◢█◤█",
		"██◥█◢█",
		"◥███◥█",
		"      ",
	},
	'@': {
		" ◢███◣ ",
		"██ ◢██◣",
		"██ █ ██",
		"██ ◥███",
		" ◥███  ",
		"       ",
	},
	'#': {
		" ██ ██ ",
		"███████",
		" ██ ██ ",
		"███████",
		" ██ ██ ",
		"       ",
	},
	'$': {
		" ◢███ ",
		"██ █  ",
		" ███  ",
		"  █ ██",
		" ███◤ ",
		"      ",
	},
	'%': {
		"██  ◢█",
		"██ ◢█◤",
		"  ◢█◤ ",
		" ◢█◤██",
		"◢█◤ ██",
		"      ",
	},
	'^': {
		" ◢█◣ ",
		"◢█ █◣",
		"     ",
		"     ",
		"     ",
		"     ",
	},
	'`': {
		"█◣ ",
		" ◥█",
		"   ",
		"   ",
		"   ",
		"   ",
	},
	'~': {
		"      ",
		"◢█◣ ◢█",
		"█◥███◤",
		"      ",
		"      ",
		"      ",
	},
	'0': {
		"◢████◣",
		"██  ██",
		"██  ██",
		"██  ██",
		"◥████◤",
		"      ",
	},
	'1': {
		" ◢██  ",
		"████  ",
		"  ██  ",
		"  ██  ",
		"██████",
		"      ",
	},
	'2': {
		"◢████◣",
		"    ██",
		" ◢███◤",
		"◢█◤   ",
		"██████",
		"      ",
	},
	'3': {
		"█████◣",
		"    ◥█",
		" ◢███◤",
		"    ◢█",
		"█████◤",
		"      ",
	},
	'4': {
		"◢█  ██",
		"██  ██",
		"██████",
		"    ██",
		"    ██",
		"      ",
	},
	'5': {
		"██████",
		"██    ",
		"█████◣",
		"    ◥█",
		"█████◤",
		"      ",
	},
	'6': {
		"◢████◣",
		"██    ",
		"█████◣",
		"██  ◥█",
		"◥████◤",
		"      ",
	},
	'7': {
		"██████",
		"   ◢█◤",
		"  ◢█◤ ",
		" ◢█◤  ",
		"◢█◤   ",
		"      ",
	},
	'8': {
		"◢████◣",
		"██  ██",
		"◥████◤",
		"◢█  █◣",
		"◥████◤",
		"      ",
	},
	'9': {
		"◢████◣",
		"██  ██",
		"◥█████",
		"    ██",
		"◥████◤",
		"      ",
	},
}

BlockLetters maps runes to their block letter representation. Each letter is 6 lines tall and variable width. Uses block elements for solid letters with smooth corners:

██ full blocks - solid letter bodies
◢ ◣ ◤ ◥ - filled triangles for smooth rounded corners

Triangles replace blocks only at curved edges to eliminate blocky corners.

View Source
var DefaultTheme = Theme{
	Primary:   lipgloss.Color("#FFFFFF"),
	Secondary: lipgloss.Color("#888888"),
	Accent:    lipgloss.Color("#FFB347"),
	Correct:   lipgloss.Color("#32CD32"),
	Incorrect: lipgloss.Color("#FF6B6B"),
	Cursor:    lipgloss.Color("#FFFFFF"),
	Delete:    lipgloss.Color("#FF4444"),
	Change:    lipgloss.Color("#FF8C00"),
	Target:    lipgloss.Color("#00FF00"),
	Pending:   lipgloss.Color("#666666"),
}

DefaultTheme provides a default color theme

View Source
var GradientColors = []string{
	"#8B0000", "#B22222", "#CD5C5C", "#F08080",
	"#FF6B35", "#FF8C00", "#FFA500", "#FFB347",
	"#FFD700", "#ADFF2F", "#32CD32", "#00FF00",
}

GradientColors provides a gradient from red (slow) to green (fast)

View Source
var KartozaTheme = Theme{
	Primary:   lipgloss.Color("#FFFFFF"),
	Secondary: lipgloss.Color("#888888"),
	Accent:    lipgloss.Color("#FF6B35"),
	Correct:   lipgloss.Color("#32CD32"),
	Incorrect: lipgloss.Color("#FF4444"),
	Cursor:    lipgloss.Color("#FFB347"),
	Delete:    lipgloss.Color("#B22222"),
	Change:    lipgloss.Color("#FF6B35"),
	Target:    lipgloss.Color("#00FF00"),
	Pending:   lipgloss.Color("#555555"),
}

KartozaTheme provides a Kartoza-branded color theme

Functions

func AlignLines

func AlignLines(lines []string, alignment Alignment, width int) []string

AlignLines aligns lines according to the specified alignment and width.

func CalculateTotalWidth

func CalculateTotalWidth(runes []rune, cursorIdx int, isInsertMode bool) int

CalculateTotalWidth calculates the total display width including cursor

func CenterLines

func CenterLines(lines []string, width int) []string

CenterLines centers each line within the given width. ANSI escape codes are excluded from width calculations.

func GetAnimationInterval

func GetAnimationInterval() time.Duration

GetAnimationInterval returns the recommended tick interval

func GetDisplayWidth

func GetDisplayWidth(text string) int

GetDisplayWidth returns the display width of text when rendered in large font

func GetGradientColor

func GetGradientColor(value float64, colors []string) string

GetGradientColor returns a color from the gradient based on a value (0.0 to 1.0)

func GetLetterWidth

func GetLetterWidth(char rune) int

GetLetterWidth returns the width of a letter in runes (for proper Unicode handling).

func GetProgressColor

func GetProgressColor(progress float64) string

GetProgressColor returns a color based on progress value (0.0 to 1.0)

func GetTotalWidth

func GetTotalWidth(word string) int

GetTotalWidth returns the total display width of a word in the block font.

func GetWPMColor

func GetWPMColor(wpm int) string

GetWPMColor returns a color based on words per minute value

func InsertAt

func InsertAt(base, overlay string, x int) string

InsertAt inserts overlay text at position x in the base string. Handles overlapping text composition while preserving ANSI codes.

func InvertLine

func InvertLine(line string) string

InvertLine inverts a single line using ANSI inverse video. This swaps foreground/background colors for the entire line.

func JoinBlockLines

func JoinBlockLines(lines [][]string, spacing int) []string

JoinBlockLines joins multiple lines from RenderWord with the specified spacing.

func LeftJustify

func LeftJustify(lines []string, margin int) []string

LeftJustify left-justifies lines with optional left margin.

func MaxLineWidth

func MaxLineWidth(lines []string) int

MaxLineWidth returns the maximum visible width across all lines.

func PadToWidth

func PadToWidth(line string, width int) string

PadToWidth pads or truncates a string to the exact visible width. ANSI escape codes are preserved.

func RemoveANSI

func RemoveANSI(s string) string

RemoveANSI removes ANSI escape codes from a string. This is useful for calculating visible width of styled text.

func RenderPlainText

func RenderPlainText(text string, color string) []string

RenderPlainText renders plain text in large font without any highlighting. Used for reference/target text display.

func RenderText

func RenderText(text string) string

RenderText renders text as block letters and returns a single string with lines joined. This is a convenience function for simple rendering without per-character control.

func RenderWithCursor

func RenderWithCursor(text string, cursorIdx int, highlights []CharHighlight, isInsertMode bool, maxWidth int, theme Theme) []string

RenderWithCursor renders text with cursor and character-level highlighting support. Returns multiple lines (6 per row of characters + 1 underline row) that can be displayed. This is the full-featured rendering function used by typing/editing applications.

func RenderWord

func RenderWord(word string) [][]string

RenderWord renders a word as block letters, returning each line separately. Each rune in the returned slices corresponds to one character of the original word.

func RightJustify

func RightJustify(lines []string, width int) []string

RightJustify right-justifies lines within the given width. ANSI escape codes are excluded from width calculations.

func VisibleStringWidth

func VisibleStringWidth(s string) int

VisibleStringWidth calculates the visible width of a string, excluding ANSI escape codes. Returns the rune count of the visible text.

func WrapOnWordBoundaries

func WrapOnWordBoundaries(text string, maxWidth int) []string

WrapOnWordBoundaries wraps text at word boundaries (spaces) to fit within maxWidth. Returns the text split into multiple lines.

func WrapWithColor

func WrapWithColor(text, color string) string

WrapWithColor wraps text with ANSI color codes.

Types

type Alignment

type Alignment int

Alignment represents text alignment options

const (
	// AlignLeft aligns text to the left
	AlignLeft Alignment = iota
	// AlignCenter centers text
	AlignCenter
	// AlignRight aligns text to the right
	AlignRight
)

type AnimationTickMsg

type AnimationTickMsg struct{}

AnimationTickMsg is sent when animation should update

type Animator

type Animator struct {

	// Current values (0.0 to 1.0 representing animation progress)
	Position float64
	Opacity  float64
	Scale    float64

	// Animation state
	IsAnimating bool
	// contains filtered or unexported fields
}

Animator handles spring-based animations for smooth transitions

func NewAnimator

func NewAnimator() *Animator

NewAnimator creates a new animator with default spring settings

func (*Animator) GetOffset

func (a *Animator) GetOffset(maxOffset int) int

GetOffset returns the vertical offset based on position (for slide animations)

func (*Animator) GetOpacityLevel

func (a *Animator) GetOpacityLevel(maxOpacity float64) float64

GetOpacityLevel returns opacity as a value from 0.0 to maxOpacity

func (*Animator) GetScaleFactor

func (a *Animator) GetScaleFactor(minScale float64) float64

GetScaleFactor returns scale factor (e.g., 0.7 to 1.0)

func (*Animator) Reset

func (a *Animator) Reset()

Reset stops any animation and resets to default state

func (*Animator) TriggerTransition

func (a *Animator) TriggerTransition(t TransitionType)

TriggerTransition starts an animation of the specified type

func (*Animator) Update

func (a *Animator) Update() bool

Update advances all springs by one frame. Returns true if animation is still in progress.

type Buffer

type Buffer struct {
	// contains filtered or unexported fields
}

Buffer represents a text buffer with cursor position for vim-style editing

func NewBuffer

func NewBuffer(text string) *Buffer

NewBuffer creates a new buffer with the given text

func (*Buffer) CharAt

func (b *Buffer) CharAt(x, y int) rune

CharAt returns the character at the given position

func (*Buffer) CharUnderCursor

func (b *Buffer) CharUnderCursor() rune

CharUnderCursor returns the character under the cursor

func (*Buffer) Clone

func (b *Buffer) Clone() *Buffer

Clone creates a copy of the buffer

func (*Buffer) CurrentLine

func (b *Buffer) CurrentLine() string

CurrentLine returns the current line

func (*Buffer) CursorIndex

func (b *Buffer) CursorIndex() int

CursorIndex returns the absolute character index in the buffer

func (*Buffer) CursorPosition

func (b *Buffer) CursorPosition() (x, y int)

CursorPosition returns the cursor position (x=column, y=line)

func (*Buffer) Delete

func (b *Buffer) Delete(n int) string

Delete deletes n characters starting at cursor

func (*Buffer) DeleteLine

func (b *Buffer) DeleteLine() string

DeleteLine deletes the current line

func (*Buffer) DeleteToEndOfLine

func (b *Buffer) DeleteToEndOfLine() string

DeleteToEndOfLine deletes from cursor to end of line

func (*Buffer) GetRegister

func (b *Buffer) GetRegister() string

GetRegister returns the yank register content

func (*Buffer) Insert

func (b *Buffer) Insert(text string)

Insert inserts text at the cursor position

func (*Buffer) IsInsertMode

func (b *Buffer) IsInsertMode() bool

IsInsertMode returns true if in insert mode

func (*Buffer) Lines

func (b *Buffer) Lines() []string

Lines returns all lines

func (*Buffer) Mode

func (b *Buffer) Mode() Mode

Mode returns the current mode

func (*Buffer) MoveDown

func (b *Buffer) MoveDown(n int)

MoveDown moves cursor down by n lines

func (*Buffer) MoveLeft

func (b *Buffer) MoveLeft(n int)

MoveLeft moves cursor left by n characters

func (*Buffer) MoveRight

func (b *Buffer) MoveRight(n int)

MoveRight moves cursor right by n characters

func (*Buffer) MoveToFirstLine

func (b *Buffer) MoveToFirstLine()

MoveToFirstLine moves cursor to first line

func (*Buffer) MoveToLastLine

func (b *Buffer) MoveToLastLine()

MoveToLastLine moves cursor to last line

func (*Buffer) MoveToLineEnd

func (b *Buffer) MoveToLineEnd()

MoveToLineEnd moves cursor to end of line

func (*Buffer) MoveToLineStart

func (b *Buffer) MoveToLineStart()

MoveToLineStart moves cursor to start of line

func (*Buffer) MoveUp

func (b *Buffer) MoveUp(n int)

MoveUp moves cursor up by n lines

func (*Buffer) ReplaceChar

func (b *Buffer) ReplaceChar(r rune)

ReplaceChar replaces the character under the cursor

func (*Buffer) SetCursorIndex

func (b *Buffer) SetCursorIndex(index int)

SetCursorIndex sets cursor by absolute character index

func (*Buffer) SetCursorPosition

func (b *Buffer) SetCursorPosition(x, y int)

SetCursorPosition sets the cursor position

func (*Buffer) SetMode

func (b *Buffer) SetMode(mode Mode)

SetMode sets the current mode

func (*Buffer) SetRegister

func (b *Buffer) SetRegister(text string)

SetRegister sets the yank register content

func (*Buffer) SetText

func (b *Buffer) SetText(text string)

SetText replaces the buffer content

func (*Buffer) Text

func (b *Buffer) Text() string

Text returns the full buffer content as a string

type CharHighlight

type CharHighlight int

CharHighlight represents different highlight states for characters

const (
	// HighlightNone indicates no highlight
	HighlightNone CharHighlight = iota
	// HighlightCorrect indicates correctly typed/matched
	HighlightCorrect
	// HighlightIncorrect indicates incorrectly typed/mismatched
	HighlightIncorrect
	// HighlightCursor indicates cursor position
	HighlightCursor
	// HighlightDelete indicates text to be deleted
	HighlightDelete
	// HighlightChange indicates text to be changed
	HighlightChange
	// HighlightTarget indicates target/goal text
	HighlightTarget
	// HighlightPending indicates untyped/pending text
	HighlightPending
)

type CursorStyle

type CursorStyle int

CursorStyle represents how the cursor should be displayed

const (
	// CursorBlock uses a block cursor (inverts character)
	CursorBlock CursorStyle = iota
	// CursorLine uses a vertical line cursor
	CursorLine
	// CursorUnderline uses an underline cursor
	CursorUnderline
)

type Mode

type Mode int

Mode represents vim editing modes

const (
	// ModeNormal is the default mode for navigation and commands
	ModeNormal Mode = iota
	// ModeInsert is for typing text
	ModeInsert
	// ModeVisual is for selecting text
	ModeVisual
	// ModeVisualLine is for selecting whole lines
	ModeVisualLine
	// ModeVisualBlock is for selecting rectangular blocks
	ModeVisualBlock
	// ModeCommand is for entering ex commands
	ModeCommand
)

func (Mode) String

func (m Mode) String() string

String returns the mode name for display

type StyleConfig

type StyleConfig struct {
	Theme       Theme
	CursorStyle CursorStyle
}

StyleConfig holds styling configuration for the widget

func DefaultStyleConfig

func DefaultStyleConfig() StyleConfig

DefaultStyleConfig returns the default style configuration

type Theme

type Theme struct {
	// Primary color for main text
	Primary lipgloss.Color
	// Secondary color for dimmed/inactive text
	Secondary lipgloss.Color
	// Accent color for highlights
	Accent lipgloss.Color
	// Correct color for correctly matched text
	Correct lipgloss.Color
	// Incorrect color for incorrectly matched text
	Incorrect lipgloss.Color
	// Cursor color for cursor highlights
	Cursor lipgloss.Color
	// Delete color for text to be deleted
	Delete lipgloss.Color
	// Change color for text to be changed
	Change lipgloss.Color
	// Target color for target/goal text
	Target lipgloss.Color
	// Pending color for untyped text
	Pending lipgloss.Color
}

Theme holds colors and styles for block font rendering

func (Theme) NewStyle

func (t Theme) NewStyle(highlight CharHighlight) lipgloss.Style

NewStyle creates a lipgloss style for the given highlight

type TransitionType

type TransitionType int

TransitionType represents different animation transition types

const (
	// TransitionSlideUp slides content up
	TransitionSlideUp TransitionType = iota
	// TransitionSlideDown slides content down
	TransitionSlideDown
	// TransitionFadeIn fades content in
	TransitionFadeIn
	// TransitionFadeOut fades content out
	TransitionFadeOut
	// TransitionScale scales content
	TransitionScale
)

type Widget

type Widget struct {
	// contains filtered or unexported fields
}

Widget is a high-level component for rendering block text in bubbletea applications. It implements tea.Model for easy integration.

func NewWidget

func NewWidget(opts WidgetOptions) *Widget

NewWidget creates a new Widget with the given options

func (*Widget) Blur

func (w *Widget) Blur()

Blur removes focus from the widget

func (*Widget) Buffer

func (w *Widget) Buffer() *Buffer

Buffer returns the underlying buffer (for vim mode)

func (*Widget) ColorCharacter

func (w *Widget) ColorCharacter(index int, color lipgloss.Color)

ColorCharacter sets a color for a specific character index

func (*Widget) ColorRange

func (w *Widget) ColorRange(start, end int, color lipgloss.Color)

ColorRange sets a color for a range of characters

func (*Widget) DisableAnimations

func (w *Widget) DisableAnimations()

DisableAnimations disables animations

func (*Widget) DisableVimMode

func (w *Widget) DisableVimMode()

DisableVimMode disables vim-style editing

func (*Widget) EnableAnimations

func (w *Widget) EnableAnimations()

EnableAnimations enables animations

func (*Widget) EnableVimMode

func (w *Widget) EnableVimMode()

EnableVimMode enables vim-style editing

func (*Widget) Focus

func (w *Widget) Focus()

Focus sets the widget focus state

func (*Widget) Init

func (w *Widget) Init() tea.Cmd

Init implements tea.Model

func (*Widget) IsAnimating

func (w *Widget) IsAnimating() bool

IsAnimating returns whether an animation is in progress

func (*Widget) IsFocused

func (w *Widget) IsFocused() bool

IsFocused returns whether the widget is focused

func (*Widget) Mode

func (w *Widget) Mode() Mode

Mode returns the current vim mode

func (*Widget) Render

func (w *Widget) Render() []string

Render returns the rendered block text as lines

func (*Widget) RenderCentered

func (w *Widget) RenderCentered(width int) []string

RenderCentered renders the text centered within the given width

func (*Widget) ResetColors

func (w *Widget) ResetColors()

ResetColors clears all character colors

func (*Widget) SetAlignment

func (w *Widget) SetAlignment(alignment Alignment)

SetAlignment sets the text alignment

func (*Widget) SetHeight

func (w *Widget) SetHeight(height int)

SetHeight sets the widget height

func (*Widget) SetHighlights

func (w *Widget) SetHighlights(highlights []CharHighlight)

SetHighlights sets character-level highlights

func (*Widget) SetText

func (w *Widget) SetText(text string)

SetText sets the widget text

func (*Widget) SetTheme

func (w *Widget) SetTheme(theme Theme)

SetTheme sets the color theme

func (*Widget) SetWidth

func (w *Widget) SetWidth(width int)

SetWidth sets the widget width

func (*Widget) Text

func (w *Widget) Text() string

Text returns the current text

func (*Widget) TriggerAnimation

func (w *Widget) TriggerAnimation(t TransitionType) tea.Cmd

TriggerAnimation starts an animation

func (*Widget) Update

func (w *Widget) Update(msg tea.Msg) (*Widget, tea.Cmd)

Update implements tea.Model

func (*Widget) View

func (w *Widget) View() string

View implements tea.Model

type WidgetOptions

type WidgetOptions struct {
	// Width is the target width for rendering
	Width int
	// Height is the target height (optional)
	Height int
	// Alignment controls text alignment
	Alignment Alignment
	// VimMode enables vim-style editing
	VimMode bool
	// Animate enables animations
	Animate bool
	// WordWrap enables word wrapping
	WordWrap bool
	// CursorStyle controls cursor appearance
	CursorStyle CursorStyle
	// Theme provides colors and styles
	Theme Theme
}

WidgetOptions configures the Widget behavior

func DefaultWidgetOptions

func DefaultWidgetOptions() WidgetOptions

DefaultWidgetOptions returns sensible defaults

type WordCarouselAnimator

type WordCarouselAnimator struct {

	// Positions (0.0 to 1.0)
	PrevPos    float64
	CurrentPos float64
	NextPos    float64

	// State
	IsAnimating bool
	// contains filtered or unexported fields
}

WordCarouselAnimator handles the three-word carousel animation Used for speed reading applications

func NewWordCarouselAnimator

func NewWordCarouselAnimator() *WordCarouselAnimator

NewWordCarouselAnimator creates a new carousel animator

func (*WordCarouselAnimator) GetCurrentOffset

func (w *WordCarouselAnimator) GetCurrentOffset() int

GetCurrentOffset returns vertical offset for current word

func (*WordCarouselAnimator) GetCurrentScale

func (w *WordCarouselAnimator) GetCurrentScale() float64

GetCurrentScale returns scale factor for current word

func (*WordCarouselAnimator) GetNextOffset

func (w *WordCarouselAnimator) GetNextOffset() int

GetNextOffset returns vertical offset for next word

func (*WordCarouselAnimator) GetNextOpacity

func (w *WordCarouselAnimator) GetNextOpacity() float64

GetNextOpacity returns opacity for next word (max 60%)

func (*WordCarouselAnimator) GetPrevOffset

func (w *WordCarouselAnimator) GetPrevOffset() int

GetPrevOffset returns vertical offset for previous word

func (*WordCarouselAnimator) GetPrevOpacity

func (w *WordCarouselAnimator) GetPrevOpacity() float64

GetPrevOpacity returns opacity for previous word (max 50%)

func (*WordCarouselAnimator) TriggerTransition

func (w *WordCarouselAnimator) TriggerTransition()

TriggerTransition starts the word carousel animation

func (*WordCarouselAnimator) Update

func (w *WordCarouselAnimator) Update() bool

Update advances all springs by one frame

Directories

Path Synopsis
examples
animated command
Animated example demonstrating blockfont widget with animations.
Animated example demonstrating blockfont widget with animations.
demo command
Demo application showcasing all blockfont library features.
Demo application showcasing all blockfont library features.
editor command
Editor example demonstrating vim-style editing with blockfont.
Editor example demonstrating vim-style editing with blockfont.
lowercase_preview command
Preview all lowercase letters.
Preview all lowercase letters.
simple command
Simple example demonstrating basic blockfont usage.
Simple example demonstrating basic blockfont usage.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL