This is a faithful recreation of the DEC VT220 fonts in bitmap font format. It uses a VT220 ROM dump and applies the same pixel operations described in the VT220 technical manual. The only departure is that the bitmap is stretched 2x vertically, since the VT220’s vertical pixel density was about half its horizontal pixel density.
Fonts with 150 x-resolution are double-width fonts. They are created by doubling the width before stretching, as described in the DEC manual.
Additionally, I have added a few new characters based on the original glyphs, mostly from the General Punctuation Unicode block (U+2000 - U+206F), since they are encountered regularly when using terminal-based web browsers. Bold, italic, and bold italic fonts (generated using mkbolditalic) are also included, although they are anachronistic for a VT220.
The default base BDF set is the 80-column xterm master set: normal 10x20 at 75 x-resolution, double-wide 20x20 at 150 x-resolution, and double-size 20x40 at 75 x-resolution. Additional scaled sizes and 132-column variants can be generated explicitly.
Taylor Hardy’s original contributions are licensed under the MIT License. The font masters and generated fonts incorporate historical DEC VT220 glyph data from a ROM-derived image published by VT100.net. The MIT grant covers only rights held by the repository author and does not relicense pre-existing material. See Third-party notices and license scope for the exact provenance and affected files.
The default fonts in dist/fonts cover the 80-column xterm master set; scaled sizes and 132-column variants are opt-in generator outputs.
- Use
bdffor X core-font clients such asxterm. This is the recommended format when you want DEC/xterm double-width and double-height line controls to use matching bitmap masters. - Use
otbfor fontconfig/Xft applications. - Use
psffor the Linux console withsetfont.
Most users only need the default 80-column 10x20 font plus the two additional bitmap masters that xterm can use for VT-style double-width and double-height lines:
| Purpose | File |
|---|---|
| normal/default line | DIGITAL-VT220-Normal-80col-10x20-75xres.bdf |
double-width line (ESC # 6) | DIGITAL-VT220-Normal-80col-20x20-150xres.bdf |
double-width/double-height line halves (ESC # 3 / ESC # 4) | DIGITAL-VT220-Normal-80col-20x40-75xres.bdf |
Install those BDFs into a per-user font directory:
git clone https://github.com/htayj/DEC-Fonts.git
cd DEC-Fonts
install_dir="$HOME/.local/share/fonts/digital-vt220-bdf"
mkdir -p "$install_dir"
cp \
dist/fonts/bdf/DIGITAL-VT220-Normal-80col-10x20-75xres.bdf \
dist/fonts/bdf/DIGITAL-VT220-Normal-80col-20x20-150xres.bdf \
dist/fonts/bdf/DIGITAL-VT220-Normal-80col-20x40-75xres.bdf \
"$install_dir"/
# Optional but recommended if you configure xterm to use real bold fonts.
cp \
dist/fonts/bdf/DIGITAL-VT220-Normal-80col-Bold-10x20-75xres.bdf \
dist/fonts/bdf/DIGITAL-VT220-Normal-80col-Bold-20x20-150xres.bdf \
dist/fonts/bdf/DIGITAL-VT220-Normal-80col-Bold-20x40-75xres.bdf \
"$install_dir"/
(cd "$install_dir" && mkfontscale && mkfontdir)
fc-cache -fv "$install_dir"
# This affects the current X session. Add the two xset lines to ~/.xprofile
# or ~/.xinitrc if you want them applied automatically at login.
xset +fp "$install_dir"
xset fp rehashThen configure xterm in ~/.Xresources:
! Use X core fonts rather than Xft so xterm can load the BDF XLFDs above.
XTerm*renderFont: false
! Keep xterm's VT102 double-size-line support enabled. This is true by
! default, but setting it here documents that ESC # 3/# 4/# 6 are expected
! to use matching bitmap fonts rather than spacing-only simulation.
XTerm*fontDoublesize: true
XTerm*cacheDoublesize: 8
*VT100.font: -digital-vt220-medium-r-normal-80col-20-200-75-75-c-100-iso10646-1
*VT100.wideFont: -digital-vt220-medium-r-normal-80col-20-200-150-75-c-200-iso10646-1
! Include these two lines if you installed the optional Bold BDFs above.
*VT100.boldFont: -digital-vt220-bold-r-normal-80col-20-200-75-75-c-100-iso10646-1
*VT100.wideBoldFont: -digital-vt220-bold-r-normal-80col-20-200-150-75-c-200-iso10646-1
Load the resources:
xrdb -merge ~/.XresourcesYou can test the result with the included script:
xterm -fn '-digital-vt220-medium-r-normal-80col-20-200-75-75-c-100-iso10646-1' \
-e ./fonttestThe double-width section should use the 20x20/150-xres font. The double-height section should use the 20x40 font for the top and bottom halves. The most noticeable difference is that double-width p and q should have a small separation between the top of the stem and bowl; in the 20px font the top of the character is not a continuous line.
If you have opted into extra sizes or 132-column variants during a local build, copy all generated BDF files instead of the minimal set:
git clone https://github.com/htayj/DEC-Fonts.git
cd DEC-Fonts
# Optional: regenerate every base size and width before conversion.
sbcl --load "$HOME/quicklisp/setup.lisp" \
--eval '(asdf:load-asd (merge-pathnames "dec-fonts.asd" (uiop:getcwd)))' \
--eval '(ql:quickload :dec-fonts)' \
--eval '(dec-fonts.generator:main :include-scaled-sizes t :include-132-column t)' \
--quit
./convert.bash
install_dir="$HOME/.local/share/fonts/digital-vt220-bdf"
mkdir -p "$install_dir"
cp dist/fonts/bdf/*.bdf "$install_dir"/
(cd "$install_dir" && mkfontscale && mkfontdir)
fc-cache -fv "$install_dir"
xset +fp "$install_dir"
xset fp rehashYou may need to restart running fontconfig/Xft applications before the font becomes an option. xset +fp is per X session, so add it to your X startup files for permanent xterm/core-font use.
The repository includes Makefile targets for the release-packaging path used by CI:
make bdf
make fonts
make check
make package VERSION=local-test
make ci VERSION=local-ci
make distro-packages VERSION=local-ci
make package-arch VERSION=local-ci
make nix-checkDistribution packages are written under dist/packages:
make package-deb VERSION=local-cibuildsdist/packages/deb/dec-fonts_<version>-1_all.deb.make package-rpm VERSION=local-cibuildsdist/packages/rpm/dec-fonts-<version>-1.noarch.rpm.make package-arch VERSION=local-cibuildsdist/packages/arch/dec-fonts-<version>-1-any.pkg.tar.*from the current checkout.make package-void VERSION=local-cibuildsdist/packages/void/dec-fonts-<version>_1.noarch.xbpsand a matching.sha256withxbps-create, using a Void container fallback if needed.make test-deb-package,make test-rpm-package,make test-arch-package, andmake test-void-packageinstall the packages in Debian/Fedora/Arch/Void containers and verify the font files plus fontconfig visibility. SetCONTAINER_RUNTIME=podmanif you prefer Podman.- The GitHub Actions workflow builds/tests the generated-font release tarball, runs the Nix flake check in a container, and builds/tests the DEB, RPM, Arch, and Void package outputs. Tag pushes create or update a GitHub Release and attach the release tarball, distro package files, and matching checksums.
- The stable AUR recipe is published; Guix and Gentoo recipes remain local/manual, and the Void
xbps-srctemplate is also manual even though the lightweight.xbpspackage is built/tested by CI.
The DEB and Gentoo layouts install PSF console fonts under /usr/share/consolefonts/dec-fonts. The RPM package installs them under /usr/lib/kbd/consolefonts/dec-fonts. The Arch and Void layouts install them under /usr/share/kbd/consolefonts/dec-fonts. The FHS-style packages install BDF/OTB fonts under /usr/share/fonts/dec-fonts, data under /usr/share/dec-fonts, and the README, license, and third-party notice under /usr/share/doc/dec-fonts. They also enable a package-scoped fontconfig config. Release archives include LICENSE and THIRD_PARTY_NOTICES.md at their top level.
Pass generator options through GENERATOR_OPTIONS when you want opt-in outputs:
make fonts GENERATOR_OPTIONS="--include-scaled-sizes --include-132-column"make package and make ci write archives to dist/release/DEC-Fonts-$VERSION.tar.gz and a matching .sha256 file. To run the GitHub Actions path locally, use act if it is installed; otherwise make ci VERSION=local-ci exercises the same build, check, and packaging command path.
The stable AUR package =dec-fonts= regenerates the styled BDF, OTB, and PSF derivatives from the three tracked textual BDF masters in the exact tagged project source. It does not download or redistribute the native Arch package attached to the GitHub release. The current AUR pkgver is 0.1.0alpha2 so that Arch correctly orders it before the eventual 0.1.0 final release.
git clone https://aur.archlinux.org/dec-fonts.git
cd dec-fonts
makepkg --syncdeps --installThe recipe does not run the ROM-image importer or fetch through Quicklisp. Its AUR-only make dependencies bdf2psf and mkbold-mkitalic must be installed first when using makepkg directly; AUR helpers resolve them automatically.
Maintainers can refresh the tracked metadata with make aur-srcinfo. The AUR repository contains only the recipe, generated .SRCINFO, ignore rules, and 0BSD/REUSE package-source licensing files.
For a local package from the current checkout, use:
make package-arch VERSION=local-ci
make test-arch-package CONTAINER_RUNTIME=podmanA best-effort flake is provided for local Nix builds, checks, and development shells. It uses ASDF-provided Common Lisp dependencies rather than Quicklisp and overrides BDF2PSF_EQUIVALENTS for the Nix bdf2psf package.
nix flake metadata
nix build .#dec-fonts
nix flake check
make test-nix-flake-container CONTAINER_RUNTIME=podman
nix developmake test-nix-flake-container runs nix flake check inside a clean docker.io/nixos/nix container; set NIX_CONTAINER_IMAGE=... to try another image. GitHub Actions runs the same Make target with Docker as the Nix CI check. Inside nix develop, DEC_FONTS_ASDF_LOAD_MODE is set to asdf so scripts/generate-fonts.sh loads dec-fonts through ASDF directly. Outside Nix, the default remains Quicklisp; set DEC_FONTS_ASDF_LOAD_MODE=asdf only when dependencies such as png and array-operations are already visible to ASDF.
A local Guix package module is available under packaging/guix. It packages the generated dist font artifacts from this checkout; it does not regenerate fonts in the Guix build.
guix lint -L packaging/guix dec-fonts
guix build -L packaging/guix dec-fonts
make test-guix-package GUIX=guixmake test-guix-package builds the package, exposes the resulting store item to guix shell --container, and runs the shared file/fontconfig verifier against that store prefix. Lint may warn that the local/manual package has no updater.
The Gentoo live ebuild lives in the local overlay at packaging/gentoo:
# Example repos.conf entry for manual use on a Gentoo system:
cat >/etc/portage/repos.conf/dec-fonts.conf <<EOF
[dec-fonts]
location = /path/to/DEC-Fonts/packaging/gentoo
masters = gentoo
auto-sync = no
EOF
mkdir -p /etc/portage/package.accept_keywords
printf '%s\n' '=media-fonts/dec-fonts-9999 **' \
>/etc/portage/package.accept_keywords/dec-fonts
emerge -1 =media-fonts/dec-fonts-9999For a quick container smoke test that avoids a full dependency-resolution run, use:
make test-gentoo-package CONTAINER_RUNTIME=podmanThe live ebuild has no stable keywords, so manual installs must accept ** for media-fonts/dec-fonts-9999. The helper uses gentoo/stage3, runs emerge-webrsync for eclasses, verifies the overlay with emerge -p plus that keyword override, installs the live ebuild with a local checkout override, and verifies the package database plus file layout. The minimal stage3 image usually lacks fontconfig, so the quick test skips runtime fontconfig checks; Portage may also print a policy warning for the intentionally FHS-style /usr/share/doc/dec-fonts documentation directory.
Void support has both a lightweight binary-package builder and a standard xbps-src template.
make package-void VERSION=local-ci CONTAINER_RUNTIME=podman
make test-void-package CONTAINER_RUNTIME=podmanThe package builder uses xbps-create and xbps-rindex to produce a local .xbps under dist/packages/void. If those tools are not installed locally, it falls back to a Void container, overrides the stale default mirror with https://repo-default.voidlinux.org/current, updates xbps, installs bash, and builds the package there.
The manual xbps-src template is under packaging/void/srcpkgs/dec-fonts. For a private void-packages checkout, copy or symlink that directory into srcpkgs/dec-fonts and provide a release tarball/checksum or a local source override, for example:
cd /path/to/void-packages
ln -s /path/to/DEC-Fonts/packaging/void/srcpkgs/dec-fonts srcpkgs/dec-fonts
DEC_FONTS_SOURCE_DIR=/path/to/DEC-Fonts ./xbps-src pkg dec-fontsA redistributable Void template should replace the local source override with a tagged release tarball URL and checksum.
Run the Common Lisp generator from the repository root with SBCL and Quicklisp:
sbcl --load "$HOME/quicklisp/setup.lisp" \
--eval '(asdf:load-asd (merge-pathnames "dec-fonts.asd" (uiop:getcwd)))' \
--eval '(ql:quickload :dec-fonts)' \
--eval '(dec-fonts.generator:main)' \
--quitThis regenerates dist/dec.set and the default three base BDF files in dist/fonts/bdf:
DIGITAL-VT220-Normal-80col-10x20-75xres.bdfDIGITAL-VT220-Normal-80col-20x20-150xres.bdfDIGITAL-VT220-Normal-80col-20x40-75xres.bdf
The generator is loadable as the ASDF system dec-fonts; loading the system does not write files. Call dec-fonts.generator:generate or dec-fonts.generator:main to generate fonts explicitly. By default, stale generated DIGITAL-VT220-Normal-*.bdf files are removed from dist/fonts/bdf before writing the selected base BDFs.
Opt into the additional scaled 80-column sizes:
sbcl --load "$HOME/quicklisp/setup.lisp" \
--eval '(asdf:load-asd (merge-pathnames "dec-fonts.asd" (uiop:getcwd)))' \
--eval '(ql:quickload :dec-fonts)' \
--eval '(dec-fonts.generator:main :include-scaled-sizes t)' \
--quitOpt into the analogous 132-column masters:
sbcl --load "$HOME/quicklisp/setup.lisp" \
--eval '(asdf:load-asd (merge-pathnames "dec-fonts.asd" (uiop:getcwd)))' \
--eval '(ql:quickload :dec-fonts)' \
--eval '(dec-fonts.generator:main :include-132-column t)' \
--quitGenerate the historical full 20-base-BDF matrix:
sbcl --load "$HOME/quicklisp/setup.lisp" \
--eval '(asdf:load-asd (merge-pathnames "dec-fonts.asd" (uiop:getcwd)))' \
--eval '(ql:quickload :dec-fonts)' \
--eval '(dec-fonts.generator:main :include-scaled-sizes t :include-132-column t)' \
--quitThe same options are available through the exported CLI entry point:
sbcl --load "$HOME/quicklisp/setup.lisp" \
--eval '(asdf:load-asd (merge-pathnames "dec-fonts.asd" (uiop:getcwd)))' \
--eval '(ql:quickload :dec-fonts)' \
--eval '(dec-fonts.generator:cli-main)' \
--quit -- --include-scaled-sizes --include-132-columnTo verify a refactor against a previously captured baseline, use:
scripts/check-generated.sh /path/to/baseline-directory [GENERATOR_OPTION ...]The baseline directory must contain cl-generated.sha256, for example from sha256sum over dist/dec.set and the base non-bold/non-italic BDF files before making changes. Any extra arguments are passed to dec-fonts.generator:cli-main, so you can verify opt-in outputs with options such as --include-scaled-sizes or --include-132-column.
To generate the OTB and PSF fonts, along with the bold, italic, and bold italic variants, run convert.bash. The script requires fonttosfnt for OTB, bdf2psf for PSF, and mkbold/mkitalic/mkbolditalic for the derived styles:
./convert.bashThe conversion script is safe to repeat: it processes only the base BDF files, removes stale generated style variants, regenerates OTB/PSF outputs, and refreshes fonts.dir / fonts.scale.
To audit BDF/XLFD metadata after generation or conversion, run:
python3 scripts/check-bdf-metadata.py dist/fonts/bdfThe generated BDF metadata follows BDF 2.1 and XLFD conventions: SIZE uses point size plus x/y resolution, POINT_SIZE is decipoints, 150-xres fonts set RESOLUTION_X to 150 and RESOLUTION_Y to 75, SWIDTH is derived from DWIDTH, point size, and x-resolution, and DEFAULT_CHAR points at U+25C6 (diamond). Base and bold fonts are marked character-cell (SPACING "c"); italic and bold-italic derived fonts are marked monospace (SPACING "m") because their slanted ink can overhang the cell.
A giant thank-you to Paul Flo Williams for creating VT100.net, which provided the ROM dump image (rom-separated.png) that is parsed to create the font, along with the instructions for how the font is created.
https://www.vt100.net/dec/vt220/glyphs.html
- DEC Terminal Modern - a TTF modern interpretation of the VT220 font.
- GlassTTY - a TTF version of the font with scan lines

