Marc WäckerlinandClaude Opus 5 adc58e19d7 One LaTeX design for a company, in three templates
A company that writes with LaTeX ends up with a document class, a letter class
and a presentation theme that share a design and not a line of code. Every fix
is then made three times, two of them late and the third never.

Here the page is written once. A company declares its colours, faces and logo in
one file, and the document template, the letter class and the presentation theme
read that one file. Nothing in the suite carries a colour value, a font name or
a file name of any company, which is what lets it be published while the
companies stay private.

Every measure of the page follows from a measurement or from a named definition:
the room the head and the foot need is taken from the boxes they really build,
one line of the body text stands between the head and the text and between the
text and the foot, a heading never stands alone at the foot of a page, a picture
takes the size of the family, and a Markdown file reaches the same page as the
same document written in LaTeX.

The suite ships with a company that does not exist, Nordwind AG, so that it
builds and is measured anywhere: three colours, the TeX Gyre families every
installation carries, and an icon drawn in TikZ.

574 checks over five measurements, all of them on the rendered page or on the
build log rather than on the source.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-22 15:06:07 +02:00

Business Suite

Business Suite provides shared LaTeX templates for reports, letters and Beamer presentations. A single company package defines the corporate identity—colours, fonts, logo and contact details—and all templates use that configuration.

The suite contains no company-specific colour values, font names or asset paths. Corporate identities therefore remain private while the reusable templates can be published and tested independently.

Components

Component Purpose
business-identity.sty Defines colours, fonts, logos and shared commands
business-suite.sty Formats reports and other standard LaTeX documents
business-brief.cls Provides business letters based on g-brief2
business-beamer.sty Provides the shared Beamer presentation design
md2pdf.py Converts Markdown to a branded PDF through Pandoc and XeLaTeX

Requirements

  • A LaTeX installation with XeLaTeX
  • Pandoc and Python 3 for Markdown conversion
  • Inkscape when a document contains SVG images

Company-specific fonts and packages must also be available to XeLaTeX.

Quick Start

Install the Suite

Link the suite and converter into the local TeX and executable trees. Symbolic links keep the installation aligned with the working copy.

mkdir -p ~/texmf/tex/latex ~/bin
ln -s ~/git/mrw/business-suite/texmf/tex/latex/business-suite \
  ~/texmf/tex/latex/business-suite
ln -s ~/git/mrw/business-suite/bin/md2pdf.py ~/bin/md2pdf.py

Install a company identity in the same way:

ln -s ~/git/nordwind/latex ~/texmf/tex/latex/nordwind

For builds that must not depend on the local installation, set TEXINPUTS to the source tree. The npm scripts in this repository do this automatically.

Create a Company Identity

Each company has one package, such as nordwind.sty. It defines the palette, maps colours to semantic roles, configures the fonts and registers the logo before loading the document template.

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{nordwind}[2026/09/21 Nordwind AG corporate identity]

\RequirePackage{business-identity}

\definecolor{nordwind-deep}{HTML}{14425C}
\definecolor{nordwind-sea}{HTML}{3E8EA8}

\businesscolours{
  brand          = nordwind-deep,
  title          = nordwind-deep,
  titlemeta      = nordwind-deep!60,
  text           = black,
  running-strong = nordwind-deep,
  running-quiet  = nordwind-deep!55,
  folio          = nordwind-deep!55,
  caption        = nordwind-deep!70,
  rowrule        = nordwind-deep!25,
  heading-bg     = nordwind-deep,
  heading-fg     = white,
  border         = nordwind-sea,
  thick-border   = nordwind-deep,
  black-border   = black,
}

\setmainfont{TeX Gyre Pagella}
\setsansfont{TeX Gyre Heros}
\setmonofont{TeX Gyre Cursor}[Scale=MatchLowercase]

\businessfonts{
  default   = rm,
  symbols   = DejaVu Sans,
  smallcaps = false,
}

\businessidentity{
  name      = Nordwind,
  url       = https\://nordwind.example,
  address   = https\://nordwind.example,
  lockup    = icon+text,
  icon      = nordwind-icon,
}

\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{business-suite}}
\ProcessOptions\relax
\RequirePackage{business-suite}

\endinput

Create a Document

Load the company package instead of the generic template:

\documentclass[a4paper,10pt]{article}
\usepackage{nordwind}

\title{Annual Report}
\author{Erika Muster}
\date{\today}

\begin{document}
\maketitle

\section{Current Position}
Dolor sit amet.

\end{document}

The template automatically applies the corporate logo, page header, footer, title block, heading rules, table widths, image sizing, PDF outline and PDF metadata.

Convert Markdown

md2pdf.py --identity nordwind report.md

The equivalent npm command is:

npm run md2pdf -- --identity nordwind report.md

To provide a company-specific command, add a wrapper to the PATH:

#!/bin/sh
exec md2pdf.py --identity nordwind "$@"

Corporate Identity

Colour Roles

Company packages define concrete colours and assign them to semantic roles. Templates use only these roles.

Role Usage
brand Logo and primary accents
text Body text
title Document title
titlemeta Author and date
running-strong First line of the running header
running-quiet Second line of the running header
folio Page number
caption Image captions
rowrule Table row separators
success, fail Status marks
heading-bg, heading-fg Heading bands and presentation bars
border, thick-border, black-border Document frames

A role can reference a palette colour directly or use an xcolor mixture such as nordwind-deep!50!black. The success and fail roles default to green and red and do not have to be part of the company palette.

Font Settings

The company package loads and configures fontspec; \businessfonts tells the templates how to use the configured families.

Key Meaning
default Default document family: rm or sf
emphasis Face used for emphasis; defaults to bold when omitted
symbols Fallback family for missing symbols
smallcaps Set to false if the selected font has no small capitals
microtype Set to false to disable microtypography
protrusion Set to true to allow punctuation to extend into the margin

The font encoding remains associated with the selected family. This prevents a class that preselects a family using T1 encoding from silently falling back to Computer Modern.

Logo Configuration

The identity can reference an image file or a drawing command:

\businessidentity{logo = company-logo}
\businessidentity{icon code = \companydrawing}

Image filenames omit the extension. The suite checks PDF, EPS, PNG and JPEG in that order. Convert SVG logos before the build.

A drawing command receives the requested height and must produce a box of exactly that height. TikZ drawings should freeze their bounding box with \pgfresetboundingbox and an explicit \path[use as bounding box]. The selected logo colour is available as \businesslogocolour.

The lockup setting defines the logo structure:

  • banner: the asset already contains the icon and company name.
  • icon+text: the suite places the company name beside the icon.

With a banner lockup, the tagline appears below the complete banner and aligns with its right edge.

Tagline

Add a second line below the company name with tagline:

\businessidentity{
  name    = Nordwind,
  tagline = Vernunft und Freiheit,
}

The following optional keys change the default appearance:

\businessidentity{
  name face     = {\bfseries},
  tagline face  = {\mdseries},
  tagline color = business-running-quiet,
}

The name is 80% of the requested logo height. The tagline is set to the size at which it is exactly as wide as the name above it, so both lines share one left edge and one right edge whatever the sentence says. The gap between them is 20% of the name size and taglinegap changes it.

The icon takes the height of the text block beside it and keeps the proportions of its own drawing. A mark with a height of its own matches the text at one type size and at no other.

Each measured size has a key that overrides it:

Key Overrides
taglinefactor the tagline size, as a share of the name instead of its width
iconheight the icon height, instead of the height of the text block
iconwidth the icon width; the height follows from the drawing

Never give both icon sizes at once: two fixed sizes distort the mark. A width also reaches a drawn icon, not only an image file. The suite sets the icon once, measures its width and scales the height by the ratio.

Templates request the tagline where sufficient space is available. Logos in running text remain on one line unless tagline is explicitly requested.

Shared Commands

Logos

\logo
\logo[height=2cm]
\logo[address]
\logo[icon]
\logo[text]
\logo[nolink]
\logo[color=business-text]
\logo[tagline]
\logo[tagline,address]

Use \businesslogo where another package owns \logo; Beamer, for example, uses \logo to set the presentation logo.

By default, logos are 1.25 em high in running text and 2 em high in template headers. The company name is 80% of the logo height. Gaps beside the icon and above the address are 10% of the logo height. Each value can be overridden.

The address line is scaled to the exact width of the logo or lockup above it. The icon is vertically centred beside the name while the name retains the surrounding text baseline.

Status Marks

\success and \fail render white status symbols on green and red backgrounds. The Unicode characters ✅, ❌, ✓, ✗, ✔ and ✘ map to the same marks, which allows Markdown sources to use them directly.

Other common symbols—including arrows, information signs, warnings, stars and checkboxes—use the active text font when available and the configured symbol family otherwise. Unsupported characters are omitted without adding a gap or log message.

Images

Use \businessgraphic for template-controlled image sizing:

\businessgraphic{diagram}
\businessgraphic[width=4cm]{diagram}

Default sizing depends on orientation:

  • Portrait images use up to the full line width and half the text height.
  • Landscape images use up to the full line width and the free height remaining on the page.
  • Images retain their aspect ratio and are centred.
  • If an image would leave no more than 25% of a page empty, it moves to the next page. Otherwise, it is reduced to fit the current page.
  • Vector graphics may use the full calculated size. Raster images are enlarged by at most a factor of two.
Option Default Meaning
portraitwidth 1 Maximum share of the line width for portrait images
portraitheight 0.5 Maximum share of the text height for portrait images
landscapewidth 1 Maximum share of the line width for landscape images
landscapeheight 1 Maximum share of the remaining page height
pictureempty 0.25 Maximum empty page share before an image is reduced
picturezoom 2 Maximum enlargement factor for raster images

Markdown conversion applies these rules automatically.

The outer footer shows the current page and total page count. Add optional content to the inner footer in the preamble:

\businessfootleft{\includegraphics[height=2em]{product}}

The footer may contain a product logo, classification or series name. Its reserved height is measured from the rendered content. Define it before \begin{document} because page geometry cannot be recalculated afterwards.

Columns

businesscolumns creates equal-width columns. Their widths follow from the current line width, and the gap between columns equals one body-text line.

\begin{businesscolumns}[3]
  \businesscell{First}
  \businesscell{Second}
  \businesscell{Third}
\end{businesscolumns}

Use \businessuse{<name>} to include a reusable block from the TeX tree, such as a sender block or terms page.

Tables

Use standard LaTeX table environments with the shared table commands:

\begin{tabular}{lr}
  \toprule
  \businesstablehead{Figure} & \businesstablehead{Value} \\
  \midrule
  Turnover & 4.2 million \\ \businessrowrule
  People & 31 \\
  \bottomrule
\end{tabular}
  • \businesstablehead{...} formats a header cell.
  • \businessrowrule draws the separator between rows.

Keep an introductory sentence with the following table or list using:

\businessleadin[2]
The annual figures:
\businesstogether

The optional argument specifies the number of lines occupied by the introduction. The default is six. The Markdown converter inserts both commands where required.

Document Layout

The first page shows the corporate logo and address. Subsequent pages use two running-header lines and display the current and total page count in the footer.

The suite measures the actual header and footer content. It leaves one body-text line between the header and text area and the same distance between the text area and footer. The headsep option changes the upper distance; the lower distance is derived from it.

Page Composition

The first text line begins at the upper edge of the text block. Paragraph spacing may stretch by up to half a line so that pages end on a consistent baseline. The pagestretch option controls this flexibility.

Headings remain attached to their following content. Tables and images use the current line width and available page height instead of fixed dimensions from a particular company design.

Business Letters

business-brief.cls extends g-brief2 with the corporate identity and shared logo handling. Create a company-specific class:

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{nordwind-brief}[2026/09/21]

\DeclareOption*{\PassOptionsToClass{\CurrentOption}{business-brief}}
\ProcessOptions\relax
\LoadClass{business-brief}
\RequirePackage[plain]{nordwind}

\RetourAdresse{Nordwind~AG~-~Hafenstrasse~4~-~8000~Zürich}
\NameZeileA{Nordwind AG}
\NameZeileB{Hafenstrasse 4}
\NameZeileC{CH~--~8000 Zürich}
\InternetZeileA{https\://nordwind.example}
\InternetZeileB{post\@nordwind.example}
\BankZeileA{CH00 0000 0000 0000 0000 0}
\Gruss{Mit freundlichen Grüssen}{2em}

\endinput

The class preserves the existing g-brief2 field names. It adds:

Command Purpose
\Unterschriftsbild{<file>}{<name>} Inserts a printed signature instead of reserving space for a handwritten one
\businessnowindow Removes the envelope window, folding marks and return line, then reduces the address field to the current address height
\businesslogoheight Sets the header logo height, capped at the available 20 mm

The first page places the logo and address above the sender block. Later pages place the page number and date on the left and the logo on the right.

Example:

\documentclass[english]{nordwind-brief}

\Datum{\today}
\Adresse{Ms\\Erika Muster\\Beispielweg 7\\8001 Zurich}
\Betreff{Our offer for the harbour}
\Anrede{Dear Ms Muster}
\Unterschrift{Hans Beispiel\\Managing Director}

\begin{document}
\begin{g-brief}
We are pleased to send you our offer.
\end{g-brief}
\end{document}

Presentations

Create a two-line company theme:

% beamerthemenordwind.sty
\RequirePackage[plain]{nordwind}
\RequirePackage{business-beamer}

Load it from a presentation with \usetheme{nordwind}:

\documentclass[12pt]{beamer}
\usetheme{nordwind}

\title{The Harbour}
\author{Hans Beispiel}
\date{\today}

\begin{document}
\begin{frame}[plain]
  \titlepage
\end{frame}

\section{Current Position}

\begin{frame}
  \frametitle{Project Status}
  \begin{itemize}
    \item \success{} Permission granted
    \item \fail{} Funding open
  \end{itemize}
\end{frame}
\end{document}

The theme uses Beamer's sidebar outer theme. Configure it with Beamer's standard width, height, left, right, hideothersubsections and hideallsubsections options.

Business Suite adds:

Option Effect
titleprefix Adds content before every frame title
canvas=brand Uses the brand colour as the slide background
nosectionframe Disables the opening frame for each section

Markdown Converter

md2pdf.py passes the selected identity and document template to Pandoc, then builds the generated LaTeX with XeLaTeX.

Option Default Effect
--identity <name> Required Selects the company identity package
--out-dir <dir> Source directory Sets the PDF output directory
--lang <tag> auto Controls hyphenation; auto detects the language unless the document defines lang:
--paper <name> a4paper Sets the paper format
--fontsize <pt> 10pt Sets the document font size
--toc Off Adds a table of contents
--highlight Off Enables Pandoc syntax highlighting in code blocks
--keep-tex Off Retains the generated LaTeX and build files

Use $E = mc^2$ for inline formulas and $$...$$ for display formulas. The converter joins multi-line formulas before Pandoc parses them and reports this correction. This avoids Markdown interpreting a line containing only = as a level-one heading underline.

Development

npm run build   # Build all examples
npm test        # Run all measurement tests
npm run clean   # Remove generated files

The examples in examples/ use nordwind.sty, a fictional company identity built from portable TeX Gyre fonts. The dedicated name avoids collisions with existing TeX Live packages.

Additional project documentation:

Design Decisions

No Company Data

Reusable templates contain no company-specific colour values, font names or asset paths. Tests scan all template sources and fail when they find such values.

Measure Actual Content

The suite calculates logo height, address width, header and footer space, table-column widths and the space required by connected blocks from the rendered content. Fixed values derived from one font, paper format or company identity do not remain correct for another.

Probe Document

The Pandoc table filter runs before LaTeX exists and therefore cannot directly inspect \linewidth. The converter builds a probe document with the selected company identity, then reads \linewidth and the width of a reference line from that document. This prevents table widths from depending on constants copied from another identity.

Single Definition

Each company value has one authoritative definition in its identity package. The document, letter and presentation templates consume that package instead of copying its values. Tests therefore verify that templates contain no company-specific values, rather than checking whether duplicated values still match.

Shared table commands such as \businessrowrule and \businesstablehead belong to the identity layer because tables can appear in documents, letters and presentations. Loading an identity with the plain option retains these shared commands but omits document geometry and page styles.

Document Language

The template does not set the document language. When Babel is loaded, Hyperref obtains the language from Babel. Setting it again would produce an Option 'pdflang' has already been used warning. Tests verify the resulting language in the document's XMP metadata.

Native Beamer Sidebar

The presentation template uses Beamer's maintained sidebar outer theme instead of carrying a private copy.

Letter Address Field

Window-envelope letters retain the physical 63 mm address field. With \businessnowindow, the field shrinks to the height required by the current recipient address and makes the remaining space available to the letter body.

Licence

MIT, see LICENSE. Use it, change it, sell what you build with it; keep the copyright notice in a copy.

Every source file of the suite carries the notice and the SPDX identifier in its first lines. A LaTeX package is installed file by file: what a company copies into its own tree is business-suite.sty, and the licence file does not travel with it.

S
Description
LaTeX company template suite with configurable font, colour palette, logo. Provides letter, document, presentation, ...
Readme MIT
273 KiB
0 Stars 1 Watchers 0 Forks
Languages
TeX 50.4%
Python 42.3%
Lua 7.3%