From c42f316cbf7903beb1b5a13a28df8c086116f3b0 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 16 Oct 2026 17:59:06 -0400 Subject: [PATCH] Place the PolicyEngine wordmark in the PDF and HTML title blocks The theme declared a wordmark that neither title partial used, and the SVG was invalid XML: its comment contained "--primary", which XML forbids inside , so rsvg-convert refused the file. - Reword the SVG comment and record the ui-kit source file. - Ship a vector policyengine-wordmark.pdf, built by scripts/build-wordmark-pdf.sh and listed under the PDF format-resources, so xelatex includes it with no conversion at render time. The SVG is an HTML format-resource. - Both title blocks place the wordmark above the kicker by default. `wordmark: false` omits it, for a document or for one format. While it shows, it replaces the theme's fallback "PolicyEngine" byline. - before-title.tex loads graphicx, which Quarto's template loads only under its `graphics` variable. - scripts/check.sh validates the SVGs, checks that the PDF still matches the SVG, and renders the example plus opt-out, per-format, embedded, base-format and website cases. A new Check workflow runs it on Quarto 1.7.34 and 1.10.19. - README and example/paper.qmd document the key and the copied files. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/check.yml | 37 ++++ .gitignore | 2 + README.md | 22 ++ _extensions/policyengine-paper/_extension.yml | 5 + _extensions/policyengine/_extension.yml | 5 + .../assets/policyengine-wordmark.pdf | Bin 0 -> 3933 bytes .../assets/policyengine-wordmark.svg | 2 +- .../policyengine/partials/before-title.tex | 3 + .../policyengine/partials/title-block.html | 12 +- _extensions/policyengine/partials/title.tex | 6 + _extensions/policyengine/policyengine.scss | 7 + .../policyengine/theme-policyengine.yml | 8 +- example/paper.qmd | 6 +- scripts/build-wordmark-pdf.sh | 18 ++ scripts/check.sh | 197 ++++++++++++++++++ 15 files changed, 324 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/check.yml create mode 100644 _extensions/policyengine/assets/policyengine-wordmark.pdf create mode 100755 scripts/build-wordmark-pdf.sh create mode 100755 scripts/check.sh diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..96771fa --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,37 @@ +name: Check + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + render: + name: Render (Quarto ${{ matrix.quarto }}) + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + # The extensions declare quarto-required >=1.7.0; test that floor and + # the current stable release. + quarto: ["1.7.34", "1.10.19"] + steps: + - uses: actions/checkout@v7 + + - name: Install XeLaTeX and image tools + run: | + sudo apt-get update + sudo apt-get install --yes --no-install-recommends \ + texlive-xetex texlive-latex-recommended texlive-latex-extra \ + texlive-fonts-recommended lmodern \ + libxml2-utils librsvg2-bin poppler-utils imagemagick + + - uses: quarto-dev/quarto-actions/setup@v2 + with: + version: ${{ matrix.quarto }} + + - run: scripts/check.sh diff --git a/.gitignore b/.gitignore index a58ad0d..337aa65 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ /example/paper.html /example/paper.pdf /example/fonts/ +/example/policyengine-wordmark.pdf +/example/policyengine-wordmark.svg /output/ /tmp/ diff --git a/README.md b/README.md index 6602462..2ac617d 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,11 @@ Use `policyengine-paper-pdf` and `policyengine-paper-html` in the document Metadata: +- `wordmark`: the PolicyEngine wordmark heads the PDF and HTML title blocks; + defaults to `true`. Set `wordmark: false` to omit it from a document, or set + it under one format to omit it there only. When no author lists an + affiliation, the title block falls back to a "PolicyEngine" byline; the + wordmark replaces that fallback. Author affiliations always print. - `kicker`: short register line above the title; defaults to `WORKING PAPER`. - `revision`: revision number shown with the ISO document date. - `status`: Markdown body for the status banner; the format supplies its label. @@ -21,6 +26,23 @@ Metadata: See `example/paper.qmd` for a minimal two-format paper. +Rendering copies the format's resources beside the document: `fonts/` and +`policyengine-wordmark.pdf` for PDF, `policyengine-wordmark.svg` for HTML. +Projects with an output directory also copy the SVG beside each page. Add these +copies to `.gitignore`. + +## Development + +`scripts/check.sh` validates the SVG assets, confirms the committed PDF +wordmark still matches the SVG, and renders test documents in every paper +format with and without the wordmark. It needs Quarto, XeLaTeX, xmllint, +rsvg-convert, pdftoppm and ImageMagick; CI runs it on every pull request. + +The PDF wordmark is a vector conversion of +`_extensions/policyengine/assets/policyengine-wordmark.svg`, committed so +rendering needs no conversion step. After editing the SVG, run +`scripts/build-wordmark-pdf.sh` and commit both files. + ## License Code in this repository is released under the [MIT License](LICENSE). Original text and figures are released under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) with attribution to PolicyEngine. Third-party data and materials keep their own terms. diff --git a/_extensions/policyengine-paper/_extension.yml b/_extensions/policyengine-paper/_extension.yml index 5bc4018..6ca33f7 100644 --- a/_extensions/policyengine-paper/_extension.yml +++ b/_extensions/policyengine-paper/_extension.yml @@ -6,6 +6,8 @@ contributes: formats: common: number-sections: true + # The title block shows the theme wordmark; `wordmark: false` omits it. + wordmark: true metadata-files: - ../policyengine/theme-policyengine.yml pdf: @@ -15,6 +17,7 @@ contributes: - margin=1.1in format-resources: - ../policyengine/fonts + - ../policyengine/assets/policyengine-wordmark.pdf colorlinks: true # Source: policyengine-ui-kit/src/theme/tokens.css:51 (--border). code-block-border-left: "#E2E8F0" @@ -32,5 +35,7 @@ contributes: - default - ../policyengine/policyengine.scss css: ../policyengine/fonts.css + format-resources: + - ../policyengine/assets/policyengine-wordmark.svg template-partials: - ../policyengine/partials/title-block.html diff --git a/_extensions/policyengine/_extension.yml b/_extensions/policyengine/_extension.yml index d429344..feb5ebc 100644 --- a/_extensions/policyengine/_extension.yml +++ b/_extensions/policyengine/_extension.yml @@ -6,6 +6,8 @@ contributes: formats: common: number-sections: true + # The title block shows the theme wordmark; `wordmark: false` omits it. + wordmark: true metadata-files: - theme-policyengine.yml pdf: @@ -15,6 +17,7 @@ contributes: - margin=1.1in format-resources: - fonts + - assets/policyengine-wordmark.pdf colorlinks: true # Source: policyengine-ui-kit/src/theme/tokens.css:51 (--border). code-block-border-left: "#E2E8F0" @@ -32,5 +35,7 @@ contributes: - default - policyengine.scss css: fonts.css + format-resources: + - assets/policyengine-wordmark.svg template-partials: - partials/title-block.html diff --git a/_extensions/policyengine/assets/policyengine-wordmark.pdf b/_extensions/policyengine/assets/policyengine-wordmark.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6e22a7a5d14e1aa4f5f7e1186e1a5df5a0860c72 GIT binary patch literal 3933 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 literal 0 HcmV?d00001 diff --git a/_extensions/policyengine/assets/policyengine-wordmark.svg b/_extensions/policyengine/assets/policyengine-wordmark.svg index 4d82226..7f75c32 100644 --- a/_extensions/policyengine/assets/policyengine-wordmark.svg +++ b/_extensions/policyengine/assets/policyengine-wordmark.svg @@ -1,5 +1,5 @@ - + diff --git a/_extensions/policyengine/partials/before-title.tex b/_extensions/policyengine/partials/before-title.tex index 46a386c..a1537ff 100644 --- a/_extensions/policyengine/partials/before-title.tex +++ b/_extensions/policyengine/partials/before-title.tex @@ -5,6 +5,9 @@ \usepackage{titlesec} \usepackage{etoolbox} \usepackage{xurl} +% Quarto's template loads graphicx only under its `graphics` variable; the +% title block's wordmark needs it regardless. +\usepackage{graphicx} \setmainfont[ Path={$policyengine-font-dir$/inter/}, diff --git a/_extensions/policyengine/partials/title-block.html b/_extensions/policyengine/partials/title-block.html index 8062359..0ff95e7 100644 --- a/_extensions/policyengine/partials/title-block.html +++ b/_extensions/policyengine/partials/title-block.html @@ -8,6 +8,10 @@
+ $if(wordmark)$ +
$policyengine-theme.wordmark-alt$ + $endif$ +
$if(kicker)$$kicker$$else$WORKING PAPER$endif$ @@ -24,13 +28,17 @@

$title$

$endif$ -
$if(by-affiliation)$ +
$for(by-affiliation)$$it.name$$sep$$endfor$ +
+ $elseif(wordmark)$ + $-- The wordmark already names the theme affiliation. $elseif(policyengine-theme.affiliation)$ +
$policyengine-theme.affiliation$ - $endif$
+ $endif$ $if(revision)$
Revision $revision$$if(date-meta)$ $date-meta$$endif$
diff --git a/_extensions/policyengine/partials/title.tex b/_extensions/policyengine/partials/title.tex index 8a28f07..3e918c2 100644 --- a/_extensions/policyengine/partials/title.tex +++ b/_extensions/policyengine/partials/title.tex @@ -3,6 +3,10 @@ \begingroup \setlength{\parindent}{0pt}% \begin{flushleft} + $if(wordmark)$ + \includegraphics[height=0.3in,alt={$policyengine-theme.wordmark-alt$}]{$policyengine-theme.wordmark-pdf$}\par + \vspace{1.6em} + $endif$ {\policyenginemono\fontsize{7}{9}\selectfont {\color{policyengineaccent}Σ}\hspace{0.7em}% \MakeUppercase{$if(kicker)$$kicker$$else$WORKING PAPER$endif$}\par} @@ -18,6 +22,8 @@ $if(by-affiliation)$ {\sffamily\small\color{policyenginemuted} $for(by-affiliation)$$it.name$$sep$\enspace\textperiodcentered\enspace{}$endfor$\par} + $elseif(wordmark)$ + $-- The wordmark already names the theme affiliation. $elseif(policyengine-theme.affiliation)$ {\sffamily\small\color{policyenginemuted} $policyengine-theme.affiliation$\par} $endif$ diff --git a/_extensions/policyengine/policyengine.scss b/_extensions/policyengine/policyengine.scss index 2f0e66d..2030692 100644 --- a/_extensions/policyengine/policyengine.scss +++ b/_extensions/policyengine/policyengine.scss @@ -62,6 +62,13 @@ a:focus { margin-block: 0 2.2rem; } +.policyengine-wordmark { + display: block; + width: auto; + height: 2.25rem; + margin-bottom: 1.6rem; +} + .policyengine-kicker, .policyengine-revision, .policyengine-status-label { diff --git a/_extensions/policyengine/theme-policyengine.yml b/_extensions/policyengine/theme-policyengine.yml index 812d77b..737a46a 100644 --- a/_extensions/policyengine/theme-policyengine.yml +++ b/_extensions/policyengine/theme-policyengine.yml @@ -9,4 +9,10 @@ policyengine-theme: # Source: policyengine-ui-kit/src/theme/tokens.css:66 (--chart-3). accent-hover-tex: "285E61" affiliation: PolicyEngine - wordmark: assets/policyengine-wordmark.svg + # Quarto copies format-resources beside the document by basename, so the + # partials name the copies, not the assets/ paths. + # Source: policyengine-ui-kit/src/assets/logos/policyengine/teal.svg. + wordmark-svg: policyengine-wordmark.svg + # Built from the SVG by scripts/build-wordmark-pdf.sh. + wordmark-pdf: policyengine-wordmark.pdf + wordmark-alt: PolicyEngine diff --git a/example/paper.qmd b/example/paper.qmd index 33908ee..5fd717d 100644 --- a/example/paper.qmd +++ b/example/paper.qmd @@ -6,6 +6,8 @@ author: - name: PolicyEngine date: 2026-08-15 date-format: iso +# The wordmark heads the title block by default; false omits it. +wordmark: true kicker: working paper revision: "1" status: | @@ -13,8 +15,8 @@ status: | [local-font link](https://policyengine.org/). theme: policyengine abstract: | - A minimal paper that exercises the title, abstract, status, headings, - links, footnotes, and code treatments. + A minimal paper that exercises the wordmark, title, abstract, status, + headings, links, footnotes, and code treatments. format: policyengine-paper-pdf: default policyengine-paper-html: default diff --git a/scripts/build-wordmark-pdf.sh b/scripts/build-wordmark-pdf.sh new file mode 100755 index 0000000..9b6e850 --- /dev/null +++ b/scripts/build-wordmark-pdf.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Rebuild the vector PDF wordmark that xelatex includes in the PDF title block. +# The PDF is committed so rendering a paper needs no SVG conversion step; run +# this script whenever assets/policyengine-wordmark.svg changes, then commit +# both files. scripts/check.sh fails if the two drift apart. +set -euo pipefail + +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +assets="$root/_extensions/policyengine/assets" + +# A fixed epoch keeps cairo's CreationDate stable, so a rebuild with the same +# librsvg and cairo versions is byte-identical. +SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-0}" rsvg-convert \ + --format=pdf \ + --output="$assets/policyengine-wordmark.pdf" \ + "$assets/policyengine-wordmark.svg" + +echo "Wrote $assets/policyengine-wordmark.pdf" diff --git a/scripts/check.sh b/scripts/check.sh new file mode 100755 index 0000000..8da597c --- /dev/null +++ b/scripts/check.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env bash +# Validate the wordmark assets, then render test documents in every paper +# format with and without the wordmark and check each title block. Needs +# quarto, xelatex, xmllint, rsvg-convert, pdftoppm and ImageMagick's compare. +set -euo pipefail + +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +assets="$root/_extensions/policyengine/assets" +work="$(mktemp -d)" +trap 'rm -rf "$work"' EXIT + +failures=0 +ok() { printf 'ok - %s\n' "$1"; } +not_ok() { + printf 'not ok - %s\n' "$1" + failures=$((failures + 1)) +} +check() { + local description="$1" + shift + if "$@"; then ok "$description"; else not_ok "$description"; fi +} +has() { grep -qF -- "$2" "$1"; } +lacks() { ! grep -qF -- "$2" "$1"; } + +# The SVG assets must parse as XML; rsvg-convert and browsers reject a +# comment that contains a double hyphen. +while IFS= read -r svg; do + check "$svg parses as XML" xmllint --noout "$root/$svg" +done < <(git -C "$root" ls-files '*.svg') + +# The committed PDF must still depict the SVG. Rasterize both at the SVG's +# size and count pixels that differ by more than 10%: the two renderers +# disagree on about 0.06% (antialiasing), a blank or mirrored wordmark on +# 10-18%, so 0.5% separates drift from noise. +pdf_matches_svg() { + local width height differing + rsvg-convert --background-color=white --output="$work/svg.png" \ + "$assets/policyengine-wordmark.svg" || return 1 + read -r width height < <(identify -format '%w %h\n' "$work/svg.png") || return 1 + pdftoppm -singlefile -png -scale-to-x "$width" -scale-to-y "$height" \ + "$assets/policyengine-wordmark.pdf" "$work/pdf" || return 1 + differing="$({ compare -metric AE -fuzz 10% "$work/svg.png" "$work/pdf.png" null: 2>&1 || true; } | awk '{print $1}')" + printf '# %s of %d pixels differ\n' "$differing" "$((width * height))" + awk -v d="$differing" -v n="$((width * height))" 'BEGIN { exit !(d != "" && d / n < 0.005) }' +} +check "policyengine-wordmark.pdf matches the SVG" pdf_matches_svg + +project="$work/project" +mkdir -p "$project" +cp -R "$root/_extensions" "$project/" +printf 'project:\n type: default\n' >"$project/_quarto.yml" + +render() { + local log="$work/$1.log" + if (cd "$project" && quarto render "$1/paper.qmd" -M keep-tex:true) >"$log" 2>&1; then + ok "$1 renders" + else + not_ok "$1 renders" + sed 's/^/ /' "$log" + return 1 + fi +} + +wordmark_tex=']{policyengine-wordmark.pdf}' +wordmark_html='PolicyEngine' +theme_affiliation_tex='\color{policyenginemuted} PolicyEngine\par}' +affiliation_html='PolicyEngine' + +# The shipped example: wordmark by default, author affiliation kept. +mkdir -p "$project/example" +cp "$root/example/paper.qmd" "$project/example/" +if render example; then + d="$project/example" + check "example PDF includes the wordmark" has "$d/paper.tex" "$wordmark_tex" + check "example PDF exists" test -s "$d/paper.pdf" + check "example HTML includes the wordmark" has "$d/paper.html" "$wordmark_html" + check "example HTML wordmark file sits beside the page" test -s "$d/policyengine-wordmark.svg" + check "example HTML keeps the author affiliation" has "$d/paper.html" "$affiliation_html" +fi + +case_document() { + mkdir -p "$project/$1" + cat >"$project/$1/paper.qmd" +} + +# Without author affiliations, the wordmark replaces the theme byline. +case_document no-affiliation <<'EOF' +--- +title: "No affiliation" +author: Ada Example +format: + policyengine-paper-pdf: default + policyengine-paper-html: default +--- +Body. +EOF +if render no-affiliation; then + d="$project/no-affiliation" + check "no-affiliation PDF includes the wordmark" has "$d/paper.tex" "$wordmark_tex" + check "no-affiliation PDF omits the theme byline" lacks "$d/paper.tex" "$theme_affiliation_tex" + check "no-affiliation HTML includes the wordmark" has "$d/paper.html" "$wordmark_html" + check "no-affiliation HTML omits the theme byline" lacks "$d/paper.html" "policyengine-affiliations" +fi + +# `wordmark: false` removes it from both formats and restores the byline. +case_document opt-out <<'EOF' +--- +title: "Opt out" +author: Ada Example +wordmark: false +format: + policyengine-paper-pdf: default + policyengine-paper-html: default +--- +Body. +EOF +if render opt-out; then + d="$project/opt-out" + check "opt-out PDF omits the wordmark" lacks "$d/paper.tex" "policyengine-wordmark" + check "opt-out PDF prints the theme byline" has "$d/paper.tex" "$theme_affiliation_tex" + check "opt-out HTML omits the wordmark" lacks "$d/paper.html" "policyengine-wordmark" + check "opt-out HTML prints the theme byline" has "$d/paper.html" "$affiliation_html" +fi + +# A format-level `wordmark: false` affects only that format. +case_document pdf-opt-out <<'EOF' +--- +title: "PDF opt out" +author: Ada Example +format: + policyengine-paper-pdf: + wordmark: false + policyengine-paper-html: default +--- +Body. +EOF +if render pdf-opt-out; then + d="$project/pdf-opt-out" + check "pdf-opt-out PDF omits the wordmark" lacks "$d/paper.tex" "policyengine-wordmark" + check "pdf-opt-out HTML includes the wordmark" has "$d/paper.html" "$wordmark_html" +fi + +# Self-contained HTML embeds the SVG instead of linking it. +case_document embedded <<'EOF' +--- +title: "Embedded" +author: Ada Example +format: + policyengine-paper-html: + embed-resources: true +--- +Body. +EOF +if render embedded; then + d="$project/embedded" + check "embedded HTML inlines the wordmark" has "$d/paper.html" 'class="policyengine-wordmark" src="data:image/svg+xml;base64,' + check "embedded HTML does not link the wordmark file" lacks "$d/paper.html" 'src="policyengine-wordmark.svg"' +fi + +# The base extension's HTML format shares the partials. Its PDF format is not +# rendered here: it already failed before the wordmark, because Quarto +# resolves its policyengine-font-dir to an extension path that pandoc escapes. +case_document base-html <<'EOF' +--- +title: "Base HTML" +author: Ada Example +format: + policyengine-html: default +--- +Body. +EOF +if render base-html; then + check "base-html includes the wordmark" has "$project/base-html/paper.html" "$wordmark_html" +fi + +# Projects with an output directory copy the wordmark beside the page. +site="$work/site" +mkdir -p "$site/papers" +cp -R "$root/_extensions" "$site/" +printf 'project:\n type: website\n output-dir: _site\n' >"$site/_quarto.yml" +printf -- '---\ntitle: Home\n---\n' >"$site/index.qmd" +printf -- '---\ntitle: "In a website"\nformat: policyengine-paper-html\n---\nBody.\n' >"$site/papers/paper.qmd" +if (cd "$site" && quarto render) >"$work/site.log" 2>&1; then + ok "website renders" + check "website output includes the wordmark" has "$site/_site/papers/paper.html" "$wordmark_html" + check "website output copies the wordmark file" test -s "$site/_site/papers/policyengine-wordmark.svg" +else + not_ok "website renders" + sed 's/^/ /' "$work/site.log" +fi + +if ((failures > 0)); then + printf '%d check(s) failed\n' "$failures" + exit 1 +fi +echo "All checks passed"