• Stars
    star
    3,237
  • Rank 13,777 (Top 0.3 %)
  • Language
    JavaScript
  • License
    Other
  • Created about 9 years ago
  • Updated about 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A terminal-to-gif recorder minus the headaches.

ttystudio

A terminal-to-gif recorder minus the headaches.

ttystudio

Record your terminal and compile it to a GIF or APNG without any external dependencies, bash scripts, gif concatenation, etc.

Install with: $ npm install ttystudio. (Add -g for global install).

Usage

$ ttystudio output.gif --log
  $ vim
    hello world
    :q!
  $ ^Q # stop recording with ctrl-q
initializing writer
writing image
writing head
writing frame 0 - 132 left
writing frame 1 - 131 left
writing frame 2 - 130 left
...
writing frame 131 - 1 left
writing eof
wrote image to /home/chjj/output.gif
$ chromium output.gif
# or if you wrote to output.png (an APNG)
$ firefox output.png

The Difference

ttystudio differs from other terminal recorders in that:

  1. It has its own built-in gif and apng writer, no imagemagick required. The writer now has built-in frame offset optimization.
  2. It has a font parser to render the font during image writing so no terminal playback is required when writing the image (this also means no GUI is required at all - you can record on a remote machine via ssh).
  3. No concatenation of hundreds of gif files required. ttystudio automatically writes out to one gif or apng.
  4. No glitchy frames due to imperfect GUI recording of the playback or gif concatenation.
  5. ttystudio will record frames even if nothing is being updated on the screen.

This project has ended up making use of years of work I've done writing terminal libraries (my personal obsession). Once all the pieces were there, this project became possible. It also sprang out of a need to find a terminal-to-gif recorder that actually worked.

(NOTE: The above .gif was recorded with ttystudio - nested ttystudio instances cause a slight glitch where the cursor is not visible. Not to matter in most cases).

More Usage

$ ttystudio output.gif --log # record and compile
$ ttystudio frames.json --log # record
$ ttystudio frames.json output.gif --range=0-50 # compile

Use a frames.json file

$ ttystudio --record frames.json --interval=100 # grab each frame on a 100ms interval
  $ vim
    hello world
    :q!
  $ ^Q # stop recording with ctrl-q
$ ttystudio --compile frames.json output.gif --log
parsing json
initializing writer
writing image
writing head
writing frame 0 - 132 left
writing frame 1 - 131 left
writing frame 2 - 130 left
...
writing frame 131 - 1 left
writing eof
wrote image to /home/chjj/output.gif
$ chromium output.gif
# or if you wrote to output.png (an APNG)
$ firefox output.png

How it works

  1. $ ttystudio --record frames.json: blessed+term.js+pty.js will spawn a pseudo-terminal to let you record until you press ^Q.
  2. $ ttystudio --compile frames.json output.gif: ttystudio will parse each set of frames into a bitmap, keeping in mind the foreground color and character in each cell.
  3. It will use its parsed font (terminus-u14n/b by default) to render pixels for each characters in the image.
  4. It will write out each frame to a .gif or .png file of your choice.

It's that simple. No bash script to run. No gifs to concatenate. No external dependencies required (i.e. ffmpeg or imagemagick) - ttystudio does it all on its own, in 99% javascript (aside from pty.js which is a node c++ binding to spawn terminals).

Options and Examples

Compiling to APNG:

$ ttystudio frames.json output.png --log

Accidentally recorded something you don't want in your image? The range option can help:

# compile only frames 5 to 130
$ ttystudio frames.json output.gif --log --range=5-130

The delay option sets the delay between frames in the final image:

# 100ms between output frames
$ ttystudio frames.json output.png --log --delay=100

The --no-palette/--rgba option can be used to avoid use a global palette (color type 3) when compiling APNGs (this is known to cause high memory usage when building the palette since it has to parse every frame beforehand). Instead, it will use color type 6 (RGBA). This will make the APNG larger, but does not risk OOMing the process. OOMing the process is unlikely to happen, but if it does, this option is here. Use pngcrush afterwards to optimize.

$ ttystudio frames.json output.png --log --rgba

Piping:

$ ttystudio frames.json - | feh -

Replaying frames in the terminal:

$ ttystudio --play frames.json

Adding a border:

# explanation of arguments:
$ ttystudio output.gif --log --border=[width],[r],[g],[b],[a]
# add a red border:
$ ttystudio output.gif --log --border=10,255,0,0,255
# white border:
$ ttystudio output.gif --log --border=10,255
$ ttystudio output.gif --log --border=10,255,255,255
$ ttystudio output.gif --log --border=10

Start in screenshot mode. This allows you to take multiple screenshot whenever C-p is pressed. ttystudio will write them all to separate images.

$ ttystudio o.gif --screenshot --screenshot-key C-p

Full Options List

  • -l, --log

    • Log status to stderr (now default).
  • -q, --quiet

    • Do not log status to stderr.
  • -f, --font [font-file]

    • Choose a BDF font in ttystudio's JSON format.
  • -b, --font-bold [font-file]

    • Choose a bold BDF font in ttystudio's JSON format.
  • -d, --delay [delay-ms]

    • Specify frame delay in ms (default: 100).
  • -i, --interval [interval-ms]

    • Specify frame snapshot interval in ms (default: 100).
  • -k, --key [quit-key]

    • Choose a key combination to quit recording (default: C-q).
  • -n, --num-plays [num-plays]

    • Specify a number of plays for the animation (default: 0 - infinite).
  • -r, --range [frame-range]

    • Choose a range of frames to compile. e.g. 5-200.
  • -x, --ratio [pixel-cell-ratio]

    • Choose pixel to cell ratio. This option is useless right now since it is overwritten by the font (default: 8x14).
  • -t, --term [term-name]

    • Choose the terminal name for terminfo.
  • --palette

    • Use a global palette for APNGs instead of RGBA.
  • --no-palette, --rgba, --lct

    • Use RGBA for APNGs instead of a global palette. This will also avoid building a global palette for GIFs and only use a local color table for each frame.
  • --border [width,r,g,b,a]

    • Add a border around the animation using the specified parameters.
  • play, --play

    • Replay a frames file in the terminal.
  • record, --record

    • Explicitly choose to record (not very useful).
  • compile, --compile

    • Explicitly choose to compile (not very useful).
  • screenshot, --screenshot

    • Start ttystudio in screenshot mode. It will take a screenshot on C-p unless specified otherwise by --screenshot-key.
  • --screenshot-key

    • Set the screenshot key when in screenshot mode. Default is C-p.
  • --version

    • Display ttystudio version.
  • -h, --help

    • Display help information.

Choosing a new font for your terminal recording

Since ttystudio does not record a GUI, it needs to know which font you want to use (it has no real idea of the font your terminal is using). ttystudio uses terminus (ter-u14n/b) by default, but you can change this.

Your font must be in BDF format. Once you have your font ready, place it in the fonts/ directory in ttystudio and run $ make. ttystudio+pxxl.js will convert the .bdf font to a glyph bitmap format in a json file, which is what ttystudio uses.

$ cp ~/ter-u12n.bdf ~/ttystudio/fonts/
$ cp ~/ter-u12b.bdf ~/ttystudio/fonts/
$ cd ~/ttystudio/fonts
$ make
...
$ ttystudio output.gif --log \
  --font ~/ttystudio/fonts/ter-u12n.json \
  --font-bold ~/ttystudio/fonts/ter-u12b.json

OSX

pty.js seems to currently be causing sporadic input lag on OSX. This is being investigated.

Notes

A special thanks to the folks who developed pxxl.js - a BDF font parser. Without them, it would not have been possible to render a reasonable looking font to the output gif/png.

Todo

  • More fonts and font formats supported.
  • Antialiased fonts.
  • Emit frames as events in writers.

Contribution and License Agreement

If you contribute code to this project, you are implicitly allowing your code to be distributed under the MIT license. You are also implicitly verifying that all code is your original work. </legalese>

License

Copyright (c) 2015, Christopher Jeffrey. (MIT License)

See LICENSE for more info.

More Repositories

1

blessed

A high-level terminal interface library for node.js.
JavaScript
11,260
star
2

tty.js

A terminal for your browser, using node/express/socket.io
JavaScript
4,184
star
3

compton

A compositor for X11.
C
2,245
star
4

term.js

A terminal written in javascript.
JavaScript
1,547
star
5

pty.js

Bindings to forkpty(3) for node.js.
C++
855
star
6

mako

Bitcoin node written in C
C
572
star
7

termcoin

A bitcoin wallet and blockchain explorer for your terminal.
JavaScript
480
star
8

liburkel

Authenticated key-value store (i.e. an urkel tree)
C
303
star
9

zest

An absurdly fast CSS selector engine.
JavaScript
238
star
10

slock

Fork of suckless screen locker for the extremely paranoid.
C
152
star
11

tiny

A small database for node.js.
JavaScript
111
star
12

lcdb

LevelDB implemented in C (unofficial -- not affiliated with Google in any way)
C
94
star
13

bns

Recursive DNS server and resolver for node.js
JavaScript
66
star
14

parted

Streaming body parser for node.js.
JavaScript
63
star
15

bthreads

worker threads for javascript
JavaScript
48
star
16

bpkg

Bundler and release tool for node.js
JavaScript
44
star
17

tng

A full-featured PNG renderer for the terminal.
JavaScript
41
star
18

coined

A high-level wrapper around BCoin
JavaScript
25
star
19

node-uo

A UO server for node.js
JavaScript
25
star
20

n64

Int64 object for javascript
JavaScript
24
star
21

liquor

A templating engine minus the code.
JavaScript
19
star
22

daemonic

A dead-simple module to daemonize a node. No compilation required.
JavaScript
19
star
23

node-telnet2

Telnet implementation for node.js, based on node-telnet
JavaScript
18
star
24

gitj

gitk in your terminal.
JavaScript
15
star
25

node-pingback

pingbacks for node.js
JavaScript
15
star
26

dilated

A blog for node.js.
JavaScript
14
star
27

csslike

A CSS preprocessor for node.js, designed to conform to the most recent www-style proposals.
CSS
12
star
28

cmake-node

node.js toolchain for cmake
C
11
star
29

rondo

DOM library and app framework.
JavaScript
11
star
30

st

A fork of st implementing scrollback, keyboard selection, and tabs.
C
11
star
31

highlighter.js

a quick and dirty JS highlighter
JavaScript
10
star
32

charged

High-level Chargify API binding for node.js
JavaScript
10
star
33

supersha

Fast SHA256 for node.js
C
10
star
34

dwm

My dwm fork and configuration.
C
10
star
35

tmux

A fork of tmux implementing xterm behavior.
C
8
star
36

vanilla

A framework for node.js.
JavaScript
8
star
37

Live-Stylesheets

small google chrome extension for editing a page's raw css
JavaScript
8
star
38

shim.htc

An HTML5 Shim in an HTML Component
JavaScript
8
star
39

epsilon-not

Weblog
PHP
5
star
40

unbound

Bindings to libunbound for node.js
C
5
star
41

evilpart

A Node multipart parser that is positively evil
JavaScript
5
star
42

N

pretty control for js
JavaScript
5
star
43

nmterm

A wicd-curses-like interface for NetworkManager
JavaScript
5
star
44

pulsemixer.js

An alsamixer-like interface for PulseAudio
JavaScript
4
star
45

rocksdown

RocksDB backend for LevelUP
C++
4
star
46

bsert

Minimal assertions for javascript
JavaScript
4
star
47

bitcoind.js

bitcoind.js has moved to https://github.com/bitpay/bitcoind.js
C++
4
star
48

wazm

WASM abstraction and EMCC preamble
JavaScript
3
star
49

babylonia

zero-dependency babel
JavaScript
3
star
50

bslint

eslint with less (or more) bullshit
JavaScript
3
star
51

bdoc

zero-dependency jsdoc
JavaScript
3
star
52

pkg-verify

Dependency verifier for node.js
JavaScript
3
star
53

buffer-map

Buffer-keyed map for javascript
JavaScript
2
star
54

loady

dynamic loader for node.js
JavaScript
2
star
55

qrsuite

jsqrcode and qr.js rolled into one package
JavaScript
1
star