Customized Bible version for reading and notetaking compiled with Typst (main-branch-only mirror of https://forge.ejuarezg.com/ejuarezg/tailcat-wormhole)
Python 89%
Typst 8%
Makefile 3%

README.md

Typst Bible editions for reading and notes #

This project builds print-oriented Bible PDFs with optional verse numbers and space for handwritten notes. Translation metadata lives in translations.json and is described by translations.schema.json; downloaded scripture and generated files stay outside version control.

Development disclosure #

This project has been developed with substantial assistance from large language models (LLMs), a form of probabilistic automation. Such tools can produce plausible but incorrect code or explanations; their output does not establish that behavior is correct. The human maintainer is responsible for reviewing changes and validating them with tests.

This wording follows GNOME's “Probabilistically Automated” label and its focus on describing how work was produced without treating a model as a human-like agent. For more on precise, non-anthropomorphic language, see “We Need to Talk About How We Talk About ‘AI’”.

Planned enhancements and their implementation status are tracked in ROADMAP.md.

Included translations #

ID Translation Contents Source
spav1602p Santa Biblia Valera 1602 Purificada 66 books eBible.org
eng-kjv King James Version, standardized 1769 text Preface, 66-book canon, and Apocrypha eBible.org
eng-kjv2006 King James (Authorized) Version with Strong’s identifiers 66-book canon eBible.org
eng-nkjv New King James Version 66 books (private use only) bible.com
eng-esv English Standard Version 66 books (private use only) bible.com
eng-amp Amplified Bible 66 books (private use only) bible.com

Why USFM? #

USFM retains paragraphs, poetry, headings, verse numbers, supplied words, divine-name styling, words of Jesus, and translator footnotes. VPL is easier to parse but discards much of that structure. XeTeX source already mixes the text with one presentation system.

Requirements #

  • Python 3.10 or newer with venv support
  • Python packages from requirements.txt (installed into .venv by make setup)
  • Optional graphical configurator: GTK 4, libadwaita 1.5 or newer, and PyGObject for the system Python
  • Optional terminal inline previews: a Kitty-graphics-compatible terminal and kitten icat
  • Typst 0.15.1 or newer
  • make (optional)
  • Internet access for the first source download
  • Libertinus Serif, or another font selected in config.typ

Build #

Create the project-local virtual environment and install the declared Python requirements:

make setup

The Python-backed Make targets also run this setup automatically when .venv is missing or requirements.txt changes. They use .venv/bin/python, so requirements are not installed into the system Python environment and the virtual environment does not need to be activated.

Fonts #

The unified standard-library-only font installer downloads EB Garamond, Lora, Newsreader, and Cardo from Google Fonts by default. EB Garamond, Lora, and Newsreader use their regular and italic variable fonts; Cardo currently falls back to its static regular, bold, and italic faces.

# Install the default set under this repository's ignored fonts/ directory
python3 scripts/install_foundry_font.py google

# Install any Google Fonts families available at the pinned repository revision
python3 scripts/install_foundry_font.py google "Source Serif 4" "Atkinson Hyperlegible Next"

# Install for the current user, or beneath a custom root
python3 scripts/install_foundry_font.py google --user Lora Newsreader
python3 scripts/install_foundry_font.py google --install-dir ~/my-fonts Cardo

Project installs are placed in fonts/<family-slug>/; EB Garamond retains the legacy-compatible fonts/EBGaramond/ path and replaces an installation made by the former shell script. install_google_fonts.py remains as a compatibility entry point; use install_foundry_font.py google for new commands. Make discovers these directories automatically. Direct Typst commands should add --font-path fonts. User and custom installs refresh fc-cache when available unless --no-cache is passed. --user supports macOS and XDG-based Unix systems; on Windows, use --install-dir. The installer prints the exact family names detected by Typst; at the pinned revision, Newsreader's optical-size variable font is exposed as Newsreader 16pt.

The Google Fonts repository revision is pinned. Every download is checked against its Git blob ID and recorded with SHA-256 provenance in INSTALL_SOURCE.json; the four default families also require exact reviewed file manifests and SHA-256 pins. GITHUB_TOKEN can be set when GitHub's unauthenticated API rate limit is insufficient. Use --category for an unusual family location or --revision when intentionally reviewing an upstream update. Arbitrary-family support covers the TrueType family directories used by Google Fonts under ofl, apache, and ufl.

Fanwood and Andada Pro #

Use the general installer for a free font page from The League of Moveable Type or Huerta Tipográfica. Pass the foundry identifier and the page's URL slug:

python3 scripts/install_foundry_font.py league fanwood
python3 scripts/install_foundry_font.py huerta andada
python3 scripts/install_foundry_font.py league raleway --user
python3 scripts/install_foundry_font.py huerta andada --install-dir ~/my-fonts

The installer accepts only source repositories linked by that foundry and owned by its GitHub organization. Huerta fonts must be identified as free on their foundry page. It resolves the current source tip to a full commit ID, verifies every file against the commit's Git blob ID, and records the commit plus SHA-256 provenance in INSTALL_SOURCE.json. Pass a reviewed commit explicitly with --revision COMMIT to make a repeatable install. It selects TrueType faces when available (otherwise OpenType), copies the source license, and supports --project, --user, --install-dir, and --no-cache.

Apple New York #

A second installer downloads Apple's New York serif font from the official Apple disk image and installs the variable New York family (upright and italic, exposing the weight axis) under fonts/newyork/:

python3 scripts/install_new_york.py
python3 scripts/install_new_york.py --all          # also install the static optical-size families
python3 scripts/install_new_york.py --user         # install for the current user
python3 scripts/install_new_york.py --install-dir ~/my-fonts

The disk image is pinned and verified by SHA-256, and every font file is checked against reviewed SHA-256 pins before install. Extraction needs 7z (p7zip, e.g. 7z/7zz) on any platform, or the built-in hdiutil/pkgutil on macOS. Apple licenses New York only for creating mock-ups of user interfaces to be used in software running on iOS, iPadOS, macOS, tvOS, or watchOS; the license is copied to fonts/newyork/LICENSE.rtf and users are responsible for complying with it.

Font specimen PDF #

Create a compact PDF containing the default John 3:16–21 passage once for every distinct font family discovered under fonts/:

python3 scripts/font_demo.py

The default output is build/font-demo.pdf. Choose another local translation or passage with --translation and --passage, for example:

python3 scripts/font_demo.py --translation eng-kjv --passage JHN:1:1-5 --output build/kjv-font-demo.pdf

The script omits the normal cover, rights, and table-of-contents pages. It uses Typst's discovered family names, so multiple weights and styles belonging to one family are shown together as one specimen. If generated data for the selected translation is missing, it runs make generate first.

V1602P is the default translation:

make sample                         # build John
make pdf                            # build the complete edition

Select the KJV with TRANSLATION. Its default build includes the preface and Apocrypha:

make sample TRANSLATION=eng-kjv
make pdf TRANSLATION=eng-kjv

The separate eng-kjv2006 archive contains the 66-book standardized 1769 text with Strong’s identifiers in its USFM source. The current converter preserves the words but omits the identifiers from generated data pending R07:

make sample TRANSLATION=eng-kjv2006
make pdf TRANSLATION=eng-kjv2006

# Equivalent reusable baselines with explicit overrides
make pdf PROFILE=kjv-reading
make pdf PROFILE=kjv-study TEXT_SIZE_PT=12 FONT_WEIGHT=450
make sample PROFILE=v1602p-margin

Build only the 66-book Protestant canon, use one line per verse, or combine both options:

make pdf TRANSLATION=eng-kjv CANON_ONLY=true
make pdf TRANSLATION=eng-kjv VERSE_LAYOUT=lines
make pdf TRANSLATION=eng-kjv CANON_ONLY=true VERSE_LAYOUT=lines

# Set scripture pages in two columns; cover, rights, and contents stay one column
make pdf TRANSLATION=eng-kjv COLUMNS=2

# Build a chapter or same-chapter verse range
make pdf TRANSLATION=eng-kjv CANON_ONLY=true PASSAGE=JHN:1-3
make pdf TRANSLATION=eng-kjv CANON_ONLY=true PASSAGE=JHN:3:16-21

# Build named collections, optionally united with explicit books
make pdf TRANSLATION=eng-kjv2006 COLLECTIONS=gospels,pauline-epistles
make pdf TRANSLATION=eng-kjv2006 COLLECTIONS=gospels BOOKS=ROM
make pdf TRANSLATION=eng-kjv COLLECTIONS=apocrypha

# Hide literal pilcrows without changing source paragraph spacing
make pdf TRANSLATION=eng-kjv2006 PARAGRAPH_MARKS=false

# Hide section headings within chapters
make pdf TRANSLATION=eng-kjv HEADINGS=false

# Name chapter headings after their books: Genesis 1, Psalm 1, John 1, etc.
make pdf TRANSLATION=eng-kjv2006 CHAPTER_LABEL_STYLE=book

# Add the current book name to each scripture-page header
make pdf TRANSLATION=eng-kjv BOOK_HEADER=true

# Color words marked by the source as spoken by Jesus
make pdf TRANSLATION=eng-kjv WORDS_OF_JESUS=true WORDS_OF_JESUS_COLOR=1f4e79

# Dark (inverted) edition with black pages and white text
make pdf TRANSLATION=eng-kjv BACKGROUND_COLOR=000000 TEXT_COLOR=ffffff

BACKGROUND_COLOR and TEXT_COLOR set the page background and body text as six-digit RGB hex values without a leading #. Verse numbers, page numbers, and note patterns are derived from these two colors so they stay legible on any background. The words-of-Jesus color is configured independently, so its default dark red (7b1e1e) can be hard to read on a dark background; set WORDS_OF_JESUS_COLOR to a lighter red (for example e06666) when combining it with a dark edition.

Representative outputs include build/eng-kjv-66.pdf, build/eng-kjv-verse-lines.pdf, build/eng-kjv-66-verse-lines.pdf, build/eng-kjv2006-book-chapter-labels.pdf, build/eng-kjv-book-header.pdf, and build/eng-kjv-words-of-jesus.pdf. The 66-book edition omits the KJV preface and all 14 Apocrypha books, and its cover title is “King James Version.”

Missing eBible sources are downloaded and converted automatically. Bible.com imports require a local checkout of the external scraper as described below. A complete build currently produces approximately:

Output Pages Size
build/spav1602p.pdf 1,184 10 MB
build/eng-kjv.pdf 1,457 29 MB
build/eng-kjv2006.pdf 1,351 28 MB
build/eng-nkjv.pdf 1,075 9.8 MB
build/eng-esv.pdf 1,120 15 MB
build/eng-amp.pdf 1,506 18 MB

Page counts and file sizes can vary with Typst, fonts, and configuration. The converter checks the source totals declared in translations.json. The eng-kjv2006 archive contains 66 books, 1,189 chapters, and 31,102 verse records. The reconstructed bible.com sources contain 66 books and 1,189 chapters each, with 31,102 NKJV, 31,086 ESV, and 31,103 AMP verse records.

Run the local checks with:

make test
make release-check

Every conversion writes a deterministic machine-readable report to generated/TRANSLATION/conversion-report.json, including marker inventories, source-file hashes, structural totals, and diagnostics. Failed conversions preserve the last successful generated data and write conversion-report.failed.json; see conversion-report.schema.json.

Private bible.com imports #

The NKJV, ESV, and AMP sources are not distributed by this repository. To create a local, private-use 66-book Bible, clone tobiashellerslien/bible-scraper, install its dependencies, and point this build at the checkout:

git clone https://github.com/tobiashellerslien/bible-scraper ../bible-scraper
git -C ../bible-scraper checkout ba0ec6a4346c32a75bb3a4e9ef9cd6756e7a676d
make setup
make source TRANSLATION=eng-nkjv BIBLE_SCRAPER=../bible-scraper
make sample TRANSLATION=eng-nkjv SAMPLE_BOOK=JHN
make pdf TRANSLATION=eng-nkjv

make source TRANSLATION=eng-esv BIBLE_SCRAPER=../bible-scraper
make sample TRANSLATION=eng-esv SAMPLE_BOOK=JHN
make pdf TRANSLATION=eng-esv

make source TRANSLATION=eng-amp BIBLE_SCRAPER=../bible-scraper
make sample TRANSLATION=eng-amp SAMPLE_BOOK=JHN
make pdf TRANSLATION=eng-amp

The importer requests the configured books, waits between requests, retries transient failures, and saves each completed chapter locally so an interrupted run can resume. Cache files use stable book IDs, and caches from the former eng-nkjv-nt configuration are migrated automatically, so extending a partial Bible does not download completed books again. Set SCRAPE_RATE_LIMIT to increase the delay; the default is 0.5 seconds. The external checkout is pinned and then imported as executable Python, so review it before use. Delete the translation's directory under source/ to start over, or pass --refresh when invoking scripts/fetch_source.py directly.

NKJV, ESV, and AMP request headings and footnotes. The verified imports contain 2,970 headings/descriptions and no note.f footnotes for NKJV, 2,527 headings/descriptions and 3,444 footnotes for ESV, and 2,394 headings/descriptions and 3,956 amplification notes for AMP. Cross-references are never misrepresented as footnotes.

This is a lossy reconstruction rather than publisher-provided USFM. Bible.com supplies verse text and headings but not the original paragraph, poetry, words-of-Jesus, or exact note-placement markers. The importer emits conservative paragraph markers and anchors any available note at the end of its verse. Scraped JSON, USFM, generated Typst, and PDFs remain ignored by Git.

Configuration #

All Make variables, Typst inputs, page options, note-area controls, and config.typ design defaults are documented in CONFIGURATION.md. Run make configure-gui for the GTK 4/libadwaita configurator or make configure for the terminal interface. Both use the option catalog in build-options.json, expose tracked and private profiles plus named collections, and automatically reopen an existing build-config.mk, so a saved configuration can be edited and saved again. Pass --output PATH when invoking either Python script directly to continue editing another configuration file.

Both configurators can save the current effective settings as a private profile under gitignored profiles/private/ and load it immediately; private profiles are subsequently available from the normal Build profile selector with (private) after their display name, and through make PROFILE=name using the unadorned name. Use Save Profile or Ctrl+Shift+S in GTK and S in the terminal interface.

The graphical configurator follows GNOME preferences patterns, with grouped settings, adaptive sizing, live validation, per-setting and global reset controls, a copyable command preview, visual page previews, and saving to build-config.mk. Run (Ctrl+B) executes the displayed Make command and shows its output in a cancellable build dialog. The Preview action (Ctrl+P, shown in its tooltip) prepares the selected translation and asks Typst to render only the first page of one representative scripture chapter directly to PNG, rather than rendering the complete PDF. When full parity note pages are selected, the preview dialog also provides a separate note-page view.

Install its system dependencies with the command for your distribution:

# Fedora
sudo dnf install python3-gobject gtk4 libadwaita

# Debian or Ubuntu
sudo apt install python3-gi gir1.2-gtk-4.0 gir1.2-adw-1

# Arch Linux
sudo pacman -S python-gobject gtk4 libadwaita

Then launch it without activating .venv:

make configure-gui
# or
python3 scripts/configure_gui.py

The terminal configurator offers the same representative page preview when it runs in Kitty, WezTerm, Ghostty, or another detected Kitty-graphics-compatible terminal with kitten icat installed. Press uppercase or lowercase P; the image is transferred through the Kitty graphics protocol and fitted to the terminal. Press B to run the displayed Make command; curses temporarily yields the terminal so build output can be inspected before returning. Interleaved layouts can switch between scripture and note pages with the arrow keys. Unsupported terminals receive a status message instead of raw escape sequences.

# Landscape tablet edition with notes permanently on the left
make pdf TRANSLATION=eng-esv \
  PAGE_ORIENTATION=landscape NOTES=margin MARGIN_NOTES_SIDE=left \
  MARGIN_NOTE_FRACTION=0.3

# Duplex print edition with mirrored outer-margin notes
make pdf TRANSLATION=eng-kjv CANON_ONLY=true \
  NOTES=margin MARGIN_NOTES_SIDE=outer NOTE_STYLE=ruled

# Full note-taking pages on even physical pages
make pdf TRANSLATION=eng-esv NOTE_PAGE_PARITY=even NOTE_STYLE=grid

Cleaning and source updates #

Remove generated files and PDFs while keeping downloaded USFM:

make clean

Remove downloads as well:

make distclean

Each archive is pinned by SHA-256. If eBible changes an archive, the fetch command stops before extraction. To review an update:

  1. Download the new archive directly from the archive_url in translations.json.
  2. Compare its text, USFM markers, book counts, and rights notice with the previous archive.
  3. Calculate its digest with sha256sum ARCHIVE.zip.
  4. Update archive_sha256 and any changed expected counts in translations.json.
  5. Remove that translation's source/ID and generated/ID directories, then run its sample and complete builds.

Do not replace a checksum only to make a failed download pass.

Adding another translation #

  1. Confirm that its license permits the intended use.
  2. Add its source configuration, titles, labels, canonical exclusions, explicit book order, named book collections, rights notice, and expected counts to translations.json, following translations.schema.json. Archive sources require an HTTPS URL and SHA-256; bible.com sources require a version ID and explicit book list.
  3. Fetch or import it with .venv/bin/python scripts/fetch_source.py --translation ID.
  4. Generate it with .venv/bin/python scripts/generate_typst.py --translation ID.
  5. Compile it with typst compile --input translation=ID main.typ build/ID.pdf.

The parser rejects unsupported content-bearing USFM markers rather than silently dropping text. It records encountered markers, ignored metadata, structural totals, and file/line diagnostics in the conversion report. New marker support should include parser/report tests and a representative PDF build. See CONTRIBUTING.md for the contribution checklist.

CI and release artifacts #

The current SourceHut build manifest only mirrors successful commits to Bitbucket. It does not currently install dependencies, run the test or release checks, fetch translation sources, or compile PDFs.

Run the checks and representative builds locally:

make test
make release-check
make sample TRANSLATION=eng-kjv2006

No CI PDFs or translation source files are currently published. In particular, the private bible.com sources are never fetched by CI.

Limitations #

  • The parser implements the USFM markers used by the configured sources, not the entire USFM specification.
  • The eng-kjv2006 source includes Strong’s identifiers, but the converter currently omits those attributes from generated data and rendered editions.
  • Bible.com imports reconstruct minimal USFM from HTML and cannot recover paragraph, poetry, words-of-Jesus, or exact inline-note structure absent from the scraped data.
  • Layout options require recompilation; the PDF itself has no interactive toggles.
  • The KJV archive includes its preface and Apocrypha by default. Use canon-only=true for its 66-book Protestant canon or the collections/books inputs for another selection.
  • Upstream rights notices can change. Check the source page before distributing a generated edition.

The scripts, Typst templates, tests, and documentation are available under the MIT License.

V1602P is copyrighted © 2007, 2019, 2024 Iglesia Bautista Bíblica de la Gracia. Both KJV archives are public domain outside the United Kingdom, where printing and import restrictions remain in force. NKJV is copyrighted © 1982 Thomas Nelson, ESV is copyrighted © 2001 Crossway, and AMP is copyrighted © 2015 The Lockman Foundation; this project configures them only for local, private-use imports and does not distribute their text or output. NOTICE.md contains the third-party notices and source links.

Downloaded USFM, generated Typst data, and PDFs are ignored by Git. They are not covered by the project's MIT license.