From b88a845aa52d230f0b4adb26b948e358a50099bb Mon Sep 17 00:00:00 2001
From: Oscar Levin
Date: Wed, 8 Jul 2026 13:18:33 -0600
Subject: [PATCH 1/7] add beamer support
---
CHANGELOG.md | 7 ++++++
poetry.lock | 49 ++++++++-----------------------------
pretext/__init__.py | 4 +--
pretext/constants.py | 22 +++++++++++++++++
pretext/project/__init__.py | 15 ++++++++++++
pyproject.toml | 2 +-
6 files changed, 56 insertions(+), 43 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 791e59e7..a92bbddb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,13 @@ Instructions: Add a subsection under `[Unreleased]` for additions, fixes, change
## [Unreleased]
+### Added
+- Experimental support for beamer format builds (from a ``). Use `` in the manifest to build a beamer PDF.
+- Publication variable to use cdn javascript/css for HTML output instead of local copies.
+
+### Fixed
+- Better heading levels for HTML output to improve accessibility.
+
## [2.43.2] - 2026-07-07
Includes updates to core through commit: [ad605bb](https://github.com/PreTeXtBook/pretext/commit/ad605bb27faf9f12c2bcb3b98ea953533f1aacb4)
diff --git a/poetry.lock b/poetry.lock
index ed2f0ce7..b90844e4 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,4 +1,4 @@
-# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand.
+# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
[[package]]
name = "annotated-types"
@@ -17,32 +17,6 @@ type = "legacy"
url = "https://pypi.org/simple"
reference = "pypi-public"
-[[package]]
-name = "anyio"
-version = "4.13.0"
-description = "High-level concurrency and networking framework on top of asyncio or Trio"
-optional = true
-python-versions = ">=3.10"
-groups = ["main"]
-markers = "extra == \"homepage\" or extra == \"all\""
-files = [
- {file = "anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708"},
- {file = "anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc"},
-]
-
-[package.dependencies]
-exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""}
-idna = ">=2.8"
-typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
-
-[package.extras]
-trio = ["trio (>=0.32.0)"]
-
-[package.source]
-type = "legacy"
-url = "https://pypi.org/simple"
-reference = "pypi-public"
-
[[package]]
name = "autocommand"
version = "2.2.2"
@@ -648,12 +622,12 @@ version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
-groups = ["main", "dev"]
+groups = ["dev"]
+markers = "python_version == \"3.10\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
]
-markers = {main = "(extra == \"homepage\" or extra == \"all\") and python_version == \"3.10\"", dev = "python_version == \"3.10\""}
[package.extras]
test = ["pytest (>=6)"]
@@ -677,7 +651,7 @@ files = [
]
[package.dependencies]
-pytz = ">=0a0"
+pytz = ">=0a"
[package.source]
type = "legacy"
@@ -2041,15 +2015,15 @@ reference = "pypi-public"
[[package]]
name = "prefig"
-version = "0.6.5"
+version = "0.6.7"
description = "An authoring system for mathematical diagrams"
optional = true
python-versions = ">=3.10,<4.0"
groups = ["main"]
markers = "extra == \"prefigure\" or extra == \"all\""
files = [
- {file = "prefig-0.6.5-py3-none-any.whl", hash = "sha256:2b9fd5aee2d007e5283d82ab2e01b34812aeef1e6751f0703fdea32d2ed15bb9"},
- {file = "prefig-0.6.5.tar.gz", hash = "sha256:93fd53be07ff981192ad31cab94c00f9d20835c694cbe038351f6c1ca903e609"},
+ {file = "prefig-0.6.7-py3-none-any.whl", hash = "sha256:6a857179fa14bc16c938adbf4ca12ba2f94745f8a788f4b15eb0879fe0f148c3"},
+ {file = "prefig-0.6.7.tar.gz", hash = "sha256:6a3664e284dfe9b8a40fa05d84a0a9d45637948c9bd54b29539593d47479025c"},
]
[package.dependencies]
@@ -3363,9 +3337,9 @@ reference = "pypi-public"
[[package]]
name = "watchfiles"
version = "0.24.0"
-description = "Simple, modern and high performance file watching and code reload in python."
+description = ""
optional = true
-python-versions = ">=3.8"
+python-versions = "*"
groups = ["main"]
markers = "extra == \"homepage\" or extra == \"all\""
files = [
@@ -3454,9 +3428,6 @@ files = [
{file = "watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1"},
]
-[package.dependencies]
-anyio = ">=3.0.0"
-
[package.source]
type = "legacy"
url = "https://pypi.org/simple"
@@ -3617,4 +3588,4 @@ prefigure = ["prefig"]
[metadata]
lock-version = "2.1"
python-versions = "^3.10"
-content-hash = "51f765b499df48be46c7907930c9a189c3e2faec4bc43c43253ef137a5f4564a"
+content-hash = "0ab0b613cb7b2c30649b74a16d92b7d02ab99cc090c2fbf779d71443c06dfd7e"
diff --git a/pretext/__init__.py b/pretext/__init__.py
index e794a8d5..9e5be705 100644
--- a/pretext/__init__.py
+++ b/pretext/__init__.py
@@ -18,9 +18,7 @@
VERSION = get_version("pretext", Path(__file__).parent.parent)
-
-CORE_COMMIT = "ad605bb27faf9f12c2bcb3b98ea953533f1aacb4"
-
+CORE_COMMIT = "07c8b5c9a9a55e95ec27073e88bd5c9c61b9c161"
def activate() -> None:
"""
diff --git a/pretext/constants.py b/pretext/constants.py
index bc840a17..66603bcf 100644
--- a/pretext/constants.py
+++ b/pretext/constants.py
@@ -12,6 +12,7 @@
"kindle",
"braille",
"revealjs",
+ "beamer",
"webwork",
"custom",
]
@@ -123,6 +124,20 @@
"datafile",
"myopenmath",
],
+ "beamer": [
+ "webwork",
+ "sageplot",
+ "asymptote",
+ "prefigure",
+ "youtube",
+ "codelens",
+ "datafile",
+ "interactive",
+ "qrcode",
+ "mermaid",
+ "myopenmath",
+ "dynamic-subs",
+ ],
"webwork": [
"webwork",
],
@@ -239,6 +254,13 @@
"sageplot": ["html", "svg"],
"prefigure": ["svg"],
},
+ "beamer": {
+ "asymptote": ["pdf"],
+ "latex-image": [],
+ "sageplot": ["pdf", "png"],
+ "prefigure": ["pdf"],
+ "mermaid": ["png"],
+ },
"webwork": {
"asymptote": [],
"latex-image": [],
diff --git a/pretext/project/__init__.py b/pretext/project/__init__.py
index c31eaba6..d7ed5b9a 100644
--- a/pretext/project/__init__.py
+++ b/pretext/project/__init__.py
@@ -56,6 +56,7 @@ class Format(str, Enum):
KINDLE = "kindle"
BRAILLE = "braille"
REVEALJS = "revealjs"
+ BEAMER = "beamer"
WEBWORK = "webwork"
CUSTOM = "custom"
@@ -67,6 +68,7 @@ class Format(str, Enum):
Format.EPUB: ".epub",
Format.KINDLE: ".epub",
Format.BRAILLE: ".brl",
+ Format.BEAMER: ".pdf",
}
@@ -874,6 +876,7 @@ def build(
dest_dir=self.output_dir_abspath().as_posix(),
method=self.pdf_method,
outputs="all" if latex else "pdf-only",
+ format_xsl=None,
)
elif self.format == Format.LATEX:
core.pdf(
@@ -885,6 +888,7 @@ def build(
dest_dir=self.output_dir_abspath().as_posix(),
method=self.pdf_method,
outputs="prebuild",
+ format_xsl=None
)
elif self.format == Format.EPUB:
utils.mjsre_npm_install()
@@ -930,6 +934,17 @@ def build(
out_file=out_file,
dest_dir=self.output_dir_abspath().as_posix(),
)
+ elif self.format == Format.BEAMER:
+ core.beamer(
+ xml=self.source_abspath(),
+ pub_file=self.publication_abspath().as_posix(),
+ stringparams=stringparams_copy,
+ extra_xsl=custom_xsl,
+ out_file=out_file,
+ dest_dir=self.output_dir_abspath().as_posix(),
+ method=self.pdf_method,
+ outputs="all" if latex else "pdf-only",
+ )
elif self.format == Format.BRAILLE:
log.warning(
"Braille output is still experimental, and requires additional libraries from liblouis (specifically the file2brl software)."
diff --git a/pyproject.toml b/pyproject.toml
index 541c124e..08166013 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -45,7 +45,7 @@ plastex = "^3"
jinja2 = "^3"
coloraide = "^4"
pelican = { extras = ["markdown"], version = "^4.10", optional = true }
-prefig = { extras = ["text"], version = "^0.6.5", optional = true }
+prefig = { extras = ["text"], version = "^0.6.7", optional = true }
citeproc-py = "^0"
From 506877dd5cbb1614e90774414fd7b30e89022235 Mon Sep 17 00:00:00 2001
From: Oscar Levin
Date: Wed, 8 Jul 2026 13:48:50 -0600
Subject: [PATCH 2/7] format
---
pretext/__init__.py | 1 +
pretext/project/__init__.py | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/pretext/__init__.py b/pretext/__init__.py
index 9e5be705..ebc96c78 100644
--- a/pretext/__init__.py
+++ b/pretext/__init__.py
@@ -20,6 +20,7 @@
CORE_COMMIT = "07c8b5c9a9a55e95ec27073e88bd5c9c61b9c161"
+
def activate() -> None:
"""
This function was provided by the original `pretext` package
diff --git a/pretext/project/__init__.py b/pretext/project/__init__.py
index d7ed5b9a..a8cc5e24 100644
--- a/pretext/project/__init__.py
+++ b/pretext/project/__init__.py
@@ -888,7 +888,7 @@ def build(
dest_dir=self.output_dir_abspath().as_posix(),
method=self.pdf_method,
outputs="prebuild",
- format_xsl=None
+ format_xsl=None,
)
elif self.format == Format.EPUB:
utils.mjsre_npm_install()
From 81c70cd7c0d13e6d3cb240eb4f2b2c4737cedba6 Mon Sep 17 00:00:00 2001
From: Oscar Levin
Date: Wed, 8 Jul 2026 14:10:15 -0600
Subject: [PATCH 3/7] Update slideshow templates
---
templates/slideshow/project.ptx | 5 +
templates/slideshow/source/main.ptx | 392 +++++++++++++++++++++++++++-
2 files changed, 390 insertions(+), 7 deletions(-)
diff --git a/templates/slideshow/project.ptx b/templates/slideshow/project.ptx
index 8d31e02c..a77a15c7 100644
--- a/templates/slideshow/project.ptx
+++ b/templates/slideshow/project.ptx
@@ -7,5 +7,10 @@
format="revealjs"
output-filename="index.html"
/>
+
diff --git a/templates/slideshow/source/main.ptx b/templates/slideshow/source/main.ptx
index 63f58dd1..a551d691 100644
--- a/templates/slideshow/source/main.ptx
+++ b/templates/slideshow/source/main.ptx
@@ -2,15 +2,19 @@
@@ -20,6 +24,10 @@ along with PreTeXt. If not, see .
\newcommand{\definiteintegral}[4]{\int_{#1}^{#2}\,#3\,d#4}
+
+ \usepackage{tikz}
+ \usepackage{nicematrix} % for multi-run latex-image (label="latex-three-pass")
+
@@ -27,13 +35,16 @@ along with PreTeXt. If not, see .
A Slideshow
-
+ Robert A. BeezerUniversity of Puget SoundAt a Test Conference
+
+
+
@@ -177,6 +188,10 @@ along with PreTeXt. If not, see .
+
+
+
+ Blocks and codeBlocks: definition
@@ -188,7 +203,7 @@ along with PreTeXt. If not, see .
indefinite integral of f(x)
-
Suppose that \frac{d}{dx}F(x)=f(x). Then the indefinite integral of f(x) is F(x) and is written as \int\,f(x)\,dx=F(x).
+
Suppose that \frac{d}{dx}F(x)=f(x). Then the indefinite integral of f(x) is F(x) and is written as \int\,f(x)\,dx=F(x).
@@ -203,7 +218,7 @@ along with PreTeXt. If not, see .
Fundamental Theorem of Calculus
-
If f(x) is continuous, and the derivative of F(x) is f(x), then \definiteintegral{a}{b}{f(x)}{x}=F(b)-F(a)test: buried in theorem/statement/p
+
If f(x) is continuous, and the derivative of F(x) is f(x), then \definiteintegral{a}{b}{f(x)}{x}=F(b)-F(a)test: buried in theorem/statement/p
Left to the reader.
@@ -211,6 +226,33 @@ along with PreTeXt. If not, see .
+
+ Code
+
+
Here is an inline bit of code with surrounding text. print("hello world"). Here is a more text. And some more. And yet more. And a full program... with Prism support.
+
+ A simple program
+
+ def f(x):
+ return x**2
+
+ # many intentional blank lines below...
+ # you may to zoom out, but at some point better to scroll a long listing
+
+
+
+
+
+
+
+
+
+
+ print(f(3))
+
+
+
+
@@ -219,9 +261,9 @@ along with PreTeXt. If not, see .
Ramanujan and Integration
-
This Sage Cell should execute properly, but some extra CSS is being applied. It is also difficult to edit properly. Perhaps the two are related. You may need to zoom out your browser to see all the content, especially after running the cell.
+
This Sage Cell is testing styling.
-
We have some mathematics on the page, to look for Javascript interference with MathJax. An identity due to Ramanujan:\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\ldots} } } }.
+
We have some mathematics on the page, to look for Javascript interference with MathJax. An identity due to Ramanujan:\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\ldots} } } }.
numerical_integral(sin(x)^2, (0, 2))
@@ -229,7 +271,89 @@ along with PreTeXt. If not, see .
-
And some more mathematics. An identity due to Ramanujan:\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\ldots} } } }.
+
And some more mathematics. An identity due to Ramanujan:\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\ldots} } } }.
+
+
+
+
+ More Elements
+
+
+ Displayed Mathematics
+
+
A single displayed equation, unnumbered on a slide.
+ \definiteintegral{0}{\pi}{\sin(x)}{x} = 2
+
+
+
And a multi-line display, with alignment on the equals signs.
+ (a+b)^2 \amp= (a+b)(a+b)
+ \amp= a^2 + ab + ba + b^2
+ \amp= a^2 + 2ab + b^2
+
+
+
+
+ A Table
+
+
A tabular inside a table, whose title serves as a caption.
+
+
+ Conversions of a slideshow
+
+
+
+
+
+ Format
+ Engine
+ Output
+
+
+ reveal.js
+ browser
+ HTML
+
+
+ Beamer
+
+ PDF
+
+
+
+
+
+
+ Console Sessions
+
+
A console reproduces an interactive command-line session, input distinguished from output.
The problem with quotes on the Internet is that it is hard to verify their authenticity.
+ Abraham Lincoln
+
+
+
A blockquote can carry an attribution, as above.
+
+
+
+ Cross-References and URLs
+
+
A cross-reference to a block on another slide renders as static text, since a PDF slideshow has no knowls: see .
+
+
One with text from the target's title: .
+
+
An external reference is live in capable outputs: .
@@ -262,6 +386,260 @@ along with PreTeXt. If not, see .
But this is still visible from the outset.
+
+ Images, from an external source
+
+
+ Images can be included from external sources.
+ As with other formats,
+ you can specify the location of your exteral images in the publication file.
+ The image below also appears in the Sample Article,
+ and originated at www.texample.net.
+
+
+
+
+ You will want to ensure your image has an width if you want it to fit correctly in your slide.
+
+
+
+
+ Images, from source
+
+
+ Images can also be generated from source. TikZ works well, and Asymptote.
+ They can be placed in a sidebyside, and inside a figure (or both).
+
+
+
+ Common formatting macros for TikZ and Asymptote (which you expect to use repeatedly)
+ can be placed in docinfo, using latex-image-preamble
+ and asymptote-preamble, respectively.
+
+
+
+ Note that 3D Asymptote images will be rendered in WebGL, and will be interactive within your slide.
+
+
+
+
Two cone images borrowed from the Sample Article. The one on the left is written in TiZ, and the one on the right is written in Asymptote