Skip to main content

Write scientific articles in Markdown and convert them to journal-ready LaTeX/PDF (Copernicus, Science, AMS, AGU, Nature, Elsevier, PNAS, arXiv, ...)

Project description

texmark

texmark

pypi python tests

Write scientific articles in markdown — and submit them to any journal.

  • Instant preview. Markdown renders live in most editors (VS Code, Cursor, JetBrains, vim) and on GitHub itself, so you see your draft as you type. No more wait-on-pdflatex cycles every time you change a sentence.
  • Git + GitHub as a paper backend. Branches, pull requests, issues, blame, and diffs work the way they were designed to. Collaborators review changes with the same tooling they already use for code.
  • One source, any journal. texmark compiles your markdown to any of the supported LaTeX templates. Start writing first, decide on a target journal later, and switch mid-way (or after rejection) by flipping a single yaml field — no rewriting needed.
  • No lock-in. The intermediate .tex is right there next to the PDF. Unplug texmark whenever you want and continue the manuscript in plain LaTeX — useful for the final polish that journals usually demand.

Installation

pip install texmark

External dependencies

texmark itself is pure Python, but it shells out to a few external tools to produce the final PDF. Install them via your system package manager.

  • pandoc — the markdown → tex engine (the pypandoc PyPI dependency is a wrapper, the binary is not installable via pip).
  • A LaTeX distribution providing pdflatex, bibtex, and latexmk (texmark's default driver) plus the standard package set (hyperref, natbib, amsmath, graphicx, geometry, microtype, booktabs, caption, mathptmx, newtxtext, newtxmath, apacite, draftwatermark, mdframed, tikz, xcolor, appendix, lineno, epstopdf, …). Optionally tectonic as a single-binary alternative (see Build backends).

On Debian / Ubuntu:

sudo apt install pandoc \
    texlive-latex-extra texlive-bibtex-extra \
    texlive-publishers texlive-fonts-extra

…or just texlive-full for the easy answer.

On macOS (Homebrew):

brew install pandoc
brew install --cask mactex     # or basictex + tlmgr install <packages>

A handful of LaTeX packages that aren't in TeX Live's smaller installs (notably trackchanges, algorithm / algorithmicx, jabbrv) are bundled with texmark under texmark/templates/<journal>/ and copied into the build directory automatically, so you don't need to install them separately.

Example

See example.md for a sample markdown file with yaml metadata in the header.

The command to convert the markdow to tex is:

texmark example.md

And to convert to PDF

texmark example.md --pdf

For another journal, it is enough to change the journal -> template' field in the yaml metadata. For testing it is also possible to pass -jfor--journal-template`:

texmark example.md --pdf -j science -o build/example-science.pdf --tex build/example-science.tex

See the example tex and pdf results in build

Build backends and engines

texmark separates the driver (what orchestrates LaTeX passes and bibtex) from the engine (the actual TeX program). Both have sensible defaults and both are configurable from the CLI or YAML.

--backend What it does Honors --engine?
latexmk (default) Reads .aux/.fls/.bbl between passes and reruns only what's stale. Drives bibtex automatically. Typically 2–3× faster on incremental edits than the old fixed 3-pass sequence. yes
raw Runs engine → bibtex → engine → engine unconditionally — the original behaviour. Use when latexmk isn't available. yes
tectonic Standalone Rust rewrite of the TeX stack: engine + driver + bibtex-equivalent in one binary. Auto-fetches missing packages on first run. no — uses its own XeTeX-derived engine

--engine selects the TeX program when the backend honors it:

  • pdflatex (default) — broadest package compatibility, fastest cold start.
  • xelatex — native Unicode + system OpenType fonts (fontspec).
  • lualatex — LuaTeX scripting + modern fontspec.

YAML frontmatter equivalents:

backend: latexmk          # or raw, tectonic
engine: pdflatex          # or xelatex, lualatex

CLI flags win over YAML.

Live preview (--watch)

texmark sources/main.md --pdf --watch

Rebuilds whenever the input markdown, bibliography, or template changes. Combine with an auto-reloading PDF viewer (zathura, evince, okular) for a live-preview workflow — the output PDF is rewritten in place so viewers that follow inode changes keep your scroll position.

Journal templates

Pick the template that matches your target journal and add it to the yaml header of your markdown:

journal:
    template: ametsoc          # template name, see table below
    options: twocol            # optional, per-template — see the docs page
template covers example docs
copernicus (aliases cp, esd, ...) Copernicus / EGU: ACP, BG, CP, ESD, HESS, NHESS, TC, ... PDF docs
science AAAS Science, Science Advances PDF docs
ametsoc (aliases jclim, jas, mwr, bams, ...) AMS: J. Climate, JAS, MWR, BAMS, ... PDF docs
arxiv (alias preprint) arXiv preprint, generic article-class PDF docs
elsarticle (alias elsevier) Elsevier: QSR, EPSL, GPC, Earth-Science Reviews, Cell, Lancet, ... PDF docs
agujournal (aliases agu, jgr, grl, james, wrr, ...) AGU: JGR family, GRL, Earth's Future, JAMES, ... PDF docs
springernature (aliases nature, naturecomms, natclimchange, natgeoscience, scirep) Springer Nature: Nature, Nature Communications, Nature Climate Change, Nature Geoscience, Scientific Reports, ... PDF docs
pnas PNAS PDF docs

Each template ships a default journal.options value chosen to produce a publication-style PDF (typeset 2-column journal look, no draft watermarks). For peer-review submission you usually want to switch to the publisher's submission options (e.g. preprint,12pt for Elsevier, draft for AGU, the empty default for AMS 1.5-spacing). The per-journal docs page lists the alternatives.

Partial support only. Before submitting, you will likely need to hand-edit the final LaTeX — appendix structure, special sections (Methods Online, Extended Data, Significance, …) and journal-specific cross-reference macros are not all wired up automatically. Use the example PDF to confirm the layout looks reasonable, then run texmark --tex out.tex and finish the manuscript in LaTeX directly.

Common yaml fields (all templates)

title: "Paper title"
authors:
  - firstname: Mahé
    lastname: Perrette
    affiliation: 1              # integer index into `affiliations` (most templates)
    email: mahe.perrette@gmail.com
  - firstname: Co
    lastname: Author
    affiliation: 2
affiliations:
  - "Alfred Wegener Institute, ..."
  - "Another Institution"
date: "2026-05-26"
bibliography: references.bib
journal:
    template: <name>            # required: picks the journal template + filters
    options: <str or list>      # optional: class options (per-template default)
collect_figures_and_tables: true       # optional: see section below
figure-width: 80%                      # optional: pandoc figure default
figure-span: full                      # optional: wraps in figure* (full text width)
                                       #   per-figure override: ![cap](https://github.com/perrette/texmark/raw/v0.10.0/img){figure-span=full}
copy_figures: false                    # optional: see "Figure paths" below
figure_folders: [images, ../shared]    # optional: see "Figure paths" below
project_root: .                        # optional: see "Figure paths" below

Section-style metadata can also be given as markdown # ... headings. Any of # Abstract, # Acknowledgments, # Data Availability, # Appendix, # Supplementary Material, # Significance, # Capsule, # Key Points, # Plain Language Summary, # Author Contributions, # Competing Interests, # Materials and Methods, # Funding, # Highlights, # Keywords will be extracted out of the body and injected into the right LaTeX command for the target journal. The exact list each template recognises is in texmark/filters/main.py.

Figure paths

texmark interprets ![](https://github.com/perrette/texmark/raw/v0.10.0/path) URLs by the same rules as GitHub's markdown renderer:

  • No leading slash — relative to the markdown file's directory (the standard markdown spec).
  • Leading slash — relative to the project root. By default the project root is detected via git rev-parse --show-toplevel, run from the markdown's directory so submodules and worktrees resolve to their own root rather than the outer repo's. For non-git projects, the invocation directory (CWD) is used. You can override either by passing --project-root <path> on the CLI (or project_root: <path> in the yaml front-matter).

Once resolved, each URL is rewritten in the generated .tex to be relative to the build directory. The figure files stay where they are on disk; nothing is copied.

If you would rather have short paths in the .tex (e.g. eof.png instead of ../images/eof.png), pass --figure-folders <dir> [<dir> ...] on the CLI (yaml: figure_folders: [<dir>, ...]). Each folder is interpreted relative to the current working directory and feeds LaTeX's \graphicspath. Figures that live under any of these folders get short URLs in the .tex; figures elsewhere keep the relative-to-build-dir form. Folder search order is respected (first match wins, matching pdflatex's own resolution).

For a self-contained build (e.g. to hand the .tex + figures to a journal portal), pass --copy-figures on the CLI (yaml: copy_figures: true). In that mode every referenced figure is copied flat into <build>/figures/:

  • Files keep their basename when unique.
  • When two figures share a basename but have different contents, both are renamed to <stem>-<short-content-hash><ext> for disambiguation.
  • Same file referenced from multiple paths collapses to a single bundled copy.
  • A .texmark-figures manifest in <build>/figures/ records which files texmark wrote, so the next build can delete only files it owns; files you put there by hand are preserved.

--figure-folders is ignored when --copy-figures is set (every figure ends up in <build>/figures/ either way).

Remote (http(s)://) figure URLs are always downloaded into <build>/figures/<hash>/<basename> by the texmark-download-images filter, regardless of these settings.

Collect figures and tables at the end of the document

Just add

collect_figures_and_tables: true

to your markdown yaml metadata.

Advanced: latex template

The templates are written in jinja2.

Just copy from e.g. texmark/templates/science/template.tex to your own, e.g. custom_template.tex And run again with:

texmark example.md --pdf -j science -o build/example-science.pdf --tex build/example-science.tex --template custom_template.tex

The -j journal template option (here science) is still used to set custom filters (e.g. only \cite for Science, no \citet ; extract specific sections as metadata to be injected as {{section}} instead of {{body}} etc). The machinery is defined in texmark/filters.py and can in principle be extended or copied. Two approaches are possible:

  • just add more filters via the --filters command or in the yaml metadata.
  • extend the existing filters in a module, e.g. custom_filter.py, that extends the filters dict from the texmark.filters module (see the source code to check the details). And then pass it via --filters-module custom_filter parameter (or custom_filter in the metadata) to prompt the texmark filter to load that module and make it available via -j your-custom-name. Note that will require you to explicitly pass --template as well. Unless you overwrite an existing filter.

Ackowledgements

This project benefited greatly from AI support to extend the initial list of supported journals and further extend this package capability.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

texmark-0.10.0.tar.gz (395.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

texmark-0.10.0-py3-none-any.whl (394.8 kB view details)

Uploaded Python 3

File details

Details for the file texmark-0.10.0.tar.gz.

File metadata

  • Download URL: texmark-0.10.0.tar.gz
  • Upload date:
  • Size: 395.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for texmark-0.10.0.tar.gz
Algorithm Hash digest
SHA256 046c4672cc06a016113cd962dfaae84533c44ada40c3fa8fc82389ceab1bd54a
MD5 67b595ef18ea8a85e1f27fc32c24b11d
BLAKE2b-256 19e51e787d89b3cb3266dcc9c45f4d26ce854ca19c1ab69077f100962f4ffa2d

See more details on using hashes here.

Provenance

The following attestation bundles were made for texmark-0.10.0.tar.gz:

Publisher: tests.yml on perrette/texmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file texmark-0.10.0-py3-none-any.whl.

File metadata

  • Download URL: texmark-0.10.0-py3-none-any.whl
  • Upload date:
  • Size: 394.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for texmark-0.10.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c929a707561ff6b2d259589cf3b9a3bf049bbf006c973b2aac4d3fb08bf15e75
MD5 5c5c922013bc1e8854ec8a11319a2f36
BLAKE2b-256 f6a2382776e85d795474947a4f1f6dfee8a356259453e673c27c3c88b45b41b5

See more details on using hashes here.

Provenance

The following attestation bundles were made for texmark-0.10.0-py3-none-any.whl:

Publisher: tests.yml on perrette/texmark

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page