ExBanner

______ ____
/ ____/ __/ __ )____ _____ ____ ___ _____
/ __/ | |/_/ __ / __ `/ __ \/ __ \/ _ \/ ___/
/ /____> </ /_/ / /_/ / / / / / / / __/ /
/_____/_/|_/_____/\__,_/_/ /_/_/ /_/\___/_/

ASCII art banners for Elixir applications.

Installation

def deps do
[
{:exbanner, "~> 0.3"}
]
end

Requires Elixir 1.15+ and OTP 25+.

Startup banner

Tell ExBanner which application owns the banner:

# config/config.exs
config :exbanner, otp_app: :my_app

Then create priv/banner.txt in your application:

$[gold] __ __ _
| \/ |_ _ / \ _ __ _ __
| |\/| | | | | / _ \ | '_ \| '_ \
| | | | |_| | / ___ \| |_) | |_) |
|_| |_|\__, | /_/ \_\ .__/| .__/
|___/ |_| |_|$[reset]
$[dimgray]$app v$version | Elixir $elixir_version | OTP $otp_release$[reset]

ExBanner starts before your application, so the banner is printed before any of your logs. It works with mix run, iex -S mix, mix phx.server and releases.

Without otp_app ExBanner prints nothing, so a library that depends on ExBanner never prints a banner in your application unless you opt in. When otp_app is set and priv/banner.txt does not exist, ExBanner prints a default banner with the application name in the :standard font.

A failure while printing the startup banner is logged as a warning and never stops your application.

Placeholders

banner.txt is plain text. ExBanner replaces these placeholders, in the same style as Logger formats:

Placeholder Value
$app The otp_app name
$version Application version
$description Application description
$elixir_version System.version()
$otp_release System.otp_release()
$exbanner_version ExBanner version
$node node()
$hostname Host name
$release RELEASE_NAME, empty outside a release
$schedulers System.schedulers_online()

Only known names are replaced. Any other $ stays as written, so ASCII art with $$$$ is safe. A placeholder is read as a whole word: $app_name is not $app followed by _name, and stays literal.

Add your own values with :vars, as a map, a keyword list or an {module, function, args} tuple that returns one. Your values win over the built-in ones.

config :exbanner, otp_app: :my_app, vars: %{env: config_env()}

Colors

Write any Bunt color or style between brackets: $[red], $[gold], $[darkorange], $[bright], $[underline], $[reset]. Background colors use the _background suffix, as in $[darkblue_background].

ExBanner adds a reset at the end of a banner that uses colors. Colors are removed when ANSI is disabled and in :log mode. Unknown colors stay in the text and are logged as a warning. Sequences that move the cursor or clear the screen are not accepted.

Configuration

Option Default Description
:otp_app nil Application that owns the banner. Required to print anything.
:location priv/banner.txt of :otp_app A path, or {:priv, app, "file.txt"}. A missing file logs a warning and prints the default banner.
:mode :console :console writes to stdout, :log uses Logger.info/1, :off disables the startup banner.
:mix_tasks :all :all, :none, or a list of task names such as ["phx.server", "run"].
:vars %{} Extra placeholders.
:font_paths [] Directories with your own .flf fonts.

The startup banner also appears in mix tasks such as mix test and mix ecto.migrate. To limit it:

# only when the application runs
config :exbanner, mix_tasks: ["phx.server", "run"]
# or never in tests
# config/test.exs
config :exbanner, mode: :off

iex -S mix counts as run. Releases have no mix tasks and always print the banner.

To print the banner yourself, set mode: :off and call ExBanner.show/0 where you want it.

Rendering text

iex> ExBanner.print("Hello", font: :small)
_ _ _ _
| || |___| | |___
| __ / -_) | / _ \
|_||_\___|_|_\___/
:ok
iex> ExBanner.render("Hello", font: :slant)
{:ok, " __ __ ____ \n ..."}
iex> ExBanner.render!("Hello")
" _ _ _ _ \n ..."
iex> ExBanner.render("Hello", font: :nope)
{:error, {:unknown_font, "nope"}}
Function Returns
render(text, opts) {:ok, string} or {:error, reason}
render!(text, opts) The string, or raises ExBanner.Error
print(text, opts) :ok, raises on errors
show() Prints the startup banner, ignoring mode: :off and :mix_tasks
showcase(text, opts) :ok, after printing text in every font, page by page
fonts() The bundled font names

Options:

Option Default Description
:font :standard A bundled font, a font in :font_paths, or a path to a .flf file
:width 80 Line width. Longer text wraps at word boundaries, like figlet -w.
:color nil Bunt color, print/2 only
:device :stdio IO device, print/2 only

Characters the font does not have are rendered without accents when possible (ç becomes c), and as ? otherwise. They are never dropped silently.

Choosing a font

showcase/2 prints your text in every bundled font, each one under a header with its name ready to paste:

iex> ExBanner.showcase("Hello")
font: :"1row" (1/333)
...
-- 50 of 333 fonts, Enter for more, q to quit --
iex> ExBanner.showcase("Hello", match: "small")
iex> ExBanner.showcase("Hello", fonts: [:slant, :doom, :big], page_size: :infinity)

It pauses every 50 fonts (:page_size), filters by name with :match or takes an explicit list with :fonts, and accepts :width, :color and :device like print/2. Without a terminal it prints everything without pausing. Fonts read by showcase/2 are not kept in the font cache.

Fonts

ExBanner bundles 333 FIGlet and TOIlet fonts: the 18 fonts of the FIGlet 2.2.5 distribution and hundreds of fonts collected by the FIGlet community, including Crazy, Doom, Epic and ANSI Shadow. ExBanner.fonts/0 lists them all, and the site shows each one rendered.

Every font is credited to its author in CREDITS.md, with the terms stated in its file. Many fonts were published without a license; if you are the author of a font and want it removed or credited differently, write to contato@setbox.com.br and it will be removed or updated in the next release.

Font names are atoms. Names that start with a digit need quotes: font: :"3_d".

Your own fonts

Point ExBanner to a directory with .flf or .tlf files:

config :exbanner, font_paths: [Path.expand("../priv/fonts", __DIR__)]
ExBanner.print("Hello", font: :my_font)
ExBanner.print("Hello", font: "/path/to/my_font.flf")

Fonts in :font_paths take precedence over bundled fonts with the same name. Fonts are parsed on first use and cached with :persistent_term.

Security

ExBanner never evaluates code from banner.txt or from font files. Control characters, ANSI escape sequences and Unicode bidirectional overrides are removed from banner.txt, from placeholder values and from rendered text, and replaced by spaces in font glyphs, so a hostname or an environment variable cannot inject terminal sequences or fake log lines. Placeholder values are always a single line. Only ExBanner emits ANSI sequences, from a fixed list of colors and styles. Font and color names are never converted to atoms.

License

ExBanner is released under the MIT license. Bundled fonts keep the terms of their authors: see CREDITS.md, LICENSE and priv/fonts/LICENSE.figlet.