← ブログ

Text.jsのFIGletフォント

@textjs/fontはFIGletの.flfフォントを解析し、figletプログラムと同じように配置します。テストではfiglet 2.2.5で記録した273件の出力を再現し、すべて一致しています。

Adam

Text.js 0.3では、FIGletフォントのパーサーとレンダラーである @textjs/font を追加しました。FIGlet 2.2.5の配布物に含まれる17のフォントをそれぞれ個別のESモジュールとして同梱し、出力は figlet 2.2.5のバイナリーと完全に一致します。

import { FigletText } from "@textjs/font/react";import { slant } from "@textjs/font/slant";export default function Page() {  return <FigletText font={slant} color="accent">Text.js</FigletText>;}
  ______          __      _ /_  __/__  _  __/ /_    (_)____  / / / _ \| |/_/ __/   / / ___/ / / /  __/>  </ /__   / (__  )/_/  \___/_/|_|\__(_)_/ /____/                   /___/

FIGletを採用した理由

<AsciiFont> には0.1以降、block と compact の2種類の組み込み文字スタイルがあります。FIGletは1991年からこの種の文字表現の標準であり、数百もの .flf フォントが存在します。この形式に対応することで、どのフォントもコンソールアプリに組み込めます。

FIGletフォントはプレーンテキストファイルです。ヘッダー行で高さ、ハードブランク文字、レイアウト規則を設定し、各文字を複数行のブロックとして描画します。各行の末尾には終端マークがあります。デフォルトのレイアウトでは、FIGletは各文字を直前の文字に接するまで左に移動し、フォントのスマッシング規則に従って、接した2つの構成文字を1つに結合するかどうかを決めます。

レイアウトモード

figlet には5種類の水平レイアウトがあり、renderFiglet でも layout を通じて同じ5種類を指定できます。

layoutfiglet効果
"default"-sフォント固有のレイアウト。通常はスマッシング
"full"-W全幅。文字同士の接触なし
"fitted"-k文字同士が接するまで間隔を縮小
"smushed"-Sフォントの規則に従ったスマッシング
"universal"-o後の文字を前の文字に重ね合わせ

-1〜63の数値は、-m のレイアウトモードを直接指定します。-1 は全幅、0 はフィット、1 〜 63 はスマッシング規則を選択します。水平スマッシングの規則は、同一文字、アンダースコア、階層、対向ペア、大きなX、ハードブランクの6種類すべてを実装しています。パーサーは、この形式のほかの要素にも対応しています。コメント行、10進数・8進数・16進数のコードタグ付き文字、欠落文字用グリフ、ivrit などの右から左に書くフォントを扱えます。

折り返しもFIGletに従います。width は figlet -w と同じ位置で、単語の境界、または単語が行幅を超える場合は単語の途中で折り返します。figlet -w 80 の出力は最大79列なので、-w N は width: N - 1 に対応します。

バイナリーとの出力一致

packages/font/test/fixtures/references.json には、実際の figlet 2.2.5をすべての同梱フォントとすべてのレイアウトモードで実行して生成した273の出力が格納されています。折り返し、行揃え、右から左へのテキスト、段落モードに加え、FIGlet自身の回帰テスト入力を run-tests.sh のフラグで実行した結果も含みます。各ケースには引数、入力、正確な出力が保存され、テストはコマンドラインをオプションに戻します。

for (const f of flags) {  if (f === "W") opts.layout = "full";  else if (f === "k") opts.layout = "fitted";  else if (f === "S") opts.layout = "smushed";  else if (f === "o") opts.layout = "universal";  else if (f === "s") opts.layout = "default";  else if (f === "c") opts.align = "center";  else if (f === "r") opts.align = "right";  else if (f === "l") opts.align = "left";  else if (f === "R") opts.direction = "rtl";  else if (f === "L") opts.direction = "ltr";  else if (f === "p") opts.paragraph = true;  else throw new Error(`unsupported flag -${f}`);}

273件すべてが一致します。フィクスチャを再生成するには、figlet 2.2.5を PATH に配置し、bun run --cwd packages/font references を実行します。

セルグリッド上のフォント

同梱フォントはすべて印字可能なASCIIまたはLatin-1で描画するため、各構成文字はMenloで正確に1セルを占め、グリッドに揃います。<FigletText> は行をセル単位で計測するため、ほかの <Text> と同じようにflexboxレイアウト内に文字を配置でき、columns と align でボックス内の折り返しと行揃えを指定できます。

各フォントは独立したモジュールなので、アプリにはインポートしたフォントだけが含まれ、フォントの解析はインポート時ではなく初回描画時に実行されます。@textjs/font/all はギャラリー向けにすべてのフォントをエクスポートします。

ほかのFIGfontも実行時に取得して解析できます。

import { parseFont } from "@textjs/font";const doom = parseFont(await (await fetch("/fonts/doom.flf")).text(), "Doom");

ライセンス

同梱フォントは figlet-2.2.5.tar.gz 内のものとバイト単位で同一であり、FIGletのBSD 3-Clauseライセンスの下で配布されます。各フォントのクレジットはコメント行に保持され、font.comment で参照できます。Doom、Larry 3D、ANSI Shadow、Calvin Sなど、再配布の許諾がない人気フォントは同梱していません。

完全なリファレンスはフォントにあります。