Convert Figma logo to code with AI

yaronn logoblessed-contrib

Build terminal dashboards using ascii/ansi art and javascript

15,465
841
15,465
95

Top Related Projects

11,248

A high-level terminal interface library for node.js.

9,827

Minimalist Go package aimed at creating Console User Interfaces.

13,132

Golang terminal dashboard

50,268

simple terminal UI for git commands

26,628

A powerful little TUI framework 🏗

10,830

Build terminal user interfaces and dashboards using Rust

Quick Overview

Blessed-contrib is a Node.js library that builds on top of the blessed library to create beautiful terminal dashboards using ASCII art and Unicode characters. It provides a collection of widgets and charts that can be easily composed to create rich, interactive command-line interfaces and dashboards.

Pros

  • Offers a wide variety of pre-built widgets and charts for terminal-based dashboards
  • Provides an easy-to-use API for creating complex layouts and arrangements
  • Supports real-time updates and animations
  • Highly customizable with extensive styling options

Cons

  • Limited to terminal environments, not suitable for GUI applications
  • May have performance issues with large datasets or complex layouts
  • Learning curve for users unfamiliar with blessed or terminal-based interfaces
  • Some widgets may not render correctly in all terminal emulators

Code Examples

Creating a simple dashboard with a line chart:

const blessed = require('blessed');
const contrib = require('blessed-contrib');

const screen = blessed.screen();
const grid = new contrib.grid({rows: 1, cols: 1, screen: screen});

const line = grid.set(0, 0, 1, 1, contrib.line, {
  style: {line: "yellow", text: "green", baseline: "black"},
  xLabelPadding: 3,
  xPadding: 5,
  label: 'Sales Growth'
});

const data = {
  x: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
  y: [10, 15, 25, 30, 35, 40]
};

line.setData([data]);

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render();

Adding a map widget to the dashboard:

const map = grid.set(0, 1, 1, 1, contrib.map, {label: 'World Map'});

const data = [
  {lat: 37.5, lon: -122.1, color: "red", char: "X"}
];

map.setData(data);

Creating a log widget:

const log = grid.set(1, 0, 1, 2, contrib.log, {
  fg: "green",
  selectedFg: "green",
  label: 'Server Log'
});

log.log("System started");
log.log("Listening on port 8080");

Getting Started

To get started with blessed-contrib:

  1. Install the library:

    npm install blessed blessed-contrib
    
  2. Create a new JavaScript file (e.g., dashboard.js) and import the required modules:

    const blessed = require('blessed');
    const contrib = require('blessed-contrib');
    
  3. Create a screen and grid:

    const screen = blessed.screen();
    const grid = new contrib.grid({rows: 2, cols: 2, screen: screen});
    
  4. Add widgets to the grid and render the screen:

    const line = grid.set(0, 0, 1, 2, contrib.line, {label: 'Line Chart'});
    // Add data to the line chart
    screen.render();
    
  5. Run your dashboard:

    node dashboard.js
    

Competitor Comparisons

11,248

A high-level terminal interface library for node.js.

Pros of blessed

  • More mature and stable project with a larger user base
  • Provides a lower-level API for greater flexibility and control
  • Better documentation and more extensive examples

Cons of blessed

  • Steeper learning curve for beginners
  • Requires more code to create complex layouts and widgets
  • Less out-of-the-box functionality for creating dashboards

Code Comparison

blessed:

const blessed = require('blessed');
const screen = blessed.screen();
const box = blessed.box({
  content: 'Hello, world!'
});
screen.append(box);

blessed-contrib:

const contrib = require('blessed-contrib');
const screen = contrib.screen();
const grid = new contrib.grid({rows: 1, cols: 1});
const box = grid.set(0, 0, 1, 1, contrib.box, {content: 'Hello, world!'});
screen.render();

Summary

blessed is a more flexible and powerful library for creating terminal-based user interfaces, offering greater control and customization options. It's ideal for developers who need fine-grained control over their UI elements.

blessed-contrib, built on top of blessed, provides a higher-level API with pre-built widgets and layouts, making it easier to create complex dashboards and data visualizations quickly. It's more suitable for rapid prototyping and creating data-rich terminal applications with less code.

Both libraries have their strengths, and the choice between them depends on the specific requirements of your project and your familiarity with terminal-based UI development.

9,827

Minimalist Go package aimed at creating Console User Interfaces.

Pros of gocui

  • Written in Go, offering better performance and lower resource usage
  • Simpler API, making it easier to create basic terminal user interfaces
  • Focuses on core TUI functionality without extra widgets or charts

Cons of gocui

  • Less feature-rich compared to blessed-contrib's extensive widget library
  • Limited to terminal-based interfaces, while blessed-contrib can create web-based dashboards
  • Lacks built-in support for complex data visualizations like graphs and charts

Code Comparison

gocui example:

g, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
    log.Panicln(err)
}
defer g.Close()

g.SetManagerFunc(layout)

blessed-contrib example:

var blessed = require('blessed')
  , contrib = require('blessed-contrib')
  , screen = blessed.screen()
  , grid = new contrib.grid({rows: 12, cols: 12, screen: screen})

The gocui example demonstrates its simplicity in creating a basic GUI, while the blessed-contrib example showcases its grid-based layout system for more complex dashboards.

13,132

Golang terminal dashboard

Pros of termui

  • Written in Go, offering better performance and easier deployment
  • More actively maintained with recent updates
  • Simpler API and easier to get started with

Cons of termui

  • Less extensive widget library compared to blessed-contrib
  • Limited to terminal-based applications, while blessed-contrib can be used in web browsers

Code Comparison

blessed-contrib (JavaScript):

var blessed = require('blessed');
var contrib = require('blessed-contrib');
var screen = blessed.screen();
var grid = new contrib.grid({rows: 12, cols: 12, screen: screen});
grid.set(0, 0, 4, 4, contrib.line, {label: 'Stocks'});

termui (Go):

ui := termui.New()
defer ui.Close()
p := widgets.NewParagraph()
p.Text = "Hello World!"
ui.Render(p)

Both libraries provide ways to create terminal-based user interfaces, but termui's approach is more straightforward and idiomatic to Go, while blessed-contrib offers more flexibility and a wider range of widgets in JavaScript.

50,268

simple terminal UI for git commands

Pros of lazygit

  • Focused specifically on Git operations, providing a more streamlined and intuitive interface for Git users
  • Offers interactive staging, commit management, and branch operations within a single TUI
  • Regularly updated with new features and improvements

Cons of lazygit

  • Limited to Git functionality, lacking the versatility of blessed-contrib for creating various dashboard components
  • Steeper learning curve for users not familiar with Git concepts
  • Less customizable in terms of layout and visual elements compared to blessed-contrib

Code Comparison

lazygit (Go):

func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
    message := gui.trimmedContent(v)
    if message == "" {
        return gui.createErrorPanel(gui.Tr.NoCommitMessageErr)
    }
    return gui.handleCommitSubmit(message)
}

blessed-contrib (JavaScript):

function line(options) {
  if (!(this instanceof Line)) {
    return new Line(options)
  }
  options = options || {}
  this.options = options
  this.type = 'line'
  this.data = []
}

While both repositories provide terminal-based user interfaces, lazygit focuses on Git operations with a more opinionated design, whereas blessed-contrib offers a flexible framework for creating various dashboard components. The code snippets illustrate the different languages and approaches used in each project.

26,628

A powerful little TUI framework 🏗

Pros of Bubbletea

  • Written in Go, offering better performance and concurrency support
  • More flexible and customizable, allowing for complex TUI applications
  • Active development with frequent updates and a growing community

Cons of Bubbletea

  • Steeper learning curve, especially for developers new to Go
  • Less out-of-the-box components compared to Blessed-contrib

Code Comparison

Blessed-contrib example:

var blessed = require('blessed')
var contrib = require('blessed-contrib')
var screen = blessed.screen()
var grid = new contrib.grid({rows: 12, cols: 12, screen: screen})
grid.set(0, 0, 4, 4, contrib.line, {label: 'Stocks'})

Bubbletea example:

import (
    "github.com/charmbracelet/bubbles/viewport"
    tea "github.com/charmbracelet/bubbletea"
)

type model struct {
    viewport viewport.Model
}

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

Both libraries offer powerful tools for creating terminal user interfaces, but they cater to different needs and preferences. Blessed-contrib provides a rich set of pre-built components and is easier to get started with, especially for JavaScript developers. Bubbletea, on the other hand, offers more flexibility and performance, making it suitable for complex applications, but requires more setup and Go knowledge.

10,830

Build terminal user interfaces and dashboards using Rust

Pros of tui-rs

  • Written in Rust, offering better performance and memory safety
  • More flexible and customizable, allowing for complex terminal UIs
  • Actively maintained with regular updates and improvements

Cons of tui-rs

  • Steeper learning curve, especially for developers not familiar with Rust
  • Less out-of-the-box widgets compared to blessed-contrib

Code Comparison

tui-rs:

use tui::widgets::{Block, Borders};
let block = Block::default()
    .title("Block")
    .borders(Borders::ALL);
f.render_widget(block, chunks[0]);

blessed-contrib:

var blessed = require('blessed');
var contrib = require('blessed-contrib');
var screen = blessed.screen();
var line = contrib.line(
  { style: { line: "yellow", text: "green", baseline: "black" } }
);
screen.append(line);

Summary

tui-rs offers a more performant and flexible solution for building terminal user interfaces, leveraging Rust's strengths. It provides greater customization options but requires more setup and Rust knowledge. blessed-contrib, on the other hand, offers a simpler JavaScript-based approach with more pre-built widgets, making it easier for quick prototyping and development. The choice between the two depends on the project requirements, performance needs, and the developer's familiarity with the respective languages and ecosystems.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

blessed-contrib

Build dashboards (or any other application) using ascii/ansi art and javascript.

Friendly to terminals, ssh and developers. Extends blessed with custom drawille and other widgets.

You should also check WOPR: a markup for creating terminal reports, presentations and infographics.

Contributors:

Yaron Naveh (@YaronNaveh) Chris (@xcezzz) Miguel Valadas (@mvaladas) Liran Tal (@lirantal)

Demo (full size):

term term

(source code)

Running the demo

git clone https://github.com/yaronn/blessed-contrib.git
cd blessed-contrib
npm install
node ./examples/dashboard.js

Works on Linux, OS X and Windows. For Windows follow the pre requisites.

Installation (to build custom projects)

npm install blessed blessed-contrib

Usage

You can use any of the default widgets of blessed (texts, lists and etc) or the widgets added in blessed-contrib (described below). A layout is optional but useful for dashboards. The widgets in blessed-contrib follow the same usage pattern:

   var blessed = require('blessed')
     , contrib = require('blessed-contrib')
     , screen = blessed.screen()
     , line = contrib.line(
         { style:
           { line: "yellow"
           , text: "green"
           , baseline: "black"}
         , xLabelPadding: 3
         , xPadding: 5
         , label: 'Title'})
     , data = {
         x: ['t1', 't2', 't3', 't4'],
         y: [5, 1, 7, 5]
      }
   screen.append(line) //must append before setting data
   line.setData([data])

   screen.key(['escape', 'q', 'C-c'], function(ch, key) {
     return process.exit(0);
   });

   screen.render()

See below for a complete list of widgets.

Widgets

Line Chart

Bar Chart

Stacked Bar Chart

Map

Gauge

Stacked Gauge

Donut

LCD Display

Rolling Log

Picture

Sparkline

Table

Tree

Markdown

Line Chart

line
   var line = contrib.line(
         { style:
           { line: "yellow"
           , text: "green"
           , baseline: "black"}
         , xLabelPadding: 3
         , xPadding: 5
         , showLegend: true
         , wholeNumbersOnly: false //true=do not show fraction in y axis
         , label: 'Title'})
   var series1 = {
         title: 'apples',
         x: ['t1', 't2', 't3', 't4'],
         y: [5, 1, 7, 5]
      }
   var series2 = {
         title: 'oranges',
         x: ['t1', 't2', 't3', 't4'],
         y: [2, 1, 4, 8]
      }
   screen.append(line) //must append before setting data
   line.setData([series1, series2])

Examples: simple line chart, multiple lines, 256 colors

Bar Chart

bar
    var bar = contrib.bar(
       { label: 'Server Utilization (%)'
       , barWidth: 4
       , barSpacing: 6
       , xOffset: 0
       , maxHeight: 9})
    screen.append(bar) //must append before setting data
    bar.setData(
       { titles: ['bar1', 'bar2']
       , data: [5, 10]})

Stacked Bar Chart

stacked-bar
    bar = contrib.stackedBar(
       { label: 'Server Utilization (%)'
       , barWidth: 4
       , barSpacing: 6
       , xOffset: 0
       //, maxValue: 15
       , height: "40%"
       , width: "50%"
       , barBgColor: [ 'red', 'blue', 'green' ]})
    screen.append(bar)
    bar.setData(
       { barCategory: ['Q1', 'Q2', 'Q3', 'Q4']
       , stackedCategory: ['US', 'EU', 'AP']
       , data:
          [ [ 7, 7, 5]
          , [8, 2, 0]
          , [0, 0, 0]
          , [2, 3, 2] ]
       })

Map

map
   var map = contrib.map({label: 'World Map'})
   map.addMarker({"lon" : "-79.0000", "lat" : "37.5000", color: "red", char: "X" })

Gauge

gauge
   var gauge = contrib.gauge({label: 'Progress', stroke: 'green', fill: 'white'})
   gauge.setPercent(25)

Stacked Gauge

stackedgauge

Either specify each stacked portion with a percent and stroke...

   var gauge = contrib.gauge({label: 'Stacked '})
   gauge.setStack([{percent: 30, stroke: 'green'}, {percent: 30, stroke: 'magenta'}, {percent: 40, stroke: 'cyan'}])

Or, you can just supply an array of numbers and random colors will be chosen.

   var gauge = contrib.gauge({label: 'Stacked Progress'})
   gauge.setStack([30,30,40])

Donut

donut
   var donut = contrib.donut({
	label: 'Test',
	radius: 8,
	arcWidth: 3,
	remainColor: 'black',
	yPadding: 2,
	data: [
	  {percent: 80, label: 'web1', color: 'green'}
	]
  });

Data passed in uses percent and label to draw the donut graph. Color is optional and defaults to green.

   donut.setData([
   	{percent: 87, label: 'rcp','color': 'green'},
	{percent: 43, label: 'rcp','color': 'cyan'},
   ]);

Updating the donut is as easy as passing in an array to setData using the same array format as in the constructor. Pass in as many objects to the array of data as you want, they will automatically resize and try to fit. However, please note that you will still be restricted to actual screen space.

You can also hardcode a specific numeric into the donut's core display instead of the percentage by passing an percentAltNumber property to the data, such as:

   var donut = contrib.donut({
	label: 'Test',
	radius: 8,
	arcWidth: 3,
	remainColor: 'black',
	yPadding: 2,
	data: [
	  {percentAltNumber: 50, percent: 80, label: 'web1', color: 'green'}
	]
  });

See an example of this in one of the donuts settings on ./examples/donut.js.

LCD Display

lcd
   var lcd = contrib.lcd(
     { segmentWidth: 0.06 // how wide are the segments in % so 50% = 0.5
     , segmentInterval: 0.11 // spacing between the segments in % so 50% = 0.550% = 0.5
     , strokeWidth: 0.11 // spacing between the segments in % so 50% = 0.5
     , elements: 4 // how many elements in the display. or how many characters can be displayed.
     , display: 321 // what should be displayed before first call to setDisplay
     , elementSpacing: 4 // spacing between each element
     , elementPadding: 2 // how far away from the edges to put the elements
     , color: 'white' // color for the segments
     , label: 'Storage Remaining'})

	lcd.setDisplay(23 + 'G'); // will display "23G"
	lcd.setOptions({}) // adjust options at runtime

Please see the examples/lcd.js for an example. The example provides keybindings to adjust the segmentWidth and segmentInterval and strokeWidth in real-time so that you can see how they manipulate the look and feel.

Rolling Log

log
   var log = contrib.log(
      { fg: "green"
      , selectedFg: "green"
      , label: 'Server Log'})
   log.log("new log line")

Picture

(Also check the new blessed image implementation which has several benefits over this one.)

log
    var pic = contrib.picture(
       { file: './flower.png'
       , cols: 25
       , onReady: ready})
    function ready() {screen.render()}

note: only png images are supported

Sparkline

spark
   var spark = contrib.sparkline(
     { label: 'Throughput (bits/sec)'
     , tags: true
     , style: { fg: 'blue' }})

   sparkline.setData(
   [ 'Sparkline1', 'Sparkline2'],
   [ [10, 20, 30, 20]
   , [40, 10, 40, 50]])

Table

table
   var table = contrib.table(
     { keys: true
     , fg: 'white'
     , selectedFg: 'white'
     , selectedBg: 'blue'
     , interactive: true
     , label: 'Active Processes'
     , width: '30%'
     , height: '30%'
     , border: {type: "line", fg: "cyan"}
     , columnSpacing: 10 //in chars
     , columnWidth: [16, 12, 12] /*in chars*/ })

   //allow control the table with the keyboard
   table.focus()

   table.setData(
   { headers: ['col1', 'col2', 'col3']
   , data:
      [ [1, 2, 3]
      , [4, 5, 6] ]})

Tree

table
   var tree = contrib.tree({fg: 'green'})

   //allow control the table with the keyboard
   tree.focus()

   tree.on('select',function(node){
     if (node.myCustomProperty){
       console.log(node.myCustomProperty);
     }
     console.log(node.name);
   }

   // you can specify a name property at root level to display root
   tree.setData(
   { extended: true
   , children:
     {
       'Fruit':
       { children:
         { 'Banana': {}
         , 'Apple': {}
         , 'Cherry': {}
         , 'Exotics': {
             children:
             { 'Mango': {}
             , 'Papaya': {}
             , 'Kiwi': { name: 'Kiwi (not the bird!)', myCustomProperty: "hairy fruit" }
             }}
         , 'Pear': {}}}
     , 'Vegetables':
       { children:
         { 'Peas': {}
         , 'Lettuce': {}
         , 'Pepper': {}}}}})

Options

  • keys : Key to expand nodes. Default : ['enter','default']
  • extended : Should nodes be extended/generated by default? Be careful with this setting when using a callback function. Default : false
  • template :
    • extend : Suffix "icon" for closed node. Default : '[+]'
    • retract : Suffix "icon" for opened node. Default : '[-]'
    • lines : Show lines in tree. Default : true

Nodes

Every node is a hash and it can have custom properties that can be used in "select" event callback. However, there are several special keys :

  • name
    • Type : string
    • Desc : Node name
    • If the node isn't the root and you don't specify the name, will be set to hash key
    • Example : { name: 'Fruit'}
  • children
    • Type : hash or function(node){ return children }
    • Desc : Node children.
    • The function must return a hash that could have been used as children property
    • If you use a function, the result will be stored in node.childrenContent and children
    • Example :
      • Hash : {'Fruit':{ name: 'Fruit', children:{ 'Banana': {}, 'Cherry': {}}}}
      • Function : see examples/explorer.js
  • childrenContent
    • Type : hash
    • Desc : Children content for internal usage DO NOT MODIFY
    • If node.children is a hash, node.children===node.childrenContent
    • If node.children is a function, it's used to store the node.children() result
    • You can read this property, but you should never write it.
    • Usually this will be used to check if(node.childrenContent) in your node.children function to generate children only once
  • extended
    • Type : boolean
    • Desc : Determine if this node is extended
    • No effect when the node have no child
    • Default value for each node will be treeInstance.options.extended if the node extended option is not set
    • Example : {'Fruit':{ name: 'Fruit', extended: true, children:{ 'Banana': {}, 'Cherry': {}}}}

Markdown

table
   var markdown = contrib.markdown()
   markdown.setMarkdown('# Hello \n blessed-contrib renders markdown using `marked-terminal`')

Colors

You can use 256 colors (source):

  function randomColor() {
    return [Math.random() * 255,Math.random()*255, Math.random()*255]
  }

  line = contrib.line(
  {
    ...
    , style: { line: randomColor(), text: randomColor(), baseline: randomColor() }
  })

Layouts

Grid

Carousel

Grid

A grid layout can auto position your elements in a grid layout. When using a grid, you should not create the widgets, rather specify to the grid which widget to create and with which params. Each widget can span multiple rows and columns.

   var screen = blessed.screen()

   var grid = new contrib.grid({rows: 12, cols: 12, screen: screen})

   //grid.set(row, col, rowSpan, colSpan, obj, opts)
   var map = grid.set(0, 0, 4, 4, contrib.map, {label: 'World Map'})
   var box = grid.set(4, 4, 4, 4, blessed.box, {content: 'My Box'})

   screen.render()

Carousel

A carousel layout switches between different views based on time or keyboard activity. One use case is an office dashboard with rotating views:

    var blessed = require('blessed')
      , contrib = require('./')
      , screen = blessed.screen()

    function page1(screen) {
       var map = contrib.map()
       screen.append(map)
    }

    function page2(screen) {
      var line = contrib.line(
       { width: 80
       , height: 30
       , left: 15
       , top: 12
       , xPadding: 5
       , label: 'Title'
       })

      var data = [ { title: 'us-east',
                 x: ['t1', 't2', 't3', 't4'],
                 y: [0, 0.0695652173913043, 0.11304347826087, 2],
                 style: {
                  line: 'red'
                 }
               }
            ]

      screen.append(line)
      line.setData(data)
    }

    screen.key(['escape', 'q', 'C-c'], function(ch, key) {
      return process.exit(0);
    });

    var carousel = new contrib.carousel( [page1, page2]
                                       , { screen: screen
                                         , interval: 3000 //how often to switch views (set 0 to never swicth automatically)
                                         , controlKeys: true  //should right and left keyboard arrows control view rotation
                                         })
    carousel.start()

Samples

Terminal Dashboard

term

Running the sample

git clone https://github.com/yaronn/blessed-contrib.git
cd blessed-contrib
npm install
node ./examples/dashboard.js

Installation (for a custom dashboard)

npm install blessed
npm install blessed-contrib

A simple dashboard

   var blessed = require('blessed')
     , contrib = require('blessed-contrib')
     , screen = blessed.screen()
     , grid = new contrib.grid({rows: 1, cols: 2, screen: screen})

   var line = grid.set(0, 0, 1, 1, contrib.line,
     { style:
       { line: "yellow"
       , text: "green"
       , baseline: "black"}
     , xLabelPadding: 3
     , xPadding: 5
     , label: 'Stocks'})

   var map = grid.set(0, 1, 1, 1, contrib.map, {label: 'Servers Location'})

   var lineData = {
      x: ['t1', 't2', 't3', 't4'],
      y: [5, 1, 7, 5]
   }

   line.setData([lineData])

   screen.key(['escape', 'q', 'C-c'], function(ch, key) {
     return process.exit(0);
   });

   screen.render()

Rich dashboard

See source code

Troubleshooting

If you see questions marks or some (or all) missign characters try running with these env vars to fix encoding / terminal:

    $> LANG=en_US.utf8 TERM=xterm-256color node your-code.js 

License

This library is under the MIT License

More Information

Created by Yaron Naveh (twitter, blog)

NPM DownloadsLast 30 Days