ExBanner
______ ____
/ ____/ __/ __ )____ _____ ____ ___ _____
/ __/ | |/_/ __ / __ `/ __ \/ __ \/ _ \/ ___/
/ /____> </ /_/ / /_/ / / / / / / / __/ /
/_____/_/|_/_____/\__,_/_/ /_/_/ /_/\___/_/
ASCII art banners for Elixir applications.
- Prints a startup banner from
priv/banner.txtwhen your application boots. - Renders text with FIGlet fonts:
ExBanner.print("Hello", font: :slant). - Output matches
figlet2.2.5 byte for byte, including smushing and word wrapping, in 329 of the 333 fonts; the other 4 have malformed glyphs wherefigletitself misbehaves. - 333 bundled fonts, each credited to its author.
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.