charmbracelet / lipgloss

Style definitions for nice terminal layouts 👄
MIT License
8.22k stars 231 forks source link

proposal: add support for gradient strings #326

Closed Delta456 closed 1 month ago

Delta456 commented 4 months ago

Is your feature request related to a problem? Please describe. I would love lipgloss to support gradient strings. Something similar is already present in charmbracelet/bubbles#progress

Describe the solution you'd like lipgloss to have functionality to support gradient strings.

Describe alternatives you've considered Currently working on a POC and later integrating it into lipgloss. I can make a PR later.

Additional context Check bokub/gradient-string for more reference

Delta456 commented 4 months ago

Have a POC ready

https://github.com/Delta456/gradient-string/blob/main/examples/simple.go

package main

import (
    "fmt"

    "github.com/charmbracelet/lipgloss"
    "github.com/delta456/gradient-strings"
)

func main() {
    b, _ := gradient.NewGradientBuilder(gradient.WithColors(lipgloss.Color("123"), lipgloss.Color("202")),
        gradient.WithDomain(0.0, 1.0)).Build()

    b1, _ := gradient.NewGradientBuilder(gradient.WithColors(lipgloss.Color("253"), lipgloss.Color("129")),
        gradient.WithDomain(0.0, 1.0)).Build()

    fmt.Println(b1.RenderBackground(b.RenderForeground("Hello World")))
}
0xPerseus commented 4 months ago

Under linux / macos, this is fairly simple to implement as per the below. From my limited knowledge of windows, it doesn't support the same style of ANSI escape codes without a bit of tweaking.

package main

import (
    "fmt"
)

func interpolateColor(start, end [3]float64, fraction float64) [3]float64 {
    return [3]float64{
        start[0] + (end[0]-start[0])*fraction,
        start[1] + (end[1]-start[1])*fraction,
        start[2] + (end[2]-start[2])*fraction,
    }
}

func rgbToAnsi(r, g, b int) string {
    return fmt.Sprintf("\033[38;2;%d;%d;%dm", r, g, b)
}

func main() {
    text := "This is an example of smooth gradient text that transitions from a light cyan color to purple. HELLO WORLD!"

    startColor := [3]float64{173, 216, 230}
    endColor := [3]float64{128, 0, 128}

    length := len(text)

    for i, char := range text {
        fraction := float64(i) / float64(length-1)
        color := interpolateColor(startColor, endColor, fraction)
        fmt.Print(rgbToAnsi(int(color[0]), int(color[1]), int(color[2])), string(char))
    }

    fmt.Print("\033[0m\n")
}
Delta456 commented 4 months ago

I know it's fairly simple but how can this be added alongside with the current lipgloss API design.

bashbunni commented 2 months ago

Hey, you can totally do this in Lip Gloss https://github.com/charmbracelet/lipgloss/pull/96 -> https://github.com/charmbracelet/lipgloss/blob/rainbow/examples/layout/main.go

I gotta merge that PR