Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions .github/scripts/package_release.sh
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/usr/bin/env bash
# Make the release files for one family or for the site.
# Usage: .github/scripts/package_release.sh weft|sans|heddle|site VERSION OUT_DIR
# Usage: .github/scripts/package_release.sh weft|sans|heddle|warp|site VERSION OUT_DIR
# VERSION is the version from the tag, for example 0.1.0.
# OUT_DIR receives the zip file and the single files to attach.
# Run from the repository root, after the build and the checks.
# For weft, OUT_DIR/readability.json must exist already (the release
# workflow writes it with weft/tools/readability.py --gate).
# For weft and warp, OUT_DIR/readability.json must exist already (the
# release workflow writes it with <family>/tools/readability.py --gate).
set -euo pipefail

fam="${1:?family: weft, sans, heddle or site}"
fam="${1:?family: weft, sans, heddle, warp or site}"
version="${2:?version, for example 0.1.0}"
out="${3:?output folder}"
mkdir -p "$out"
Expand Down Expand Up @@ -135,6 +135,37 @@ case "$fam" in
fonts/heddle/webfonts/MachineMadeHeddle-Bold.woff2 \
"fonts/heddle/variable/MachineMadeHeddle[wdth,wght].ttf" "$out/"
;;
warp)
name="machine-made-warp-${version}"
need fonts/warp/ttf/MachineMadeWarp-Regular.ttf fonts/warp/ttf/MachineMadeWarp-Italic.ttf \
fonts/warp/ttf/MachineMadeWarp-Bold.ttf fonts/warp/ttf/MachineMadeWarp-BoldItalic.ttf \
fonts/warp/ttf/MachineMadeWarpDisplay-Regular.ttf fonts/warp/ttf/MachineMadeWarpDisplay-Italic.ttf \
fonts/warp/otf/MachineMadeWarp-Regular.otf fonts/warp/webfonts/MachineMadeWarp-Regular.woff2 \
warp/OFL.txt "warp/RELEASE-NOTES-${notes_version}.md" "$out/readability.json"
mkdir -p "$stage/$name"
cp -r fonts/warp/ttf fonts/warp/otf fonts/warp/webfonts "$stage/$name/"
cp warp/OFL.txt "$stage/$name/OFL.txt"
cp "warp/RELEASE-NOTES-${notes_version}.md" "$stage/$name/RELEASE-NOTES.md"
cp "$out/readability.json" "$stage/$name/readability.json"
{
echo "# machine-made Warp ${version}"
echo
echo "A Modern serif for science, drawn by a pen model in code."
echo "machine-made Warp: Regular, Italic, Bold, Bold Italic (text, opsz 10)."
echo "machine-made Warp Display: Regular, Italic (titles, opsz 60)."
echo
echo "- ttf/, otf/: the six static fonts"
echo "- webfonts/: WOFF2 of the six fonts"
echo "- readability.json: the OCR readability report of this release"
echo "- RELEASE-NOTES.md: what is in this release"
echo
echo "Licence: SIL Open Font License 1.1, Reserved Font Name \"machine-made\" (OFL.txt)."
echo "Source: https://github.com/machine-made/type"
echo "Specimen: https://machine-made.github.io/type/warp/"
} > "$stage/$name/README.md"
make_zip "$stage" "$out/$name.zip"
cp fonts/warp/webfonts/*.woff2 fonts/warp/ttf/*.ttf "$out/"
;;
site)
name="machine-made-type-site-${version}"
need site/_site/index.html site/_site/data/readability.json
Expand All @@ -143,7 +174,7 @@ case "$fam" in
make_zip "$stage" "$out/$name.zip"
;;
*)
echo "error: unknown family $fam (use weft, sans, heddle or site)." >&2
echo "error: unknown family $fam (use weft, sans, heddle, warp or site)." >&2
exit 1
;;
esac
Expand Down
141 changes: 140 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ name: release
# weft-vX.Y.Z machine-made Weft
# sans-vX.Y.Z machine-made Sans
# heddle-vX.Y.Z machine-made Heddle
# warp-vX.Y.Z machine-made Warp and machine-made Warp Display
# site-vX.Y.Z the specimen site (zip of site/_site; the live deploy is site.yml)
# Each job builds again from the tagged commit, fails if the build differs
# from the committed fonts, runs the checks, makes the zip and the single
Expand All @@ -19,11 +20,12 @@ on:
- "weft-v*"
- "sans-v*"
- "heddle-v*"
- "warp-v*"
- "site-v*"
workflow_dispatch:
inputs:
tag:
description: "Tag to make and release: weft-vX.Y.Z, sans-vX.Y.Z, heddle-vX.Y.Z or site-vX.Y.Z"
description: "Tag to make and release: weft-vX.Y.Z, sans-vX.Y.Z, heddle-vX.Y.Z, warp-vX.Y.Z or site-vX.Y.Z"
required: true
type: string

Expand Down Expand Up @@ -424,6 +426,143 @@ jobs:
"$OUT/MachineMadeHeddle\[wdth,wght\].ttf" \
"$OUT/SHA256SUMS"

warp:
if: startsWith(inputs.tag || github.ref_name, 'warp-v')
runs-on: ubuntu-24.04
timeout-minutes: 40
permissions:
contents: write
id-token: write
attestations: write
steps:
- name: Check out
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Get the version from the tag
run: |
version="${RELEASE_TAG#warp-v}"
if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Tag ${RELEASE_TAG} is not warp-vX.Y.Z."
exit 1
fi
echo "VERSION=$version" >> "$GITHUB_ENV"

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.14"

- name: Install dependencies
working-directory: warp
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends tesseract-ocr tesseract-ocr-eng fonts-dejavu-core
tesseract --version
python -m pip install --upgrade pip
python -m pip install -e ".[test]"
node --version

- name: Run tests
working-directory: warp
run: python -m pytest -q

- name: Build fonts
working-directory: warp
run: scripts/build.sh

- name: Check that the build is the same as the committed fonts
run: |
if [ -n "$(git status --porcelain -- fonts/warp)" ]; then
git status --short -- fonts/warp
echo "::error::The build differs from the committed fonts/warp. Do not release these files."
exit 1
fi
echo "The build has the same bytes as the committed fonts/warp."

- name: Check the outlines against the pen sweep
working-directory: warp
run: python tools/fidelity.py --gate --out "$RUNNER_TEMP/fidelity.json"

- name: Install Fontspector
run: |
name="fontspector-${FONTSPECTOR_VERSION}-x86_64-unknown-linux-gnu"
curl -sSfL -o "$RUNNER_TEMP/fontspector.tar.gz" \
"https://github.com/fonttools/fontspector/releases/download/fontspector-v${FONTSPECTOR_VERSION}/${name}.tar.gz"
echo "${FONTSPECTOR_SHA256} $RUNNER_TEMP/fontspector.tar.gz" | sha256sum --check
tar xzf "$RUNNER_TEMP/fontspector.tar.gz" -C "$RUNNER_TEMP"
sudo install -m 755 "$RUNNER_TEMP/${name}/fontspector" /usr/local/bin/fontspector
fontspector --version

- name: Check fonts (Fontspector, universal profile)
working-directory: warp
run: scripts/check.sh fontspector

- name: Readability gate (Tesseract OCR)
working-directory: warp
run: |
mkdir -p "$OUT"
python tools/readability.py --gate --out "$OUT/readability.json"

- name: Make the release files
run: .github/scripts/package_release.sh warp "$VERSION" "$OUT"

- name: Attest build provenance
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
with:
subject-path: |
${{ env.OUT }}/machine-made-warp-*.zip
${{ env.OUT }}/*.woff2
${{ env.OUT }}/*.ttf
${{ env.OUT }}/readability.json

- name: Make and push the tag (manual run only)
if: github.event_name == 'workflow_dispatch'
run: |
if [ "$GITHUB_REF" != "refs/heads/main" ]; then
echo "::error::Run the release from main, not ${GITHUB_REF}."
exit 1
fi
# A tag that exists already is fine when its commit has the same release files
# (fonts/warp warp) as this commit: that is a re-run after a failed upload, and the
# release goes onto that tag. Any other change needs a new version.
existing="$(git ls-remote --tags origin "refs/tags/${RELEASE_TAG}^{}" "refs/tags/${RELEASE_TAG}" | awk '{print $1}' | tail -n 1)"
if [ -n "$existing" ]; then
git fetch --quiet --depth=1 origin "$existing"
if git diff --quiet "$existing" "$GITHUB_SHA" -- fonts/warp warp; then
echo "Tag ${RELEASE_TAG} exists already on ${existing} with the same release files. Re-running the release."
exit 0
fi
echo "::error::Tag ${RELEASE_TAG} exists already on ${existing}, and the release files differ. Use a new version."
exit 1
fi
git tag "$RELEASE_TAG" "$GITHUB_SHA"
git push origin "refs/tags/${RELEASE_TAG}"

- name: Create the release
# gh reads each file argument as a glob. The Warp file names have no
# brackets; any bracket in a future name must be escaped (\[ \]).
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "$RELEASE_TAG" --verify-tag \
--title "machine-made Warp ${VERSION}" \
--notes-file "warp/RELEASE-NOTES-${VERSION%.*}.md" \
"$OUT/machine-made-warp-${VERSION}.zip" \
"$OUT/MachineMadeWarp-Regular.woff2" \
"$OUT/MachineMadeWarp-Italic.woff2" \
"$OUT/MachineMadeWarp-Bold.woff2" \
"$OUT/MachineMadeWarp-BoldItalic.woff2" \
"$OUT/MachineMadeWarpDisplay-Regular.woff2" \
"$OUT/MachineMadeWarpDisplay-Italic.woff2" \
"$OUT/MachineMadeWarp-Regular.ttf" \
"$OUT/MachineMadeWarp-Italic.ttf" \
"$OUT/MachineMadeWarp-Bold.ttf" \
"$OUT/MachineMadeWarp-BoldItalic.ttf" \
"$OUT/MachineMadeWarpDisplay-Regular.ttf" \
"$OUT/MachineMadeWarpDisplay-Italic.ttf" \
"$OUT/readability.json" \
"$OUT/SHA256SUMS"

site:
if: startsWith(inputs.tag || github.ref_name, 'site-v')
runs-on: ubuntu-24.04
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ jobs:
run: |
for f in "fonts/weft/MachineMadeWeft[FRAG,wght].woff2" "fonts/sans/MachineMadeSans[wght].woff2" \
"fonts/sans/MachineMadeSans-Italic[wght].woff2" "fonts/heddle/MachineMadeHeddle[wdth,wght].woff2" \
data/readability.json data/heddle.json index.html weft/index.html heddle/index.html; do
fonts/warp/MachineMadeWarp-Regular.woff2 fonts/warp/MachineMadeWarp-Italic.woff2 \
fonts/warp/MachineMadeWarp-Bold.woff2 fonts/warp/MachineMadeWarp-BoldItalic.woff2 \
fonts/warp/MachineMadeWarpDisplay-Regular.woff2 fonts/warp/MachineMadeWarpDisplay-Italic.woff2 \
data/readability.json data/heddle.json data/warp.json index.html weft/index.html heddle/index.html \
warp/index.html; do
test -s "site/_site/$f" || { echo "::error::site/_site/$f is missing."; exit 1; }
done
python -c 'import json,sys; r=json.load(open("site/_site/data/readability.json")); sys.exit(0 if r.get("rows") else 1)'
Expand Down
103 changes: 103 additions & 0 deletions .github/workflows/warp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: warp

on:
push:
branches: [main]
paths: ["warp/**", "fonts/warp/**", "proofs/warp/**", ".github/workflows/warp.yml"]
pull_request:
paths: ["warp/**", "fonts/warp/**", "proofs/warp/**", ".github/workflows/warp.yml"]
workflow_dispatch:

permissions:
contents: read

env:
FONTSPECTOR_VERSION: "1.9.0"
# SHA-256 of fontspector-1.9.0-x86_64-unknown-linux-gnu.tar.gz.
FONTSPECTOR_SHA256: "0d4a7fbc577f7f99a084dec2a7acc13f64f923cbe44c0e3c5e3d76469786b8e2"

jobs:
build:
runs-on: ubuntu-24.04
timeout-minutes: 40
defaults:
run:
working-directory: warp
steps:
- name: Check out
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set up Python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.14"

- name: Install dependencies
run: |
sudo apt-get update
# Raqm sets the proofs with OpenType features. Tesseract and DejaVu
# Serif are for the readability gate.
sudo apt-get install -y --no-install-recommends libraqm0 libfribidi0 \
tesseract-ocr tesseract-ocr-eng fonts-dejavu-core
tesseract --version
python -m pip install --upgrade pip
python -m pip install -e ".[test]"
# The tests and the proofs run the sketch engine (reference/warp-sketch-0.2.js).
node --version

- name: Run tests
run: python -m pytest -q

- name: Build fonts
run: scripts/build.sh

- name: Check that the committed fonts are current
run: |
if [ -n "$(git -C .. status --porcelain -- fonts/warp)" ]; then
git -C .. status --short -- fonts/warp
echo "::error::fonts/warp differs from a fresh build. Run warp/scripts/build.sh and commit the fonts."
exit 1
fi

- name: Check the outlines against the pen sweep (fidelity report)
run: |
python tools/fidelity.py --gate
if [ -n "$(git -C .. status --porcelain -- proofs/warp/fidelity.json)" ]; then
git -C .. diff --stat -- proofs/warp/fidelity.json
echo "::error::proofs/warp/fidelity.json differs. Run warp/tools/fidelity.py and commit the report."
exit 1
fi

- name: Readability gate (Tesseract OCR)
run: python tools/readability.py --gate --out build/reports/readability.json

- name: Install Fontspector
run: |
name="fontspector-${FONTSPECTOR_VERSION}-x86_64-unknown-linux-gnu"
curl -sSfL -o fontspector.tar.gz \
"https://github.com/fonttools/fontspector/releases/download/fontspector-v${FONTSPECTOR_VERSION}/${name}.tar.gz"
echo "${FONTSPECTOR_SHA256} fontspector.tar.gz" | sha256sum --check
tar xzf fontspector.tar.gz
sudo install -m 755 "${name}/fontspector" /usr/local/bin/fontspector
fontspector --version

- name: Check fonts (Fontspector, universal profile)
run: scripts/check.sh fontspector

- name: Add check reports to the summary
if: always()
run: cat build/reports/*.md >> "$GITHUB_STEP_SUMMARY" || true

- name: Render proof sheets
run: python tools/proof.py

- name: Upload fonts, proofs and reports
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: warp-0.1
path: |
fonts/warp/
proofs/warp/
warp/build/reports/
if-no-files-found: warn
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,21 @@ Each family keeps its own changelog:
- machine-made Weft: [`weft/CHANGELOG.md`](weft/CHANGELOG.md)
- machine-made Sans: [`sans/CHANGELOG.md`](sans/CHANGELOG.md)
- machine-made Heddle: [`heddle/CHANGELOG.md`](heddle/CHANGELOG.md)
- machine-made Warp: [`warp/CHANGELOG.md`](warp/CHANGELOG.md)

Release tags: `weft-vX.Y.Z`, `sans-vX.Y.Z`, `heddle-vX.Y.Z`, `site-vX.Y.Z`.
Release tags: `weft-vX.Y.Z`, `sans-vX.Y.Z`, `heddle-vX.Y.Z`, `warp-vX.Y.Z`, `site-vX.Y.Z`.

## 2026-10-27: Warp 0.1

- machine-made Warp 0.1.0 (font version 0.100): machine-made Warp
Regular, Italic, Bold, Bold Italic and machine-made Warp Display
Regular, Italic. See `warp/CHANGELOG.md`.
- Add `.github/workflows/warp.yml` (tests, build, byte check, fidelity
report, OCR gate, Fontspector, proofs) and a `warp` job in
`release.yml` for `warp-v*` tags. `package_release.sh` packs Warp.
- Site: add the Warp page (style switch, a paragraph from a paper,
Greek, figures and small caps, equations, glyph map), Warp on the
home and download pages, and Warp in the nav.

## 2026-10-27: Heddle 0.1

Expand Down
7 changes: 5 additions & 2 deletions LICENSING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@ code.
| `fonts/heddle/**` | SIL Open Font License 1.1, Reserved Font Name "machine-made" | `heddle/OFL.txt` |
| `heddle/loom/glyphs.py`, `heddle/loom/kerning.py` (the glyph and kerning tables that define the outlines and spacing; each file says so in its header) | SIL Open Font License 1.1, Reserved Font Name "machine-made" | `heddle/OFL.txt` |
| `heddle/reference/**` | The approved sketch (engine, page, screenshot): same licence as the font it defines | `heddle/OFL.txt` |
| `fonts/warp/**` | SIL Open Font License 1.1, Reserved Font Name "machine-made" | `warp/OFL.txt` |
| `warp/loom/sketch.py`, `warp/loom/extended.py`, `warp/loom/kerning.py` (the glyph and kerning tables that define the outlines and spacing; each file says so in its header) | SIL Open Font License 1.1, Reserved Font Name "machine-made" | `warp/OFL.txt` |
| `warp/reference/**` | The approved sketch (engine, page): same licence as the font it defines | `warp/OFL.txt` |
| `fonts/sans/**` | SIL Open Font License 1.1, Reserved Font Name "machine-made" (copyright: Plus Jakarta Sans Project Authors and machine-made Sans Project Authors) | `sans/OFL.txt` |
| `sans/sources/**` | SIL Open Font License 1.1, as for `fonts/sans/` | `sans/OFL.txt` |
| `sans/upstream/**` | Upstream Plus Jakarta Sans credit files, unchanged (SIL OFL 1.1) | `sans/upstream/OFL.txt` |
| `proofs/**` | Images and reports made from the fonts: same licence as the font they show | `weft/OFL.txt`, `sans/OFL.txt` or `heddle/OFL.txt` |
| Every other file, for example the rest of `weft/loom/` and `heddle/loom/`, `weft/tools/`, `weft/scripts/`, `weft/tests/`, `heddle/tools/`, `heddle/scripts/`, `heddle/tests/`, `sans/scripts/`, `sans/tests/`, `site/`, `.github/` | Apache License 2.0 | `LICENSE` |
| `proofs/**` | Images and reports made from the fonts: same licence as the font they show | `weft/OFL.txt`, `sans/OFL.txt`, `heddle/OFL.txt` or `warp/OFL.txt` |
| Every other file, for example the rest of `weft/loom/`, `heddle/loom/` and `warp/loom/`, `weft/tools/`, `weft/scripts/`, `weft/tests/`, `heddle/tools/`, `heddle/scripts/`, `heddle/tests/`, `warp/tools/`, `warp/scripts/`, `warp/tests/`, `sans/scripts/`, `sans/tests/`, `site/`, `.github/` | Apache License 2.0 | `LICENSE` |

The Reserved Font Name "machine-made" means: if you change a font and
distribute it, give it a name that does not contain "machine-made".
Expand Down
Loading